Got TX/RX working with aioax25+direwolf over TCP

This patch gets APRSD fully working with the TCPKISS socket
to direwolf.
This commit is contained in:
Hemna 2021-09-01 14:48:22 -04:00
parent 54c9a6b55a
commit f4dee4b202
6 changed files with 41 additions and 148 deletions

View File

@ -1,7 +1,6 @@
import asyncio
import logging
from aioax25 import frame as axframe
from aioax25 import interface
from aioax25 import kiss as kiss
from aioax25.aprs import APRSInterface
@ -38,7 +37,7 @@ class KISSClient:
return True
if "tcp" in config["kiss"]:
if config["kiss"]["serial"].get("enabled", False):
if config["kiss"]["tcp"].get("enabled", False):
return True
@property
@ -88,14 +87,15 @@ class Aioax25Client:
):
LOG.debug(
"Setting up KISSTCP Connection to {}:{}".format(
self.config["kiss"]["host"],
self.config["kiss"]["port"],
self.config["kiss"]["tcp"]["host"],
self.config["kiss"]["tcp"]["port"],
),
)
self.kissdev = kiss.TCPKISSDevice(
self.config["kiss"]["host"],
self.config["kiss"]["port"],
self.config["kiss"]["tcp"]["host"],
self.config["kiss"]["tcp"]["port"],
loop=self.loop,
log=LOG,
)
self.kissdev.open()
@ -107,7 +107,7 @@ class Aioax25Client:
LOG.debug("Creating APRSInterface")
self.aprsint = APRSInterface(
ax25int=self.ax25int,
mycall=self.config["ham"]["callsign"],
mycall=self.config["kiss"]["callsign"],
log=LOG,
)
@ -119,20 +119,17 @@ class Aioax25Client:
def consumer(self, callback, callsign=None):
if not callsign:
callsign = self.config["ham"]["callsign"]
self.aprsint.bind(callback=callback, callsign=callsign, regex=True)
self.aprsint.bind(callback=callback, callsign="WB4BOR", ssid=12, regex=False)
def send(self, msg):
"""Send an APRS Message object."""
payload = msg._filter_for_send()
frame = axframe.AX25UnnumberedInformationFrame(
msg.tocall,
msg.fromcall.encode("UTF-8"),
pid=0xF0,
repeaters=b"WIDE2-1",
payload=payload,
payload = f"{msg._filter_for_send()}"
self.aprsint.send_message(
addressee=msg.tocall,
message=payload,
path=["WIDE1-1", "WIDE2-1"],
oneshot=True,
)
LOG.debug(frame)
self.ax25int.transmit(frame)
def get_client():

View File

@ -469,6 +469,12 @@ def server(
cl.client
except LoginError:
sys.exit(-1)
rx_thread = threads.APRSDRXThread(
msg_queues=threads.msg_queues,
config=config,
)
rx_thread.start()
else:
LOG.info(
"APRS network connection Not Enabled in config. This is"
@ -486,13 +492,6 @@ def server(
packets.PacketList(config=config)
rx_thread = threads.APRSDRXThread(
msg_queues=threads.msg_queues,
config=config,
)
rx_thread.start()
if "watch_list" in config["aprsd"] and config["aprsd"]["watch_list"].get(
"enabled",
True,

View File

@ -489,6 +489,9 @@ class AckMessage(Message):
self.id,
)
def _filter_for_send(self):
return f"ack{self.id}"
def send(self):
LOG.debug(f"Send ACK({self.tocall}:{self.id}) to radio.")
thread = SendAckThread(self)

View File

@ -8,9 +8,7 @@ import tracemalloc
import aprslib
from aprsd import (
client, kissclient, messaging, packets, plugin, stats, trace, utils,
)
from aprsd import client, kissclient, messaging, packets, plugin, stats, utils
LOG = logging.getLogger("APRSD")
@ -182,9 +180,10 @@ class APRSDRXThread(APRSDThread):
class APRSDProcessPacketThread(APRSDThread):
def __init__(self, packet, config):
def __init__(self, packet, config, transport="aprsis"):
self.packet = packet
self.config = config
self.transport = transport
name = self.packet["raw"][:10]
super().__init__(f"RX_PACKET-{name}")
@ -239,6 +238,7 @@ class APRSDProcessPacketThread(APRSDThread):
self.config["aprs"]["login"],
fromcall,
msg_id=msg_id,
transport=self.transport,
)
ack.send()
@ -257,6 +257,7 @@ class APRSDProcessPacketThread(APRSDThread):
self.config["aprs"]["login"],
fromcall,
subreply,
transport=self.transport,
)
msg.send()
@ -273,6 +274,7 @@ class APRSDProcessPacketThread(APRSDThread):
self.config["aprs"]["login"],
fromcall,
reply,
transport=self.transport,
)
msg.send()
@ -285,6 +287,7 @@ class APRSDProcessPacketThread(APRSDThread):
self.config["aprs"]["login"],
fromcall,
reply,
transport=self.transport,
)
msg.send()
except Exception as ex:
@ -296,6 +299,7 @@ class APRSDProcessPacketThread(APRSDThread):
self.config["aprs"]["login"],
fromcall,
reply,
transport=self.transport,
)
msg.send()
@ -349,7 +353,7 @@ class KISSRXThread(APRSDThread):
# and the aprslib developer didn't want to allow a PR to add
# kwargs. :(
# https://github.com/rossengeorgiev/aprs-python/pull/56
kiss_client.consumer(self.process_packet, callsign="APN382")
kiss_client.consumer(self.process_packet, callsign=self.config["kiss"]["callsign"])
kiss_client.loop.run_forever()
except aprslib.exceptions.ConnectionDrop:
@ -361,131 +365,21 @@ class KISSRXThread(APRSDThread):
client.Client().reset()
# Continue to loop
@trace.trace
def process_packet(self, interface, frame, match):
def process_packet(self, interface, frame):
"""Process a packet recieved from aprs-is server."""
LOG.debug(f"Got an APRS Frame '{frame}'")
# try and nuke the * from the fromcall sign.
frame.header._source._ch = False
payload = str(frame.payload.decode())
msg = f"{str(frame.header)}:{payload}"
LOG.debug(f"Decoding {msg}")
packet = aprslib.parse(msg)
LOG.debug(packet)
try:
stats.APRSDStats().msgs_rx_inc()
msg = packet.get("message_text", None)
msg_format = packet.get("format", None)
msg_response = packet.get("response", None)
if msg_format == "message" and msg:
# we want to send the message through the
# plugins
self.process_message_packet(packet)
return
elif msg_response == "ack":
self.process_ack_packet(packet)
return
if msg_format == "mic-e":
# process a mic-e packet
self.process_mic_e_packet(packet)
return
except (aprslib.ParseError, aprslib.UnknownFormat) as exp:
LOG.exception("Failed to parse packet from aprs-is", exp)
@trace.trace
def process_message_packet(self, packet):
LOG.debug("Message packet rx")
fromcall = packet["from"]
message = packet.get("message_text", None)
msg_id = packet.get("msgNo", "0")
messaging.log_message(
"Received Message",
packet["raw"],
message,
fromcall=fromcall,
msg_num=msg_id,
)
found_command = False
# Get singleton of the PM
pm = plugin.PluginManager()
try:
results = pm.run(fromcall=fromcall, message=message, ack=msg_id)
for reply in results:
found_command = True
# A plugin can return a null message flag which signals
# us that they processed the message correctly, but have
# nothing to reply with, so we avoid replying with a usage string
if reply is not messaging.NULL_MESSAGE:
LOG.debug(f"Sending '{reply}'")
msg = messaging.TextMessage(
self.config["aprs"]["login"],
fromcall,
reply,
transport=messaging.MESSAGE_TRANSPORT_TCPKISS,
)
self.msg_queues["tx"].put(msg)
else:
LOG.debug("Got NULL MESSAGE from plugin")
if not found_command:
plugins = pm.get_plugins()
names = [x.command_name for x in plugins]
names.sort()
# reply = "Usage: {}".format(", ".join(names))
reply = "Usage: weather, locate [call], time, fortune, ping"
msg = messaging.TextMessage(
self.config["aprs"]["login"],
fromcall,
reply,
transport=messaging.MESSAGE_TRANSPORT_TCPKISS,
)
self.msg_queues["tx"].put(msg)
except Exception as ex:
LOG.exception("Plugin failed!!!", ex)
reply = "A Plugin failed! try again?"
msg = messaging.TextMessage(
self.config["aprs"]["login"],
fromcall,
reply,
transport=messaging.MESSAGE_TRANSPORT_TCPKISS,
)
self.msg_queues["tx"].put(msg)
# let any threads do their thing, then ack
# send an ack last
ack = messaging.AckMessage(
self.config["aprs"]["login"],
fromcall,
msg_id=msg_id,
thread = APRSDProcessPacketThread(
packet=packet, config=self.config,
transport=messaging.MESSAGE_TRANSPORT_TCPKISS,
)
self.msg_queues["tx"].put(ack)
LOG.debug("Packet processing complete")
def process_ack_packet(self, packet):
ack_num = packet.get("msgNo")
LOG.info(f"Got ack for message {ack_num}")
messaging.log_message(
"ACK",
packet["raw"],
None,
ack=ack_num,
fromcall=packet["from"],
)
tracker = messaging.MsgTrack()
tracker.remove(ack_num)
stats.APRSDStats().ack_rx_inc()
return
def process_mic_e_packet(self, packet):
LOG.info("Mic-E Packet detected. Currenlty unsupported.")
messaging.log_packet(packet)
stats.APRSDStats().msgs_mice_inc()
thread.start()
return

View File

@ -1,4 +1,4 @@
aioax25
aioax25>=0.0.10
aprslib
click
click-completion

View File

@ -4,7 +4,7 @@
#
# pip-compile requirements.in
#
aioax25==0.0.9
aioax25==0.0.10
# via -r requirements.in
aprslib==0.6.47
# via -r requirements.in