Porównaj commity

...

50 Commity

Autor SHA1 Wiadomość Data
NØBOY ef4f2fab92
Merge pull request #92 from N0BOY/Dev
v0.92 release
2024-01-23 23:10:21 -08:00
wangg 84fe2ffdf8 v0.92 release
- Feature: support all FT8 message types, e.g. DXpedition (Hound only), RTTY RU, etc.
- Feature: add QSO mark in waterfall
- Feature: add support to manually set COM port settings

- Enhancement: add support of some ICOM radios
- Enhancement: improvement of SWL QSO logs
- Enhancement: optimization of QSO sequence for callsign with /P or /R

- Bugfix: COM port error message doesn't show in correct language
2024-01-24 02:09:36 -05:00
NØBOY e965043cbd
Merge pull request #77 from N0BOY/Dev
update Yaesu3RigConstant.java
2023-09-18 19:08:28 -07:00
wangg 822a353abe update Yaesu3RigConstant.java
- Bugfix: incorrect mode selected for Yaesu FT-891/991 (DATA-USB)
2023-09-18 22:07:44 -04:00
NØBOY 89500cb162
Merge pull request #74 from N0BOY/Dev
v0.91 release
2023-09-11 22:47:35 -07:00
wangg 48e9c9066c v0.91 release
- Feature: callsign quick lookup in QSO log
- Feature: Simple List Mode to display messages
- Enhancement: add (tr)uSDX audio over CAT (Code contributed by DS1UFX)
- Enhancement: add Xiegu X6100 WiFi mode (cannot TX due to FW 1.1.7 issue)
- Enhancement: add support for Kenwood TS-570D
- Enhancement: add Yaesu FT-891/991 USB-DATA mode

- Bugfix: send 73 instead of RR73, when replying NonStd Call (message type i3 = 4),
- Bugfix: reply timeout or miss 73, when deep decoding is enabled
- Bugfix: generate wrong sender callsign when both parties are using callsign suffix
- Bugfix: auto-reply may lose focus when receiving multiple calls
2023-09-12 01:45:53 -04:00
wangg 069205d44a Rollback and fix MainViewModel.java
- Minor fix based on PR #67 MainViewModel.java
2023-08-18 00:42:28 -04:00
wangg ffed0a8898 Update MainViewModel.java
minor fix to PR #67
2023-08-16 00:53:08 -04:00
NØBOY 68e1c79b6a
Merge pull request #67 from d3m3vilurr/trusdx
Support audio streaming over CAT of (tr)uSDX
2023-08-15 23:18:03 -04:00
Sunguk Lee 1f09f61e8d
TrUSDXRig: Remove dead comments 2023-08-16 00:46:53 +09:00
Sunguk Lee 8bbcc2be6f
TrUSDXRig: Send TX streaming
IDK reason, generated packet was broken.
it send signal in multiple positions.
2023-08-16 00:46:53 +09:00
Sunguk Lee ca08aa3479
TrUSDXRig: Decode RX streaming data 2023-08-16 00:46:53 +09:00
Sunguk Lee 40d4c06a65
TrUSDXRig: Apply resample
still return wrong RX streaming data
2023-08-16 00:46:53 +09:00
Sunguk Lee 262704af00
libs: Add resample
BSD-2-Clause
https://github.com/jackz314/resample
2023-08-16 00:46:51 +09:00
Sunguk Lee 8f5975b107
TrUSDXRig: Receive RX streams
but still spectrum is wrong
2023-08-16 00:46:01 +09:00
Sunguk Lee c731f6e507
TrUSDXRig: Intial resampling RX streaming data 2023-08-16 00:46:01 +09:00
Sunguk Lee 98fc73ba75
TrUSDXRig: Restore CAT processing and call RX streaming data
it doesn't work yet
2023-08-16 00:46:01 +09:00
Sunguk Lee a37a5307f7
CableConnector: Receive wave data via CAT connection 2023-08-16 00:46:01 +09:00
Sunguk Lee ff4db69b61
TrUSDXRig: Reactivate sound when exit the application 2023-08-16 00:46:01 +09:00
Sunguk Lee aecd8f03c5
gradle: Add missing `so` jni files 2023-08-16 00:46:01 +09:00
Sunguk Lee b905f92cf3
TrUSDXRig: Initial work for (tr)uSDX's stream over CAT
Remove unused command
2023-08-16 00:45:58 +09:00
NØBOY 40d3e95e7d
Merge pull request #66 from N0BOY/Dev
Dev -> release v0.90
2023-08-14 22:19:37 -07:00
wangg 824b4bdd00 v0.9 release
- Added QSO log importing WebUI
- Fixed map crash when importing large amount of logs (10k+)
- Optimized database structure to improve log importing speed and stability
- Fixed typo in translation
- Added support for UA3REO Wolf SDR
- Added support for GUOHE PMR-171
2023-08-15 01:18:25 -04:00
wangg d6e50da2e0 file sync 2023-08-15 01:17:41 -04:00
NØBOY ed6847e481
Merge pull request #65 from N0BOY/dev
file sync up
2023-08-14 21:58:19 -07:00
wangg a1e5c8c4eb file sync 2023-08-15 00:49:10 -04:00
NØBOY ded02df37d
Delete ft8CN/app/src/main/java/com/bg7yoz/ft8cn directory 2023-08-14 21:47:59 -07:00
NØBOY 7d046a0a5e
Delete ft8cn/app/src/main/java/com/bg7yoz/ft8cn directory 2023-08-14 21:46:26 -07:00
NØBOY ae6ce5a2c6
Merge pull request #64 from N0BOY/dev
v0.90 release
2023-08-14 21:43:19 -07:00
wangg db5c112690 v0.90 release
- Added QSO log importing WebUI
- Fixed map crash when importing large amount of logs (10k+)
- Optimized database structure to improve log importing speed and stability
- Fixed typo in translation
- Added support for UA3REO Wolf SDR
- Added support for GUOHE PMR-171
2023-08-15 00:42:44 -04:00
NØBOY 0b78e47b4b
Merge pull request #55 from N0BOY/dev
cpp del
2023-07-16 09:59:01 -07:00
wangg 9ad039fae3 cpp del 2023-07-16 12:58:36 -04:00
NØBOY 292430322f
Merge pull request #52 from N0BOY/dev
Create FT8CN软件设计初衷及使用说明0.88版.pdf
2023-07-12 15:29:39 -07:00
wangg cb1d1284c1 Create FT8CN软件设计初衷及使用说明0.88版.pdf 2023-07-12 18:29:13 -04:00
NØBOY 0eae0821d9
Merge pull request #48 from N0BOY/dev
Dev 0.89 -> Release
2023-07-08 22:03:56 -07:00
wangg 65c38571b7 Ver. 0.89
Jul. 08, 2023

- New feature: Deep Decoding. Once enabled, received signal will be processed in multiple passes to retrieve decoding from overlaying signals.
- Improved overall decoding stability
- Fixed a bug that worked zones won't update after log importing
- Fixed TX crackling sounds when using ICOM radios via network mode
- Fixed QSO sequence sometimes stuck at sending RR73 if not received any reply
- Fixed prompt message when downloading QSO log without a valid Wi-Fi connection
2023-07-09 01:02:45 -04:00
wangg f2562bc7ae Create FT8CN快速手册0.88版.pdf 2023-05-02 21:59:22 -04:00
NØBOY 3a6d07f1aa
Merge pull request #39 from N0BOY/dev
update the user manual
2023-05-02 18:52:01 -07:00
wangg cb0d88dc73 update the user manual 2023-05-02 21:51:22 -04:00
NØBOY ceef6e9e76
Update README.md 2023-05-02 07:56:25 -07:00
NØBOY 82b9517316
Merge pull request #36 from N0BOY/dev
Dev - v0.88 patch 2
2023-05-02 07:56:09 -07:00
wangg 42e652f679 Merge branch 'dev' of https://github.com/N0BOY/FT8CN into dev 2023-05-02 10:53:52 -04:00
wangg 92acc33514 v0.88 patch 2
- 修正“通联记录”定位闪退问题

- Fixed crash when checking QSO logs in map view
2023-05-02 10:51:44 -04:00
NØBOY bd295531fb
Hot fix for v0.88 2023-05-01 20:01:02 -07:00
NØBOY 6d099c0f78
Merge pull request #35 from N0BOY/dev
Update README.md
2023-05-01 19:56:24 -07:00
NØBOY a42cc77db1
Merge branch 'release' into dev 2023-05-01 19:56:06 -07:00
wangg d94e5ddcd9 Revert "Merge pull request #33 from N0BOY/dev"
This reverts commit 295ff4d1f2, reversing
changes made to 356f5f90f0.
2023-05-01 22:48:51 -04:00
wangg 03760ab94a Update README.md 2023-05-01 22:42:51 -04:00
NØBOY 295ff4d1f2
Merge pull request #33 from N0BOY/dev
PR for v0.88
2023-05-01 19:38:45 -07:00
wangg 1dfca70dcb Release of v0.88
2023-05-02

