CSVF2 - radio text/file modem      (version 1.7, 2026-09-21)
==========================================================

CSVF = client server via frequency.

Sends text or a file over a voice radio as audio tones, and receives it again.
Your callsign is spoken (NATO phonetics + numbers) at the start, at the end and often enough on
long transmissions to stay inside the 10 minute rule. audio/website.wav plays right after the
tones and before the closing callsign.

Long transmissions are sent in bursts of 2 minutes with a silent gap between them, so a radio
with a time-out timer (e.g. TYT MD-390, 180 s) un-keys and resets. Each burst starts with a
steady 400 Hz keying tone for VOX radios. Both are settings on the Transmit tab.

Quick start
  1. Install Python 3.10 or newer.
  2. pip install -r requirements.txt
  3. python radio_gui.py

radio_server_template.py runs a station that answers on its own: it listens all the time, and
when it hears the text "ping" it transmits "pong" (both texts are settings); it also answers
any message sent to path "document" by sending document.txt's text back as a plain message,
not a file. It has the same settings as the window and remembers them.
  python radio_server_template.py

This file is a TEMPLATE: it is meant to be copied and edited, not run as-is forever. To make
your own CSVF2 server -- your own commands, your own files -- copy radio_server_template.py
and edit route_for() and transmit_reply() in it (see the comments at the top of the file).

radio_server_25.py is a worked example of exactly that: it started as a copy of the template
and now has three more paths, alongside "ping" and "document":
  "chatgpt"  sends your message to OpenAI (gpt-4o-mini) and sends the reply back, capped at
             100 calls a day. Needs your own OPENAI_API_KEY environment variable and a working
             internet connection -- see the comments at the top of the file. Nothing here
             stores that key in a file.
  "smpost"   logs your message to a small local file (sm_posts.json, created on first use,
             keeping only the last 5 posts) and replies "200".
  "smget"    replies with the last 5 logged posts, numbered, oldest first.
document_25.txt is what "document" sends back on this server: a short reference for these
paths, meant for a person to read, not a program to parse.
  python radio_server_25.py

The Server tab of the window talks to a station built from either server script: you give an
8-character path (like the part after the / in a web address), send text or a file, and the
tab starts listening the moment the send is finished. After your last callsign it sends an
end tone (450 Hz, 2 s) so the server knows you are done and answers 1 s later, instead of
waiting a fixed 30 s.

Transmit tab : pick Text or File, type your callsign, choose a Speed, Transmit.
Receive tab  : choose the radio's audio input, Start listening. The Sensitivity slider sets how
               weak a signal may be and still start a message (higher = weaker signals, but a
               greater chance of starting on noise). Messages appear in the log; when a file
               finishes you get a save prompt.

Files
  radio_gui.py               the window
  radio_server_template.py   the automatic ping/pong + "document" station -- edit this to
                              build your own server
  radio_server_25.py         the same, plus "chatgpt", "smpost" and "smget" (see above) -- a
                              worked example, also yours to edit
  document.txt               the text radio_server_template.py sends back for path "document"
  document_25.txt            the text radio_server_25.py sends back for path "document"
                              (replace either one with your own, keeping to letters, digits,
                              space and !@#$%^&*() so nothing is dropped)
  radio_modem.py             the modem (encoder + decoder, no GUI, protocol described at the top)
  audio/                     a-z (phonetic words) and 0-9 clips for the spoken callsign, and
                              website.wav (replace it with your own announcement, or delete it
                              to skip it). Keep this folder next to the .py files.

Full documentation: the CSVF2 page on the KE9GDP site.
You are responsible for operating within your licence and local rules, including for what a
third-party service like OpenAI sends back if you use the "chatgpt" path.
