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>
142 lines
6.1 KiB
Markdown
142 lines
6.1 KiB
Markdown
# 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.
|