You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 

135 lines
3.7 KiB

import queue
import threading
import subprocess
import frames
import crypto
def wrap_frame(message, callsign):
return f"Syncronizing... Synchronizing... Synchronizing...{message}https://kj7rrv.com/leonet DE {callsign}\n\n"
class Transmitter:
def __init__(self, callsign):
self.callsign = callsign
self.queue = queue.Queue()
self.transmit = self.queue.put
threading.Thread(target=self.tx_loop).start()
def tx_loop(self):
while True:
send(wrap_frame(self.queue.get(), callsign))
def send(data):
print(data)
subprocess.run(
["minimodem", "--tx", "300"],
input=data,
encoding="ascii",
)
class InvalidFrameError(BaseException):
pass
class FrameDecodeError(InvalidFrameError):
pass
class FrameAuthenticationError(InvalidFrameError):
pass
def decode(frame_bytes, passwords):
try:
frame = frame_bytes.decode("ascii")
main, checksum, auth_code = frame.split(" ")[1:-1]
if checksum != crypto.find_checksum(main):
raise FrameDecodeError()
frame_type, recipient, originator, payload = main.split("#")
if passwords is not None:
password = passwords.get(
originator if directions[frame_type] == "OR" else recipient, ""
)
if auth_code != crypto.find_auth_code(password, main):
raise FrameAuthenticationError
if frame_type == "MSG":
body, message_id = payload.split(";")
timestamp, safe_message = body.split("&")
message = make_message_unsafe(safe_message)
return frame_objects.MsgFrame(
recipient,
originator,
message_id,
timestamp,
message,
)
elif frame_type == "QRY":
return frame_objects.QryFrame(recipient, originator, payload)
elif frame_type == "ACK":
return frame_objects.AckFrame(recipient, originator, payload)
elif frame_type == "Nak":
return frame_objects.NakFrame(recipient, originator, payload)
else:
raise FrameDecodeError()
except BaseException:
raise FrameDecodeError()
class Receiver:
def __init__(self, identifier):
self.modem = subprocess.Popen(
["minimodem", "--quiet", "--rx", "300"], stdout=subprocess.PIPE
)
self.running = True
self.queue = queue.Queue()
self.receive = self.queue.get
self.identifier = identifier
threading.Thread(target=self.rx_loop).start()
def rx_loop(self):
rx_buffer = b""
while True:
if not self.running:
break
byte = self.modem.stdout.read(1)
if byte == b"\n":
if rx_buffer.startswith(b"LEONET") and rx_buffer.endswith(
b"TENOEL"
):
try:
frame = decode(rx_buffer, None) # passwords dict
if (
self.identifier is None
or frame.frame_recipient == self.identifier
):
self.queue.put(frame)
except InvalidFrameError as e:
pass
rx_buffer = b""
else:
rx_buffer += byte
class Transceiver:
def __init__(self, identifier, callsign):
self.transmitter = Transmitter(callsign)
self.receiver = Receiver(identifier)
self.tx_queue = self.transmitter.queue
self.rx_queue = self.receiver.queue
self.transmit = self.transmitter.transmit
self.receive = self.receiver.receive