Every other spot click — cluster grid, band map, watchlist, alert list — goes
through handleSpotClick, which applies the operator's per-mode panadapter
width after the tune. The Chase new panel had its own pick handler that tuned
and stopped there; it now makes the same view change, after the tune for the
same reason.
clublog.org/watch.php, per entry: the DXpedition flag, OQRS, LiveStream, the
log's QSO total and the last-24h rate — the fields the schema has carried since
phase 1. Refreshed on DXHunter's own cadence (hourly for expeditions,
six-hourly for the rest), two at a time with a breath between requests: the
application API key is shared by every install, so a hundred-entry list must
read as a trickle at ClubLog's end. Nothing to configure — OpsLog's own key,
already used for cty and Most Wanted, serves.
A starred pattern is asked about by its base (ClubLog has no log for VK9*).
The card gains the 24h rate beside the QSO total and the Live link to the
expedition's stream.
The two-click arm goes: removing an entry is cheap to undo (type it again), so
it does not earn a confirmation its neighbours do not have. The bin reddens on
hover and the green line confirms the removal.
The two-click arm compared against the STATE variable, which each click's
handler captured at render time — a quick double-click read the pre-arm value
twice, so both clicks merely armed: the bin turned red and nothing was ever
deleted. The arm lives in a ref now, compared synchronously, and the window
grows to three seconds.
A green line under the toolbar says what was added (and as what — the contest
variant names the per-UTC-day rule); the already-exists error keeps its red
line. Both fade after four seconds: a stale 'added' from ten minutes ago reads
as a fresh one.
It was created after the (possibly remote) logbook connect, so a 10-30 s MySQL
dial left the tab saying 'Watchlist: 0' until the next refresh tick — twenty
seconds of an empty list for a JSON file that reads in a millisecond. It now
opens right after the data dir is known; only the auto-contest pattern waits
for the settings store.
The prefix matching ported from DXHunter swallowed too much: a three-letter
special-event entry N8W lit up NEEDED for N8WCR, a different station entirely.
The implicit becomes explicit — a bare entry matches exactly that call, a
trailing star makes it a family: VK9* catches every VK9…, RI0SP* the
expedition's portable forms. A star anywhere else (or alone) is refused at Add
rather than silently matching nothing. Same rule in the backend Match and the
tab's own matcher, pinned by test.
Add-controls left, filters right, justify-between: when the pane narrows, the
whole filter group drops below as a block instead of shedding its last chip.
Shorter chip labels (Active / Needed) and a slimmer search keep both groups on
one line at the tab's normal width.
The F1 panel widens 560 → 600 px, the header row drops its outer padding and
wide gaps, and the country badge tightens — so 'Central African Republic' and
the NEW SLOT chip share one line instead of the chip dropping alone underneath.
The counters are the tab's headline and now sit alone, centred, above the
toolbar; everything one interacts with lives on the second row. The inputs stop
shouting their placeholders — the uppercase belonged to the VALUE (callsigns),
not the hint text — and the auto-contest field says what it is.
A new spot rendered as Needed the instant it arrived and was withdrawn half a
second later when the worked answer landed — the list twitched on every burst.
Unsettled spots are now invisible everywhere (card lines, counters, the
Active/Needed-only filters) until their verdict is in: nobody needs a spot
150 ms early, they need it settled. The answer map is merged rather than
replaced, so a settled line can never fall back to unknown, and the query
debounce drops to 150 ms since there is nothing on screen waiting for it.
DXHunter's header row, ported: Watchlist / Active / Needed counts up front and
the All-Modes select beside the other filters (DIGI matches the digital class,
SSB folds USB/LSB). Counters, card lists and the Active/Needed-only filters all
read the same mode-filtered view, so the numbers add up to what is on screen.
And the notify alert now asks the SAME worked-slot question the tab asks —
before making a sound. It used to fire on the raw spot while the tab's verdict
arrived on a debounce, so the bell rang for a slot that showed Worked a moment
later. Judged in the backend at emit time: exact slot for named modes, digital
class for generic DATA, today-only for contest entries.
The wiring script died on an app.go anchor mid-run: the backend half was
committed, the frontend half (the pattern field, the changed-event refresh, the
i18n keys) never ran. Replayed; the field sits after Add.
A needed line already says so twice — the amber left border and the Needed!
badge — and the exclamation mark was noise. The green tick stays on worked
lines.
A field in the tab's toolbar (e.g. WWA): while non-empty, any spotted callsign
CONTAINING it joins the watchlist as a contest entry by itself — a
special-event fleet (HB9WWA, DL0WWA, F4WWA/P…) is collected as it appears
instead of typed in one by one, and each is judged per UTC day like any contest
entry. Contains, not prefix, because the event string sits anywhere in those
calls.
Global setting, cached in an atomic so the spot pipeline never touches the
settings store per spot. Emptying the field stops the collecting but keeps what
was collected — DXHunter deletes non-matching contest entries on a pattern
change, and a setting that silently empties an operator's list is the one
behaviour of the original this port refuses.
The tab also refreshes on backend auto-adds (event) and on a slow tick, so
last-seen and the counters stay honest while it sits open.
max-w-4xl left 'Central African R…' cut mid-name: the column grows to 5xl and
the country cell flexes with the row (capped at 14rem) instead of a hard 8rem.
7.0589 falls in the band plan's generic [7.04-7.1] DATA segment — an F/H
DXpedition off the standard dials — and 'DATA' is in nobody's log, so the spot
read NEW MODE / Needed while the FT8 contact sat right there. A generic mode
cannot be matched exactly; it is now judged at digital-class grain — worked if
ANY digital mode of that call is logged on that band — against a second
class-folded slot set built beside the exact one (shared when the grouping
option already folds them). DXHunter answers this with a finer frequency table,
which fails on exactly these off-dial expeditions; the class rule cannot.
The toolbar also wraps as a whole with tighter gaps instead of dropping its
last filter chip onto a lone second line.
The watchlist joins the Main-tab pane list (Settings → Main view), rendered in
a card like the other docked panels.
The three filters persist across tab switches — the component unmounts on every
switch, and filters that reset each time are filters nobody trusts.
Needed-only now hides the worked SPOT LINES as well as the all-worked cards,
which is DXHunter's own Not-Worked behaviour and the reported complaint: a
filter that says needed and still lists five green Worked rows answers a
different question than the one asked.
The add-row checkbox is relabelled 'as contest' — it marks the entry being
ADDED, and read as a filter beside the All/DX/Contest buttons it looked
redundant.
The first version asked the alerts' worked-index — keyed by RAW mode (FT8) —
with a CLASS name (DIGI). Nothing ever matched, and a DXpedition worked on five
bands showed every slot as Needed.
The verdict now reads the cluster's own WorkedCallSlotKeys set, built in the
cached status maps (now unconditionally — it used to exist only when a display
option wanted it). Same index, same mode normalisation as the grid, so the
watchlist can never contradict the cluster about the same spot. The contest
today-set is normalised through the same function.
And the cards column is capped at a reading width instead of stretching
callsign-to-badge lines across the whole window.
The concept, transplanted: a list of callsigns or prefixes being hunted,
matched against the live spot stream, one card per entry with the spots
underneath and the two questions that matter answered on every line — is this
slot still needed, and what is it worth (the cluster's own NEW badges, read
from the same status index).
The file is DXHunter's own watchlist.json, field for field, ClubLog block
included though phase 2 will fill it — a file that round-trips unchanged is the
whole of 'same format', and a test pins it with a real DXHunter entry. Global
(dataDir), not per profile.
CONTEST is per entry, not the global mode DXHunter has: a contest entry is
judged against the current UTC day — the boundary lives in the query's date
bound, so midnight needs no timer and resets nothing. Normal entries read the
same in-memory worked index the alerts use. Prefix matching is why RI0SP
catches RI0SP/MM, pinned by test.
Notify goes through the existing alert:fired event — the frontend already
toasts and sounds it — throttled to one alert per entry per two minutes,
because a DXpedition lights every skimmer on the planet.
Tab wired like NET Control: opt-in from Tools, persisted, closable. Single
click fills the callsign, double click works the spot — the cluster's own
gesture, kept.
The My-station group covered nineteen fields and not the three numeric ones.
They take their own integer path rather than the generic text setter: the
columns are nullable integers, and while SQLite would coerce '14' quietly, a
shared MySQL logbook would not — and empty must become NULL, never ''. Bounds
checked (DXCC <1000, CQ 1-40, ITU 1-90) so a slip cannot stamp zone 400 across
a thousand rows.
'None of the consoles look alike' is the complaint ShiftRow exists to answer,
and the Elecraft panel was still driving its offset with a row of nudge buttons.
It now uses the shared control — ±, wheel, typed value — plus the same
Ctrl+←/→ 10 Hz clarifier the Icom and TCI panels have. The K3 keeps ONE offset
for RIT and XIT, so both rows show it, exactly like the Icom's.
The backend gains the absolute setter the shared control speaks
(SetKenwoodRITOffset, funnelled through the same RO write as the nudge), and
the power slider moves in 1 W steps — nobody asks a K3 for 'between 10 and 15
watts' in fives.
Also per review: the chase switches are labelled 'Chase POTA' / 'Chase SOTA',
matching 'Chase new grids' beside them.
An operator who does not chase parks does not want NEW POTA shouting from every
activator spot. Two switches (Settings → DX Cluster, on by default): off, the
marker is withdrawn at the display layer — applySpotDisplay, the same chokepoint
the grid, the band map and the filter read through — so the badge, the colour,
the filter chip and the reference column all go quiet together, and a new-band +
new-POTA spot reads NEW BAND alone. The facts keep being computed; only the
telling stops, so ticking the box back on needs no rescan.
Per review: the digital-grouping sentence on the same-slot option, the
spot-lifetime explanation, the ring-buffer paragraph on the spots-kept field,
and the free-public-nodes line all go.
The report: switching the K3 to a data mode 'does not work for FT8 — the K3
does not go into DATA'. The mode digit is only half the answer on that radio:
MD6 keeps whatever DT submode the previous session left, and with FSK D still
armed the rig keys FT8 with no rear-audio modulation.
The panel buttons say the whole thing: DATA is MD6+DT0 (DATA A, the soundcard
path), DATA RTTY is MD6+DT2 (FSK D). The DT submode is also read on the
settings beat — Elecraft only, a plain Kenwood would '?;' it — so the active
DATA button follows what the rig is actually in, front-panel changes included.
A dedicated SetKenwoodPanelMode rather than the logger's SetMode: a panel
button is the operator saying exactly what the rig should do, not an ADIF mode
to be mapped through preferences.
Three from review. Aqua for NEW SLOT sat right next to the POTA green — it is
now the sky cyan the panadapter palette has shipped for new-slot all along.
The NEW COUNTY chip was green while its badge is violet, and NEW SLOT's chip
was still caution yellow: chips now carry the badge's own colour (color-mix for
the muted border/背景), because a filter that does not look like what it selects
has to be learned twice.
And the NEW CALL chip matched only the DISPLAYED status, which is manufactured
by the slot-highlight option — with that option off the chip matched nothing
and read as broken. It now filters on the fact itself (worked_slot false), so
it works either way.
The whole new-* family shared the warning amber while the NEW PFX marker sits in
caution yellow — two different facts, two near-identical colours in one cell.
NEW SLOT now takes aqua (chart-2), the same story the panadapter palette already
tells: its default for new-slot has been cyan all along.
The Send-spot dialog took catState.freq_hz, which is the TX frequency. Working
a DXpedition split, that is where WE transmit: the spot went out five up from
the DX, pointing the whole cluster at the pile-up instead of the station. The
RX frequency is where we listen — where the DX is — and is what a spot names.
Two rounds of fixes and the SunSDR's meters are still silent. The one remaining
difference from the protocol document is the case: its examples read
TX_SENSORS_ENABLE:true,200; and ours went out lower-case. Every other command
works lower-case, but nothing proves this newer path does — a case-insensitive
server ignores the duplicate, a sensitive one finally hears it.
The report from a real SunSDR: transmit power and SWR still empty after the
sensors fix. The subscription went out once, at connect — while ExpertSDR3 is
still streaming its initial state dump, exactly where a unidirectional control
command can be ignored. It is now renewed every time the server says 'ready'.
The sensor messages also join the logged-on-arrival set, capped like the rest:
the next log will say whether TX_SENSORS ever arrives, which is the question —
a radio that never sends it (AetherSDR may not) and a frame that arrived and
was dropped leave the same blank meters and need opposite fixes.
Per review: the panel-wide 'saved instantly' hint goes; the date-format picker
loses its embedded sample line (kept as the buttons' tooltip) so the row is one
line tall; the IARU region moves up under the date format, before the themes;
and the parentheticals after Distances-in-miles, Check-updates and the
telemetry opt-out go. The telemetry and ClubLog explanations survive as
tooltips — an opt-out about data leaving the machine, and an option changing
how entities resolve, should still say what they do somewhere.
The band maps carried one hard-coded table — Region 1's — so a US operator's
40 m stopped at 7200 with stations spotted at 7250 hanging past the top of the
map, and the SSB wash started 25 kHz early. The region is a station-level fact
stated once (Settings → General, portable pref); lib/bandplan owns the three
tables and publishes changes to the open maps the way the distance unit reaches
the grids.
The tables stay deliberately coarse: a band map's wash is context, not a
regulatory chart, so only the differences an operator notices are split out —
Region 2's 80 m to 4000 and 40 m to 7300 (phone from 7125), Region 3's 80 m to
3900, the wider VHF/UHF allocations. National fine print does not belong in a
background tint.
The feature needs more rounds than the next release can wait for, so main goes
back to before it: the packages, bindings, migration, UI and i18n all move to
the feature/labels branch, which holds every commit. The 0.26.23 block keeps
only the Station column.
The 0031 migration may already have run on a machine that launched a dev build;
the two label tables it created are inert and the recorded migration row is
harmless — the runner only applies filenames it has, so re-adding the migration
when the branch merges will skip cleanly there and apply everywhere else.
Three corrections from the first real session. Routed via a manager, the box
was prefilled with the DX's own address — the one thing that must not go on
that envelope. It now starts empty and the QRZ fetch fills in the MANAGER's;
switching the routing recomputes the box unless the operator has typed in it,
because a hand-checked address is not the app's to replace.
A fetch that came back with no street was overwriting a reviewed address with a
bare country — the cty.dat fallback dressed as an answer. It now refuses to
touch the box and says nothing was found. And the prefill no longer stacks the
same town three times (address + QTH + country all carrying it).
The output is ONE PDF for the whole session, each page at its own label size,
written to the temp dir and opened straight in the viewer — no save dialog: the
file is a print run, not a document to keep.
The printing session in three steps. The worklist is the paper queue (ADIF
qsl_sent R/Q), grouped by callsign since several QSOs of one station share a
card. Each recipient is reviewed before anything prints: routing first — via
manager when qsl_via says so, direct when an address is known, bureau otherwise
— then the address itself, editable and fetchable from QRZ (the MANAGER's
address when routing says via). What is printed is the reviewed text verbatim,
not a re-resolution that could differ from what was checked.
One PDF per label kind, never one file for all: a roll printer holds one stock
at a time, and a file mixing 29 mm addresses with 62 mm QSO labels could not be
printed at all. Pages are rasterised by the designer's own renderer at the
stock's dpi and carried into the PDF untouched — internal/pdf is a hand-written
image-page writer (DeviceGray + flate: monochrome, lossless, no cgo) because
that is the entire need.
Bureau stations get no address label (no envelope); return labels are printed
one per envelope. Finishing offers the log update: QSL_SENT=Y, the chosen date,
via B or D per routing — through the same BulkUpdateQSL the paper view uses.
A fixed 720 px cap cut a 98 mm label off at the RST column and wasted half the
window; the scale now follows the centre pane's measured size, with a floor so
small stock never renders unreadably.
The designer's data model lives in internal/labels: STOCKS are the physical
roll in the printer (geometry in mm, margins, dpi — seeded with the common
Brother DK sizes, the QL family being what prompted the feature), TEMPLATES are
one design each, of two kinds: the QSO label glued on the card, whose repeating
table carries several contacts of the same station, and the address label for
the envelope, whose lines collapse when a variable is empty.
Everything is measured in millimetres — labels are sold in mm, and an operator
lining a design up against a physical sticker thinks in mm; pixels exist only in
the renderer, at the stock's dpi. The canvas renderer is shared between the
editor's preview and the future print path, so there is no second
implementation for the preview to disagree with.
The preview is fed with the log's latest contacts rather than lorem ipsum: real
data shows a too-narrow column immediately.
Printing (PDF, one page per label at exact size) is the next module; nothing
here prints yet.
With 'All my callsigns' the report spans F4BPO, F4BPO/P and TM2Q at once, and a
list mixing them says nothing about which one a confirmation belongs to — which
is the question that option creates.
The column appears only when the rows actually carry a station: the other
services return one, and an empty column for them would be noise.
The grouping keyed on the callsign alone, so every spot of a station outside the
first one's band and mode was dropped from the list. RI1FJL spotted on 17m CW,
20m, 30m, 12m and 15m FT8 showed as a single row: four slots gone from the one
view an operator uses to find them.
A duplicate is the dozen skimmers that all heard the same CQ — same station,
same band, same mode. The same station on another band is the opposite of a
duplicate; it is what the chaser is scanning for.
Expert Electronics' own document gives the command whole:
SPOT:RN6LHF,CW,7100000,16711680,ANY_TEXT;
16711680 is 0x00FF0000 — positive. This backend sent the same field as a SIGNED
32-bit value, from a third-party example: with the alpha byte set to FF for
opacity, 0xFFFFA500 becomes -22336, and a spot whose colour ExpertSDR cannot
read is dropped without a reply or an error.
Reported on ExpertSDR3 1.3, which speaks TCI 2.x — the protocol version was
never the problem, and my first reading of that report was wrong.
The first three spots are now logged verbatim: an ignored spot leaves no trace
whatsoever, so that line is the only evidence of what went out.
TCI meters: the S-meter came only from RX_SMETER and the transmit meters from
TX_POWER / TX_SWR — commands ExpertSDR3 does not send. The protocol's answer is
a subscription (RX_SENSORS_ENABLE / TX_SENSORS_ENABLE, §4.4 of the TCI PDF),
after which the radio pushes RX_CHANNEL_SENSORS and TX_SENSORS. Nobody had
asked, so the console's meters sat empty in RX and in TX while everything else
worked.
Cluster: the held-spot counter looked for the row it froze on. A station spotted
again REPLACES its row, so that row vanishes in the ordinary course of things
and the count fell through to 'everything is new' — 4, 5, then 500. Counted by
timestamp now, which survives both the replacement and the ring buffer.
SMTP: '535 5.7.139 basic authentication is disabled' is a policy, not a typo.
The message now says so, and says what actually helps, without claiming a policy
when the server simply rejected the password.
Every flush commits state the whole window re-renders on, and the window was a
flat 50 ms — twenty full renders a second under an RBN firehose. That is paid
everywhere else in the interface, and it is what a dropdown highlighting its
entries a beat behind the mouse actually is.
The window now follows the rate: 50 ms on a quiet cluster, where a spot should
appear the moment it arrives; 200 ms past five a second; 500 ms past twenty,
where half a second's delay on a line already scrolling past is invisible.
The pane drew its own title bar above the grid's toolbar, so the cluster spent
two lines on headers where Recent QSOs beside it spent one — in a pane often
only a few spots tall. The grid's toolbar now takes what the caller wants on its
left, and the pane passes its title, live count and Filters button there.
Reported by VK4DX.
UploadLoTW returns both a terse error ('no QSOs processed') and a Message
carrying TQSL's own lines — '17 QSO records were already uploaded', 'N QSO
records are out of date range'. The caller took the error whenever there was
one, which is precisely the half that explains nothing: the operator saw a red
line naming a condition with three unrelated causes and no way to tell which.
The sixth CW engine, and the one the TCI backend was left without. A SunSDR
keys from the WebSocket that already carries the CAT: no WinKeyer, no second
serial port, nothing to wire.
CW_MACROS:0,<text>; send
CW_MACROS_SPEED:<wpm>; speed
CW_MACROS_STOP; abort
Confirmed against the TCI command table in ars-ka0s/eesdr-tci — the source that
settled SPOT. CW_MACROS rather than TCI 2.0's CW_MSG: it exists from 1.6, and
OpsLog resolves its own variables, so the before/after callsign fields have
nothing to carry.
Commas and semicolons are stripped before sending. They are the protocol's own
separators: a comma would become another argument, a semicolon would end the
command with the message half keyed and the rest parsed as a command.
Only the MACRO speed is set, not the paddle keyer's — an operator who set their
paddle to 28 wpm did not ask for it to change because a macro went out at 25.
And there is no backspace: TCI can stop a message but cannot un-type one, so the
type-ahead correction the Flex engine offers is absent rather than faked.
Wails saves and restores in two different coordinate systems. WindowGetPosition
returns GetWindowRect — absolute. WindowSetPosition is winc's ControlBase.SetPos,
which adds the CURRENT monitor's work-area origin:
w32.SetWindowPos(hwnd, HWND_TOP, int(info.RcWork.Left)+x, ...)
On the primary monitor that origin is 0 and nothing shows. With a monitor to the
LEFT it compounds: a station with its left screen at x=-3840 saved -3844,
reopened there, had -3840 added, and stored -7684 — then -11524, one screen
further out at every launch, until the window was off the desktop entirely.
So the placement is done here, with SetWindowPos and no offset, falling back to
the toolkit when the handle cannot be found. Compact mode had the same pairing
and is fixed with it.
Clicking a spot sets the frequency, then the mode 150 ms later, and SetMode
chose USB or LSB from t.freqA — the frequency the radio had ECHOED. From 7 MHz
onto a 14 MHz spot that echo has often not landed, so the sideband was computed
for the band being left: LSB on 20 m. Clicking the same spot again, the echo
having arrived, gave USB. Reported from a SunSDR as 'the frequency is right, the
mode is wrong until I click twice'.
SetFrequency now records what was asked for and SetMode prefers it until the
radio's own echo confirms the move.
The server's 'protocol:' announcement is also kept instead of being filed under
unhandled: it names the ExpertSDR and its TCI version, and panorama spots need
TCI 1.5 — older servers accept the spot commands and silently drop them, which
is indistinguishable from a broken logger. Now it says so.
The status comes from spotEntityStatus: it means the country has been worked on
this band and mode. The label said 'Worked (this band + mode already in log)',
which reads as 'I have had this station' — so a spot the cluster called NEW PFX
looked like a contradiction, when the two were answering different questions
about different subjects.
The callsign-level fact has its own marker and its own words ('Callsign already
worked'), so the two are now told apart by reading them.
The strip deliberately shows three markers of five — the pill is 22 px and a
fourth segment makes it a colour code nobody reads. But the tooltip has room and
was filtering them out too, so the same spot read NEW PFX in the cluster and
'Worked (this band + mode already in log)' on the map. Both were true: the
entity is worked on that slot and the WPX prefix never has been. Neither view
said so.
A tester compared LogHX's two download options on the same account: two minutes
for the confirmations, twenty for the confirmations with QSO details. OpsLog was
always sending qso_qsldetail=yes — LogHX's slow option — which is the whole of
the wait people were reporting.
Marking a confirmation needs call, date, band and mode; the detail adds the QSL
date and the station's grid, state and county. Now a choice, off by default, and
forced on when the download is also ADDING the QSOs it cannot find — the one
case where those fields have no other source.
Miles and the LoTW download progress landed after v0.26.20 was tagged, so they
belonged to the next block: an entry appended to a shipped one never reaches the
operators who installed it, and misstates what that version contained. The .20
block is byte-identical to the tag again.
Deferred, it stopped at the end of the function — so 'still waiting for LoTW to
build the report' kept printing between the megabyte lines, saying the opposite
of what was happening.
The progress lines only start once bytes arrive, and on a large account nothing
arrives for minutes — LoTW builds the entire report before sending any of it.
That silence WAS the complaint: the window still just said 'working'.
A heartbeat every fifteen seconds until the headers land, then the HTTP status,
then the megabytes — the first at 256 KB rather than 1 MB, so the very first
sign that it is moving comes early.
Three reports of the same shape: a 503 for anything wider than a few days
before, and since the timeout was raised, a window that sits at 'working'
forever. Both are the same missing thing — nothing said what the transfer was
doing.
The body is now read in chunks and every megabyte is reported. A 503/502/504 is
retried twice, 20 s then 40 s, each attempt announced: LoTW answers 'busy' to a
wide report often enough that other loggers simply ask again. And the deadline
is no longer on the whole exchange, which either cut off a healthy slow download
or hid a dead one for twenty minutes — it is ten minutes to START answering
(LoTW builds the whole report first) and two minutes of silence once it has,
which is the difference between slow and dead.
Everything is computed in kilometres and converted once at display time, in
lib/units — storing miles anywhere would give the same number two sources of
truth and a rounding error that grows with every hop.
The grids capture the unit inside their column definitions, header and formatter
both, so a change is published to them the way the date format already is;
without that a toggle would only appear after a language change or a restart.
The preference is portable, like the other display ones.
Without qso_qslsince LoTW does not answer 'every confirmation' — it answers
with a few recent ones, as a 200 and a valid ADIF. 'All' therefore downloaded a
nearly empty report and said 'matched 1 of 1' on an account holding twelve
thousand. It now asks from 1945-11-15, older than any QSO LoTW accepts.
And the request had two minutes: LoTW spends several of them building a full
account before the first byte, so asking for everything ended in 'context
deadline exceeded while reading body' — a network-shaped message for a
too-short deadline. Twenty minutes, and the read cap raised past the 18 MB such
a report actually weighs.
Unscoped, the report carries every station on the account — including the calls
belonging to another profile's logbook. Those match nothing here, and with 'add
the ones not found' ticked they would pour a second log into this one. The
station callsigns this logbook actually holds are now the filter: a portable
worked here is kept, an expedition call never used here is skipped and counted.
A near-empty report is also the failure that reads as success — 'matched 1 of 1'
where the account holds twelve thousand. Under 4 KB, what LoTW answered is shown
verbatim instead.
The download passes qso_owncall so one profile does not pull another's
confirmations. That scope also hides them: a QSO made as F4BPO/P is confirmed at
LoTW and can never come back to an F4BPO profile, so it stays unconfirmed here
for good while the ARRL counts it — found while reconciling a DXCC account
against the panel, where it was the whole of the CW gap (Jersey, worked as
F4BPO/P).
Off by default: the scope is right for anyone whose profiles are separate
stations.
The filter keeps a REFERENCE for its unconfirmed slots, so its confirmed ones
come along — and green on grey means the answer is the quietest thing in the
row. Faded to a quarter under that filter only, not hidden: which band is
already done is part of deciding which one to chase.
The Challenge line says 1832 worked against 1554 confirmed and stops there —
278 band-slots waiting for a card with nothing pointing at them. Every existing
filter works per REFERENCE, so an entity confirmed on 20 m answers 'confirmed'
and its unconfirmed 15 m contact stays invisible.
The new filter keeps the references holding at least one such slot, and the
count beside the reference total is the gap itself, recomputed over whatever the
other filters left on screen and over the bands actually displayed — so it
always adds up to the columns in front of the operator.
The SOTA feeds put the summit in the spot's own text, so there is nothing to
poll: a regex on the comment gives the reference, and clicking the spot writes
SOTA@<ref> into the award references the way a park already wrote POTA@<ref>.
The regex is narrow on purpose — association/region-NNN, anchored — because
POTA (US-4475), WWFF (DLFF-0001) and portable callsigns (DL/SP9DPM/P) share
that field and none of them is a summit. Pinned by a table test.
Off by default: the reference is only there on the summit feeds, and an empty
column for every operator who does not chase them is worse than a checkbox.
The chip read a.spe ?? a.acom ?? a.pgxl, so a KPA fell through to the
not-connected fallback: red on a working amplifier, and a click that opened the
settings instead of switching to STANDBY. Reported from a KPA500 whose panel
showed band, SWR and temperature at the same time.
The card's offline text also borrowed the Acom's string, so a KPA that dropped
its link announced itself as an Acom.
The CI-V trace settles it: the IC-7851 answers 27 10 01 with FB and 27 14 00
with its mode, but refuses 27 11 in BOTH shapes — it controls its scope over
CI-V and never streams it. Its last firmware is from 2016, older than the
waveform stream itself; Hamlib's caps claim otherwise, the radio is the
authority.
Rejected both ways is a permanent answer, so it is remembered and reported:
the panadapter says the radio does not send its scope, which is the one thing a
black rectangle could not say.
Hamlib documents the spectrum scope on the IC-785x, so a rejected 0x27 0x11 is
not proof the command is missing — and taking 0x27 0x10 for the data switch
would have blanked that operator's own scope screen when OpsLog disabled it.
Both shapes were refused within 96 ms, so neither was a timeout, and guessing
the next subcommand is how the last two rounds went. The retry now logs the
second attempt's own error and the failure points at the CI-V trace.
The IC-7851 rejects 0x27 0x11 in BOTH shapes: on that radio 0x27 0x10 is the
waveform-output switch itself, not a display switch. Rejected both ways, take
0x10 as the output command and switch it off on disable too — there it stops a
stream rather than blanking the operator's own scope screen.
A mode/span/edge answer also settles the selector question directly: three bytes
or more means the rig wants the main/sub form. Worth reading, because a
wrong-shaped SET is answered with silence on this firmware, and a timeout is
something the rejection retry cannot act on — which is why the fixed/centre
sets were timing out.
The IC-7851 rejects "27 11 01" and wants "27 11 00 01" — the main/sub selector
its two scopes need. The shape was picked from a list of CI-V addresses, so an
address not on it got the wrong one and the scope stayed blank with a rejection
in the log and nothing on screen.
A rejection is an unambiguous answer, so a rejected 0x27 set is now re-sent in
the other shape and the winner remembered. A TIMEOUT deliberately is not
retried: several firmwares never ack a 0x27 set, and treating silence as a
wrong guess would flip a rig that was already working.
The header counts QSOs with the callsign through callMatch — RI1FJL/1 and
ZA/RI1FJL included — while the grid's own per-callsign columns matched the bare
string. A cell could hold one of the QSOs the header had counted and show
nothing.
The dot is drawn over all five cell backgrounds, so it cannot borrow one of
their colours; it defaults to the theme foreground with a background ring and
now takes two overrides of its own, worked and confirmed, alongside the rest of
the matrix palette.
The worked-before cell answered one question with two facts fused into it.
bandStatusCode takes the highest of them, so a confirmed entity outranks a
worked callsign — right for awards, wrong while chasing: a slot worked with the
DXpedition this morning reads "entity confirmed" and says nothing about it.
BandStatus now carries the callsign's own answer alongside the entity's, and the
cell draws a dot for it. The dot is deliberately identical everywhere — same
shape, same colour, over all five backgrounds — so it is read as one thing
rather than as five variants of the colour underneath it.
Operating conditions describe a plan; a logged QSO asks which radio was
keying. With one rig those were the same answer, with several they are
not — so each saved radio carries its own MY_RIG, ahead of the per-band
station and doing nothing at all when left empty.
With one rig, MY_RIG belonged in Operating conditions and nowhere else.
With several, that becomes the wrong place: operating conditions describe
a PLAN — 'on 20 m I use the beam and the 7300' — while the question a
logged QSO asks is which radio was keying.
So each saved radio carries its own MY_RIG, consulted BEFORE the per-band
station. When the two disagree — a second rig borrowed for one evening on
20 m — the one that is transmitting is the true answer.
Left empty it changes nothing at all: the old chain (band default, then
the profile's rig) answers exactly as it did, which is what every
single-radio station will keep doing without touching a setting.
The answer to 'I have two rigs' was 'make two profiles', which moves the
whole station — logbook included — to change which radio is connected.
Radios are a list now, like amplifiers, and the CAT chip switches between
them while everything else stays put.
The active radio still lives in the settings keys the rest of OpsLog
reads, so the consoles, the CAT sharing and the band-follow needed no
change at all.
It showed what the radio calls itself over CAT — 'Kenwood (911)' for a K3,
a bare 'CAT' for a Flex that reports nothing useful. That is the answer to
a question nobody asks once the rig has a name in the list, and it made
the two radios look alike in the one place they have to be told apart.
The name the operator typed comes first now, on the chip and in the menu,
and falls back to the radio's own identity when they typed none. The model
identity is still in the tooltip, where it answers 'what is actually
connected' without taking the place of 'which of my rigs is this'.
It only became a menu from two radios, on the reasoning that a single
radio has nothing to switch to. That hides the feature from precisely the
operator who has not made a second radio yet — the click lands on a
settings dialog they did not ask for, which is what happened on the first
try. With one radio the menu now shows that radio and 'Add a radio…'.
Right-click still goes straight to the CAT settings.
The answer to 'I have two rigs' was 'make two profiles', which is a heavy
instrument for a light question: a profile carries the whole station —
logbook, callsign, awards, cluster, macros — so switching one to change
which radio is connected takes all of that with it, including a change of
logbook when the profiles point at different databases.
Radios are a list now, the way amplifiers already are. The CAT chip in the
status bar opens it, one click connects the chosen rig, and nothing else
about the station moves.
The storage keeps the ACTIVE radio in the same settings keys everything
already reads (cat.backend, cat.icom_port, …), and switching writes the
chosen entry into them and reloads the link. So the consoles, the CAT
sharing, the band-follow and every panel see exactly what they saw before
and needed no change at all — the list is a second store beside the
configuration, not a replacement for it.
Details that matter more than they look:
- An operator who has run one rig for a year opens the list and finds it
there, because a missing list reads as the CURRENT settings rather
than as nothing. It is written on the first save, not on the first
read.
- Editing the CAT panel updates the active entry, or an edit made before
switching away would be lost on the way back.
- A new radio starts as a COPY of the current one: a second rig is
usually the same shape with one port changed, and an empty form is a
form to fill in twice.
- Switching saves the panel first, so edits to the radio being left
behind are kept.
- The chip only becomes a menu with more than one radio; with one it
opens the CAT settings exactly as it always did.
THE README WAS GONE. A commit of mine last night replaced OpsLog's readme
with the text of the TCI protocol specification — 322 lines of ours for 77
of Expert Electronics' — and nobody noticed because nothing builds from
it. Restored from the commit before, then updated.
What it was missing, all of it shipped since: the Kenwood/Elecraft and
Yaesu CAT backends and their consoles, the SunSDR console, TCI audio in
both directions, CAT sharing over Hamlib rigctl or TCI, the Elecraft
KPA500/KPA1500 and the Tuner Genius XL, Cloudlog and HAMLOG uploads, the
RDA district work, the DXCC Challenge, the editable satellite list, four
main-view panes instead of two, and Esri basemaps in place of Carto.
Also a section on importing a log, which had none — including the rule
that matters most to somebody moving years of contacts across: a deleted
DXCC entity keeps the number the file gives it, because cty.dat only knows
where a callsign is today.
It has not shipped yet, so an operator reading about the SunSDR console
should meet what it does — not a list of repairs to a thing they have
never run.
Everything here came from one operator with the radio in front of him, and
most of it was mine to fix. The drive commands need the transceiver index
('drive:0,15;', not 'drive:15;') or the radio ignores them without a word.
The console now holds a click the radio does not echo, so a working button
stops looking dead — and lets go the moment the radio contradicts it, so a
REFUSED setting still tells the truth. Filters per mode, APF only in CW,
levels on wide rows with typed values, the RIT control shared with the
Icom console, the transmit meters, and a TUNE that can be switched off
again.
Two findings worth keeping: this radio re-asserts sql_enable eighty
milliseconds after being told to turn the squelch off, and it never
answers TX_POWER or TX_SWR — both are its own doing, and both are visible
in the log rather than argued about.
The transmit meters are asked for four times a second while keyed, so
logging every arrival would fill an evening's log — and a diagnostic that
fills a log is one that gets switched off instead of read. Twenty of each
is enough to tell an answer from a silence, which is all it is for.
Reported with a Logger32 export: the record said <DXCC:3>151 and OpsLog
stored 54.
cty.dat answers one question — where is this callsign TODAY — and that is
the wrong question for a log. R1MVI was Malyj Vysotskij Island, entity
151, until the ARRL deleted it in 2012; the same call resolves to European
Russia today. Forcing the lookup onto a 2004 contact therefore destroys a
credit that can NEVER be worked again, because the place no longer counts.
So the ADIF's number wins whenever it names a deleted entity, and nothing
is corrected on those records at all — the country name and the zones of a
deleted entity are equally beyond what a present-day prefix table knows.
The list is the ADIF specification's own enumeration, sixty-odd entities
that only change when the ARRL deletes another one.
The guard sits in the forced path, so it also covers the grid's 'Update
from cty.dat' on a selection — the other way an operator could have lost
the same credits, one right-click at a time.
Two things from one screenshot, and the second is arithmetic rather than a
bug.
Editing an award refreshed the grid and not the statistics matrix, so
changing which confirmations count left the table showing the old rule's
numbers with nothing to mark them stale. That is how a setting comes to
look as though it does nothing.
And OpsLog's 3229 against LoTW's 3004: the Challenge counts confirmed
band-slots on ten bands, and 60 m is not one of them. 3229 less the 224 in
the 60 m column is 3005. So the number was right and the QUESTION was
different — the panel now answers the Challenge one too, under the table
where the comparison is made.
The two totals also say what they are on hover. 'Total' and 'Général' side
by side tell nobody which counts entities and which counts band-slots, and
3309 read as entities is an impossible number — which is exactly how it
was read.
The log shows 'tx_power;' going out four times a second during a tune and
nothing coming back — but that proves less than it looks: a reply that
arrived and failed to parse leaves exactly the same trace as one that
never came. Both are now visible.
Two faults with one cause: this radio does not echo 'tune:0,true'.
So the panel never knew a tune was running. The button stayed on TUNE and
every further press sent another START — there was no way to stop it from
here at all. The state is recorded when the command is sent now; whatever
the radio says afterwards still wins, it simply never says anything.
And the transmit meters were asked for only while t.tx, which a tune
carrier does not set: the radio reports tuning as its own state, not as a
transmission. So power and SWR sat at zero for the whole tune — the exact
carrier an operator holds a tune for in order to watch an SWR on. They now
follow PTT or TUNE, and the S-meter reads '—' under our own carrier
either way.