Something already sitting where Documents/N1MM Logger+ should go — a file, or a link to somewhere that is not there — threw out of Directory.CreateDirectory before the program had a window, so the operator got a stack trace and nothing else. CreateFolders answers with what stopped it, and the program shows it in a window naming the path and stops there. NONEMM_HOME moves the whole lot somewhere else, for a station that keeps its files off the Documents folder. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RoGtneMQaz4M9w7Kk49AVD
910 lines
49 KiB
Markdown
910 lines
49 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, or a
|
|
mode — `CW`, `SSB`, `USB`, `LSB`, `RTTY`, `FT8` and the rest — to change mode.
|
|
A radio that is connected is moved with it; with no radio it is the way to
|
|
reach a mode at all. **View** opens the log, check, bandmap, score and telnet
|
|
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 (CW, SSB, RTTY), CQ WPX (CW, SSB, RTTY), WAE (CW, SSB, RTTY), ARRL DX, IARU HF, Sweepstakes, RTTY Roundup, NAQP, OK/OM DX (CW), YOTA, IOTA, EU DX Contest, CQ 160, ARRL 10M, REF, Ukrainian DX, Russian DX RTTY, RDAC, YO DX HF, Oceania DX, All Asian, SARTG RTTY, BARTG Sprint, Mexico RTTY, IARU Region 1 Field Day, 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, exchange filled from a call history file |
|
|
| Windows | entry, log, check, bandmap, available mults and Qs, score summary, grey line, telnet, digital interface |
|
|
| Editing | double-click a cell in the log, or open the whole contact with Ctrl+Y; Delete removes it. All of it goes out to the other stations |
|
|
| Radio | one or two radios over hamlib `rigctld`, split, reconnecting on its own |
|
|
| Cluster | DX cluster over telnet: a telnet window with the node's traffic, the published list of nodes, command buttons and spot filters, spots feeding the bandmap, Alt+P to spot a station |
|
|
| Bandmap | drawn like N1MM's: a frequency scale with the receiver on it and callsigns beside it, joined by leader lines |
|
|
| 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 |
|
|
| Digital | N1MM's digital interface window, running MMTTY or 2Tone under Wine through the same `XMMT.ocx` N1MM drives them with |
|
|
|
|
### The digital window
|
|
|
|
**Window ▸ Digital Interface** opens N1MM's digital interface. **Engine ▸
|
|
Settings** says where MMTTY or 2Tone is; **Engine ▸ Start** runs it under Wine.
|
|
`docs/digital-bridge.md` covers setting the Wine prefix up.
|
|
|
|
What the window does, and what each part of it is for:
|
|
|
|
| Part | What it does |
|
|
|---|---|
|
|
| Receive pane | the decoded text. Every word shaped like a callsign is coloured by what working it would bring, the same four colours the entry window uses, and our own call is coloured as ours |
|
|
| Left click on a call | puts that call in the entry window. With call stacking on, the call already being typed goes on the stack first, so neither is lost |
|
|
| Left click on anything else | copies the word into the exchange box the contest keeps for that kind of value: a serial number to the number box, a section or a state to the box that holds the list it is in. The box the cursor is in takes the word where it fits, which is what N1MM does. 599, a colon and the Z on a time are cut off first |
|
|
| Left click on a gap | stops the pane scrolling so a call can be read while text keeps arriving. Moving the pointer off the pane starts it again |
|
|
| Right click | presses Enter in the entry window, which is ESM's next message. Off by default: Options ▸ Right click presses Enter |
|
|
| Pointer | the word under the pointer is underlined and shown at the bottom left |
|
|
| Grab list | the calls heard, newest first and coloured the same way. Click one to work it, right-click to drop it, or press Grab for the next one |
|
|
| Macro buttons | three rows of eight. Right-click any of them to edit all twenty-four. `{TX}` starts the transmission, `{RX}` ends it, `{ENTER}` sends a carriage return, and the rest are the macros the function keys use |
|
|
| Transmit pane | what is typed goes out as it is typed. Escape stops sending |
|
|
| Buttons | Clr RX and CLR empty the two panes, Align puts the demodulator back on the mark tone, TX and RX key and unkey, Ham loads MMTTY's default profile, Lock is AFC and Rev swaps the tones |
|
|
|
|
Options ▸ Grab list decides which calls are kept: everything heard, everything
|
|
but dupes, or only calls the callsign database knows. Call stacking chooses the
|
|
order stacked calls come back off: multipliers first, first in, last in, or off.
|
|
|
|
On a digital mode the function keys, ESM and the QTC window all send through the
|
|
engine rather than through the CW keyer, so the whole entry window works the way
|
|
it does on CW.
|
|
|
|
### 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) and sets the speed. Escape stops sending.
|
|
|
|
The messages are edited as their file, in a plain text editor: right-click any
|
|
of the function key buttons under the entry window, or use the two buttons in
|
|
Config → Keyer and messages. One line per key — the button label, a comma, then
|
|
the message — and a line starting with `#` is a comment. Which key a line
|
|
belongs to is decided by where it is in the file: the first twelve lines are F1
|
|
to F12 while running, and twelve more give the same keys while searching, with
|
|
the ones left out keeping their running message. The buttons say what the file
|
|
says, and they change as you move between running and searching.
|
|
|
|
The lines are coloured as N1MM colours them: grey for a comment, blue for the
|
|
keys while running, green for the keys while searching, and red for anything
|
|
past the twenty-four lines that are read, so a file with a line too many says so
|
|
on the screen.
|
|
|
|
This is N1MM's `.mc` format. **Import…** reads a file somebody published for
|
|
N1MM, **Export…** writes one out, and **Back to the defaults** puts the built-in
|
|
messages back. Escape closes the editor and keeps what was there before.
|
|
|
|
The macros are N1MM's, spelled the way N1MM's function-key documentation spells
|
|
them, so a `.mc` file written for either program says the same thing. The text
|
|
macros that are filled in:
|
|
|
|
| | |
|
|
|---|---|
|
|
| `*`, `{MYCALL}` | your callsign |
|
|
| `!`, `{CALL}` | the call being worked, or the last one logged when the box is empty |
|
|
| `#` | the serial number for this contact, or the last one when the box is empty |
|
|
| `{LASTCALL}`, `{PREVNR}` | the call and the serial of the contact just logged |
|
|
| `{EXCH}` | the sent exchange from the contest setup |
|
|
| `{SENTRST}`, `{SENTRSTCUT}` | the report you send, plain or in cut numbers |
|
|
| `{NAME}`, `{NAMEANDSPACE}`, `{CHNAME}` | the other operator's name, from the entry window or the call history file |
|
|
| `{GRID}` / `{GRIDSQUARE}` | your grid / theirs |
|
|
| `{GRIDBEARING}`, `{REVGRIDBEARING}`, `{KMGRIDDISTANCE}` | bearing and distance between the two |
|
|
| `{FREQ}`, `{FREQROUND}` | this radio's frequency in kilohertz, with `R` for the decimal point on CW |
|
|
| `{OTHERFREQ}`, `{OTHERFREQROUND}`, `{OTHERMHZ}`, `{OTHERBAND}`, `{LRMHZ}`, `{RRMHZ}` | the other radio, for passing a station |
|
|
| `{TIMESTAMP}`, `{TIME2}` | the time now |
|
|
|
|
The action macros run rather than standing for text: `{WIPE}`, `{LOG}`,
|
|
`{RUN}`, `{S&P}`, `{SPACE}`, `{SPOTME}`, `{STOPTX}`, `{FREQUP}`, `{FREQDN}`,
|
|
`{PGUP}`, `{PGDN}`, `{JUMPRX}`, `{JUMPRXTX}`, `{STACKANOTHER}`, `{SOCALLSTACK}`,
|
|
`{LOGTHENPOP}`, `{LOGTHENNEXT}`, `{CLRSTACK}`, `{CTRLF1}` to `{CTRLF12}` to send
|
|
on the other radio, `{TELNET sh/dx}` to put a command on the cluster, and
|
|
`{OTRSP TX2}` to send one to the SO2R box. An action runs before the message
|
|
goes out, unless it stands after `{END}`, and then it runs once the message has
|
|
been sent — so `TU {LOG}{END}{WIPE}` logs the contact, sends TU, and clears the
|
|
boxes when the key has finished. Text after `{END}` is dropped, as it is in
|
|
N1MM.
|
|
|
|
How far `{FREQUP}` and the rest move the radio is `FrequencyStepHertz` and
|
|
`PageStepHertz` in `settings.json`, 100 Hz and 1 kHz out of the box; N1MM asks
|
|
for the same two numbers in its Configurer.
|
|
|
|
The rest of N1MM's action macros — the CAT families, audio, rotators, stereo,
|
|
the digital TNC macros — are read and passed over, so a message that holds one
|
|
still sends the right characters.
|
|
|
|
### ESM — Enter sends the message
|
|
|
|
**Config → ESM** turns it on, and it stays on between runs. Enter then sends
|
|
whatever the contact has got to, instead of only logging, which is how most
|
|
people run N1MM. The keys Enter would send next are highlighted, so what is
|
|
about to happen is on the screen.
|
|
|
|
Searching: type a call, Enter sends your call (F4), space moves to the exchange,
|
|
and when the exchange is filled in Enter sends yours (F2) and logs the contact.
|
|
Running: Enter calls CQ (F1); a call in the box makes Enter send his call and
|
|
your exchange (F5 and F2); once the exchange you copied is in the boxes, Enter
|
|
sends the message that ends the contact (F3) and logs it. A station already in
|
|
the log gets QSO B4 (F6) while running, and nothing at all while searching.
|
|
Pressing F1 while searching puts you into run mode, as it does in N1MM.
|
|
|
|
`=` sends whatever Enter last sent, without deciding again. Escape and F12 clear
|
|
the boxes and put ESM back to the start of a contact.
|
|
|
|
Three switches live in `settings.json`, and are N1MM's own:
|
|
`EsmSendsCallOnce` sends your call once while searching and then moves to the
|
|
exchange (N1MM's "big gun" switch), `EsmWorksDupes` works a station that calls
|
|
in again while you are running, and `EsmSendsCorrectedCall` sends the call again
|
|
in front of the last message when you have corrected it — copy `SM3AB`, fix it
|
|
to `SM3ABC`, and the key sends `SM3ABC TU DL1ABC`.
|
|
|
|
### Name, comment, and the two lights
|
|
|
|
Beside the exchange are a Name box and a Comment box, as N1MM has them. Neither
|
|
is part of the exchange, so neither holds up a contact: they fill the log's Name
|
|
and Comment columns, and a contest that exchanges a name uses that instead.
|
|
Neither is in the space walk, as neither is in N1MM's; tab reaches both. The name is filled from the call history file when there is one,
|
|
and what the call history says in its UserText column appears under the entry
|
|
boxes.
|
|
|
|
### Space and tab
|
|
|
|
They are not the same key, and N1MM does not treat them as one.
|
|
|
|
Space moves between the callsign box and the exchange boxes and round again,
|
|
stepping over the report boxes, because nobody types 599: leaving the callsign
|
|
box fills them with the report for the mode, 599 on CW and digital, 59 on phone.
|
|
It also steps over a box this station is not asked for, such as the state in
|
|
CQ WW RTTY for a station outside the US and Canada. So in CQ WW, space takes you
|
|
from the callsign straight to the zone, and space again brings you back.
|
|
|
|
Tab walks every box in turn — callsign, the exchange including the reports, the
|
|
name and the comment — and round again; shift and tab go the other way. N1MM
|
|
does not touch the tab key at all, so tab there walks its boxes in the order
|
|
they are laid out, which is what this does.
|
|
|
|
Run and S&P are two buttons beside the lights; the one you are in is marked.
|
|
Ctrl+? switches between them, and F1 puts you into run mode, as in N1MM.
|
|
|
|
Two lights sit beside them: the left one is green while a radio is answering,
|
|
the right one red while something is going out on the air.
|
|
|
|
### Call stacking
|
|
|
|
A CQ is answered by more than one station at a time. Rather than ask the others
|
|
to call again, put them on the call stack and work them one after another. This
|
|
is N1MM's single-operator call stacking, with N1MM's keys.
|
|
|
|
| Key | Macro | What it does |
|
|
|---|---|---|
|
|
| Ctrl+Alt+G | `{STACKANOTHER}` | puts the call being typed on the stack and clears the boxes, so the next caller can be copied |
|
|
| Alt+G | | the call on top of the stack replaces what is typed |
|
|
| Alt+D | | drops the call on top without working it |
|
|
| | `{SOCALLSTACK}` | one key that both stacks and unstacks: it swaps the call being typed for the one on top, stacks it when the stack is empty, and takes the top call when the boxes are |
|
|
| | `{LOGTHENPOP}`, `{LOGTHENNEXT}` | logs the contact and brings the next caller into the boxes in one key |
|
|
| | `{CLRSTACK}` | empties the stack |
|
|
|
|
Stacking only works while running: a station you are chasing is worked now, not
|
|
later. A dupe is not stacked, nor is your own call, nor a frequency typed into
|
|
the callsign box. `{SOCALLSTACK}` takes the stacked call off before it puts the
|
|
typed one on, so a multiplier you have just typed cannot come straight back into
|
|
the boxes.
|
|
|
|
A call that would bring a multiplier goes to the front of the stack and the rest
|
|
to the back, which is the order N1MM uses on CW and phone. N1MM's digital window
|
|
also offers plain first-in-first-out and last-in-first-out; there is no digital
|
|
window here, so every mode gets that one order.
|
|
|
|
The stack window opens by itself when the first call goes on and closes when the
|
|
last one comes off, or **Window ▸ Call Stack** opens it. The next call out is
|
|
ringed, and each is coloured by what working it would bring, as everywhere else.
|
|
Double-click a call to bring it to the front, right-click to drop it.
|
|
|
|
What is not here: N1MM's ESM "next call key" setting, which picks the function
|
|
key ESM sends when a contact is logged with calls still stacked, and passing
|
|
stacked calls to the other stations of a multi-operator entry.
|
|
|
|
### The buttons and the title bar
|
|
|
|
The twelve function keys sit in two rows of six, with the row of actions under
|
|
them, between the entry boxes and the bearing line, which is where N1MM puts
|
|
them. Each row fills the width, and the first button of the action row takes the
|
|
23 per cent N1MM gives it.
|
|
|
|
The action row is N1MM's: Esc: Stop, Wipe, Log It, Edit, Mark, Store, Spot It
|
|
and QRZ, each doing what its key does. QRZ opens the callsign's page in a
|
|
browser.
|
|
|
|
Mark and Store put something on your own bandmap rather than on the cluster, and
|
|
have N1MM's keys:
|
|
|
|
- **Mark**, Alt+M, leaves a `Busy@` mark where the radio is, so you know not to
|
|
come back to that frequency. It is not a station: nothing judges it, it is
|
|
never offered as a call to work, space does not take it into the callsign box,
|
|
and the bandmap paints it like a station already worked, which is how N1MM
|
|
marks it.
|
|
- **Store**, Alt+O, puts the call being typed on the bandmap at this frequency
|
|
so it can be worked later. Spot It sends the same call to the cluster; Store
|
|
keeps it here.
|
|
|
|
The title bar says what N1MM's says: the frequency, the mode, whether the
|
|
frequency came from a radio or was typed, and which radio the window belongs to
|
|
when there are two.
|
|
|
|
### The band panel
|
|
|
|
Down the left of the entry window is N1MM's band panel: a row per band, a
|
|
column per mode the contest runs, and every cell painted with what the callsign
|
|
being typed would be worth on that band in that mode — red for one new
|
|
multiplier, green for more than one, blue for points, grey for a station already
|
|
worked there. So the panel says where the station is still needed without
|
|
working the bands one at a time. With nothing typed every cell is grey, as N1MM
|
|
leaves it.
|
|
|
|
The bands are the six contest bands, with 30, 17 and 12 metres added for general
|
|
logging, which is the only entry N1MM shows them for. Clicking a cell puts the
|
|
radio where you left that band and mode, or at the start of that part of the
|
|
band the first time. The band and mode the radio is on is ringed rather than
|
|
filled, so the ring does not hide what the cell is saying.
|
|
|
|
### The call frame
|
|
|
|
Above the callsign box is N1MM's call frame: it says which spotted station the
|
|
radio is sitting on, coloured the way the bandmap colours it, or `CQ-Frequency`
|
|
when this is the frequency you last called CQ on. While searching, space with an
|
|
empty callsign box takes the station out of the frame and into the box, so a
|
|
spotted station is worked without typing its call. While running it does not,
|
|
because a running station is answering callers rather than chasing the one it is
|
|
sitting on. How close the radio has to be to a spot is one number per mode in
|
|
`settings.json` — `CwTuningToleranceHertz`, `PhoneTuningToleranceHertz` and
|
|
`DigitalTuningToleranceHertz` — 300 Hz each out of the box, which is how N1MM
|
|
keeps them and what it defaults them to.
|
|
|
|
### Colours
|
|
|
|
The callsign is coloured as it is typed, in N1MM's own colours: blue for a
|
|
station worth working, red when it is new in one multiplier, green when it is
|
|
new in more than one, grey for a dupe. A call under three characters stays blue.
|
|
The same four colours paint a row in the log, a spot on the bandmap and a line
|
|
in the check window, so the three windows cannot disagree.
|
|
|
|
At the right-hand end of the callsign box is N1MM's mark: a tick when the call
|
|
is in `MASTER.SCP`, a question mark while it is not. As in N1MM it only appears
|
|
while the check window is open, for three characters or more.
|
|
|
|
Two themes ship with the program. `light` is N1MM's own palette, down to the
|
|
pale blue behind a window and the ivory on a button; `dark` is the same states
|
|
in colours for a dark screen. Config ▸ Manage Skins, Colors and Fonts picks one,
|
|
and the choice is kept in `settings.json` as `Theme`. Fonts and skins are not
|
|
part of it: the name is N1MM's, the dialog only changes colours.
|
|
|
|
### The status bar
|
|
|
|
Along the bottom of the entry window is N1MM's status bar, in three parts:
|
|
|
|
- On the left, where the call being typed is from, in N1MM's own shape:
|
|
`OM: EU -> Slovak Republic, Zn 15`. The zone is the one the contest counts in,
|
|
so IARU shows the ITU zone and CQ WW the CQ zone. When something has just
|
|
happened — a contact logged, a call stacked, a download finished — that stands
|
|
there instead until the next keystroke.
|
|
- Then the band change timer, for a contest that asks a station to stay on a
|
|
band for so long after moving to it.
|
|
- In the middle, the contacts and multipliers: `10/7/8` is ten contacts, seven
|
|
zones and eight countries, one number per multiplier the contest counts. It
|
|
reads `No Score` before the first contact, as N1MM's does.
|
|
- On the right, the score.
|
|
|
|
The numbers were in the line at the top of the window before. They are here now,
|
|
where N1MM keeps them, so the top line is the contest name alone. The bar under
|
|
the callsign box says what working the call would bring — the points and any new
|
|
multiplier — and no longer repeats the country.
|
|
|
|
### Where the other station is
|
|
|
|
Under the entry window is the line N1MM writes there: the beam heading, the
|
|
heading the long way round, the distance in kilometres, and the sunrise and
|
|
sunset times at the other station, in kilometres and miles as N1MM shows them.
|
|
When it cannot be worked out the line says which end could not be placed, rather
|
|
than going blank.
|
|
|
|
The position comes from the grid square when the contest exchanges one and it
|
|
has been copied, or from the call history file, and from the country file
|
|
otherwise, which puts the station in the middle of its country. Sunrise and
|
|
sunset are worked out from that position for today; inside the polar circles the
|
|
line says the sun does not rise or set.
|
|
|
|
### The grey line
|
|
|
|
**Window → Grey Line** draws the world with the night on it. The dark area is
|
|
where the sun is down; the band along its edge is the twilight between the
|
|
horizon and six degrees below it, which is the grey line itself — the hour when
|
|
the low bands carry furthest along it.
|
|
|
|
On the map: our own station, from the grid square in the station settings; the
|
|
station being called; and every station spotted on the band the radio is on.
|
|
The yellow dot is the point the sun is straight above. The map follows the
|
|
clock, redrawing every minute. Sunrise and sunset for the station being called
|
|
are on the line under the entry window, which is where N1MM puts them too.
|
|
|
|
The coastlines are Natural Earth's 110m coastline, which is public domain, cut
|
|
to a tenth of a degree: `src/Nonemm.App/Assets/coastline.txt`. The sun's
|
|
position is the standard low-precision solar formula, good to about a hundredth
|
|
of a degree.
|
|
|
|
### Where the files live
|
|
|
|
The program keeps its files in N1MM's own folder, `Documents/N1MM Logger+`,
|
|
with N1MM's folders inside it under N1MM's names. A station that runs both
|
|
programs has one set of files rather than two:
|
|
|
|
| Folder | What goes in it |
|
|
|---|---|
|
|
| `Databases` | the `.s3db` log files |
|
|
| `SupportFiles` | `wl_cty.dat`, `MASTER.SCP`, the downloaded cluster list |
|
|
| `UserDefinedContests` | `.udc` files |
|
|
| `FunctionKeyMessages` | `.mc` function key files, where import and export start |
|
|
| `CallHistoryFiles` | the call history files published before a contest |
|
|
| `ExportFiles` | Cabrillo and ADIF, in and out |
|
|
| `Wav` | the voice keyer's recordings, one folder per operator: `Wav/OM3KFF/Cq.wav` |
|
|
| `GoalFiles`, `LettersFiles`, `QsoRecording`, `SkinsAndLayouts`, `SystemFiles`, `TransactionLogFiles`, `Diagnostics` | N1MM's, and made for the same reason: a station that keeps files in them does not lose them moving between the two programs. Nothing here writes to them yet |
|
|
| `Nonemm` | this program's own, for what N1MM has no place for: `settings.json` |
|
|
|
|
N1MM's three `*DDL` folders and its `Piper` folders are not made: those hold
|
|
the migrations for N1MM's own admin databases and the program it speaks with,
|
|
and neither has anything to do with a log.
|
|
|
|
On a system that does not say where Documents is — most Linux systems, until
|
|
someone sets `XDG_DOCUMENTS_DIR` — it is `~/Documents/N1MM Logger+`. Setting
|
|
`NONEMM_HOME` puts the whole lot somewhere else, which is what a station keeping
|
|
its files off the Documents folder, or running two copies side by side, wants.
|
|
|
|
If a folder cannot be made — something else is already sitting at that path, or
|
|
the disk will not have it — the program says so in a window and stops, rather
|
|
than dying with a stack trace before it has a window to say anything in.
|
|
|
|
### Operators
|
|
|
|
**Ctrl+O**, or **Config → Change Operator…**, asks who is at the radio. The
|
|
callsign goes on every contact logged from then on, in the log's Op column and
|
|
in the ADIF `OPERATOR` field, and `{OPERATOR}` in a message sends it.
|
|
|
|
Each operator keeps three things of his own, which is what makes the key worth
|
|
pressing at a multi-operator station:
|
|
|
|
| Kept | What happens on the way in and out |
|
|
|---|---|
|
|
| Window positions | where every open window sits is stored against the operator leaving, and the operator taking over gets his own back. A window opened later is placed as it appears |
|
|
| Colours | the theme he last had |
|
|
| Recordings folder | the folder his wav files are in, since a voice keyer plays the recordings of whoever is at the microphone. It starts at `Wav/<his callsign>`, which is where N1MM looks, and the folder is made when he takes the radio |
|
|
|
|
An operator whose callsign is not in the list is made by typing it, and starts
|
|
with the windows and colours on the screen. **Remove** drops one from the list;
|
|
the contacts he logged keep his callsign, because those are in the log rather
|
|
than in the settings.
|
|
|
|
Nothing plays the recordings yet — there is no voice keyer — so the folder is
|
|
stored and passed on rather than used.
|
|
|
|
### The log window
|
|
|
|
The pane under the log lists what has already been worked with the call being
|
|
typed: every earlier contact whose call holds it, on any band and in any mode,
|
|
so an apparent dupe can be read off the screen. `*` stands for any run of
|
|
characters and `?` for one. With nothing typed and a grid square copied, it
|
|
lists the contacts from that grid square instead. N1MM has the same pane, and
|
|
stops at fifty contacts as this does.
|
|
|
|
Both grids get the same columns, each as wide as the longest value it can hold,
|
|
with the last column taking what is left over.
|
|
|
|
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.
|
|
|
|
**Edit → Edit Last Contact**, Ctrl+Y, or Enter on a row in the log opens the
|
|
whole contact in one dialog. That is where the fields with no log column live:
|
|
QSX frequency, name, QTH, comment, grid, power, radio number, run position, and
|
|
the country and WPX prefixes. ◀ and ▶ walk the log without closing, offering to
|
|
save first. Points and the multiplier flags are shown but cannot be typed in —
|
|
they are worked out from the rules every time the log changes, so anything typed
|
|
there would be overwritten on the next edit.
|
|
|
|
Correcting the country prefix by hand changes the score. The country file is a
|
|
best guess for calls it has no rule for, so what the contact says now wins over
|
|
what the file says.
|
|
|
|
### Call history files
|
|
|
|
**Config → Call History File…** points at one of the files published before a
|
|
contest. It is N1MM's format, so a file written for N1MM is read as it is:
|
|
`#` comments, `!!Order!!` naming the columns of the lines after it, semicolons
|
|
in preference to commas, and the directives that change what is stored —
|
|
`!!FourCharGridSq!!`, `!!NoLoc2AltGrid!!`, `!!MapStateToSect!!`,
|
|
`!!AppendUserText!!`, `!!NoAppendUserText!!` and the four that clean up the
|
|
section and state columns.
|
|
|
|
Leaving the callsign box fills what the file knows into the exchange boxes that
|
|
are still empty. A box with something in it is left alone: what the other
|
|
station actually sends beats what somebody published months ago. The check
|
|
window gets a History column of matching calls.
|
|
|
|
These files are built from years of logs, so the section and state columns
|
|
carry old names. Four directives say what to do about that, and all four are
|
|
carried out as they are read:
|
|
|
|
| Directive | What it does |
|
|
| --- | --- |
|
|
| `!!MapOnSection!!` | `GTA`, `GH`, `ONE`, `ONN` and `ONS` are stored as `ON` |
|
|
| `!!ValidateArrlSection!!` | a section that is not one of N1MM's is dropped |
|
|
| `!!GTA2GH_NT2TER!!` | `GTA` is stored as `GH`, `NT` as `TER` |
|
|
| `!!Validate50State!!` | the state column keeps one of the 50 states, turns a section into the state it is in, and drops the rest |
|
|
|
|
The section list is N1MM's, which is not the same list its entry window offers:
|
|
it holds the retired `GTA` and `NT` so a file carrying an old name is fixed
|
|
rather than thrown away, and it leaves out `ON`, so a file asking for both
|
|
`!!MapOnSection!!` and `!!ValidateArrlSection!!` ends with no section — which
|
|
is what N1MM does, and what the file's own author asked for.
|
|
|
|
### The check window
|
|
|
|
Five columns, kept apart because they answer different questions: **Log** is
|
|
what this station copied itself, **Master** is a guess about the whole world,
|
|
**History** is what was published before the contest, **Bandmap** is somebody
|
|
else's claim, and **Exchange** offers the values the exchange box with the
|
|
cursor in it can hold — the ARRL sections, or the states and provinces. A
|
|
serial number or a report has no list behind it, so that column stays empty
|
|
rather than guessing.
|
|
|
|
### Available mults and Qs
|
|
|
|
**View → Available Mults and Qs** lists what is spotted and not worked yet, a
|
|
column per band, multipliers first and then the stations that are only points.
|
|
Clicking one puts the radio there with the call in the entry window, the same as
|
|
clicking a spot on the bandmap. **Mults only** hides everything that brings no
|
|
multiplier.
|
|
|
|
A spot carries no exchange, so a station is only known to be a multiplier where
|
|
the multiplier follows from the callsign — a DXCC entity — or where the call
|
|
history file says what the station sends. That is why CQ WW shows the country
|
|
but not the zone: the zone that counts is the one the station sends, and the
|
|
country file's guess is wrong for the large countries. A call history file with
|
|
a `CQZone` column fills that in.
|
|
|
|
A spot carries no mode either. Stations are judged in the mode the radio is in,
|
|
so in a mixed-mode contest the answer follows the operator.
|
|
|
|
### Sessions, time off and band changes
|
|
|
|
A contest can be run in sessions, and a `.udc` file says so with
|
|
`MultipleSessions = 0000/30` — sessions of thirty minutes from 00:00 UTC. A
|
|
station worked in an earlier session may be worked again, and
|
|
`ResetMultsEverySession` and `ResetSNEverySession` start the multipliers and the
|
|
serial numbers over as well.
|
|
|
|
`DupeQSOMinutesAgo` is the other way a contest lets a station be worked again:
|
|
after so many minutes rather than in the next session. Its `IgnoreBand` and
|
|
`ThisMode` settings decide whether the earlier contact is looked for on this
|
|
band only and in this mode only.
|
|
|
|
The score summary shows the time on and the time off under the score. A break
|
|
counts as time off once it is as long as the contest's `MinimumOffTime`, which
|
|
is 30 minutes unless the file says otherwise. Next to them, for a contest that
|
|
limits band changes, are the changes made and the allowance —
|
|
`SingleOpCountableBandChange` and the rest of that family.
|
|
|
|
`SOBandChangeTimerDuration` and `MOBandChangeTimerDuration` say how long a
|
|
station has to stay on a band it has moved to, and the countdown stands in the
|
|
status bar while it runs, reading `band 04:12` — `band/mode 04:12` for a contest
|
|
that counts a change of mode as well. It is there only for a contest that asks
|
|
for a stay and for the category the contest counts band changes for, so most
|
|
contests show nothing. The stay starts at the minute after the contact that
|
|
changed band, which is where N1MM starts it.
|
|
|
|
### Radios
|
|
|
|
**Config → Radios** takes a `rigctld` address per radio. Each radio needs its
|
|
own `rigctld`, started for whichever rig is on that port:
|
|
|
|
rigctld -m 2028 -r /dev/ttyUSB0 -t 4532
|
|
rigctld -m 1035 -r /dev/ttyUSB1 -t 4533
|
|
|
|
Commands go out with a `+` in front, which asks `rigctld` for its extended
|
|
answer: named fields ended by an `RPRT` line. The raw answer is bare values with
|
|
no terminator, so the client has to know how many lines each command returns,
|
|
and one wrong count leaves the connection reading every later answer against
|
|
the wrong command.
|
|
|
|
Split is read from the radio and recorded: the contact stores where we
|
|
transmitted in N1MM's QSX column, the entry window shows `14008.00 ▸ 14020.0`,
|
|
and the bandmap draws a red bar at the transmit frequency. A radio that cannot
|
|
do split answers `RPRT -11`; that is an answer, not a broken connection, and
|
|
everything else it reported still counts.
|
|
|
|
A second radio makes the station SO2R and opens a second entry window. The two
|
|
windows share one log, one score and one run of serial numbers, so a station
|
|
worked on radio 1 is a dupe on radio 2. What is typed, the frequency, the mode
|
|
and whether you are running belong to each radio on its own.
|
|
|
|
| Key | What it does |
|
|
|---|---|
|
|
| Ctrl+Tab | moves you to the other radio: the keyboard, the entry window and the box all follow |
|
|
| Ctrl+Shift+Tab | puts both radios in the headphones, and back |
|
|
|
|
Both radios show on the bandmap — the one you are on in green, the other in
|
|
orange — but only the one you are on drives its entry window, so the second
|
|
radio moving cannot drag you off the station you are working.
|
|
|
|
An SO2R box speaking OTRSP routes the key and the headphones. Name its serial
|
|
port in **Config → Radios** and it follows: `TX2` when you move to radio 2,
|
|
`RX1S` when you ask for both radios, and `TX` again before every message goes
|
|
out, so a message cannot go out of the radio you have just left. A command that
|
|
would change nothing is not sent, because the box works relays. Without a box
|
|
the logger just keeps track of which radio it is on and you switch by hand.
|
|
|
|
Not there yet: voice keying on the second radio.
|
|
|
|
### Alternating CQ
|
|
|
|
**Ctrl+B** calls CQ on one radio, and when that message has gone out, moves to
|
|
the other radio and calls there, until another Ctrl+B switches it off. The
|
|
keyboard, the entry window and the SO2R box follow each turn. N1MM calls this
|
|
dueling CQs and puts it on the same key.
|
|
|
|
Only the CQ carries it on to the other radio. Sending anything else — the other
|
|
station's call, the exchange — holds the CQ where it is, and so does Escape, so
|
|
a station that answers can be worked without switching alternating CQ off. The
|
|
next CQ picks it up again, which is what the CQ after a logged contact does.
|
|
N1MM works the same way.
|
|
|
|
It runs off the keyer saying the message has gone out, not off a guess at how
|
|
long the text takes: `cwdaemon` answers the `<ESC>h` reply request, and a
|
|
WinKeyer clears the busy bit in its status byte. A keyer that cannot report this
|
|
cannot drive alternating CQ, and says so rather than keying the second radio
|
|
while the first is still sending. **Config → Keyer and messages** sets the gap
|
|
between the two, which is 100 ms by default because an SO2R box works relays.
|
|
|
|
CW only for now: it sends the F1 message, and there is no voice keyer.
|
|
|
|
Why the keying is `cwdaemon`'s job rather than the logger's, and what it would
|
|
take to key the port directly as N1MM does, is in
|
|
[`docs/keying.md`](docs/keying.md).
|
|
|
|
### The bandmap
|
|
|
|
A frequency scale down the left with the stations written out beside it. Each
|
|
callsign sits level with its frequency, and when two stations are too close to
|
|
write one above the other the lower one moves down and a leader line runs back
|
|
to where it really is. That is what N1MM does, and the stacking follows its
|
|
rule: place the label centred on its frequency, and push it below the one above
|
|
if it would cover it.
|
|
|
|
The slice shown follows the receiver — 10, 20, 40 or 100 kHz, or the whole band
|
|
— and stretches past the band edge when the radio is past it.
|
|
Callsigns are coloured by the same scorer as the entry window, so a dupe reads
|
|
as a dupe here too. Clicking a callsign puts the radio there with the call
|
|
already in the entry window; clicking anywhere else just moves the radio.
|
|
|
|
The bars on the scale are as wide as the mode passes: green where you are
|
|
listening, red where the radio transmits when working split, orange for the
|
|
other radio of a two-radio station.
|
|
|
|
Behind the scale the CW part of the band is one shade and the phone part
|
|
another, with a third shade for a digital block where one is set, and the CW
|
|
boundary named in the status line. Anything past a band edge is shaded red,
|
|
which is where the edges show. N1MM paints the same blocks from its `CWBands`,
|
|
`DigiBands` and `SSBBands` tables.
|
|
|
|
**Config → Sub bands** edits them, one row per band, in kilohertz, with a
|
|
Defaults button. The digital pair starts empty, as N1MM's does, so nothing is
|
|
painted for it until it is filled in. Only the rows that differ from the
|
|
defaults are written to the settings file.
|
|
|
|
The defaults are one worldwide set, as N1MM's are, not one per ITU region. They
|
|
are a drawing aid: a contact logs either side of a boundary just the same.
|
|
Bands where N1MM's own numbers contradict themselves — 60M, and everything
|
|
above 2M — get no shading rather than a guess.
|
|
|
|
### Worked All Europe
|
|
|
|
WAE is scored differently from everything else here. A multiplier counts four
|
|
times on 80 metres, three times on 40 and twice on 20, 15 and 10, and half the
|
|
score is QTC traffic: one station reports contacts it has already made to the
|
|
station it is working, and every line reported is a point for both of them.
|
|
|
|
The QTC lines live in the log as rows of their own, which is where N1MM keeps
|
|
them — `Exchange1` says `SQTC` or `RQTC`, the time, callsign and serial number
|
|
of the contact being reported go in the sent report, received report and sent
|
|
number columns, and the series such as `9/10` goes in the misc text column. A
|
|
log written by either program therefore opens in the other with its QTCs
|
|
intact, and a QTC row is written to the Cabrillo file as a `QTC:` record.
|
|
|
|
**Ctrl+Z** opens the QTC window for the station being worked, which is the key
|
|
N1MM uses. The window is laid out the same way: the header, ten lines of time,
|
|
callsign and serial number, an Agn and a Cfm button beside each, and Clear,
|
|
Close and Cancel underneath. Green is a line that will be saved, red one that is
|
|
still empty, yellow one that cannot be read. Enter and Tab move forward, space
|
|
moves within a line.
|
|
|
|
Receiving, the lines are typed as they arrive. Sending, they are filled from the
|
|
log — the contacts not reported to anybody yet, oldest first, never the station
|
|
being worked, and never more than the ten any station may have — and cannot be
|
|
edited. On CW and SSB the direction is fixed by the rules; on RTTY traffic goes
|
|
both ways and the window has a switch.
|
|
|
|
Right-click the window for **Setup**: how many QTCs a series carries, whether
|
|
the RX Ready and Cfm steps are stopped at, whether Hdr Agn and Agn clear what
|
|
they ask for again, and the CW messages below. The defaults are N1MM's — both
|
|
steps skipped, the header cleared, the line left alone.
|
|
|
|
On CW the window puts the traffic on the air itself, through the same keyer a
|
|
function key sends through. The buttons carry N1MM's names, which say what they
|
|
do in the direction the traffic is going.
|
|
|
|
Reading a series out:
|
|
|
|
| | |
|
|
|---|---|
|
|
| R U QRV | `QRV?`, asking whether the other station is ready |
|
|
| Snd Hdr | the header of the series, `QTC 3/10` |
|
|
| Snd1 to Snd10 | one line: the time, the callsign and the serial number |
|
|
| 1, 2, 3, 4 | sends the time, the call, the serial or the header of the last line again, for a station that missed a piece of it |
|
|
| Exit | saves the traffic and sends the TU message |
|
|
|
|
Taking one down:
|
|
|
|
| | |
|
|
|---|---|
|
|
| QRV | `QRV`, telling the other station to go ahead |
|
|
| Hdr Agn | `HDR AGN`, asking for the header again |
|
|
| Shift 1, Shift 2, Shift 3 | asks for that one field again — `AGN TIME`, `AGN CALL`, `AGN SERIAL` — and clears it |
|
|
| Exit | saves the traffic and sends the TU message |
|
|
|
|
The TU message goes out whichever way the traffic went, and `{QTC}` in it stands
|
|
for the header, so `TU {QTC} 73` goes out as `TU QTC 3/10 73`. It is empty out
|
|
of the box, and then nothing is sent. The gap between the fields of a line is
|
|
written N1MM's way, with `S` for a space, so `SS` is two and anything else goes
|
|
out as it stands. All of it is edited in Setup, with N1MM's defaults. The serial
|
|
number goes out as digits: N1MM can send cut numbers, and nothing here does, for
|
|
any message.
|
|
|
|
Nothing is sent on SSB or RTTY. N1MM plays four recordings on SSB — QRV, Agn,
|
|
Cfm and TU — and sends RTTY through its digital window; this program has no
|
|
voice keyer and no digital window, so on those two modes the buttons move the
|
|
cursor as they did before. N1MM's RTTY window also has a Send All button that
|
|
keys the whole series at once; there is nothing to send it with here.
|
|
|
|
In a WAE contest the log window has N1MM's **QTC?** column, which holds the
|
|
series a QTC row belongs to and is empty for an ordinary contact.
|
|
|
|
The scoring was checked against six real WAE logs, and agrees with N1MM on
|
|
points and on weighted multipliers to the contact.
|
|
|
|
### Band edges
|
|
|
|
A contact just outside a band edge keeps its band. `Bands.ForFrequency` first
|
|
checks the real edges, and for anything outside them falls back to the whole
|
|
megahertz: 14400 kHz is 20M, 7305 kHz is 40M. This is N1MM's rule, and it is
|
|
there because contest operating goes past the edges — someone answers a CQ at
|
|
14352, or a radio reports a frequency a few hundred hertz off — and a contact
|
|
with no band scores nothing and exports wrong. Below 1 MHz the megahertz is
|
|
always 0, so 2190M and 630M are told apart by their edges alone.
|
|
|
|
### The DX cluster
|
|
|
|
**View → Telnet**, or **Config → Cluster**, opens the telnet window. It has four
|
|
tabs, the ones N1MM has:
|
|
|
|
- **Telnet** shows the node's traffic as it arrived, spot lines in green and
|
|
what went out in blue. Type a command at the bottom, or press one of the
|
|
buttons; up and down walk back through what has been typed. Double clicking a
|
|
spot line, or "Jump to this spot" on the right-click menu, puts the radio
|
|
there with the call in the entry window. Scrolling stops while the pointer is
|
|
over the traffic, so a line can be read while the node keeps sending.
|
|
- **Clusters** keeps a list of nodes with their names, ports, passwords and the
|
|
commands to send after login. Connect and Disconnect are there, with automatic
|
|
logon, the call to log on with, and the keep-alive interval. **Download** under
|
|
it fetches the published list of nodes from
|
|
[NG3K](https://www.ng3k.com/misc/cluster.html) — around fifty nodes with the
|
|
sysop's call, the address and a note about each — and clicking one fills the
|
|
boxes in. N1MM downloads its list from its own web service, which asks the
|
|
operator to opt in to data collection; this reads a public page instead.
|
|
- **Filters** says which spots reach the bandmap: bands, modes, beacons, busted
|
|
calls, stations outside the call history file, blacklisted spotters and calls,
|
|
whether to take spots only from your country, your continent or a list of
|
|
prefixes, and how long a spot stays on the bandmap. It also holds the preferred
|
|
spotters and the switch that randomises incoming CW spot frequencies. Nothing
|
|
is filtered out of the traffic itself; the operator sees everything the node
|
|
sends.
|
|
- **Buttons** edits the twelve command buttons: a label and its commands, or
|
|
back to the defaults.
|
|
- **Spot comment** is what goes out with the spots you send.
|
|
|
|
The buttons come from the settings; without any, they are `sh/dx`, `sh/dx/20`,
|
|
`sh/wwv`, `sh/users`, `sh/c/n`, `help` and `bye`. A button holds what N1MM's
|
|
buttons hold: several commands separated by semicolons, the function-key message
|
|
macros — `sh/dx {MYCALL}` sends the station callsign — or `{CONN}` and the name
|
|
of a favourite, which connects to that node instead of sending anything. The
|
|
label takes the macros too, expanded once when the buttons load, so a label of
|
|
`{MYCALL}` reads as the callsign. Right-clicking a button opens the editor, and
|
|
its tooltip shows the command behind it. What is typed on the command line goes
|
|
out as typed, again as N1MM sends it. The one place this differs from N1MM: the
|
|
commands of one button go out together rather than a quarter of a second apart.
|
|
|
|
The window says which cluster program the node runs — DXSpider, AR-Cluster, CC
|
|
Cluster or GoCluster — once the node's banner names it, which is where N1MM
|
|
reads it too.
|
|
|
|
`sh/dx` is refused while the contest entry is single operator and not assisted,
|
|
with the same message N1MM gives. Asking the node for spots is what an
|
|
unassisted entry may not do.
|
|
|
|
Three of the filters are worth spelling out:
|
|
|
|
- **Busted spots.** A spotted call the callsign database has never heard, but
|
|
which is one character away from a call it does know, is a miscopy and is
|
|
dropped. A call nothing resembles is kept, because that is what a new station
|
|
looks like. Without `MASTER.SCP` nothing is called busted.
|
|
- **Preferred spotters.** Spot lines from those spotters are written in bold, so
|
|
the spotters worth believing stand out. They are matched on the start of the
|
|
call, so `W3LPL` also covers `W3LPL-#`. Nothing is filtered by this.
|
|
- **Randomised frequencies.** Each incoming CW spot is moved thirty or sixty
|
|
hertz either way, which is what N1MM does, so the operator has to find the
|
|
station by ear. Left where they are: phone and digital spots, stations already
|
|
worked, stations working split, your own spots, and stations passed to another
|
|
band — the same list N1MM leaves alone.
|
|
|
|
Spots wait up to a second before they reach the bandmap, and then go on together.
|
|
N1MM collects them the same way: a skimmer feed sends more spots a minute than
|
|
any window can usefully redraw.
|
|
|
|
The client speaks telnet properly: it answers the option negotiation instead of
|
|
letting the control bytes turn up in the first lines of text, and it reads the
|
|
login prompt out of a partial line, because nodes write `login: ` with no line
|
|
ending. If no prompt arrives within ten seconds the callsign goes out anyway,
|
|
which is what N1MM does. A connection that has heard nothing for four minutes
|
|
gets a blank line, so the node does not drop it as idle. A dropped connection is
|
|
retried. The last two hundred lines are kept, so a window opened mid-contest is
|
|
not blank.
|
|
|
|
Alt+P, or **Edit → Spot It**, puts the call being typed on the cluster at the
|
|
current frequency, with the comment from the Spot comment tab — which takes the
|
|
message macros too; with nothing
|
|
typed it spots the last contact logged. The spot also goes straight onto our own
|
|
bandmap rather than waiting to come back round from the node.
|
|
|
|
Filters are applied to the spots, not to the node: it is still worth filtering
|
|
at the node as well, because that is less traffic on the wire.
|
|
|
|
### 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.
|
|
|
|
A contact that arrives is put into the log where its timestamp says it belongs
|
|
and the log is scored again, so of two stations that worked the same multiplier
|
|
the one that worked it first keeps it, however late the message turns up.
|
|
Nothing else moves: what is being typed at either radio is left alone, and the
|
|
windows redraw where they stand.
|
|
|
|
## 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`, and the SO2R box |
|
|
| `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.Digital` | MMTTY and 2Tone, over the Wine bridge in `bridge/` |
|
|
| `Nonemm.Session` | The contest in progress, and one entry position per radio — 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, graphical bandmap, score and telnet 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.
|
|
|
|
Nothing here has been run against a real radio, keyer, SO2R box or cluster node.
|
|
Every one of those is tested against a fake that speaks the same protocol, which
|
|
proves the two agree with each other and nothing more.
|
|
|
|
[`docs/unfinished.md`](docs/unfinished.md) lists what is half-built and what has
|
|
never been tested against the real thing.
|