Found by tracing the app with a fake skimmer feed, a fake rigctld and
eight tool windows open (about 3,500 spots on the bandmap).
- Drop expired spots from the one-second spot timer instead of from each
window's refresh on the UI thread.
- Bandmap keeps the lists On and All return until the spots change, and
Near searches only the band the frequency is in.
- The Available window replaces its rows at most every two seconds, the
Score window redraws at most once a second, and the Telnet list takes
new lines four times a second at most (RateLimited).
- The bandmap leader line pen is made once.
Idle CPU in that setup went from about 33-70% of one core to about 16-25%.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The summary table labels had no foreground set, so only the highlighted
numbers drew. The window now has the two-line Mults/Qs and Bands/Modes
buttons, a bold summary table, a list sorted on frequency, a ringed picked
row, a tick in the Mlt column and N1MM's empty-list message.
Bands & Modes opens a window with band groups and the CW, Phone, Digital and
Contest modes. The hover text uses SpotDescription like the bandmap, so
control characters and the cluster time are gone. Grid columns keep a
minimum width of their heading in the Available, Statistics and Network
status windows.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Redraws:
- Merge bursts of session and bandmap events into one redraw
(Coalesced). Closed Bandmap and Available windows now unsubscribe.
- Grayline and Voice Keyer no longer subscribe to the session twice.
- Available summary, Score table and Log rows redraw only when their
contents change. Telnet lines are added in batches.
- Bandmap view reuses its layout, shaped text and brushes. Grayline
draws the coastlines as one cached shape.
Threads:
- Available, Bandmap colours, Check and Statistics do their judging
and counting on the thread pool and draw the result on the UI thread.
- ContestLog takes a lock in Judge and in each method that changes the
log, so a background Judge cannot read the indexes mid-edit.
Refresh rate:
- Statistics refreshes every 30 seconds and when the QSO count changes.
- Grayline refreshes at most every 15 seconds on session events.
Publish with ReadyToRun to cut startup JIT time.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The window is now a summary table of mults, Qs and totals per band over a
sortable spot grid with Call, Freq, Mode, Dir, Mlt, SN, TS, Spotter, Grid,
Sun, Pts and a preferred-spotter column. Columns can be hidden, headers
sorted, and the list stops re-sorting for six seconds under the mouse.
Adds the Mults / Mults & Qs button, a Bands & Modes filter, delete and
blacklist from the right-click menu, Alt+A stepping, and QSY to the top spot
after logging. Spot gains Snr and IsSkimmer, Bandmap gains Remaining, and
AvailableStation carries the path to the station.
The menu item no longer has apostrophes. SO2R, SO2V and the other missing
pieces are listed in docs/unfinished.md.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Frequency steps, band buttons and bandmap clicks moved the position
before the radio reported back, so the move was never seen. They now
call AppSession.TuneHere, which spots at once.
The spot was also skipped when every required exchange box had text.
Contests that fill those boxes automatically made that true for a
call alone, so the check is removed.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The window manager activates another window when the entry window
minimizes, and raising the windows then restored the entry window.
Raising is now skipped while the entry window is minimized and for a
second after its state changes. Restoring the entry window puts focus
in the callsign box.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Each key press in an entry box ran Refresh, which redraws the entry window
and every open tool window between two key presses. The refresh is now
posted at background priority, so the key presses already queued are
handled first and a burst of letters costs one refresh.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Both are checkboxes in Manage Skins, Colors and Fonts and default to on.
The entry window minimizes and restores the other windows with itself.
Activating any window raises the others that are not minimized.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
An owned window is transient-for its owner on X11, so the window manager
kept every tool window above the entry window. The windows now have no
owner. The entry window closes them when it closes, and minimizes or
restores them when its own state changes.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Station Number, Port and Version to claim are now on the Options tab of
Network Status and save when a box loses focus. The other settings
(station name, listen port, peers, link on/off) are in a Stations
Configuration window opened from a button on the same tab. The explanation
texts and the Config menu item are removed.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
A QSO logged in Run mode is no longer added to the bandmap as a local
spot, including when recent contacts are re-spotted at startup.
Releasing Alt moves focus to the menu bar. Alt+W now sets a flag, and
the Alt key-up handler puts focus back on the callsign box.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Favourites show the callsign in bold, the address and the sysop's note,
and each keeps its own password, commands, logon call and note. Clicking
one fills the boxes for editing. Autoconnect marks the favourite to
connect to at start and replaces the old reconnect-to-last-node setting.
A new published list refreshes the notes of the favourites in it. The
published list now spans the window, and the Spot comment tab becomes
Login & Spots with the logon call and keep-alive.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The spot timeouts, the QSY spot and CQ frequency distances and the
recent contact minutes leave the telnet Filters tab for a window under
Config. Each is a numeric box with a range.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
CW and digital spots time out after 10 minutes and phone spots after 30
by default, both settings on the telnet Filters tab. The mode comes from
the band plan; a frequency it has no boundaries for counts as phone.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
A contest opening and contacts arriving from the other stations, a
resync included, spot the contacts logged in the last few minutes (a
setting on the telnet Filters tab, 0 for none). A station the bandmap
already holds on that band keeps its spot. Nothing is sent out. Spots
that come from the log are drawn in italics.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
For sh/wwv, only the first record under the header is used, since the
table lists the newest first. The date, time, forecast and logger are
dropped, and the status bar reads "SFI 140 A 5 K 2". The line the node
sent is the tool tip. Announcement lines give the same three values.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The reader follows N1MM's rules for WWV and WCY lines and the sh/wwv
table. The bar is hidden until the cluster has sent some.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Starting Run stores the frequency in the position. The bandmap draws a
purple, bold "CQ Frequency" pseudospot there, which is not added to the
shared bandmap, and a click on it tunes back and sets Run. A move of more
than 3 kHz (a setting on the telnet Filters tab) while running switches
to search and pounce.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The zoom list gains 60 kHz and a "mode" level that shows the CW, digital
or phone part of the band the receiver is in, before "band". For views
from 40 to 200 kHz wide, the scale picks the smallest round step that
keeps three lines of text between ticks. The font size buttons are
removed; Ctrl with the wheel or plus and minus still change the size.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
A spot an operator put on a bandmap, here or on another computer, is
drawn in bold. Its hover text names the computer instead of the
spotter's callsign. A spot from another computer carries the name from
the ADDSPOT message.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The tool tip has no show delay and the theme's fade is removed. The
carrier tick reaches 30 px further to the right.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The radio reports the frequency in small steps as the knob turns, and
each step was compared with the one before, so no step passed the
threshold. The move is now measured from the frequency the radio had
when the call appeared in the entry window. The threshold is a box on
the Filters tab of the telnet window.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Ctrl+wheel and Ctrl+plus / Ctrl+minus change the text size of the
window in front, and Ctrl+0 puts it back. Each size is kept in the
settings file.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
- Turn off scroll bar auto-hide for ScrollViewer and DataGrid.
- Make the splitter between the two log grids 5 px, in the grid line color.
- Remove the log window status bar. The stats are in the entry window.
- Show a refused log edit in an alert dialog.
- Keep the log grid's rows in an ObservableCollection, so a new contact
does not rebuild the list and move the view.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
With a call in the entry window, a move of more than 2 kHz on the same
band puts the call on the bandmap where it was heard and wipes the boxes,
as N1MM does. The spot goes to the other stations as ADDSPOT and to the
Spots broadcast, never to the cluster. ADDSPOT from other stations is
added to the bandmap.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Listen for Radio broadcast data from another Nonemm or N1MM computer and
record its frequency, mode and split as this computer's own radio. No
radio is controlled. The settings are in the Configure Radios dialog.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Remove the status bar and the band name, add the 75 and 150 kHz spans,
add buttons for the callsign size (saved in the settings), draw the scale
in the form's text colour so it shows in the dark theme, mark the carrier
on the VFO bar and place a sideband bar on its side of the carrier, and
show who spotted a station, when, and the comment when the pointer is on it.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The entry window sizes its height to its content, and Place skipped the
saved size for any window that sizes itself on either side.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The generic name only resolves through fontconfig, so on Windows the
windows fell back to the proportional default.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The wheel steps along the span list and keeps the frequency under the
pointer in place. With Centre on VFO off, the slice stays put until the
receiver nears an edge. The span and the toggle are saved in the settings.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Lines were as tall as a list item, with padding of more than the text. A
line is now as tall as its text, the view always follows the newest line
instead of pausing under the pointer, and a burst of lines is scrolled
once. The scrollback is a thousand lines.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The window picked a brush on the socket thread, and Avalonia crashed the
program the next time it painted that line. A line that arrives is now
posted to the window thread first. Spots no longer show the bell
character as a box, and an unexpected error in the cluster loop is
shown instead of ending it silently.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
ApplyNetworkSettings disposed the station link without clearing it, so
ApplyStationLinkSettings disposed it a second time and threw. Only the
second function touches the link now, and StationLink.Dispose can be
called twice.
Contacts from the network are queued and applied together on the window
thread. Each one used to rescore the whole log and redraw the log window,
which kept the window thread busy for minutes during a resync.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The bridge launched its helper only through Wine. It now starts any
process, so on Windows it runs the helper directly. WineBridgeChannel is
renamed ProcessBridgeChannel.
WindowsControlSetup sets up the control side on Windows. The digital
dialog, AppSession, README and docs/digital-bridge.md describe the
Windows setup. publish-windows.sh builds a Windows release.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
CQ WW lists LOCATION as required, and the export never wrote it. It now
carries the ARRL section, state or province, or DX.
CQ WW M/2 has no stay on a band: it may make eight band changes in a clock
hour. It was getting the ten-minute stay that M/S has.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Going down N1MM's published list, the ones a contest operator would miss:
| | |
|---|---|
| `{LASTEXCH}` | what the last station sent, built from the boxes the contest asks for |
| `{ROVERQTH}` | where a rover is now |
| `{TIME}`, `{DATE}`, `{TIMEGMT}`, `{DATEGMT}` | the clock and the calendar |
| `{ESC}`, `{CTRL-A}` to `{CTRL-Z}` | the control characters a TNC reads as commands |
| `{CTRLHOME}` | the cursor back in the callsign box |
| `{F1}` to `{F12}` | another of this radio's keys, where `{CTRLF1}` is the other radio's |
| `{CQ}` | makes any key a CQ key: it starts running and carries alternating CQ on |
| `{DIGQTCS}`, `{DIGQTCR}` | opens the WAE QTC window the way asked for |
| `{CLEARRIT}` | the receive offset back to zero, which is rigctld's `J 0` |
| `{FORCELOG}` | logs what is in the boxes, holes and all |
`{FORCELOG}` is the one that gives something up. `LogContact` refuses an entry
that is short or holds a value the contest will not take, so that a caller who
has not checked cannot log nonsense; `LogContactAnyway` is the way past it,
because a contact in the log with a hole in it can be filled in afterwards and
one that was never logged cannot. It still needs a callsign, and the status
line says the row will need fixing before the log goes in.
A key that names itself would send for ever, so a key sending another key
ignores the macro a second time down.
What is still passed over is written down in the README and unfinished.md.
Advanced voicing is the one that matters: N1MM says a callsign or a serial by
playing a recording per letter out of `LettersFiles`, which is why `!` and `#`
say nothing on phone here and why F5 is empty in N1MM's own SSB file too. The
three packet BBS date formats are passed over because there is nothing here to
check a guess at them against.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0157i7PiZyqBkquxS9A6FTdQ
N1MM records a phone message from the entry window: Ctrl+Shift+F1 to
Ctrl+Shift+F12 records into the file that key plays, and the same pair again
stops and saves it. Escape and sending anything stop one too — there is one
microphone, and it cannot be recorded and transmitted at the same time. The
status line says what is being recorded and what was saved, which is where
N1MM says it.
The recording being made is the session's rather than the window's, for the
same reason: the voice keyer window and these keys record into the same
microphone, and now each can see what the other started.
Alt+K opens the function key editor for the mode the radio is on, which is
N1MM's shortcut for what right-clicking a key button already did.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0157i7PiZyqBkquxS9A6FTdQ
A phone function key names a wav file instead of words, which is what N1MM's
own SSB file holds: `F1 CQ,{WAVDIR}\Cq.wav`. `{WAVDIR}` is the folder named
after whoever is at the microphone, a name is taken relative to `Wav`, and
commas play several files in a row. An SSB `.mc` file written for N1MM plays
here.
Window ▸ Voice Keyer lists every recording the messages name, says which of
them are there for the operator picked at the top, plays one, and records over
one. The recording is written beside the wanted file and moved over it at the
end, so a recorder that will not start takes nothing away.
`CommandSoundCard` runs `aplay` and `arecord`, and both commands are settings:
the audio path belongs to whatever the station runs, and a library would pick
one of them for the operator. A recorder is stopped with an interrupt so it
closes its wav file, and killed only if it ignores that. PTT is cwdaemon's
`<ESC>a` for as long as the recording plays, off for a station on VOX.
Two things follow. The QTC window sends on SSB: N1MM's four recordings on the
Ready, Agn, Cfm and Close buttons, with the lines still read out by the
operator. And alternating CQ duels on phone, because the voice keyer says when
a recording has finished — which it had to, since the CQ message is picked by
the radio's mode and would otherwise have been keyed as Morse.
Nothing here has been played on a radio: this machine has no sound card, so
what is tested is the program being run, the file filled in, the exit code and
the interrupt, with shell commands standing in for the two.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0157i7PiZyqBkquxS9A6FTdQ
The score window and the stored Contest.Multiplier1Name row both said
"Prefixes" for an Asian entrant, which counts DXCC entities.
Contest.MultiplierNames is now MultiplierNamesFor(StationInfo me), the
same shape as ExchangeFieldsFor. Every other contest returns the same
list it did before; All Asian returns "Countries" from Asia and
"Prefixes" from everywhere else. ContestDefinitions.For takes the
station as well, because that name is written to the log for N1MM.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0157i7PiZyqBkquxS9A6FTdQ
A box the walk between the entry boxes steps over cannot be typed in, so it
must not hold the contact back either. `EntryFields.IsComplete` counted every
box marked required, while `MoveFocus` stepped over the ones the contest does
not ask this station for, so a contest with a box for some stations only
could lock the operator out of his own log.
The seven contests the scoring audit named do not do that any more —
`bae40bb` gave each of them the boxes N1MM shows, and fifteen reproductions
across all seven and both station types log cleanly — but the rule they broke
was still there to break again. Completeness now takes the same
applicability rule the cursor uses, and `OperatingPosition` answers it in one
place for the entry window, the ESM window and logging alike.
The audit is marked up for the three findings that are already fixed and for
item 14, which turns out to be what N1MM does rather than a fault.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0157i7PiZyqBkquxS9A6FTdQ
N1MM has four colours for a station in WAE rather than the usual three, and
the manual and the RTTY tutorial both spell them out. Red is a new
multiplier, as everywhere else. Green is a new station with QTC traffic
still to exchange, which takes the more-than-one-multiplier colour because
WAE has no second multiplier to use it. Black is a station already worked
that still has traffic left — worth working for the QTC points alone — and
it is a colour of its own, N1MM's "Color of a QTC callsign in the WAE
contest". Grey is a dupe with nothing left, the same as in other contests.
The verdict carries how much traffic is left with the station, so the
callsign box, the check window, the bandmap and everything else that colours
a station say the same thing. The contest works the number out: ten with a
station on the other side of the contest, none with one on our own
continent, and none once the ten have gone. Every other contest answers
nought. The log counts the QTC rows per station as they are indexed rather
than counting them again for each station judged, because the bandmap judges
every spot it holds on every pass.
The verdict line says it in words as well, so a dupe reads `dupe · 7 QTCs
left` rather than `dupe`.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0157i7PiZyqBkquxS9A6FTdQ