diff --git a/codec2talkie/build.gradle b/codec2talkie/build.gradle
index 5515542..558b477 100644
--- a/codec2talkie/build.gradle
+++ b/codec2talkie/build.gradle
@@ -10,8 +10,8 @@ android {
applicationId "com.radio.codec2talkie"
minSdkVersion 23
targetSdkVersion 30
- versionCode 152
- versionName "1.52"
+ versionCode 153
+ versionName "1.53"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
diff --git a/codec2talkie/src/main/java/com/radio/codec2talkie/MainActivity.java b/codec2talkie/src/main/java/com/radio/codec2talkie/MainActivity.java
index f23969e..37adf9a 100644
--- a/codec2talkie/src/main/java/com/radio/codec2talkie/MainActivity.java
+++ b/codec2talkie/src/main/java/com/radio/codec2talkie/MainActivity.java
@@ -491,12 +491,18 @@ public class MainActivity extends AppCompatActivity implements ServiceConnection
status += getString(R.string.voax25_label);
}
+ // Lora aprs text packets
+ boolean textPacketsEnabled = SettingsWrapper.isTextPacketsEnabled(_sharedPreferences);
+ if (textPacketsEnabled) {
+ status += getString(R.string.text_packets_label);
+ }
// Digirepeater
boolean isDigirepeaterEnabled = _sharedPreferences.getBoolean(PreferenceKeys.AX25_DIGIREPEATER_ENABLED, false);
if (isDigirepeaterEnabled) {
status += getString(R.string.digirepeater_label);
}
+ // APRSIS
boolean aprsisEnabled = SettingsWrapper.isAprsIsEnabled(_sharedPreferences);
if (aprsisEnabled) {
status += getString(R.string.aprsis_label);
diff --git a/codec2talkie/src/main/java/com/radio/codec2talkie/protocol/Ax25.java b/codec2talkie/src/main/java/com/radio/codec2talkie/protocol/Ax25.java
index d20a04e..0763685 100644
--- a/codec2talkie/src/main/java/com/radio/codec2talkie/protocol/Ax25.java
+++ b/codec2talkie/src/main/java/com/radio/codec2talkie/protocol/Ax25.java
@@ -15,6 +15,8 @@ import com.radio.codec2talkie.settings.SettingsWrapper;
import com.radio.codec2talkie.transport.Transport;
import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.charset.StandardCharsets;
public class Ax25 implements Protocol {
@@ -26,6 +28,7 @@ public class Ax25 implements Protocol {
private String _digipath;
private boolean _isVoax25Enabled;
private boolean _isDigiRepeaterEnabled;
+ private boolean _useTextPackets;
private ProtocolCallback _parentProtocolCallback;
@@ -44,6 +47,7 @@ public class Ax25 implements Protocol {
// NOTE, may need to pass through sendData/sendAudio
_digipath = sharedPreferences.getString(PreferenceKeys.AX25_DIGIPATH, "").toUpperCase();
_isVoax25Enabled = SettingsWrapper.isVoax25Enabled(sharedPreferences);
+ _useTextPackets = SettingsWrapper.isTextPacketsEnabled(sharedPreferences);
_isDigiRepeaterEnabled = sharedPreferences.getBoolean(PreferenceKeys.AX25_DIGIREPEATER_ENABLED, false);
}
@@ -93,7 +97,7 @@ public class Ax25 implements Protocol {
ax25Packet.digipath = path == null ? _digipath : path;
ax25Packet.isAudio = false;
ax25Packet.rawData = dataPacket;
- byte[] ax25Frame = ax25Packet.toBinary();
+ byte[] ax25Frame = _useTextPackets ? ax25Packet.toTextBinary() : ax25Packet.toBinary();
if (ax25Frame == null) {
Log.e(TAG, "Cannot convert AX.25 data packet to binary");
_parentProtocolCallback.onProtocolTxError();
diff --git a/codec2talkie/src/main/java/com/radio/codec2talkie/protocol/ax25/AX25Packet.java b/codec2talkie/src/main/java/com/radio/codec2talkie/protocol/ax25/AX25Packet.java
index 4905f70..1c2c33d 100644
--- a/codec2talkie/src/main/java/com/radio/codec2talkie/protocol/ax25/AX25Packet.java
+++ b/codec2talkie/src/main/java/com/radio/codec2talkie/protocol/ax25/AX25Packet.java
@@ -2,11 +2,14 @@ package com.radio.codec2talkie.protocol.ax25;
import androidx.annotation.NonNull;
+import com.radio.codec2talkie.protocol.aprs.tools.AprsIsData;
import com.radio.codec2talkie.tools.DebugTools;
import com.radio.codec2talkie.tools.TextTools;
import java.nio.BufferUnderflowException;
import java.nio.ByteBuffer;
+import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
public class AX25Packet {
@@ -28,6 +31,21 @@ public class AX25Packet {
public void fromBinary(byte[] data) {
isValid = false;
if (data == null) return;
+ // lora text packet with 0x3c,0xff,0x01 prefix
+ if (data.length > 3 && data[0] == (byte)0x3c && data[1] == (byte)0xff && data[2] == (byte)0x01) {
+ String rawText = new String(Arrays.copyOfRange(data, 3, data.length), StandardCharsets.US_ASCII);
+ AprsIsData textPacket = AprsIsData.fromString(rawText);
+ if (textPacket != null) {
+ src = textPacket.src;
+ dst = textPacket.dst;
+ digipath = textPacket.rawDigipath;
+ rawData = textPacket.data.getBytes(StandardCharsets.US_ASCII);
+ isAudio = false;
+ isValid = true;
+ return;
+ }
+ }
+ // binary packet
ByteBuffer buffer = ByteBuffer.wrap(data);
try {
// dst
@@ -81,6 +99,18 @@ public class AX25Packet {
}
}
+ public byte[] toTextBinary() {
+ byte[] packetContent = toString().getBytes(StandardCharsets.US_ASCII);
+ // lora aprs prefix 0x3c,0xff,0x01
+ ByteBuffer textPacketBuffer = ByteBuffer.allocateDirect(packetContent.length + 3);
+ textPacketBuffer.put((byte)0x3c).put((byte)0xff).put((byte)0x01);
+ textPacketBuffer.put(packetContent);
+ textPacketBuffer.flip();
+ byte[] ax25Frame = new byte[textPacketBuffer.remaining()];
+ textPacketBuffer.get(ax25Frame);
+ return ax25Frame;
+ }
+
public byte[] toBinary() {
ByteBuffer buffer = ByteBuffer.allocate(MaximumSize);
String[] rptCallsigns = new String[] {};
diff --git a/codec2talkie/src/main/java/com/radio/codec2talkie/settings/PreferenceKeys.java b/codec2talkie/src/main/java/com/radio/codec2talkie/settings/PreferenceKeys.java
index e3b26c3..5e0312d 100644
--- a/codec2talkie/src/main/java/com/radio/codec2talkie/settings/PreferenceKeys.java
+++ b/codec2talkie/src/main/java/com/radio/codec2talkie/settings/PreferenceKeys.java
@@ -67,6 +67,7 @@ public final class PreferenceKeys {
public static String APP_AUDIO_DESTINATION = "app_audio_destination";
public static String AX25_VOAX25_ENABLE = "aprs_voax25_enable";
+ public static String AX25_TEXT_PACKETS_ENABLE = "aprs_text_packets_enable";
public static String AX25_CALLSIGN = "aprs_callsign";
public static String AX25_SSID = "aprs_ssid";
public static String AX25_DIGIPATH = "aprs_digipath";
diff --git a/codec2talkie/src/main/java/com/radio/codec2talkie/settings/SettingsWrapper.java b/codec2talkie/src/main/java/com/radio/codec2talkie/settings/SettingsWrapper.java
index 4229c64..c16a12e 100644
--- a/codec2talkie/src/main/java/com/radio/codec2talkie/settings/SettingsWrapper.java
+++ b/codec2talkie/src/main/java/com/radio/codec2talkie/settings/SettingsWrapper.java
@@ -93,6 +93,10 @@ public class SettingsWrapper {
!isFreeDvSoundModemModulation(sharedPreferences); // no voax25 in freedv
}
+ public static boolean isTextPacketsEnabled(SharedPreferences sharedPreferences) {
+ return sharedPreferences.getBoolean(PreferenceKeys.AX25_TEXT_PACKETS_ENABLE, false);
+ }
+
public static boolean isAprsIsEnabled(SharedPreferences sharedPreferences) {
return sharedPreferences.getBoolean(PreferenceKeys.APRS_IS_ENABLE, false);
}
diff --git a/codec2talkie/src/main/res/values/strings.xml b/codec2talkie/src/main/res/values/strings.xml
index a93ecd5..9059b2b 100644
--- a/codec2talkie/src/main/res/values/strings.xml
+++ b/codec2talkie/src/main/res/values/strings.xml
@@ -232,6 +232,7 @@
Send position
☎
+ 🔔
View log
@@ -366,4 +367,6 @@
Rotate map with compass
Show range circles
Show moving stations
+ Enable text packets
+ Send lora aprs compatible text packets (0x3c,0xff,0x01 prefix)
\ No newline at end of file
diff --git a/codec2talkie/src/main/res/xml/preferences.xml b/codec2talkie/src/main/res/xml/preferences.xml
index 326d95a..f26a660 100644
--- a/codec2talkie/src/main/res/xml/preferences.xml
+++ b/codec2talkie/src/main/res/xml/preferences.xml
@@ -215,6 +215,14 @@
app:defaultValue="true">
+
+
+