- 增加音频输出设置(位深、采样率)
- 增加日志可以按条件查询并导出
- 修改日志查询以时间为降序显示
- 修正SWL QSO记录重复的问题
- 针对各主流浏览器优化后台UI

-----------------------------------------------------------------------------

May. 02, 2023

- Added option for audio output (bit depth, sample rate)
- Added option to query log with conditions
- Changed sorting of logs, sorted by newest date first
- Fixed a problem of duplicated SWL QSOs
- Optimized webUI for web browsers
2023-05-01 22:37:32 -04:00
563 zmienionych plików z 14042 dodań i 4151 usunięć

5
.gitignore vendored 100644
Wyświetl plik

@ -0,0 +1,5 @@
ft8CN/app/.gitignore 2
ft8CN/.gitignore 2
.FT8CN软件设计初衷及使用说明0.88版.pdf.icloud
ft8CN/app/src/main/assets/.nightUSGS4Layer.sqlite.icloud

Plik binarny nie jest wyświetlany.

Plik binarny nie jest wyświetlany.

Wyświetl plik

@ -1,8 +1,67 @@
# FT8CN
Developed by BG7YOZ and hosted by N0BOY
Run FT8 natively on Android
Check [Releases](https://github.com/N0BOY/FT8CN/releases) to download the latest apk file.
(More info coming up soon, check back in a while)
# FT8CN
Developed by BG7YOZ and hosted by N0BOY
Run FT8 natively on Android
Check [Releases](https://github.com/N0BOY/FT8CN/releases) to download the latest apk file.
```
免责声明:
FT8CN旨在研究的目的学习如何对FT8信号进行解码、发射等操作不对使用者操作本APP所产生的后果负责。
在中华人民共和国境内使用FT8CN请遵守《中华人民共和国无线电管理条例》等相关规定。
考虑到手机的性能和续航的限制,对信号的处理采用轻量化的运算,未做深度解码等处理。
如有好的建议或问题可以提交到到”有问题要吐槽“。
Disclaimer
FT8CN aims to learn how to decode, transmit FT8 signal for research purposes, which is not responsible for the consequences caused by the user's operation.
Please comply with local laws and regulations when using FT8CN.
Considering the performance and endurance limitations of the mobile phone, the processing of the signal adopts lightweight operations instead of deep decoding and other processing.
Please click "FAQ" if you have good suggestions or questions .
BG7YOZ
2022-07-01
致敬:
Steve Franke(K9AN)、Bill Somerville(G4WJS)、Joe Taylor(K1JT)提出FT8和FT4协议FT是Franke和Taylor的首字母并在论文《The FT4 and FT8 Communication Protocols》详细介绍了FT4和FT8的设计初衷和在WSJT-X中的具体实现细节成为完成本APP的根本指南。
Karlis Goba(YL3JG)在代码的具体实现上提供了参考。
鸣谢:
BG7YOY在FT8CN开发阶段为我在无线电基本理论上作出指导并为FT8CN设计了图标
BG4IGX在我刚刚入门业余无线电时为我在具体实践上作出指导。抖音上您可以搜到很多他的教学视频
BD7MXN帮助我对部分电台的连接控制做了一些测试并提出改进建议
BH2RSJ帮助我建立了一个FT8CN测试群为测试和后续改进提出了很多宝贵意见
BH7ACO帮助解决了某电台的驱动和相关的配置参数
BG7IKK帮助解决了只支持通过RTS控制PTT发射的电台的测试
BI1NIZ帮助注册账号用于收集问题反馈和FAQ的功能
BD3OOX以及石家庄业余无线电俱乐部FT8CN的呼号地区归属数据提取至JTDX石家庄版使呼号定位可以精确到中国的省级
VR2UPU(BD7MJO)在FT8的开发和使用经验上提供指导并在多语言方面给予帮助
BA2BI在业余无线电的基础知识和通联的日志处理方面上给予帮助和指导
BI3QXJ在对某品牌系列电台的指令集上给予专业性的指导
BG6TQD在对某型号电台的指令集测试上给予帮助
BG5CSS提供某型号电台用于测试
BG7YXN提供某型号电台用于测试
BG7YRB对呼号规则运算提供帮助
BG8KAH提供设备用于测试
BA7LVG、JE6WUD完成日文的翻译校对工作
BG6RI帮助解决日志的信号报告问题
SV1EEX完成希腊文、西班牙文UI的翻译工作
VR2VRC帮助修正历史呼号读取规则
BA7NQ提供设备用于测试
BD7MYM对某型号的电台测试给予指导
NØBOY帮助提供Github源以及翻译工作
BG5JNT帮助修正非标准呼号的识别问题
BH3NEK协助对某型号电台进行测试
BG2ALB协助对某型号电台进行测试
BG6DRU协助对某型号电台进行测试
BG7NQF提供某型号电台的隐藏指令对一些设备做兼容性测试
BH2VSQ协助对某型号电台进行测试
BG7YBW协助对部分功能进行测试
BH1RNN协助对部分功能进行测试
BG7BSM协助对一些BUG进行调试
BH4FTI发现并协助对一些BUG进行调试
BG8BXMM哥为FT8CN的使用做推广抖音和B站上有很多他的教学视频
BG7MFQ为FT8CN的使用做推广帮助测试
BG2EFX提供大数据量的日志用于测试
DS1UFX贡献(tr)uSDX audio over CAT代码
BG8HT提供某型号电台进行测试
UB6LUM帮助解决某型号电台的操作模式设置
```

Plik binarny nie jest wyświetlany.

Plik binarny nie jest wyświetlany.

Plik binarny nie jest wyświetlany.

Plik binarny nie jest wyświetlany.

Wyświetl plik

@ -1,26 +0,0 @@
package com.bg7yoz.ft8cn;
import android.content.Context;
import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
import static org.junit.Assert.*;
/**
* Instrumented test, which will execute on an Android device.
*
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
@RunWith(AndroidJUnit4.class)
public class ExampleInstrumentedTest {
@Test
public void useAppContext() {
// Context of the app under test.
Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
assertEquals("com.bg7yoz.ft8cn", appContext.getPackageName());
}
}

Wyświetl plik

@ -1,75 +0,0 @@
package com.bg7yoz.ft8cn.connector;
import android.content.Context;
import android.util.Log;
import com.bg7yoz.ft8cn.database.ControlMode;
import com.bg7yoz.ft8cn.serialport.util.SerialInputOutputManager;
/**
* 线ConnectorUSBBaseRigConnector
*
* @author BG7YOZ
* @date 2023-03-20
*/
public class CableConnector extends BaseRigConnector {
private static final String TAG="CableConnector";
private final CableSerialPort cableSerialPort;
public CableConnector(Context context,CableSerialPort.SerialPort serialPort, int baudRate
, int controlMode) {
super(controlMode);
cableSerialPort= new CableSerialPort(context,serialPort,baudRate,getOnConnectorStateChanged());
cableSerialPort.ioListener=new SerialInputOutputManager.Listener() {
@Override
public void onNewData(byte[] data) {
if (getOnConnectReceiveData()!=null){
getOnConnectReceiveData().onData(data);
}
}
@Override
public void onRunError(Exception e) {
Log.e(TAG, "CableConnector error: "+e.getMessage() );
getOnConnectorStateChanged().onRunError("与串口失去连接:"+e.getMessage());
}
} ;
//connect();
}
@Override
public synchronized void sendData(byte[] data) {
cableSerialPort.sendData(data);
}
@Override
public void setPttOn(boolean on) {
//只处理RTS和DTR
switch (getControlMode()){
case ControlMode.DTR: cableSerialPort.setDTR_On(on);//打开和关闭DTR
break;
case ControlMode.RTS:cableSerialPort.setRTS_On(on);//打开和关闭RTS
break;
}
}
@Override
public void setPttOn(byte[] command) {
cableSerialPort.sendData(command);//以CAT指令发送PTT
}
@Override
public void connect() {
super.connect();
cableSerialPort.connect();
}
@Override
public void disconnect() {
super.disconnect();
cableSerialPort.disconnect();
}
}

Wyświetl plik

@ -1,112 +0,0 @@
package com.bg7yoz.ft8cn.connector;
/**
* ICom
* IComIntFloat
*
* @author BGY70Z
* @date 2023-03-20
*/
import com.bg7yoz.ft8cn.icom.IComWifiRig;
public class IComWifiConnector extends BaseRigConnector{
private static final String TAG = "IComWifiConnector";
public interface OnWifiDataReceived{
void OnWaveReceived(int bufferLen,float[] buffer);
void OnCivReceived(byte[] data);
}
private IComWifiRig iComWifiRig;
private OnWifiDataReceived onWifiDataReceived;
public IComWifiConnector(int controlMode,IComWifiRig iComWifiRig) {
super(controlMode);
this.iComWifiRig=iComWifiRig;
this.iComWifiRig.setOnIComDataEvents(new IComWifiRig.OnIComDataEvents() {
@Override
public void onReceivedCivData(byte[] data) {
if (getOnConnectReceiveData()!=null){
getOnConnectReceiveData().onData(data);
}
if (onWifiDataReceived!=null) {
onWifiDataReceived.OnCivReceived(data);
}
}
@Override
public void onReceivedWaveData(byte[] data) {//接收音频数据事件把音频数据转换成float格式的。
if (onWifiDataReceived!=null){
float[] waveFloat=new float[data.length/2];
for (int i = 0; i <waveFloat.length ; i++) {
waveFloat[i]=readShortBigEndianData(data,i*2)/32768.0f;
}
onWifiDataReceived.OnWaveReceived(waveFloat.length,waveFloat);
}
}
});
}
@Override
public void sendWaveData(float[] data) {
if (iComWifiRig.opened) {
iComWifiRig.sendWaveData(data);
}
}
@Override
public void connect() {
super.connect();
iComWifiRig.start();
}
@Override
public void disconnect() {
super.disconnect();
iComWifiRig.close();
}
@Override
public void sendData(byte[] data) {
iComWifiRig.sendCivData(data);
}
@Override
public void setPttOn(byte[] command) {
iComWifiRig.sendCivData(command);
}
@Override
public void setPttOn(boolean on) {
if (iComWifiRig.opened){
iComWifiRig.setPttOn(on);
}
}
public OnWifiDataReceived getOnWifiDataReceived() {
return onWifiDataReceived;
}
@Override
public boolean isConnected() {
return iComWifiRig.opened;
}
public void setOnWifiDataReceived(OnWifiDataReceived onDataReceived) {
this.onWifiDataReceived = onDataReceived;
}
/**
* Short
*
* @param data
* @param start
* @return Int16
*/
public static short readShortBigEndianData(byte[] data, int start) {
if (data.length - start < 2) return 0;
return (short) ((short) data[start] & 0xff
| ((short) data[start + 1] & 0xff) << 8);
}
}

Wyświetl plik

@ -1,94 +0,0 @@
package com.bg7yoz.ft8cn.flex;
/**
* flexRadio
* @author BG7YOZ
*/
import android.util.Log;
import java.util.HashMap;
public class FlexMeters extends HashMap<Integer, FlexMeters.FlexMeter> {
private static final String TAG="FlexMeters";
public FlexMeters(String content) {
String[] temp =content.substring(content.indexOf("meter ")+"meter ".length()).split("#");
for (int i = 0; i < temp.length; i++) {
String[] val = temp[i].split("=");
if (val.length == 2) {
if (val[0].contains(".")) {
int index = Integer.parseInt(val[0].substring(0, val[0].indexOf(".")));
FlexMeter meter;
if (this.containsKey(index)){
meter=this.get(index);
}else {
meter=new FlexMeter();
this.put(index,meter);
}
if (val[0].toLowerCase().contains(".src")) {
meter.src = val[1];
}
if (val[0].toLowerCase().contains(".num")) {
meter.num = val[1];
}
if (val[0].toLowerCase().contains(".nam")) {
meter.nam = val[1];
}
if (val[0].toLowerCase().contains(".low")) {
meter.low = val[1];
}
if (val[0].toLowerCase().contains(".hi")) {
meter.hi = val[1];
}
if (val[0].toLowerCase().contains(".desc")) {
meter.desc = val[1];
}
if (val[0].toLowerCase().contains(".unit")) {
meter.unit = val[1];
}
if (val[0].toLowerCase().contains(".fps")) {
meter.fps = val[1];
}
if (val[0].toLowerCase().contains(".peak")) {
meter.peak = val[1];
}
}
}
}
}
public void getAllMeters(){
for (int key:this.keySet()) {
//s.append(String.format("%d->%s\n",key,get(key)));
Log.e(TAG, "getAllMeters: "+String.format("ID:%d FIELDS:%s\n",key,get(key)) );
}
}
public static class FlexMeter {
public String src;
public String num;
public String nam;
public String low;
public String hi;
public String desc;
public String unit;
public String fps;
public String peak;
@Override
public String toString() {
return "{" +
"src='" + src + '\'' +
", num='" + num + '\'' +
", nam='" + nam + '\'' +
", low='" + low + '\'' +
", hi='" + hi + '\'' +
", desc='" + desc + '\'' +
", unit='" + unit + '\'' +
", fps='" + fps + '\'' +
", peak='" + peak + '\'' +
'}';
}
}
}

Wyświetl plik

@ -1,437 +0,0 @@
package com.bg7yoz.ft8cn.flex;
/**
* VITA49
* @author BGY70Z
* @date 2023-03-20
*/
/*
public static intVH_PKT_TYPE(x) ((x & 0xF0000000) >> 28)
public static intVH_C(x) ((x & 0x08000000) >> 26)
public static intVH_T(x) ((x & 0x04000000) >> 25)
public static intVH_TSI(x) ((x & 0x00c00000) >> 21)
public static intVH_TSF(x) ((x & 0x00300000) >> 19)
public static intVH_PKT_CNT(x) ((x & 0x000f0000) >> 16)
public static intVH_PKT_SIZE(x) (x & 0x0000ffff)
*/
// Enumerates for field values
import android.annotation.SuppressLint;
import android.util.Log;
import java.nio.ByteBuffer;
import java.text.SimpleDateFormat;
import java.util.Date;
enum VitaPacketType {
IF_DATA,//IF Data packet without Stream Identifier
IF_DATA_WITH_STREAM,//IF Data packet with Stream Identifier
EXT_DATA,//Extension Data packet without Stream Identifier
EXT_DATA_WITH_STREAM,//Extension Data packet with Stream Identifier
IF_CONTEXT,//IF Context packet(see Section 7)
EXT_CONTEXT//Extension Context packet(see Section 7);
};
//时间戳的类型
//时间戳共有两部分小数部分和整数部分整数部分以秒为分辨率32位 主要传递UTC时间或者 GPS 时间,
//小数部分主要有三种一种是sample-count 以采样周期为最小分辨率一种是real-time以ps为最小单位第三种是以任意选择的时间进行累加得出的前面两种时间戳可以直接与整数部分叠加第三种则不能保证与整数部分保持恒定关系前两种与整数部分叠加来操作的可以在覆盖的时间范围为年
//小数部分的时间戳共有64位小数部分可以在没有整数部分的情况下使用
//所有的时间带来都是在以一个采样数据为该reference-point 时间
enum VitaTSI {
TSI_NONE,//No Integer-seconds Timestamp field included
TSI_UTC,//Coordinated Universal Time(UTC)
TSI_GPS,//GPS time
TSI_OTHER//Other
};
//时间戳小数部分类型
//小数部分主要有三种:
// 一种是sample-count ,以采样周期为最小分辨率,
// 一种是real-time以ps为最小单位
// 第三种是以任意选择的时间进行累加得出的,
// 前面两种时间戳可以直接与整数部分叠加,
// 第三种则不能保证与整数部分保持恒定关系,前两种与整数部分叠加来操作的可以在覆盖的时间范围为年
// 小数部分的时间戳共有64位小数部分可以在没有整数部分的情况下使用
// 所有的时间带来都是在以一个采样数据为该参考点reference-point的时间。
enum VitaTSF {
TSF_NONE,//No Fractional-seconds Timestamp field included. 不包括分数秒时间戳字段
TSF_SAMPLE_COUNT,//Sample Count Timestamp. 样本计数时间戳
TSF_REALTIME,//Real Time(Picoseconds) Timestamp. 实时(皮秒)时间戳
TSF_FREERUN,//Free Running Count Timestamp. 自由运行计数时间戳
};
public class VITA {
private static final String TAG = "VITA";
// 最小有效的VITA包长度
private static final int VITAmin = 28;
public static final int FRS_OUI = 0x12cd;
//public static final int VITA_PORT = 4991;
public static final int FLEX_CLASS_ID = 0x534C;
public static final int FLEX_DAX_AUDIO_CLASS_ID = 0x534C03E3;
public static final int FLEX_DAX_IQ_CLASS_ID = 0x534C00E3;
public static final int FLEX_FFT_CLASS_ID = 0x534C8003;
public static final int FLEX_METER_CLASS_ID = 0x534C8002;
public static final int FLEX_Discovery_stream_ID = 0x800;
public static final int VS_Meter = 0x8002;
public static final int VS_PAN_FFT = 0x8003;
public static final int VS_Waterfall = 0x8004;
public static final int VS_Opus = 0x8005;
public static final int DAX_IQ_24Khz = 0x00e3;
public static final int DAX_IQ_48Khz = 0x00e4;
public static final int DAX_IQ_96Khz = 0x00e5;
public static final int DAX_IQ_192KHz = 0x00e6;
public static final int VS_DAX_Audio = 0x03e3;
public static final int VS_Discovery = 0xffff;
private byte[] buffer;
public VitaPacketType packetType;
public boolean classIdPresent;//指示数据包中是否包含类标识符类ID字段
public boolean trailerPresent;//指示数据包是否包含尾部。
public VitaTSI tsi;//时间戳的类型。
public VitaTSF tsf;//时间戳小数部分类型
public int packetCount;//包计数器可以对连续的IF data packet进行计数这些packet具有相同的Stream Identifier 和packet type。
public int packetSize;//表示有多少32bit数在IF Data packet 里面
//时间戳共有两部分小数部分和整数部分整数部分以秒为分辨率32位小数部分64位。
public long integerTimestamp;//u_int32long是64位的
public long fracTimeStamp;
public long oui;
public int informationClassCode;//无用了用classId代替
public int packetClassCode;//无用了用classId代替
public int classId;//FLEX应该是0x534CFFF是informationClassCode与packetClassCode合并的
public byte[] payload = null;
public long trailer;
public boolean isAvailable = false;//电台对象是否有效。
public boolean streamIdPresent;//是否有流字符
//用来区分不同的 packet stream 。
//stream ID 不是必须的,如果仅有一个数据包在单一数据链路传递的话就可以不用要,
//如果 packet stream想用同一 stream ID 的话那每一个packet都得有
//在系统内部不同的packet stream 之间的 Stream ID是不同的。
//如果要用到 data-context 配对那么IF data packet需要 Stream ID
public long streamId;//流ID32位FLEX应当是0x0800
/*
VITA28VITA
*/
/**
* VITAidcreate stream
*
* @param id streamId
* @param data
* @return vita
*/
public byte[] audioDataToVita(int count,long id, float[] data) {
byte[] result = new byte[data.length*4 + 28];//一个float占用4个字节28字节是包头的长度7个word
//packetType = VitaPacketType.EXT_DATA_WITH_STREAM;
packetType = VitaPacketType.IF_DATA_WITH_STREAM;
classIdPresent = true;
trailerPresent = false;//没有尾巴
tsi = VitaTSI.TSI_NONE;//
// tsi = VitaTSI.TSI_OTHER;//
//tsf = VitaTSF.TSF_SAMPLE_COUNT;//--TODO---查一下这个数字是不是变化
tsf = VitaTSF.TSF_NONE;//--TODO---查一下这个数字是不是变化
//packetCount动态变化
//packetCount=?应该是这个全部音频流的总包数
//packetSize是以word32位4字节为单位
//packetSize值为263居多估计以音频还有其它的长度,263是包含7个word28字节的头长度。
packetSize = (data.length ) + 7;//7个word是VITA的包头
//----以上是Header,32位第一个word-------
streamId = id;//第二个word,此id是电台赋给的。经常是0x40000xx。
oui = 0x00001c2d;//第三个word,FlexRadio Systems OUI
classId = 0x534c0123;//第四个word64位
//classId = 0x534c03e3;//第四个word64位
//integerTimestamp =0;// System.currentTimeMillis() / 1000;//第五个word,时间戳的整数部分,以秒为单位。应该是取当前时间
//fracTimeStamp = 0;//第六七个word,时间戳的小数部分64位此处为0。
//fracTimeStamp = frac;//第六七个word,时间戳的小数部分64位此处为0。
byte temp = 0;
if (classIdPresent) {
temp = 0x08;
}
if (trailerPresent) {
temp |= 0x04;
}
//----HEADER--No.1 word------
// result[0]=0x18;
result[0] = (byte) (packetType.ordinal() << 4);//packetType
result[0] |= temp;//其实就是0011 1000,0x38//CTRR,classIdPresent、trailerPresent、R、R
result[0] |= 0x03c0;//CTRR,classIdPresent、trailerPresent、R、R
result[1]=(byte) 0xd0;
result[1]|=(byte)(count&0xf);//packet count
result[1] = (byte) (tsi.ordinal() << 6);//TSI
result[1] |= (byte) (tsf.ordinal() << 4);//TSF
result[1] |= (byte) (packetCount & 0xff);//packetCount
//packetSize默认263words
result[2] = (byte) ((packetSize >> 8) & 0xff);//packetSize 1高8位
result[3] = (byte) (packetSize & 0xff);//packetSize 2低8位
//-----Stream Identifier--No.2 word----
//streamId=id;//最后两位应当是Dax编号
result[4] = (byte) ((streamId& 0x00ff000000 >> 24) & 0xff);
result[5] = (byte) (((streamId & 0x00ff0000) >> 16) & 0xff);
result[6] = (byte) (((streamId & 0x0000ff00) >> 8) & 0xff);
result[7] = (byte) (streamId & 0x000000ff);
//----OUI--No.3 words----
//OUI = 0x001C2D
result[8] = 0x00;
result[9] = 0x00;
result[10] = 0x1c;
result[11] = 0x2d;
//---Class Identifier--No.4 word----
//class id=0x534c0123
result[12] = 0x53;
result[13] = 0x4c;
result[14] = (byte) 0x01;
result[15] = (byte) 0x23;
//---Timestamp--No.5 word----
//integerTimestamp=0x01020304
// result[16] = (byte) 0x01;
// result[17] = (byte) 0x02;
// result[18] = (byte) 0x03;
// result[19] = (byte) 0x04;
//---FracTimeStamp No.5~6 words----
//fracTimeStamp=0x10200300506070c0
// result[20] = 0x10;
// result[21] = 0x20;
// result[22] = 0x03;
// result[23] = 0x00;
// result[24] = 0x50;
// result[25] = 0x60;
// result[26] = 0x70;
// result[27] = (byte) 0xc0;
// result[20] = (byte) ((fracTimeStamp >> 56) & 0x000000ff);
// result[21] = (byte) ((fracTimeStamp >> 48) & 0x000000ff);
// result[22] = (byte) ((fracTimeStamp >> 40) & 0x000000ff);
// result[23] = (byte) ((fracTimeStamp >> 32) & 0x000000ff);
//
// result[24] = (byte) ((fracTimeStamp >> 24) & 0x000000ff);
// result[25] = (byte) ((fracTimeStamp >> 16) & 0x000000ff);
// result[26] = (byte) ((fracTimeStamp >> 8) & 0x000000ff);
// result[27] = (byte) (fracTimeStamp & 0x000000ff);
for (int i = 0; i < data.length; i++) {
byte[] bytes=ByteBuffer.allocate(4).putFloat(data[i]).array();//float转byte[]
result[i*4+28]= bytes[0];
result[i*4+29]= bytes[1];
result[i*4+30]= bytes[2];
result[i*4+31]= bytes[3];
}
/*
payload+28byte[] result=new byte[data.length+28];
streamIdPresent=true;
streamIdPresent=packetType==VitaPacketType.IF_DATA_WITH_STREAM
||packetType==VitaPacketType.EXT_DATA_WITH_STREAM;
streamId:0x4000008,STREAM_CREATE_DAX_TX
classIdPresent:0x534c03e3,packetSize:263
integerTimestamp=now/1000;
fracTimeStamp=0;
*/
return result;
}
public VITA() {
}
public VITA(byte[] data) {
this.buffer = data;
//如果包的长度太小,或包为空,就退出计算
if (data == null) return;
if (data.length < VITAmin) return;
isAvailable = true;//数据长度达到28个字节说明是有效的。
packetType = VitaPacketType.values()[(data[0] >> 4) & 0x0f];
classIdPresent = (data[0] & 0x8) == 0x8;//指示数据包中是否包含类标识符类ID字段
trailerPresent = (data[0] & 0x4) == 0x4;//指示数据包是否包含尾部。
tsi = VitaTSI.values()[(data[1] >> 6) & 0x3];//如果有时间戳的话指示时间戳的整数部分是啥类型的
tsf = VitaTSF.values()[(data[1] >> 4) & 0x3];
packetCount = data[1] & 0x0f;
packetSize = ((((int) data[2]) & 0x00ff) << 8) | ((int) data[3]) & 0x00ff;
int offset = 4;//定位
//检查是否有流字符
streamIdPresent = packetType == VitaPacketType.IF_DATA_WITH_STREAM
|| packetType == VitaPacketType.EXT_DATA_WITH_STREAM;
if (streamIdPresent) {//是否有流ID,获取流ID32位
streamId = ((((long) data[offset]) & 0x00ff) << 24) | ((((int) data[offset + 1]) & 0x00ff) << 16)
| ((((int) data[offset + 2]) & 0x00ff) << 8) | ((int) data[offset + 3]) & 0x00ff;
offset += 4;
}
if (classIdPresent) {
//只取24位前8位保留
oui = ((((int) data[offset + 1]) & 0x00ff) << 16)
| ((((int) data[offset + 2]) & 0x00ff) << 8) | ((int) data[offset + 3]) & 0x00ff;
informationClassCode = ((((int) data[offset + 4]) & 0x00ff) << 8) | ((int) data[offset + 5]) & 0x00ff;
packetClassCode = ((((int) data[offset + 6]) & 0x00ff) << 8) | ((int) data[offset + 7]) & 0x00ff;
classId = ((((int) data[offset + 4]) & 0x00ff) << 24) | ((((int) data[offset + 5]) & 0x00ff) << 16)
| ((((int) data[offset + 6]) & 0x00ff) << 8) | ((int) data[offset + 7]) & 0x00ff;
offset += 8;
}
//Log.e(TAG, "VITA: "+String.format("id: 0x%x, classIdPresent:0x%x,packetSize:%d",streamId,classId,packetSize) );
//获取时间戳,以秒为单位的时间戳32位。
//时间戳共有两部分小数部分和整数部分整数部分以秒为分辨率32位 主要传递UTC时间或者 GPS 时间,
//小数部分主要有三种一种是sample-count 以采样周期为最小分辨率一种是real-time以ps为最小单位第三种是以任意选择的时间进行累加得出的前面两种时间戳可以直接与整数部分叠加第三种则不能保证与整数部分保持恒定关系前两种与整数部分叠加来操作的可以在覆盖的时间范围为年
//小数部分的时间戳共有64位小数部分可以在没有整数部分的情况下使用
//所有的时间带来都是在以一个采样数据为该reference-point 时间
if (tsi != VitaTSI.TSI_NONE) {//32位,
integerTimestamp = ((((long) data[offset]) & 0x00ff) << 24) | ((((int) data[offset + 1]) & 0x00ff) << 16)
| ((((int) data[offset + 2]) & 0x00ff) << 8) | ((int) data[offset + 3]) & 0x00ff;
offset += 4;
}
//获取时间戳的小数部分64位。
if (tsf != VitaTSF.TSF_NONE) {
fracTimeStamp = ((((long) data[offset]) & 0x00ff) << 56) | ((((long) data[offset + 1]) & 0x00ff) << 48)
| ((((long) data[offset + 2]) & 0x00ff) << 36) | ((int) data[offset + 3]) & 0x00ff
| ((((long) data[offset + 4]) & 0x00ff) << 24) | ((((int) data[offset + 5]) & 0x00ff) << 16)
| ((((int) data[offset + 6]) & 0x00ff) << 8) | ((int) data[offset + 7]) & 0x00ff;
offset += 8;
}
//Log.e(TAG, String.format("VITA: data length:%d,offset:%d",data.length,offset) );
if (offset < data.length) {
payload = new byte[data.length - offset - (trailerPresent ? 2 : 0)];//如果有尾部就减去一个word的位置
System.arraycopy(data, offset, payload, 0, payload.length);
}
if (trailerPresent) {
trailer = ((((int) data[data.length - 2]) & 0x00ff) << 8) | ((int) data[data.length - 1]) & 0x00ff;
}
}
/**
* payloadpayload0
*
* @return payload
*/
public int getPayloadLength() {
if (buffer == null) {
return 0;
} else {
return buffer.length;
}
}
/**
*
*
* @return string
*/
public String showPayload() {
if (payload != null) {
return new String(payload).replace(" ", "\n");
} else {
return "";
}
}
public String showPayloadHex() {
if (payload != null) {
return byteToStr(payload);
} else {
return "";
}
}
/**
* VITA 49
*
* @return string
*/
@SuppressLint("DefaultLocale")
public String showHeadStr() {
return String.format("包类型(packetType): %s\n" +
"包数量(packetCount): %d\n" +
"包大小(packetSize): %d\n" +
"是否有流ID(streamIdPresent): %s\n" +
"流ID(streamId): 0x%X\n" +
"是否有类ID(classIdPresent): %s\n" +
"类ID(classId): 0x%X\n" +
"类高位(informationClassCode): 0x%X\n" +
"类低位(packetClassCode): 0x%X\n" +
"公司标识码(oui): 0x%X\n" +
"时间戳类型(tsi): %s\n" +
"时间戳整数部分(integerTimestamp):%s\n" +
"时间戳小数部分类型(tsf): %s\n" +
"时间戳小数部分值(fracTimeStamp): %d\n" +
"负载长度(payloadLength): %d\n" +
"是否有尾部(trailerPresent): %s\n"
, packetType.toString()
, packetCount
, packetSize
, streamIdPresent ? "是" : "否"
, streamId
, classIdPresent ? "是" : "否"
, classId
, informationClassCode
, packetClassCode
, oui
, tsi.toString()
, timestampToDateStr(integerTimestamp * 1000)
, tsf.toString()
, fracTimeStamp
, (payload == null ? 0 : payload.length)
, trailerPresent ? "是" : "否"
);
}
/**
* VITA 49
*
* @return string
*/
@SuppressLint("DefaultLocale")
@Override
public String toString() {
return String.format("%s负载(payload):\n%s\n"
, showHeadStr()
, (payload == null ? "" : new String(payload))
);
}
public static String timestampToDateStr(Long timestamp) {
//final String DATETIME_CONVENTIONAL_CN = "yyyy-MM-dd HH:mm:ss";
//SimpleDateFormat sdf = new SimpleDateFormat(DATETIME_CONVENTIONAL_CN);
@SuppressLint("SimpleDateFormat")
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String sd = sdf.format(new Date(timestamp)); // 时间戳转换日期
//System.out.println(sd);
return sd;
}
public static String byteToStr(byte[] data) {
StringBuilder s = new StringBuilder();
for (int i = 0; i < data.length; i++) {
s.append(String.format("%02x ", data[i] & 0xff));
}
return s.toString();
}
}

Wyświetl plik

@ -1,5 +0,0 @@
<vector android:height="36dp" android:tint="#B8B8B8"
android:viewportHeight="24" android:viewportWidth="24"
android:width="36dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M6,19c0,1.1 0.9,2 2,2h8c1.1,0 2,-0.9 2,-2L18,7L6,7v12zM8.46,11.88l1.41,-1.41L12,12.59l2.12,-2.12 1.41,1.41L13.41,14l2.12,2.12 -1.41,1.41L12,15.41l-2.12,2.12 -1.41,-1.41L10.59,14l-2.13,-2.12zM15.5,4l-1,-1h-5l-1,1L5,4v2h14L19,4z"/>
</vector>

Wyświetl plik

@ -1,5 +0,0 @@
<vector android:autoMirrored="true" android:height="24dp"
android:tint="#FFFFFF" android:viewportHeight="24"
android:viewportWidth="24" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M7.41,8.59L12,13.17l4.59,-4.58L18,10l-6,6 -6,-6 1.41,-1.41z"/>
</vector>

Wyświetl plik

@ -1,5 +0,0 @@
<vector android:autoMirrored="true" android:height="24dp"
android:tint="#FFFFFF" android:viewportHeight="24"
android:viewportWidth="24" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M7.41,15.41L12,10.83l4.59,4.58L18,14l-6,-6 -6,6z"/>
</vector>

Plik binarny nie jest wyświetlany.

Przed

Szerokość:  |  Wysokość:  |  Rozmiar: 1.5 KiB

Plik binarny nie jest wyświetlany.

Przed

Szerokość:  |  Wysokość:  |  Rozmiar: 6.9 KiB

Plik binarny nie jest wyświetlany.

Przed

Szerokość:  |  Wysokość:  |  Rozmiar: 4.6 KiB

Plik binarny nie jest wyświetlany.

Przed

Szerokość:  |  Wysokość:  |  Rozmiar: 13 KiB

Wyświetl plik

@ -1,5 +0,0 @@
<vector android:autoMirrored="true" android:height="36dp"
android:tint="#B8B8B8" android:viewportHeight="24"
android:viewportWidth="24" android:width="36dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M19,3h-4.18C14.4,1.84 13.3,1 12,1c-1.3,0 -2.4,0.84 -2.82,2L5,3c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2L21,5c0,-1.1 -0.9,-2 -2,-2zM12,3c0.55,0 1,0.45 1,1s-0.45,1 -1,1 -1,-0.45 -1,-1 0.45,-1 1,-1zM14,17L7,17v-2h7v2zM17,13L7,13v-2h10v2zM17,9L7,9L7,7h10v2z"/>
</vector>

Wyświetl plik

@ -1,5 +0,0 @@
<vector android:autoMirrored="true" android:height="36dp"
android:tint="#B8B8B8" android:viewportHeight="24"
android:viewportWidth="24" android:width="36dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M19,3h-4.18C14.4,1.84 13.3,1 12,1c-1.3,0 -2.4,0.84 -2.82,2L5,3c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2L21,5c0,-1.1 -0.9,-2 -2,-2zM12,3c0.55,0 1,0.45 1,1s-0.45,1 -1,1 -1,-0.45 -1,-1 0.45,-1 1,-1zM12,7c1.66,0 3,1.34 3,3s-1.34,3 -3,3 -3,-1.34 -3,-3 1.34,-3 3,-3zM18,19L6,19v-1.4c0,-2 4,-3.1 6,-3.1s6,1.1 6,3.1L18,19z"/>
</vector>

Wyświetl plik

@ -1,6 +0,0 @@
<vector android:autoMirrored="true" android:height="36dp" android:tint="#5A5A5A"
android:viewportHeight="24"
android:viewportWidth="24" android:width="36dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillAlpha="0.8" android:fillColor="@android:color/white" android:pathData="M4,9c-1.1,0 -2,0.9 -2,2v2c0,1.1 0.9,2 2,2h1v4h2v-4h1l5,3L13,6L8,9L4,9zM15.5,12c0,-1.33 -0.58,-2.53 -1.5,-3.35v6.69c0.92,-0.81 1.5,-2.01 1.5,-3.34z"/>
<!-- <path android:fillAlpha="1" android:fillColor="@android:color/white" android:pathData="M 7 4 L 7 20 L 9 20 L 9 4 L 7 4 M 17 4 L 15 4 L 15 20 L 17 20 L 17 4"/>-->
</vector>

Wyświetl plik

@ -1,5 +0,0 @@
<vector android:height="48dp" android:tint="#B8B8B8"
android:viewportHeight="24" android:viewportWidth="24"
android:width="48dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M9,16.17L4.83,12l-1.42,1.41L9,19 21,7l-1.41,-1.41z"/>
</vector>

Wyświetl plik

@ -1,5 +0,0 @@
<vector android:autoMirrored="true" android:height="32dp"
android:tint="#B8B8B8" android:viewportHeight="24"
android:viewportWidth="24" android:width="32dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M19,6.41L17.59,5 12,10.59 6.41,5 5,6.41 10.59,12 5,17.59 6.41,19 12,13.41 17.59,19 19,17.59 13.41,12z"/>
</vector>

Wyświetl plik

@ -1,5 +0,0 @@
<vector android:autoMirrored="true" android:height="24dp"
android:tint="#B8B8B8" android:viewportHeight="24"
android:viewportWidth="24" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M12,1c-4.97,0 -9,4.03 -9,9v7c0,1.66 1.34,3 3,3h3v-8H5v-2c0,-3.87 3.13,-7 7,-7s7,3.13 7,7v2h-4v8h4v1h-7v2h6c1.66,0 3,-1.34 3,-3V10c0,-4.97 -4.03,-9 -9,-9z"/>
</vector>

Wyświetl plik

@ -1,5 +0,0 @@
<vector android:autoMirrored="true" android:height="36dp"
android:tint="#B8B8B8" android:viewportHeight="24"
android:viewportWidth="24" android:width="36dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M3.9,12c0,-1.71 1.39,-3.1 3.1,-3.1h4L11,7L7,7c-2.76,0 -5,2.24 -5,5s2.24,5 5,5h4v-1.9L7,15.1c-1.71,0 -3.1,-1.39 -3.1,-3.1zM8,13h8v-2L8,11v2zM17,7h-4v1.9h4c1.71,0 3.1,1.39 3.1,3.1s-1.39,3.1 -3.1,3.1h-4L13,17h4c2.76,0 5,-2.24 5,-5s-2.24,-5 -5,-5z"/>
</vector>

Wyświetl plik

@ -1,5 +0,0 @@
<vector android:autoMirrored="true" android:height="36dp"
android:tint="#B8B8B8" android:viewportHeight="24"
android:viewportWidth="24" android:width="36dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M19,5v14L5,19L5,5h14m1.1,-2L3.9,3c-0.5,0 -0.9,0.4 -0.9,0.9v16.2c0,0.4 0.4,0.9 0.9,0.9h16.2c0.4,0 0.9,-0.5 0.9,-0.9L21,3.9c0,-0.5 -0.5,-0.9 -0.9,-0.9zM11,7h6v2h-6L11,7zM11,11h6v2h-6v-2zM11,15h6v2h-6zM7,7h2v2L7,9zM7,11h2v2L7,13zM7,15h2v2L7,17z"/>
</vector>

Wyświetl plik

@ -1,5 +0,0 @@
<vector android:autoMirrored="true" android:height="32dp"
android:tint="#CB89F4" android:viewportHeight="24"
android:viewportWidth="24" android:width="32dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M12,2C8.14,2 5,5.14 5,9c0,5.25 7,13 7,13s7,-7.75 7,-13c0,-3.86 -3.14,-7 -7,-7zM12.88,15.75h-1.75L11.13,14h1.75v1.75zM12.88,12.88h-1.75c0,-2.84 2.62,-2.62 2.62,-4.38 0,-0.96 -0.79,-1.75 -1.75,-1.75s-1.75,0.79 -1.75,1.75L8.5,8.5C8.5,6.57 10.07,5 12,5s3.5,1.57 3.5,3.5c0,2.19 -2.62,2.41 -2.62,4.38z"/>
</vector>

Wyświetl plik

@ -1,5 +0,0 @@
<vector android:autoMirrored="true" android:height="36dp"
android:tint="#B8B8B8" android:viewportHeight="24"
android:viewportWidth="24" android:width="36dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M19,12v7L5,19v-7L3,12v7c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2v-7h-2zM13,12.67l2.59,-2.58L17,11.5l-5,5 -5,-5 1.41,-1.41L11,12.67L11,3h2z"/>
</vector>

Wyświetl plik

@ -1,5 +0,0 @@
<vector android:height="36dp" android:tint="#B8B8B8"
android:viewportHeight="24" android:viewportWidth="24"
android:width="36dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M4,9c-1.1,0 -2,0.9 -2,2v2c0,1.1 0.9,2 2,2h1v4h2v-4h1l5,3L13,6L8,9L4,9zM15.5,12c0,-1.33 -0.58,-2.53 -1.5,-3.35v6.69c0.92,-0.81 1.5,-2.01 1.5,-3.34z"/>
</vector>

Plik binarny nie jest wyświetlany.

Przed

Szerokość:  |  Wysokość:  |  Rozmiar: 2.8 KiB

Plik binarny nie jest wyświetlany.

Przed

Szerokość:  |  Wysokość:  |  Rozmiar: 759 B

Wyświetl plik

@ -1,17 +0,0 @@
package com.bg7yoz.ft8cn;
import static org.junit.Assert.assertEquals;
import org.junit.Test;
/**
* Example local unit test, which will execute on the development machine (host).
*
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
public class ExampleUnitTest {
@Test
public void addition_isCorrect() {
assertEquals(4, 2 + 2);
}
}

0
ft8CN/.gitignore → ft8cn/.gitignore vendored 100755 → 100644
Wyświetl plik

Wyświetl plik

Wyświetl plik

Wyświetl plik

@ -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>

Wyświetl plik

@ -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>

0
ft8CN/app/.gitignore → ft8cn/app/.gitignore vendored 100755 → 100644
Wyświetl plik

Wyświetl plik

@ -5,7 +5,7 @@ plugins {
id 'com.android.application'
}
def currentTime = getCurrentTime();
def currentTime = getCurrentTime()
static def getCurrentTime() {
DateFormat df = new SimpleDateFormat("yyyy-MM-dd")
@ -22,9 +22,9 @@ android {
minSdk 23
targetSdk 33
versionCode 1
versionName '0.87'
versionName '0.92'
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
//testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
dataBinding{
enabled true
}
@ -35,14 +35,6 @@ android {
}
}
ndk{
abiFilters 'armeabi-v7a','arm64-v8a','x86','x86_64'
}
sourceSets{
main{
jniLibs.srcDirs=['libs']
}
}
signingConfig signingConfigs.debug
}
@ -56,11 +48,6 @@ android {
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
buildConfigField("String", "apkBuildTime", "\"${currentTime}\"")
// true -
//minifyEnabled true
// true -
//shrinkResources true
}
}
compileOptions {
@ -73,30 +60,33 @@ android {
// version '3.18.1'
// }
// }
sourceSets {
main {
jniLibs.srcDirs = ['libs']
}
}
namespace 'com.bg7yoz.ft8cn'
}
dependencies {
implementation 'androidx.appcompat:appcompat:1.4.1'
implementation 'com.google.android.material:material:1.5.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.3'
implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.4.1'
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.4.1'
implementation 'androidx.appcompat:appcompat:1.6.1'
implementation 'com.google.android.material:material:1.8.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
implementation 'androidx.lifecycle:lifecycle-livedata:2.5.1'
implementation 'androidx.lifecycle:lifecycle-viewmodel:2.5.1'
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
implementation 'androidx.navigation:navigation-fragment:2.4.1'
implementation 'androidx.navigation:navigation-ui:2.4.1'
implementation 'com.google.android.gms:play-services-maps:18.0.2'
implementation 'androidx.navigation:navigation-fragment:2.5.3'
implementation 'androidx.navigation:navigation-ui:2.5.3'
implementation 'com.google.android.gms:play-services-maps:18.1.0'
// implementation 'com.google.code.gson:gson:2.7'
implementation 'commons-net:commons-net:3.6'//
implementation 'com.google.guava:guava:31.1-jre'//HashTablekeyHashMap
//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/commons-net-3.6.jar')////
implementation files('src/libs/nanohttpd-2.2.0.jar')
implementation files('src/libs/osmdroid-android-6.1.14.aar')//
}

Plik binarny nie jest wyświetlany.

Plik binarny nie jest wyświetlany.

Plik binarny nie jest wyświetlany.

Plik binarny nie jest wyświetlany.

Plik binarny nie jest wyświetlany.

Wyświetl plik

@ -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"

Wyświetl plik

@ -17,6 +17,10 @@ import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.CompoundButton;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.Observer;
import com.bg7yoz.ft8cn.FAQActivity;
import com.bg7yoz.ft8cn.Ft8Message;
import com.bg7yoz.ft8cn.GeneralVariables;
@ -34,10 +38,6 @@ import com.bg7yoz.ft8cn.timer.UtcTimer;
import java.io.IOException;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.Observer;
/**
* A simple {@link Fragment} subclass.
* create an instance of this fragment.
@ -280,6 +280,18 @@ public class ConfigFragment extends Fragment {
//设置电台名称,参数列表
setRigNameSpinner();
//设置解码模式
setDecodeMode();
//设置音频输出的位数
setAudioOutputBitsMode();
//设置音频输出采样率
setAudioOutputRateMode();
//设置显示消息模式
setMessageMode();
//设置控制模式 VOX CAT
setControlMode();
@ -762,6 +774,112 @@ public class ConfigFragment extends Fragment {
}
private void setDecodeMode() {
binding.decodeModeRadioGroup.clearCheck();
binding.fastDecodeRadioButton.setChecked(!GeneralVariables.deepDecodeMode);
binding.deepDecodeRadioButton.setChecked(GeneralVariables.deepDecodeMode);
View.OnClickListener listener = new View.OnClickListener() {
@Override
public void onClick(View view) {
int buttonId = binding.decodeModeRadioGroup.getCheckedRadioButtonId();
GeneralVariables.deepDecodeMode= buttonId ==binding.deepDecodeRadioButton.getId();
writeConfig("deepMode", GeneralVariables.deepDecodeMode? "1" : "0");
}
};
binding.fastDecodeRadioButton.setOnClickListener(listener);
binding.deepDecodeRadioButton.setOnClickListener(listener);
}
/**
*
*/
private void setAudioOutputBitsMode() {
//binding.controlModeRadioGroup.setOnCheckedChangeListener(null);
binding.audioBitsRadioGroup.clearCheck();
binding.audio32BitsRadioButton.setChecked(GeneralVariables.audioOutput32Bit);
binding.audio16BitsRadioButton.setChecked(!GeneralVariables.audioOutput32Bit);
View.OnClickListener listener = new View.OnClickListener() {
@Override
public void onClick(View view) {
int buttonId = binding.audioBitsRadioGroup.getCheckedRadioButtonId();
GeneralVariables.audioOutput32Bit= buttonId ==binding.audio32BitsRadioButton.getId();
writeConfig("audioBits", GeneralVariables.audioOutput32Bit? "1" : "0");
}
};
binding.audio32BitsRadioButton.setOnClickListener(listener);
binding.audio16BitsRadioButton.setOnClickListener(listener);
}
/**
*
*/
private void setAudioOutputRateMode() {
binding.audioRateRadioGroup.clearCheck();
binding.audio12kRadioButton.setChecked(GeneralVariables.audioSampleRate==12000);
binding.audio24kRadioButton.setChecked(GeneralVariables.audioSampleRate==24000);
binding.audio48kRadioButton.setChecked(GeneralVariables.audioSampleRate==48000);
View.OnClickListener listener = new View.OnClickListener() {
@Override
public void onClick(View view) {
if (binding.audio12kRadioButton.isChecked()) GeneralVariables.audioSampleRate=12000;
if (binding.audio24kRadioButton.isChecked()) GeneralVariables.audioSampleRate=24000;
if (binding.audio48kRadioButton.isChecked()) GeneralVariables.audioSampleRate=48000;
writeConfig("audioRate", String.valueOf(GeneralVariables.audioSampleRate));
}
};
binding.audio12kRadioButton.setOnClickListener(listener);
binding.audio24kRadioButton.setOnClickListener(listener);
binding.audio48kRadioButton.setOnClickListener(listener);
}
/**
*
*/
private void setMessageMode() {
binding.messageModeRadioGroup.clearCheck();
if (GeneralVariables.simpleCallItemMode){
binding.msgSimpleRadioButton.setChecked(true);
}else {
binding.msgStandardRadioButton.setChecked(true);
}
View.OnClickListener listener = new View.OnClickListener() {
@Override
public void onClick(View view) {
int buttonId = binding.messageModeRadioGroup.getCheckedRadioButtonId();
GeneralVariables.simpleCallItemMode=
binding.messageModeRadioGroup.getCheckedRadioButtonId()
==binding.msgSimpleRadioButton.getId();
writeConfig("msgMode", GeneralVariables.simpleCallItemMode?"1":"0");
}
};
binding.msgStandardRadioButton.setOnClickListener(listener);
binding.msgSimpleRadioButton.setOnClickListener(listener);
}
/**
* VOX CAT
*/
@ -867,7 +985,9 @@ public class ConfigFragment extends Fragment {
//打开网络电台列表对话框
if (GeneralVariables.instructionSet== InstructionSet.FLEX_NETWORK) {
new SelectFlexRadioDialog(requireContext(), mainViewModel).show();
}else if(GeneralVariables.instructionSet== InstructionSet.ICOM) {
}else if(GeneralVariables.instructionSet== InstructionSet.ICOM
||GeneralVariables.instructionSet== InstructionSet.XIEGU_6100
||GeneralVariables.instructionSet== InstructionSet.XIEGUG90S) {
new LoginIcomRadioDialog(requireContext(), mainViewModel).show();
}else {
ToastMessage.show(GeneralVariables.getStringFromResource(R.string.only_flex_supported));
@ -897,68 +1017,66 @@ public class ConfigFragment extends Fragment {
binding.callsignHelpImageButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (GeneralVariables.isChina) {
new HelpDialog(requireContext(), requireActivity(), "callsign.txt", true).show();
} else {
new HelpDialog(requireContext(), requireActivity(), "callsign_en.txt", true).show();
}
new HelpDialog(requireContext(), requireActivity()
, GeneralVariables.getStringFromResource(R.string.callsign_help)
, true).show();
}
});
//梅登海德网格的帮助
binding.maidenGridImageButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (GeneralVariables.isChina) {
new HelpDialog(requireContext(), requireActivity(), "maidenhead.txt", true).show();
} else {
new HelpDialog(requireContext(), requireActivity(), "maidenhead_en.txt", true).show();
}
new HelpDialog(requireContext(), requireActivity()
, GeneralVariables.getStringFromResource(R.string.maidenhead_help)
, true).show();
}
});
//发射频率的帮助
binding.frequencyImageButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (GeneralVariables.isChina) {
new HelpDialog(requireContext(), requireActivity(), "frequency.txt", true).show();
} else {
new HelpDialog(requireContext(), requireActivity(), "frequency_en.txt", true).show();
}
new HelpDialog(requireContext(), requireActivity()
, GeneralVariables.getStringFromResource(R.string.frequency_help)
, true).show();
}
});
//延迟发射帮助
binding.transDelayImageButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (GeneralVariables.isChina) {
new HelpDialog(requireContext(), requireActivity(), "transDelay.txt", true).show();
} else {
new HelpDialog(requireContext(), requireActivity(), "transDelay_en.txt", true).show();
}
new HelpDialog(requireContext(), requireActivity()
, GeneralVariables.getStringFromResource(R.string.transDelay_help)
, true).show();
}
});
//时间偏移帮助
binding.timeOffsetImageButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (GeneralVariables.isChina) {
new HelpDialog(requireContext(), requireActivity(), "timeoffset.txt", true).show();
} else {
new HelpDialog(requireContext(), requireActivity(), "timeoffset_en.txt", true).show();
}
new HelpDialog(requireContext(), requireActivity()
, GeneralVariables.getStringFromResource(R.string.timeoffset_help)
, true).show();
}
});
//PTT延时帮助
binding.pttDelayImageButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (GeneralVariables.isChina) {
new HelpDialog(requireContext(), requireActivity(), "pttdelay.txt", true).show();
} else {
new HelpDialog(requireContext(), requireActivity(), "pttdelay_en.txt", true).show();
}
new HelpDialog(requireContext(), requireActivity()
, GeneralVariables.getStringFromResource(R.string.pttdelay_help)
, true).show();
}
});
//显示列表方式
binding.messageModeeHelpImageButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
new HelpDialog(requireContext(),requireActivity()
,GeneralVariables.getStringFromResource(R.string.message_mode_help)
,true).show();
}
});
//设置ABOUT
binding.aboutButton.setOnClickListener(new View.OnClickListener() {
@Override
@ -970,110 +1088,110 @@ public class ConfigFragment extends Fragment {
binding.operationHelpImageButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (GeneralVariables.isChina) {
new HelpDialog(requireContext(), requireActivity(), "operationBand.txt", true).show();
} else {
new HelpDialog(requireContext(), requireActivity(), "operationBand_en.txt", true).show();
}
new HelpDialog(requireContext(), requireActivity()
, GeneralVariables.getStringFromResource(R.string.operationBand_help)
, true).show();
}
});
//设置操作模式
binding.controlModeHelpImageButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (GeneralVariables.isChina) {
new HelpDialog(requireContext(), requireActivity(), "controlMode.txt", true).show();
} else {
new HelpDialog(requireContext(), requireActivity(), "controlMode_en.txt", true).show();
}
new HelpDialog(requireContext(), requireActivity()
, GeneralVariables.getStringFromResource(R.string.controlMode_help)
, true).show();
}
});
//设置CI-V地址和波特率帮助
binding.baudRateHelpImageButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (GeneralVariables.isChina) {
new HelpDialog(requireContext(), requireActivity(), "civ_help.txt", true).show();
} else {
new HelpDialog(requireContext(), requireActivity(), "civ_help_en.txt", true).show();
}
new HelpDialog(requireContext(), requireActivity()
, GeneralVariables.getStringFromResource(R.string.civ_help)
, true).show();
}
});
//电台型号列表
binding.rigNameHelpImageButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (GeneralVariables.isChina) {
new HelpDialog(requireContext(), requireActivity(), "rig_model_help.txt", true).show();
} else {
new HelpDialog(requireContext(), requireActivity(), "rig_model_help_en.txt", true).show();
}
new HelpDialog(requireContext(), requireActivity()
, GeneralVariables.getStringFromResource(R.string.rig_model_help)
, true).show();
}
});
//发射监管
binding.launchSupervisionImageButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (GeneralVariables.isChina) {
new HelpDialog(requireContext(), requireActivity(), "launch_supervision_help.txt", true).show();
} else {
new HelpDialog(requireContext(), requireActivity(), "launch_supervision_en.txt", true).show();
}
new HelpDialog(requireContext(), requireActivity()
, GeneralVariables.getStringFromResource(R.string.launch_supervision_help)
, true).show();
}
});
//无回应次数
binding.noResponseCountButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (GeneralVariables.isChina) {
new HelpDialog(requireContext(), requireActivity(), "no_response_help.txt", true).show();
} else {
new HelpDialog(requireContext(), requireActivity(), "no_response_help_en.txt", true).show();
}
new HelpDialog(requireContext(), requireActivity()
, GeneralVariables.getStringFromResource(R.string.no_response_help)
, true).show();
}
});
//自动呼叫
binding.autoFollowCountButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (GeneralVariables.isChina) {
new HelpDialog(requireContext(), requireActivity(), "auto_follow_help.txt", true).show();
} else {
new HelpDialog(requireContext(), requireActivity(), "auto_follow_help_en.txt", true).show();
}
new HelpDialog(requireContext(), requireActivity()
, GeneralVariables.getStringFromResource(R.string.auto_follow_help)
, true).show();
}
});
//连接模式
binding.connectModeHelpImageButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (GeneralVariables.isChina) {
new HelpDialog(requireContext(), requireActivity(), "connectMode.txt", true).show();
} else {
new HelpDialog(requireContext(), requireActivity(), "connectMode_en.txt", true).show();
}
new HelpDialog(requireContext(), requireActivity()
, GeneralVariables.getStringFromResource(R.string.connectMode_help)
, true).show();
}
});
//排除选项
binding.excludedHelpButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (GeneralVariables.isChina) {
new HelpDialog(requireContext(), requireActivity(), "excludeCallsign.txt", true).show();
} else {
new HelpDialog(requireContext(), requireActivity(), "excludeCallsign_en.txt", true).show();
}
new HelpDialog(requireContext(), requireActivity()
, GeneralVariables.getStringFromResource(R.string.excludeCallsign_help)
, true).show();
}
});
binding.swlHelpButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (GeneralVariables.isChina) {
new HelpDialog(requireContext(), requireActivity(), "swlMode.txt", true).show();
} else {
new HelpDialog(requireContext(), requireActivity(), "swlMode_en.txt", true).show();
}
new HelpDialog(requireContext(), requireActivity()
, GeneralVariables.getStringFromResource(R.string.swlMode_help)
, true).show();
}
});
//解码模式
binding.decodeModeHelpButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
new HelpDialog(requireContext(),requireActivity()
,GeneralVariables.getStringFromResource(R.string.deep_mode_help)
,true).show();
}
});
//音频输出帮助
binding.audioOutputImageButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
new HelpDialog(requireContext(), requireActivity()
, GeneralVariables.getStringFromResource(R.string.audio_output_help)
, true).show();
}
});
@ -1081,11 +1199,9 @@ public class ConfigFragment extends Fragment {
binding.clearCacheHelpButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (GeneralVariables.isChina) {
new HelpDialog(requireContext(), requireActivity(), "clear_cache_data.txt", true).show();
} else {
new HelpDialog(requireContext(), requireActivity(), "clear_cache_data_en.txt", true).show();
}
new HelpDialog(requireContext(), requireActivity()
, GeneralVariables.getStringFromResource(R.string.clear_cache_data_help)
, true).show();
}
});
binding.clearFollowButton.setOnClickListener(new View.OnClickListener() {

Wyświetl plik

@ -0,0 +1,5 @@
关于音频输出设置
采样位深也称采样精度FT8CN只有16位整型和32位浮点可选。采样位数是表示声音强度量化后的精细程度它的数值越大波动幅度的分辨率也就越高所发出声音的能力越强。
采样率:也称取样频率, 指每秒钟取得声音样本的次数。采样频率越高,声音的质量也就越好,但占的资源也多。

Wyświetl plik

@ -0,0 +1,5 @@
Audio Output Setting
Bit depth: Choose 16-bit int or 32-bit float. Bit depth dictates the number of possible amplitude values of audio sample. A higher bit depth will produce a higher resolution audio.
Sample rate: Sample rate refers to the number of samples that are present within one second of digital audio. Higher sample rate provides more accurate audio waveform, but consume more system resources.

Wyświetl plik

@ -0,0 +1,4 @@
关于解码模式
快速解码沿用原来FT8CN的解码对接收到的音频做一次性的解码。
多次解码:在快速解码的基础上,再做多次的解码,增加迭代的次数,并尝试解码频率有叠加的信号。
注:多次解码增加的运算量,总的解码时间会变长,会缩短设备的续航时间。

Wyświetl plik

@ -0,0 +1,4 @@
Decode mode:
Fast decode: Default mode, one decoding pass on received audio.
Deep decode: Recursive decoding that process received audio in multiple passes .
* Note: Deep decoding requires longer decoding time and more battery consumption.

Wyświetl plik

@ -0,0 +1,3 @@
消息模式,是指显示消息列表的方式。
标准列表模式就是FT8CN传统的FT8消息显示模式包含FT8消息的要素外还包括双方呼号归属地、距离、未通联的分区标志、消息类型等。
精简列表模式就是简化的FT8消息显示模式只包含必要的FT8消息。

Wyświetl plik

@ -0,0 +1,5 @@
"Message mode" refers to how messages are displayed.
Standard list mode is the default FT8 display mode. In addition to FT8 messages, it includes callsign, location, distance, worked zone indicator, message type, etc.
Simple list mode is a simplified FT8 message display mode that contains only essential FT8 messages.

Some files were not shown because too many files have changed in this diff Show More