From ac8f7cdc35ea7ac7db74ff97bdb5e29f3024ce70 Mon Sep 17 00:00:00 2001 From: Evan Pratten Date: Thu, 30 Nov 2023 18:37:20 -0500 Subject: [PATCH] updates --- scripts/kxchat | 71 ++++++++++++++++++++++++++++++++++++++++++++++ scripts/kxcq | 4 +++ scripts/kxlisten | 62 ++++++++++++++++++++++++++++++++++++++++ scripts/kxpoweroff | 42 +++++++++++++++++++++++++++ scripts/kxsend | 56 ++++++++++++++++++++++++++++++++++++ 5 files changed, 235 insertions(+) create mode 100755 scripts/kxchat create mode 100755 scripts/kxcq create mode 100755 scripts/kxlisten create mode 100755 scripts/kxpoweroff create mode 100755 scripts/kxsend diff --git a/scripts/kxchat b/scripts/kxchat new file mode 100755 index 0000000..7508af1 --- /dev/null +++ b/scripts/kxchat @@ -0,0 +1,71 @@ +#! /usr/bin/env python3 +import argparse +import sys +import logging +import serial +import subprocess + +logger = logging.getLogger(__name__) + + +def main() -> int: + # Handle program arguments + ap = argparse.ArgumentParser( + prog="kxchat", description="Chat over CW using the keyboard" + ) + ap.add_argument("--tx-only", help="Only transmit, do not receive", action="store_true") + ap.add_argument("--device", "-d", help="Serial device", default="/dev/ttyUSB0") + ap.add_argument("--baud", "-b", help="Serial baud rate", default=38400, type=int) + ap.add_argument( + "-v", "--verbose", help="Enable verbose logging", action="store_true" + ) + args = ap.parse_args() + + # Configure logging + logging.basicConfig( + level=logging.DEBUG if args.verbose else logging.INFO, + format="%(levelname)s: %(message)s", + stream=sys.stderr, + ) + + # Spawn a kxlisten process and hook its STDOUT to our STDOUT + if not args.tx_only: + logger.debug(f"Starting kxlisten process") + kxlisten = subprocess.Popen( + ["kxlisten", "-d", args.device, "-b", str(args.baud)], + ) + + # Read lines from keyboard, and send them to the radio using kxsend + try: + while True: + # Read a line from the keyboard + line = sys.stdin.readline().strip() + + # If the line is empty, skip + if not line: + continue + + # Add a space onto the end of the line + line += " " + + # Send the line to the radio + logger.debug(f"Sending line: {line}") + kxsend = subprocess.Popen( + ["kxsend", "-d", args.device, "-b", str(args.baud), line], + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + ) + + except KeyboardInterrupt: + logger.info("Done transmitting") + + # Stop the kxlisten process + if not args.tx_only: + logger.debug(f"Stopping kxlisten process") + kxlisten.terminate() + + return 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/scripts/kxcq b/scripts/kxcq new file mode 100755 index 0000000..837599c --- /dev/null +++ b/scripts/kxcq @@ -0,0 +1,4 @@ +#! /bin/bash +set -ex + +kxsend "CQ CQ CQ DE VA3ZZA VA3ZZA CQ CQ K" -v diff --git a/scripts/kxlisten b/scripts/kxlisten new file mode 100755 index 0000000..a2b688e --- /dev/null +++ b/scripts/kxlisten @@ -0,0 +1,62 @@ +#! /usr/bin/env python3 +import argparse +import sys +import logging +import serial + +logger = logging.getLogger(__name__) + + +def main() -> int: + # Handle program arguments + ap = argparse.ArgumentParser( + prog="kxlisten", description="Route inbound CW text to STDOUT" + ) + ap.add_argument("--stop", help="Stop listening", action="store_true") + ap.add_argument("--device", "-d", help="Serial device", default="/dev/ttyUSB0") + ap.add_argument("--baud", "-b", help="Serial baud rate", default=38400, type=int) + ap.add_argument( + "-v", "--verbose", help="Enable verbose logging", action="store_true" + ) + args = ap.parse_args() + + # Configure logging + logging.basicConfig( + level=logging.DEBUG if args.verbose else logging.INFO, + format="%(levelname)s: %(message)s", + stream=sys.stderr, + ) + + # Connect to the radio + logger.debug(f"Connecting to radio: {args.device}") + serial_conn = serial.Serial(args.device, args.baud) + + # Handle stopping + if args.stop: + cmd = "TT0;" + logger.debug(f"Sending command: {cmd}") + serial_conn.write(cmd.encode("ascii")) + return 0 + + # Otherwise, start listening + cmd = "TT1;" + logger.debug(f"Sending command: {cmd}") + serial_conn.write(cmd.encode("ascii")) + + # Listen for text + try: + while True: + next_char = serial_conn.read().decode("ascii") + print(next_char, end="") + sys.stdout.flush() + except KeyboardInterrupt: + logger.info("Stopping") + cmd = "TT0;" + logger.debug(f"Sending command: {cmd}") + serial_conn.write(cmd.encode("ascii")) + + return 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/scripts/kxpoweroff b/scripts/kxpoweroff new file mode 100755 index 0000000..23dec14 --- /dev/null +++ b/scripts/kxpoweroff @@ -0,0 +1,42 @@ +#! /usr/bin/env python3 +import argparse +import sys +import logging +import serial + +logger = logging.getLogger(__name__) + + +def main() -> int: + # Handle program arguments + ap = argparse.ArgumentParser( + prog="kxpoweroff", description="Turn off a KX2 or KX3" + ) + ap.add_argument("--device", "-d", help="Serial device", default="/dev/ttyUSB0") + ap.add_argument("--baud", "-b", help="Serial baud rate", default=38400, type=int) + ap.add_argument( + "-v", "--verbose", help="Enable verbose logging", action="store_true" + ) + args = ap.parse_args() + + # Configure logging + logging.basicConfig( + level=logging.DEBUG if args.verbose else logging.INFO, + format="%(levelname)s: %(message)s", + ) + + # Connect to the radio + logger.debug(f"Connecting to radio: {args.device}") + serial_conn = serial.Serial(args.device, args.baud) + + # Send the appropriate command + cmd = "PS0;" + logger.debug(f"Sending command: {cmd}") + serial_conn.write(cmd.encode("ascii")) + + + return 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/scripts/kxsend b/scripts/kxsend new file mode 100755 index 0000000..a749a92 --- /dev/null +++ b/scripts/kxsend @@ -0,0 +1,56 @@ +#! /usr/bin/env python3 +import argparse +import sys +import logging +import serial + +logger = logging.getLogger(__name__) + + +def main() -> int: + # Handle program arguments + ap = argparse.ArgumentParser( + prog="kxsend", description="Send a string over CW on a KX2" + ) + ap.add_argument("text", help="Text to send", nargs="+") + ap.add_argument("--speed", help="Transmit speed in WPM", type=int) + ap.add_argument("--device", "-d", help="Serial device", default="/dev/ttyUSB0") + ap.add_argument("--baud", "-b", help="Serial baud rate", default=38400, type=int) + ap.add_argument( + "-v", "--verbose", help="Enable verbose logging", action="store_true" + ) + args = ap.parse_args() + args.text = " ".join(args.text) + + # Configure logging + logging.basicConfig( + level=logging.DEBUG if args.verbose else logging.INFO, + format="%(levelname)s: %(message)s", + ) + + # Connect to the radio + logger.debug(f"Connecting to radio: {args.device}") + serial_conn = serial.Serial(args.device, args.baud) + + # If we have a specific speed, set it + if args.speed: + cmd = "KS{:0>3};".format(args.speed) + logger.debug(f"Sending command: {cmd}") + serial_conn.write(cmd.encode("ascii")) + + # Break the text into max 24 character chunks + chunks = [args.text[i:i+24] for i in range(0, len(args.text), 24)] + logger.info(f"Sending {len(chunks)} chunks") + + # Handle each chunk + for chunk in chunks: + # Send the text + cmd = f"KY {chunk};" + logger.debug(f"Sending command: {cmd}") + serial_conn.write(cmd.encode("ascii")) + + return 0 + + +if __name__ == "__main__": + sys.exit(main())