1
0
mirror of https://github.com/craigerl/aprsd.git synced 2025-06-17 05:42:36 -04:00

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

View File

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

View File

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

View File

@ -8,9 +8,7 @@ import tracemalloc
import aprslib import aprslib
from aprsd import ( from aprsd import client, kissclient, messaging, packets, plugin, stats, utils
client, kissclient, messaging, packets, plugin, stats, trace, utils,
)
LOG = logging.getLogger("APRSD") LOG = logging.getLogger("APRSD")
@ -182,9 +180,10 @@ class APRSDRXThread(APRSDThread):
class APRSDProcessPacketThread(APRSDThread): class APRSDProcessPacketThread(APRSDThread):
def __init__(self, packet, config): def __init__(self, packet, config, transport="aprsis"):
self.packet = packet self.packet = packet
self.config = config self.config = config
self.transport = transport
name = self.packet["raw"][:10] name = self.packet["raw"][:10]
super().__init__(f"RX_PACKET-{name}") super().__init__(f"RX_PACKET-{name}")
@ -239,6 +238,7 @@ class APRSDProcessPacketThread(APRSDThread):
self.config["aprs"]["login"], self.config["aprs"]["login"],
fromcall, fromcall,
msg_id=msg_id, msg_id=msg_id,
transport=self.transport,
) )
ack.send() ack.send()
@ -257,6 +257,7 @@ class APRSDProcessPacketThread(APRSDThread):
self.config["aprs"]["login"], self.config["aprs"]["login"],
fromcall, fromcall,
subreply, subreply,
transport=self.transport,
) )
msg.send() msg.send()
@ -273,6 +274,7 @@ class APRSDProcessPacketThread(APRSDThread):
self.config["aprs"]["login"], self.config["aprs"]["login"],
fromcall, fromcall,
reply, reply,
transport=self.transport,
) )
msg.send() msg.send()
@ -285,6 +287,7 @@ class APRSDProcessPacketThread(APRSDThread):
self.config["aprs"]["login"], self.config["aprs"]["login"],
fromcall, fromcall,
reply, reply,
transport=self.transport,
) )
msg.send() msg.send()
except Exception as ex: except Exception as ex:
@ -296,6 +299,7 @@ class APRSDProcessPacketThread(APRSDThread):
self.config["aprs"]["login"], self.config["aprs"]["login"],
fromcall, fromcall,
reply, reply,
transport=self.transport,
) )
msg.send() msg.send()
@ -349,7 +353,7 @@ class KISSRXThread(APRSDThread):
# and the aprslib developer didn't want to allow a PR to add # and the aprslib developer didn't want to allow a PR to add
# kwargs. :( # kwargs. :(
# https://github.com/rossengeorgiev/aprs-python/pull/56 # 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() kiss_client.loop.run_forever()
except aprslib.exceptions.ConnectionDrop: except aprslib.exceptions.ConnectionDrop:
@ -361,131 +365,21 @@ class KISSRXThread(APRSDThread):
client.Client().reset() client.Client().reset()
# Continue to loop # Continue to loop
@trace.trace def process_packet(self, interface, frame):
def process_packet(self, interface, frame, match):
"""Process a packet recieved from aprs-is server.""" """Process a packet recieved from aprs-is server."""
LOG.debug(f"Got an APRS Frame '{frame}'") 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()) payload = str(frame.payload.decode())
msg = f"{str(frame.header)}:{payload}" msg = f"{str(frame.header)}:{payload}"
LOG.debug(f"Decoding {msg}")
packet = aprslib.parse(msg) packet = aprslib.parse(msg)
LOG.debug(packet) LOG.debug(packet)
thread = APRSDProcessPacketThread(
try: packet=packet, config=self.config,
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,
transport=messaging.MESSAGE_TRANSPORT_TCPKISS, transport=messaging.MESSAGE_TRANSPORT_TCPKISS,
) )
self.msg_queues["tx"].put(ack) thread.start()
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()
return return

View File

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

View File

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