Add CW keying, function key messages and the documentation
The function keys send through cwdaemon or a WinKeyer, with N1MM's message macros. Escape stops sending. Settings are read with the reflection serializer rather than a generated one: the generated one hands back null for every property the file leaves out instead of the value the property is declared with, which crashed the program the first time a new setting was added. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
141
README.md
Normal file
141
README.md
Normal file
@@ -0,0 +1,141 @@
|
||||
# Nonemm
|
||||
|
||||
A contest logger for amateur radio: a from-scratch reimplementation of
|
||||
[N1MM Logger+](https://n1mmwp.hamdocs.com/) in C#, running on Linux and Windows.
|
||||
|
||||
The contest rules, log formats and database schema are written from their
|
||||
published definitions. What Nonemm keeps is **interoperability**: the log
|
||||
database is N1MM's `.s3db` in N1MM's schema, user-defined contests are N1MM's
|
||||
`.udc` files, and a log either program writes opens in the other.
|
||||
|
||||
## Running it
|
||||
|
||||
The SDK lives at `~/.dotnet` on this machine, so a shell that has not been set
|
||||
up needs:
|
||||
|
||||
```sh
|
||||
export DOTNET_ROOT=$HOME/.dotnet PATH="$HOME/.dotnet:$PATH"
|
||||
```
|
||||
|
||||
Then:
|
||||
|
||||
```sh
|
||||
dotnet run --project src/Nonemm.App # start the logger
|
||||
dotnet test Nonemm.slnx # run every test
|
||||
```
|
||||
|
||||
`./build.sh` does the same with the environment already set: `./build.sh test
|
||||
Nonemm.slnx`.
|
||||
|
||||
To work a contest: **Config → Station** for your callsign and zones, then
|
||||
**File → New Database** and **File → New Contest**. In the entry window, type a
|
||||
callsign and press **space** to move to the exchange, then **Enter** to log.
|
||||
Type a frequency into the callsign box and press Enter to change band. **View**
|
||||
opens the log, check, bandmap, score and packet windows.
|
||||
|
||||
Everything that judges a station — the bar under the callsign box, a row in the
|
||||
check window, a spot on the bandmap, a line in the log — is coloured by the same
|
||||
scorer: red for a dupe, green for a new multiplier, blue for points.
|
||||
|
||||
## What it does
|
||||
|
||||
| | |
|
||||
|---|---|
|
||||
| Contests | CQ WW, CQ WPX, ARRL DX, IARU HF, Sweepstakes, RTTY Roundup, NAQP, general logging, and user-defined `.udc` contests |
|
||||
| Log | N1MM `.s3db`, Cabrillo 3.0 out, ADIF in and out |
|
||||
| While typing | dupe check, multiplier check, points, country and zone from the country file |
|
||||
| Windows | entry, log, check, bandmap, score summary, packet |
|
||||
| Radio | hamlib `rigctld`, reconnecting on its own |
|
||||
| Cluster | DX cluster over telnet, spots feeding the bandmap |
|
||||
| Network | contacts shared with the other stations of a multi-operator entry, in N1MM's own contact message |
|
||||
| Keying | CW through `cwdaemon` or a WinKeyer, with N1MM's message macros |
|
||||
|
||||
### The country file and the callsign database
|
||||
|
||||
Neither is bundled. **Config → Download Country File** and **Download Check
|
||||
Partial File** fetch them from where they are published, which is where N1MM
|
||||
fetches them from too —
|
||||
[`country-files.com/cty/wl_cty.dat`](https://www.country-files.com/cty/wl_cty.dat)
|
||||
and
|
||||
[`supercheckpartial.com/MASTER.SCP`](https://www.supercheckpartial.com/MASTER.SCP).
|
||||
The country file is `wl_cty.dat` rather than plain `cty.dat`: same format, with
|
||||
the WAE entities listed separately, which is what CQ WW counts.
|
||||
|
||||
A download that fails changes nothing. The file is fetched, checked that it
|
||||
parses as what it claims to be, and only then put in place, so a site that
|
||||
answers with an apology page instead of a country file cannot cost an operator
|
||||
their multipliers mid-contest.
|
||||
|
||||
Both files can also be dropped into `SupportFiles` under the configuration
|
||||
directory (`~/.config/nonemm` on Linux, `Documents\Nonemm` on Windows).
|
||||
User-defined contests go in `UserDefinedContests` under the same directory.
|
||||
|
||||
Without a country file the program still runs; country- and continent-scored
|
||||
contests lose accuracy.
|
||||
|
||||
### Radio control
|
||||
|
||||
The logger reads and tunes the radio through
|
||||
[hamlib](https://hamlib.github.io/)'s `rigctld`, started separately for whichever
|
||||
radio is on the desk:
|
||||
|
||||
```sh
|
||||
rigctld -m 2028 -r /dev/ttyUSB0 # -m is the hamlib model number; rigctl -l lists them
|
||||
```
|
||||
|
||||
Then **Config → Radio**. With no radio connected nothing changes: frequency and
|
||||
mode stay where they were last typed.
|
||||
|
||||
### CW
|
||||
|
||||
**Config → Keyer and messages** picks `cwdaemon` (a UDP port, usually 6789) or a
|
||||
WinKeyer (a serial port), sets the speed, and edits the twelve function key
|
||||
messages for CW and for phone. The macros are N1MM's: `{MYCALL}`, `{CALL}`,
|
||||
`{EXCH}`, `{SENTRST}`, `{SENTNR}`, `#` for the serial number, and `{SENTRSTCUT}`
|
||||
for cut numbers. Escape stops sending.
|
||||
|
||||
### Networked stations
|
||||
|
||||
**Config → Network** names this station and lists the others. Each contact is
|
||||
sent to them as it is logged, in N1MM's `contactinfo` message, so an N1MM
|
||||
station on the same network sees them too. With no addresses listed the contacts
|
||||
are broadcast. A contact that arrives is scored again here from the rules rather
|
||||
than trusted.
|
||||
|
||||
## Layout
|
||||
|
||||
| Project | What it holds |
|
||||
|---|---|
|
||||
| `Nonemm.Core` | Frequencies, bands, modes, callsigns, grid squares, the country file and the callsign database |
|
||||
| `Nonemm.Contests` | Contest rules, the scoring engine, `.udc` files |
|
||||
| `Nonemm.Formats` | Cabrillo out, ADIF in and out |
|
||||
| `Nonemm.Storage` | The N1MM-compatible `.s3db` |
|
||||
| `Nonemm.Rig` | Radio control over `rigctld` |
|
||||
| `Nonemm.Spotting` | Spots, the bandmap, the DX cluster client |
|
||||
| `Nonemm.Network` | Contacts shared between the stations of a multi-operator entry |
|
||||
| `Nonemm.Keying` | CW through `cwdaemon` or a WinKeyer |
|
||||
| `Nonemm.Session` | What the operator is typing and what the log says about it — no UI toolkit |
|
||||
| `Nonemm.App` | The Avalonia windows |
|
||||
|
||||
The split at `Nonemm.Session` is the important one: it references no UI
|
||||
framework, so what space does, when a dupe fires and what a contact scores are
|
||||
covered by plain unit tests.
|
||||
|
||||
## Where it stands
|
||||
|
||||
Working: logging a contest end to end, live dupe and multiplier checking, eight
|
||||
built-in contests plus user-defined ones, Cabrillo and ADIF export, ADIF import,
|
||||
the log, check, bandmap, score and packet windows, radio control, DX cluster
|
||||
spots, contacts shared between networked stations, and CW keying.
|
||||
|
||||
Checked against N1MM 1.0.11031: a log this program wrote opens in N1MM, which
|
||||
reads the contest, its categories and the contacts. See
|
||||
[`docs/n1mm-interop.md`](docs/n1mm-interop.md) for what that took.
|
||||
|
||||
Not yet: voice keying, QTC handling for WAE, call history files, digital modes
|
||||
beyond logging them, and the check window's Call History and Exchange columns,
|
||||
which are left out rather than shown empty.
|
||||
|
||||
The radio, cluster, network and keyer clients are tested against fakes that
|
||||
speak the documented protocols. None has yet been run against a real radio, a
|
||||
live cluster node or a keyer.
|
||||
Reference in New Issue
Block a user