CSVF2 - radio text/file modem      (version 2.1, 2026-10-03)
==========================================================

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. Tick "Send in Morse code" next to the callsign to send it
as Morse instead (20 words per minute on a 1500 Hz tone, which receivers ignore).

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; near the far right, down to 1%, it starts
               on plain 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.
