cw-usb-keyer provides CW keying for an ICOM IC-7300MK2 using the DTR signal
on the radio's USB(B) virtual serial port. It supports manual keying, timed
Latin and Wabun text at 10–60 WPM, procedural signals, a FIFO transmission
queue, and a TUI for batch submission.
Version 0.1.0 implements the initial DTR keyer scope. CI-V, CAT, frequency control, and CW decoding are outside this release. See the Japanese development plan for the design record and current implementation status.
Safety: Start testing with the transmitter connected to a suitable dummy load or with RF output otherwise made safe.
- macOS 15 or later
- Python 3.11 or later
- pyserial, Textual, tomli, and tomli-w (installed from
requirements.txt) - An IC-7300MK2 connected by USB-C
python -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
pip install -e .The virtual environment must be activated again whenever you open a new terminal or return to the application later. Change to the project directory, then run:
cd /path/to/cw-usb-keyer
source .venv/bin/activateAfter activation, commands such as cw-usb-keyer tui are available. You do
not need to repeat the installation commands.
MENU
SET
External Connectors
USB SEND/Keying
USB Keying (CW)
USB(B) DTR
Set the radio to CW mode. Enable BK-IN or F-BKIN to transmit RF.
With break-in off, DTR keying does not send RF, but you can still verify CW
with the radio's sidetone.
List ports:
cw-usb-keyer portsWith --port omitted, the application detects both IC-7300MK2 virtual serial
ports and selects the second interface, USB(B). Test DTR with a 200 ms pulse:
cw-usb-keyer testManual keying:
Manual mode reads the physical SPACE key state and requires macOS Input Monitoring permission for the terminal application being used:
- Open System Settings.
- Open Privacy & Security, then Input Monitoring.
- Enable Terminal, iTerm2, or the terminal application running
cw-usb-keyer. - Quit that terminal application completely and reopen it.
Without this permission, manual mode can start but does not detect SPACE and
does not print DTR ON. The test command does not monitor the keyboard and
does not require this permission.
cw-usb-keyer keyUse --port /dev/cu.usbmodem... to override automatic USB(B) selection.
Preview Latin text as timed DTR events without opening a serial port:
cw-usb-keyer send --dry-run --wpm 20 "CQ CQ DE JA1ZZZ"Preview kana using Wabun Morse mode:
cw-usb-keyer send --dry-run --mode wabun --wpm 20 "こんにちは。"Hiragana and half-width katakana are normalized to full-width katakana. Voiced kana are sent as the base kana followed by a voicing mark. Kanji are rejected rather than having their reading guessed.
Stand-alone procedural-signal names delimited by spaces are automatically sent without character spacing:
cw-usb-keyer send --dry-run "DE JA1ZZZ <BK>"
cw-usb-keyer send --dry-run --mode wabun "ホレ コンニチハ ラタ"Latin mode supports <AR>, <AS>, <BK>, <SK>, <BT>, <KN>, <CL>,
<HH>, and <SOS>. Angle brackets remain available for explicit notation.
Embedded text such as the BK in JO1BKJ retains normal character spacing.
The command supports integer values from 10 to 60 WPM. Running send without --dry-run keys the
physical radio and must only be done manually by the user after confirming the
radio configuration, text, speed, USB(B) port, and RF safety.
Hold SPACE to key down, release SPACE to key up, and press ESC to exit. Ctrl+C also exits safely. Manual mode uses the native macOS keyboard-state API because Terminal.app's byte stream does not include key-release events. DTR is forced off during initialization and again whenever a connection is closed.
Start the TUI in transmit mode. It opens the auto-detected serial port and can operate DTR when text is queued:
cw-usb-keyer tuiEnter queues the complete input, Ctrl+X cancels the current item, Ctrl+L also
clears waiting items, Ctrl+P opens the command palette, Escape closes it, and
Ctrl+Q exits. Use cw-usb-keyer tui --preview to run without opening a serial
port or operating DTR. Before using the default transmit mode, complete the
radio and RF safety checks.
The Preview / Transmit selector beside the Latin/Wabun and input-mode controls
changes mode while the app is running. Selecting Preview immediately releases
DTR. When started with --preview, the serial port is opened only if the
selector is later changed to Transmit. Changing mode cancels the item currently
being sent; waiting items remain queued and continue in the newly selected
mode.
The TUI sends one queued item at a time. An item is "waiting" after it has been
submitted with Enter or a macro key but before its transmission has started.
If one item is being sent and two more have been submitted, the latter two are
waiting. Waiting (2) reports this waiting count; it does not include the item
currently being sent.
The text currently being sent is highlighted in yellow. Waiting text is shown below it as a numbered, top-to-bottom list in transmission order.
Ctrl+X and Ctrl+L differ in how they handle items still waiting in the FIFO queue:
| Key | Current transmission | Waiting items |
|---|---|---|
| Ctrl+X | Cancel | Keep; continue with the next item |
| Ctrl+L | Cancel | Discard all |
For example, if A is being sent while B and C are waiting, Ctrl+X stops A and then sends B and C. Ctrl+L stops A and removes B and C, leaving the queue empty.
In the TUI, you can also use:
- F1-F5 keys to send registered macros
- Register, edit, and delete macros in the editor at the bottom of the screen; the complete macro list remains visible below the editor
- Real-time mode to queue each Latin character as it is typed and each Wabun character when its IME input is committed; SPACE only inserts word spacing
- Switch between Latin and Wabun character sets
Macros can be registered, listed, edited, and deleted directly in the TUI. Select an F1-F5 slot, enter only the macro text, and press Save. No macro name is required in the TUI. Select a slot and press Delete to clear it. The CLI commands remain available for compatibility:
# Register a macro with an optional shortcut key
cw-usb-keyer macro add cq "CQ CQ CQ" --shortcut F1
# List all registered macros
cw-usb-keyer macro list
# Remove a macro
cw-usb-keyer macro remove cqThe five fixed slots are always displayed at the bottom of the TUI, including
empty slots. Macros are saved to ~/.config/cw-usb-keyer/config.toml and
persist between sessions. Press F1-F5 to send the corresponding macro text.
No transmission during development: Automated tests and development checks must never key the physical radio. Tests use serial test doubles, and text transmission is inspected with
--dry-run. Only the user manually runs hardware transmission tests after confirming that RF transmission is safe.
pytest
ruff check .The serial lifecycle, DTR keying, Morse codecs, timing, transmission queue, TUI, real-time typing transmission, and configurable macros are implemented. CI-V and radio control remain outside the current project scope.
This project is licensed under the MIT License.