kopia lustrzana https://github.com/ge0rg/aprsdroid
Digipeater Cleanup and move
rodzic
b830a12aa1
commit
d19f5b4f6f
|
@ -61,7 +61,7 @@
|
||||||
<string name="service_sm_no_gps">SmartBeaconing™ requires GPS!</string>
|
<string name="service_sm_no_gps">SmartBeaconing™ requires GPS!</string>
|
||||||
<!-- service result codes -->
|
<!-- service result codes -->
|
||||||
<string name="post_error">Error</string>
|
<string name="post_error">Error</string>
|
||||||
<string name="post_incmg">received</string>
|
<string name="post_incmg">Received</string>
|
||||||
<string name="post_info"></string>
|
<string name="post_info"></string>
|
||||||
<string name="post_connecting">Connecting to %1$s:%2$d...</string>
|
<string name="post_connecting">Connecting to %1$s:%2$d...</string>
|
||||||
<string name="post_reconnect">Connection lost. Reconnect in %d seconds...</string>
|
<string name="post_reconnect">Connection lost. Reconnect in %d seconds...</string>
|
||||||
|
|
|
@ -75,10 +75,6 @@ class AprsService extends Service {
|
||||||
|
|
||||||
lazy val prefs = new PrefsWrapper(this)
|
lazy val prefs = new PrefsWrapper(this)
|
||||||
|
|
||||||
lazy val dedupeTime = prefs.getStringInt("p.dedupe", 30) // Fetch NUM_OF_RETRIES from prefs, defaulting to 7 if not found
|
|
||||||
|
|
||||||
lazy val digipeaterpath = prefs.getString("digipeater_path", "WIDE1,WIDE2")
|
|
||||||
|
|
||||||
val handler = new Handler()
|
val handler = new Handler()
|
||||||
|
|
||||||
lazy val db = StorageDatabase.open(this)
|
lazy val db = StorageDatabase.open(this)
|
||||||
|
@ -86,6 +82,7 @@ class AprsService extends Service {
|
||||||
lazy val msgService = new MessageService(this)
|
lazy val msgService = new MessageService(this)
|
||||||
lazy val locSource = LocationSource.instanciateLocation(this, prefs)
|
lazy val locSource = LocationSource.instanciateLocation(this, prefs)
|
||||||
lazy val msgNotifier = msgService.createMessageNotifier()
|
lazy val msgNotifier = msgService.createMessageNotifier()
|
||||||
|
lazy val digipeaterService = new DigipeaterService(prefs, TAG, sendDigipeatedPacket)
|
||||||
|
|
||||||
var poster : AprsBackend = null
|
var poster : AprsBackend = null
|
||||||
|
|
||||||
|
@ -343,16 +340,16 @@ class AprsService extends Service {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
def sendTestPacket(packetString: String): Unit = {
|
def sendDigipeatedPacket(packetString: String): Unit = {
|
||||||
// Parse the incoming string to an APRSPacket object
|
// Parse the incoming string to an APRSPacket object
|
||||||
try {
|
try {
|
||||||
val testPacket = Parser.parse(packetString)
|
val digipeatedPacket = Parser.parse(packetString)
|
||||||
|
|
||||||
// Define additional information to be passed as status postfix
|
// Define additional information to be passed as status postfix
|
||||||
val digistatus = " - Digipeated"
|
val digistatus = "Digipeated"
|
||||||
|
|
||||||
// Send the packet with the additional status postfix
|
// Send the packet with the additional status postfix
|
||||||
sendPacket(testPacket, digistatus)
|
sendPacket(digipeatedPacket, digistatus)
|
||||||
|
|
||||||
Log.d("APRSdroid.Service", s"Successfully sent packet: $packetString")
|
Log.d("APRSdroid.Service", s"Successfully sent packet: $packetString")
|
||||||
} catch {
|
} catch {
|
||||||
|
@ -457,216 +454,7 @@ class AprsService extends Service {
|
||||||
postAddPost(StorageDatabase.Post.TYPE_INCMG, R.string.post_incmg, post)
|
postAddPost(StorageDatabase.Post.TYPE_INCMG, R.string.post_incmg, post)
|
||||||
|
|
||||||
// Process the incoming post
|
// Process the incoming post
|
||||||
processIncomingPost(post)
|
digipeaterService.processIncomingPost(post)
|
||||||
}
|
|
||||||
|
|
||||||
// Map to store recent digipeats with their timestamps
|
|
||||||
val recentDigipeats: mutable.Map[String, Instant] = mutable.Map()
|
|
||||||
|
|
||||||
// Function to add or update the digipeat
|
|
||||||
def storeDigipeat(sourceCall: String, destinationCall: String, payload: String): Unit = {
|
|
||||||
// Unique identifier using source call, destination call, and payload
|
|
||||||
val key = s"$sourceCall>$destinationCall:$payload"
|
|
||||||
recentDigipeats(key) = Instant.now() // Store the current timestamp
|
|
||||||
}
|
|
||||||
|
|
||||||
// Function to filter digipeats that are older than dedupeTime seconds
|
|
||||||
def isDigipeatRecent(sourceCall: String, destinationCall: String, payload: String): Boolean = {
|
|
||||||
// Unique identifier using source call, destination call, and payload
|
|
||||||
val key = s"$sourceCall>$destinationCall:$payload"
|
|
||||||
recentDigipeats.get(key) match {
|
|
||||||
case Some(timestamp) =>
|
|
||||||
// Check if the packet was heard within the last 30 seconds
|
|
||||||
Instant.now().isBefore(timestamp.plusSeconds(dedupeTime))
|
|
||||||
case None =>
|
|
||||||
false // Not found in recent digipeats
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Function to clean up old entries
|
|
||||||
def cleanupOldDigipeats(): Unit = {
|
|
||||||
val now = Instant.now()
|
|
||||||
// Retain only those digipeats that are within the last 30 seconds
|
|
||||||
recentDigipeats.retain { case (_, timestamp) =>
|
|
||||||
now.isBefore(timestamp.plusSeconds(dedupeTime))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def processIncomingPost(post: String) {
|
|
||||||
Log.d(TAG, "POST STRING TEST: " + post) // Log the incoming post for debugging
|
|
||||||
|
|
||||||
// Check if backendName contains "KISS" or "AFSK"
|
|
||||||
if (prefs.getBackendName().contains("KISS") || prefs.getBackendName().contains("AFSK")) {
|
|
||||||
android.util.Log.d("PrefsAct", "Backend contains KISS or AFSK")
|
|
||||||
} else {
|
|
||||||
android.util.Log.d("PrefsAct", "Backend does not contain KISS or AFSK")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
//TODO, Add workaround for unsupported formats.
|
|
||||||
// Attempt to parse the incoming post to an APRSPacket.
|
|
||||||
val packet = try {
|
|
||||||
Parser.parse(post) // Attempt to parse
|
|
||||||
} catch {
|
|
||||||
case e: Exception =>
|
|
||||||
Log.e("Parsing FAILED!", s"Failed to parse packet: $post", e)
|
|
||||||
return // Exit the function if parsing fails
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if both digipeating and regeneration are enabled. Temp fix until re-implementation. Remove later on.
|
|
||||||
if (prefs.isDigipeaterEnabled() && prefs.isRegenerateEnabled()) {
|
|
||||||
Log.d("APRSdroid.Service", "Both Digipeating and Regeneration are enabled; Set Regen to false.")
|
|
||||||
prefs.setBoolean("p.regenerate", false) // Disable regeneration
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// New regen
|
|
||||||
if (!prefs.isDigipeaterEnabled() && prefs.isRegenerateEnabled()) {
|
|
||||||
Log.d("APRSdroid.Service", "Regen enabled")
|
|
||||||
sendTestPacket(packet.toString)
|
|
||||||
return // Exit if both digipeating and regeneration are enabled
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if the digipeating setting is enabled
|
|
||||||
if (!prefs.isDigipeaterEnabled()) {
|
|
||||||
Log.d("APRSdroid.Service", "Digipeating is disabled; skipping processing.")
|
|
||||||
return // Exit if digipeating is not enabled
|
|
||||||
}
|
|
||||||
|
|
||||||
cleanupOldDigipeats() // Clean up old digipeats before processing
|
|
||||||
|
|
||||||
// Try to parse the incoming post to an APRSPacket
|
|
||||||
try {
|
|
||||||
// Now you can access the source call from the packet
|
|
||||||
val callssid = prefs.getCallSsid()
|
|
||||||
val sourceCall = packet.getSourceCall()
|
|
||||||
val destinationCall = packet.getDestinationCall();
|
|
||||||
val lastUsedDigi = packet.getDigiString()
|
|
||||||
val payload = packet.getAprsInformation()
|
|
||||||
|
|
||||||
val payloadString = packet.getAprsInformation().toString() // Ensure payload is a String
|
|
||||||
|
|
||||||
|
|
||||||
// Check if callssid matches sourceCall; if they match, do not digipeat
|
|
||||||
if (callssid == sourceCall) {
|
|
||||||
Log.d("APRSdroid.Service", s"No digipeat: callssid ($callssid) matches source call ($sourceCall).")
|
|
||||||
return // Exit if no digipeating is needed
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if this packet has been digipeated recently
|
|
||||||
if (isDigipeatRecent(sourceCall, destinationCall, payloadString)) {
|
|
||||||
Log.d("APRSdroid.Service", s"Packet from $sourceCall to $destinationCall and $payload has been heard recently, skipping digipeating.")
|
|
||||||
return // Skip processing this packet
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
val (modifiedDigiPath, digipeatOccurred) = processDigiPath(lastUsedDigi, callssid)
|
|
||||||
|
|
||||||
|
|
||||||
Log.d("APRSdroid.Service", s"Source: $sourceCall")
|
|
||||||
Log.d("APRSdroid.Service", s"Destination: $destinationCall")
|
|
||||||
Log.d("APRSdroid.Service", s"Digi: $lastUsedDigi")
|
|
||||||
Log.d("APRSdroid.Service", s"Modified Digi Path: $modifiedDigiPath")
|
|
||||||
|
|
||||||
Log.d("APRSdroid.Service", s"Payload: $payload")
|
|
||||||
|
|
||||||
// Format the string for sending
|
|
||||||
val testPacket = s"$sourceCall>$destinationCall,$modifiedDigiPath:$payload"
|
|
||||||
|
|
||||||
// Optionally, send a test packet with the formatted string only if a digipeat occurred
|
|
||||||
if (digipeatOccurred) {
|
|
||||||
sendTestPacket(testPacket)
|
|
||||||
|
|
||||||
// Store the digipeat to the recent list
|
|
||||||
storeDigipeat(sourceCall, destinationCall, payloadString)
|
|
||||||
|
|
||||||
} else {
|
|
||||||
Log.d("APRSdroid.Service", "No digipeat occurred, not sending a test packet.")
|
|
||||||
}
|
|
||||||
|
|
||||||
} catch {
|
|
||||||
case e: Exception =>
|
|
||||||
Log.e("APRSdroid.Service", s"Failed to parse packet: $post", e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def processDigiPath(lastUsedDigi: String, callssid: String): (String, Boolean) = {
|
|
||||||
// Log the input Digi path
|
|
||||||
Log.d("APRSdroid.Service", s"Original Digi Path: '$lastUsedDigi'")
|
|
||||||
|
|
||||||
// If lastUsedDigi is empty, return it unchanged
|
|
||||||
if (lastUsedDigi.trim.isEmpty) {
|
|
||||||
Log.d("APRSdroid.Service", "LastUsedDigi is empty, returning unchanged.")
|
|
||||||
return (lastUsedDigi, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove leading comma for easier processing
|
|
||||||
val trimmedPath = lastUsedDigi.stripPrefix(",")
|
|
||||||
|
|
||||||
// Split the path into components, avoiding empty strings
|
|
||||||
val pathComponents = trimmedPath.split(",").toList.filter(_.nonEmpty)
|
|
||||||
val digipeaterPaths = digipeaterpath.split(",").toList.filter(_.nonEmpty)
|
|
||||||
|
|
||||||
// Create a new list of components with modifications
|
|
||||||
val (modifiedPath, modified) = pathComponents.foldLeft((List.empty[String], false)) {
|
|
||||||
case ((acc, hasModified), component) =>
|
|
||||||
|
|
||||||
// Check if callssid* is in the path and skip if found
|
|
||||||
if (component == s"$callssid*") {
|
|
||||||
// Skip digipeating if callssid* is found
|
|
||||||
return (lastUsedDigi, false) // Return the original path, do not modify
|
|
||||||
|
|
||||||
} else if (!hasModified && (digipeaterPaths.exists(path => component.split("-")(0) == path) || digipeaterPaths.contains(component) || component == callssid)) {
|
|
||||||
// We need to check if the first unused component matches digipeaterpath
|
|
||||||
if (acc.isEmpty || acc.last.endsWith("*")) {
|
|
||||||
// This is the first unused component
|
|
||||||
component match {
|
|
||||||
|
|
||||||
case w if w.matches(".*-(\\d+)$") =>
|
|
||||||
// Extract the number from the suffix
|
|
||||||
val number = w.split("-").last.toInt
|
|
||||||
// Decrement the number
|
|
||||||
val newNumber = number - 1
|
|
||||||
|
|
||||||
if (newNumber == 0 || w == callssid) {
|
|
||||||
// If the number is decremented to 0, remove the component and insert callssid*
|
|
||||||
(acc :+ s"$callssid*", true)
|
|
||||||
|
|
||||||
} else {
|
|
||||||
// Otherwise, decrement the number and keep the component
|
|
||||||
val newComponent = w.stripSuffix(s"-$number") + s"-$newNumber"
|
|
||||||
(acc :+ s"$callssid*" :+ newComponent, true)
|
|
||||||
}
|
|
||||||
|
|
||||||
case _ =>
|
|
||||||
// Leave unchanged if there's no -N suffix
|
|
||||||
(acc :+ component, hasModified)
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
// If the first unused component doesn't match digipeaterpath, keep unchanged
|
|
||||||
(acc :+ component, hasModified)
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
// Keep the component as it is
|
|
||||||
(acc :+ component, hasModified)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Rebuild the modified path
|
|
||||||
val resultPath = modifiedPath.mkString(",")
|
|
||||||
|
|
||||||
// Log the modified path before returning
|
|
||||||
Log.d("APRSdroid.Service", s"Modified Digi Path: '$resultPath'")
|
|
||||||
|
|
||||||
// If no modification occurred, return the original lastUsedDigi
|
|
||||||
if (resultPath == trimmedPath) {
|
|
||||||
Log.d("APRSdroid.Service", "No modifications were made; returning the original path.")
|
|
||||||
return (lastUsedDigi, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return the modified path with a leading comma
|
|
||||||
(s"$resultPath", true)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def postAbort(post : String) {
|
def postAbort(post : String) {
|
||||||
|
|
|
@ -0,0 +1,219 @@
|
||||||
|
package org.aprsdroid.app
|
||||||
|
import _root_.android.util.Log
|
||||||
|
import scala.collection.mutable
|
||||||
|
import _root_.net.ab0oo.aprs.parser._
|
||||||
|
import java.time.Instant
|
||||||
|
|
||||||
|
class DigipeaterService(prefs: PrefsWrapper, TAG: String, sendDigipeatedPacket: String => Unit) {
|
||||||
|
private val recentDigipeats: mutable.Map[String, Instant] = mutable.Map()
|
||||||
|
|
||||||
|
def dedupeTime: Int = prefs.getStringInt("p.dedupe", 30) // Fetch the latest dedupe time from preferences
|
||||||
|
def digipeaterpath: String = prefs.getString("digipeater_path", "WIDE1,WIDE2") // Fetch digipeater path from preferences
|
||||||
|
|
||||||
|
// Function to add or update the digipeat
|
||||||
|
def storeDigipeat(sourceCall: String, destinationCall: String, payload: String): Unit = {
|
||||||
|
// Unique identifier using source call, destination call, and payload
|
||||||
|
val key = s"$sourceCall>$destinationCall:$payload"
|
||||||
|
recentDigipeats(key) = Instant.now() // Store the current timestamp
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function to filter digipeats that are older than dedupeTime seconds
|
||||||
|
def isDigipeatRecent(sourceCall: String, destinationCall: String, payload: String): Boolean = {
|
||||||
|
// Unique identifier using source call, destination call, and payload
|
||||||
|
val key = s"$sourceCall>$destinationCall:$payload"
|
||||||
|
recentDigipeats.get(key) match {
|
||||||
|
case Some(timestamp) =>
|
||||||
|
// Check if the packet was heard within the last 30 seconds
|
||||||
|
Instant.now().isBefore(timestamp.plusSeconds(dedupeTime))
|
||||||
|
case None =>
|
||||||
|
false // Not found in recent digipeats
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function to clean up old entries
|
||||||
|
def cleanupOldDigipeats(): Unit = {
|
||||||
|
val now = Instant.now()
|
||||||
|
// Retain only those digipeats that are within the last 30 seconds
|
||||||
|
recentDigipeats.retain { case (_, timestamp) =>
|
||||||
|
now.isBefore(timestamp.plusSeconds(dedupeTime))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def processIncomingPost(post: String) {
|
||||||
|
Log.d(TAG, "POST STRING TEST: " + post) // Log the incoming post for debugging
|
||||||
|
|
||||||
|
// Check if backendName contains "KISS" or "AFSK"
|
||||||
|
if (prefs.getBackendName().contains("KISS") || prefs.getBackendName().contains("AFSK")) {
|
||||||
|
android.util.Log.d("PrefsAct", "Backend contains KISS or AFSK")
|
||||||
|
} else {
|
||||||
|
android.util.Log.d("PrefsAct", "Backend does not contain KISS or AFSK")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
//TODO, Add workaround for unsupported formats.
|
||||||
|
// Attempt to parse the incoming post to an APRSPacket.
|
||||||
|
val packet = try {
|
||||||
|
Parser.parse(post) // Attempt to parse
|
||||||
|
} catch {
|
||||||
|
case e: Exception =>
|
||||||
|
Log.e("Parsing FAILED!", s"Failed to parse packet: $post", e)
|
||||||
|
return // Exit the function if parsing fails
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if both digipeating and regeneration are enabled. Temp fix until re-implementation. Remove later on.
|
||||||
|
if (prefs.isDigipeaterEnabled() && prefs.isRegenerateEnabled()) {
|
||||||
|
Log.d("APRSdroid.Service", "Both Digipeating and Regeneration are enabled; Set Regen to false.")
|
||||||
|
prefs.setBoolean("p.regenerate", false) // Disable regeneration
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// New regen
|
||||||
|
if (!prefs.isDigipeaterEnabled() && prefs.isRegenerateEnabled()) {
|
||||||
|
Log.d("APRSdroid.Service", "Regen enabled")
|
||||||
|
sendDigipeatedPacket(packet.toString)
|
||||||
|
return // Exit if both digipeating and regeneration are enabled
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the digipeating setting is enabled
|
||||||
|
if (!prefs.isDigipeaterEnabled()) {
|
||||||
|
Log.d("APRSdroid.Service", "Digipeating is disabled; skipping processing.")
|
||||||
|
return // Exit if digipeating is not enabled
|
||||||
|
}
|
||||||
|
|
||||||
|
cleanupOldDigipeats() // Clean up old digipeats before processing
|
||||||
|
|
||||||
|
// Try to parse the incoming post to an APRSPacket
|
||||||
|
try {
|
||||||
|
// Now you can access the source call from the packet
|
||||||
|
val callssid = prefs.getCallSsid()
|
||||||
|
val sourceCall = packet.getSourceCall()
|
||||||
|
val destinationCall = packet.getDestinationCall();
|
||||||
|
val lastUsedDigi = packet.getDigiString()
|
||||||
|
val payload = packet.getAprsInformation()
|
||||||
|
|
||||||
|
val payloadString = packet.getAprsInformation().toString() // Ensure payload is a String
|
||||||
|
|
||||||
|
|
||||||
|
// Check if callssid matches sourceCall; if they match, do not digipeat
|
||||||
|
if (callssid == sourceCall) {
|
||||||
|
Log.d("APRSdroid.Service", s"No digipeat: callssid ($callssid) matches source call ($sourceCall).")
|
||||||
|
return // Exit if no digipeating is needed
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if this packet has been digipeated recently
|
||||||
|
if (isDigipeatRecent(sourceCall, destinationCall, payloadString)) {
|
||||||
|
Log.d("APRSdroid.Service", s"Packet from $sourceCall to $destinationCall and $payload has been heard recently, skipping digipeating.")
|
||||||
|
return // Skip processing this packet
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
val (modifiedDigiPath, digipeatOccurred) = processDigiPath(lastUsedDigi, callssid)
|
||||||
|
|
||||||
|
|
||||||
|
Log.d("APRSdroid.Service", s"Source: $sourceCall")
|
||||||
|
Log.d("APRSdroid.Service", s"Destination: $destinationCall")
|
||||||
|
Log.d("APRSdroid.Service", s"Digi: $lastUsedDigi")
|
||||||
|
Log.d("APRSdroid.Service", s"Modified Digi Path: $modifiedDigiPath")
|
||||||
|
|
||||||
|
Log.d("APRSdroid.Service", s"Payload: $payload")
|
||||||
|
|
||||||
|
// Format the string for sending
|
||||||
|
val digipeatedPacket = s"$sourceCall>$destinationCall,$modifiedDigiPath:$payload"
|
||||||
|
|
||||||
|
// Optionally, send a test packet with the formatted string only if a digipeat occurred
|
||||||
|
if (digipeatOccurred) {
|
||||||
|
sendDigipeatedPacket(digipeatedPacket)
|
||||||
|
|
||||||
|
// Store the digipeat to the recent list
|
||||||
|
storeDigipeat(sourceCall, destinationCall, payloadString)
|
||||||
|
|
||||||
|
} else {
|
||||||
|
Log.d("APRSdroid.Service", "No digipeat occurred, not sending a test packet.")
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch {
|
||||||
|
case e: Exception =>
|
||||||
|
Log.e("APRSdroid.Service", s"Failed to parse packet: $post", e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def processDigiPath(lastUsedDigi: String, callssid: String): (String, Boolean) = {
|
||||||
|
// Log the input Digi path
|
||||||
|
Log.d("APRSdroid.Service", s"Original Digi Path: '$lastUsedDigi'")
|
||||||
|
|
||||||
|
// If lastUsedDigi is empty, return it unchanged
|
||||||
|
if (lastUsedDigi.trim.isEmpty) {
|
||||||
|
Log.d("APRSdroid.Service", "LastUsedDigi is empty, returning unchanged.")
|
||||||
|
return (lastUsedDigi, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove leading comma for easier processing
|
||||||
|
val trimmedPath = lastUsedDigi.stripPrefix(",")
|
||||||
|
|
||||||
|
// Split the path into components, avoiding empty strings
|
||||||
|
val pathComponents = trimmedPath.split(",").toList.filter(_.nonEmpty)
|
||||||
|
val digipeaterPaths = digipeaterpath.split(",").toList.filter(_.nonEmpty)
|
||||||
|
|
||||||
|
// Create a new list of components with modifications
|
||||||
|
val (modifiedPath, modified) = pathComponents.foldLeft((List.empty[String], false)) {
|
||||||
|
case ((acc, hasModified), component) =>
|
||||||
|
|
||||||
|
// Check if callssid* is in the path and skip if found
|
||||||
|
if (component == s"$callssid*") {
|
||||||
|
// Skip digipeating if callssid* is found
|
||||||
|
return (lastUsedDigi, false) // Return the original path, do not modify
|
||||||
|
|
||||||
|
} else if (!hasModified && (digipeaterPaths.exists(path => component.split("-")(0) == path) || digipeaterPaths.contains(component) || component == callssid)) {
|
||||||
|
// We need to check if the first unused component matches digipeaterpath
|
||||||
|
if (acc.isEmpty || acc.last.endsWith("*")) {
|
||||||
|
// This is the first unused component
|
||||||
|
component match {
|
||||||
|
|
||||||
|
case w if w.matches(".*-(\\d+)$") =>
|
||||||
|
// Extract the number from the suffix
|
||||||
|
val number = w.split("-").last.toInt
|
||||||
|
// Decrement the number
|
||||||
|
val newNumber = number - 1
|
||||||
|
|
||||||
|
if (newNumber == 0 || w == callssid) {
|
||||||
|
// If the number is decremented to 0, remove the component and insert callssid*
|
||||||
|
(acc :+ s"$callssid*", true)
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// Otherwise, decrement the number and keep the component
|
||||||
|
val newComponent = w.stripSuffix(s"-$number") + s"-$newNumber"
|
||||||
|
(acc :+ s"$callssid*" :+ newComponent, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
case _ =>
|
||||||
|
// Leave unchanged if there's no -N suffix
|
||||||
|
(acc :+ component, hasModified)
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// If the first unused component doesn't match digipeaterpath, keep unchanged
|
||||||
|
(acc :+ component, hasModified)
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// Keep the component as it is
|
||||||
|
(acc :+ component, hasModified)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rebuild the modified path
|
||||||
|
val resultPath = modifiedPath.mkString(",")
|
||||||
|
|
||||||
|
// Log the modified path before returning
|
||||||
|
Log.d("APRSdroid.Service", s"Modified Digi Path: '$resultPath'")
|
||||||
|
|
||||||
|
// If no modification occurred, return the original lastUsedDigi
|
||||||
|
if (resultPath == trimmedPath) {
|
||||||
|
Log.d("APRSdroid.Service", "No modifications were made; returning the original path.")
|
||||||
|
return (lastUsedDigi, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the modified path with a leading comma
|
||||||
|
(s"$resultPath", true)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -64,8 +64,8 @@ class MessageService(s : AprsService) {
|
||||||
// Only check for duplicate ACKs if the feature is enabled
|
// Only check for duplicate ACKs if the feature is enabled
|
||||||
if (s.prefs.isAckDupeEnabled) {
|
if (s.prefs.isAckDupeEnabled) {
|
||||||
|
|
||||||
if (lastAckTime.exists(time => (currentTime - time) < lastAckDupeTime)) {
|
if (lastAckTime.exists(time => (currentTime - time) < lastAckDupeTime) || lastAckDupeTime == 0) {
|
||||||
Log.d(TAG, s"Duplicate msg, skipping ack for ${ap.getSourceCall()} messageNumber: $messageNumber")
|
Log.d(TAG, s"Duplicate msg or ack disabled, skipping ack for ${ap.getSourceCall()} messageNumber: $messageNumber")
|
||||||
// Recent ACK exists, skip sending a new ACK
|
// Recent ACK exists, skip sending a new ACK
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
Ładowanie…
Reference in New Issue