Double-click a cell in the log window to change it. The columns follow the contest exchange instead of being fixed in the XAML, so CQ WW gets a Zone column and Sweepstakes gets Nr, Prec, Ck and Sec. QsoEditor holds the column list and applies one field edit. Validation comes from the ExchangeFieldKind the contest declared: a CQ zone is 1 to 40, an ITU zone 1 to 90, a section is looked up in the ARRL list, a grid must parse. A refused edit returns the reason and leaves the log alone, so the cell reverts. Changing the callsign runs the country lookup again. Delete, or the right-click menu, removes the selected contact after a confirmation. Either way the log is rescored, so a multiplier the removed contact held passes to the next contact that claims it. Both go out to the other stations in N1MM's own messages: contactreplace carries oldcall and oldtimestamp, contactdelete names the contact. An incoming edit or delete is matched by contact id first, falling back to call plus timestamp because N1MM does not know our ids. Country, continent and the two prefixes were filled in twice, once when logging and once when editing. They now come from CountryFields. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
161 lines
7.1 KiB
Markdown
161 lines
7.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 |
|
|
| Editing | double-click a cell in the log to change it, Delete to remove the contact; both go out to the other stations |
|
|
| 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.
|
|
|
|
### Editing the log
|
|
|
|
Double-click a cell in the log window to change it. The columns follow the
|
|
contest exchange, so CQ WW shows a Zone column and Sweepstakes shows Nr, Prec,
|
|
Ck and Sec. A value the contest does not accept — zone 41, an ARRL section that
|
|
does not exist, a callsign with a space in it — is refused and the reason
|
|
appears under the log. Changing the callsign looks the country up again.
|
|
|
|
Delete, or the right-click menu, removes the selected contact after a
|
|
confirmation. Either way the whole log is scored again, so a multiplier the
|
|
removed contact was holding passes to the next contact that claims it.
|
|
|
|
### 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. Editing a contact sends
|
|
`contactreplace` and deleting one sends `contactdelete`, the same as N1MM. With
|
|
no addresses listed the messages are broadcast. A contact that arrives is scored
|
|
again here from the rules rather than trusted.
|
|
|
|
An incoming edit or delete is matched by contact id first. N1MM does not know
|
|
our ids, so the call and the timestamp are the fallback — that is the pair N1MM
|
|
itself keys a contact on.
|
|
|
|
## 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, editing and deleting logged
|
|
contacts, 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.
|