1
0
mirror of https://github.com/craigerl/aprsd.git synced 2026-02-22 17:20:14 -05:00

Got the serial KISS driver working

This commit is contained in:
Walter Boring 2025-11-26 16:19:37 -05:00
parent 6bd0f50dc0
commit 50022e1e9e
4 changed files with 48 additions and 22 deletions

View File

@ -2,9 +2,11 @@
from aprsd.client.drivers.aprsis import APRSISDriver
from aprsd.client.drivers.fake import APRSDFakeDriver
from aprsd.client.drivers.registry import DriverRegistry
from aprsd.client.drivers.serialkiss import SerialKISSDriver
from aprsd.client.drivers.tcpkiss import TCPKISSDriver
driver_registry = DriverRegistry()
driver_registry.register(APRSDFakeDriver)
driver_registry.register(APRSISDriver)
driver_registry.register(TCPKISSDriver)
driver_registry.register(SerialKISSDriver)

View File

@ -27,6 +27,9 @@ class KISSDriver(metaclass=trace.TraceWrapperMetaclass):
last_packet_received = None
keepalive = None
# timeout in seconds
select_timeout = 1
def __init__(self):
"""Initialize the KISS client.
@ -85,7 +88,6 @@ class KISSDriver(metaclass=trace.TraceWrapperMetaclass):
frame = kissutil.recover_special_codes(kissutil.strip_nmea(bytes(buffer)))
if strip_df_start:
frame = kissutil.strip_df_start(frame)
LOG.warning(f'handle_fend {" ".join(f"{b:02X}" for b in bytes(frame))}')
return bytes(frame)
def fix_raw_frame(self, raw_frame: bytes) -> bytes:
@ -145,6 +147,7 @@ class KISSDriver(metaclass=trace.TraceWrapperMetaclass):
"""
raise NotImplementedError('read_frame is not implemented for KISS')
@trace.no_trace
def stats(self, serializable: bool = False) -> Dict[str, Any]:
"""Get client statistics.

View File

@ -7,7 +7,8 @@ non-asyncio KISSInterface implementation.
import datetime
import logging
import select
# import select
from typing import Any, Dict
import serial
@ -24,6 +25,7 @@ from aprsd import ( # noqa
)
from aprsd.client.drivers.kiss_common import KISSDriver
from aprsd.packets import core
from aprsd.utils import trace
CONF = cfg.CONF
LOG = logging.getLogger('APRSD')
@ -80,6 +82,11 @@ class SerialKISSDriver(KISSDriver):
def close(self):
"""Close the connection."""
self._connected = False
if self.socket and self.socket.is_open:
try:
self.socket.close()
except Exception:
pass
def setup_connection(self):
"""Set up the KISS interface."""
@ -118,11 +125,26 @@ class SerialKISSDriver(KISSDriver):
LOG.warning('KISS interface already connected')
return
# Close existing socket if it exists
if self.socket and self.socket.is_open:
try:
self.socket.close()
except Exception:
pass
try:
# serial.Serial() automatically opens the port, so we don't need to call open()
self.socket = serial.Serial(
CONF.kiss_serial.device, CONF.kiss_serial.baudrate
CONF.kiss_serial.device,
timeout=1,
baudrate=CONF.kiss_serial.baudrate,
# bytesize=8,
# parity='N',
# stopbits=1,
# xonxoff=False,
# rtscts=False,
# dsrdtr=False,
)
self.socket.open()
self._connected = True
except serial.SerialException as e:
LOG.error(f'Failed to connect to KISS interface: {e}')
@ -142,21 +164,21 @@ class SerialKISSDriver(KISSDriver):
return None
while self._connected:
try:
readable, _, _ = select.select(
[self.socket],
[],
[],
self.select_timeout,
)
if not readable:
continue
except Exception as e:
# No need to log if we are not running.
# this happens when the client is stopped/closed.
LOG.error(f'Error in read loop: {e}')
self._connected = False
break
# try:
# readable, _, _ = select.select(
# [self.socket],
## [],
# [],
# self.select_timeout,
# )
# if not readable:
# continue
# except Exception as e:
# # No need to log if we are not running.
# # this happens when the client is stopped/closed.
# LOG.error(f'Error in read loop: {e}')
# self._connected = False
# break
try:
short_buf = self.socket.read(1024)
@ -208,12 +230,13 @@ class SerialKISSDriver(KISSDriver):
frame_kiss = b''.join(
[kiss_constants.FEND, command.value, frame_escaped, kiss_constants.FEND]
)
self.socket.send(frame_kiss)
self.socket.write(frame_kiss)
# Update last packet sent time
self.last_packet_sent = datetime.datetime.now()
# Increment packets sent counter
self.packets_sent += 1
@trace.no_trace
def stats(self, serializable: bool = False) -> Dict[str, Any]:
"""Get client statistics.

View File

@ -39,8 +39,6 @@ class TCPKISSDriver(KISSDriver):
# Class level attributes required by Client protocol
client_name = None
socket = None
# timeout in seconds
select_timeout = 1
path = None
def __new__(cls, *args, **kwargs):