Commit Graph
31 Commits
Author SHA1 Message Date
rouggy ee148732dd feat: HAMLOG.online upload and confirmations, Yaesu antenna, a named port holder
HAMLOG.online is a seventh external service: one API key, one ADIF record per
QSO, immediate / delayed / on-close like the rest. They publish no API
documentation, so the protocol is read from THEIR OWN client — the HAMLOG Agent
(github.com/hamlogonline/Agent), which is the authoritative source short of
asking them:

	POST https://hamlog.online/api/agent/
	{"ADIFADD": {"APIKEY": k, "ADIFDATA": record}}   → {"STATUS":"OK"}
	{"KEYSTATUS": {"APIKEY": k}}                     → {"STATUS":"OK","CALLSIGN":…}

Success is STATUS == OK, not "no ERROR field": their failure carries ERROR and
no STATUS, and reading an unknown reply — a proxy page, a maintenance notice —
as an acceptance is how a contact goes missing without anyone noticing.

KEYSTATUS buys something no other service here offers: the key can be checked
BEFORE the first QSO, and the answer names the account. A key pasted from
another callsign is caught in the settings panel rather than through a week of
silent refusals.

Their confirmations are also an award source now, ticked like LoTW rather than
expressed through "custom". It reads the ADIF extras, not a column: the standard
names a field for hamlog.EU and none for hamlog.ONLINE, and borrowing the other
site's field would write a falsehood into every exported log. Three plausible
key names from their own export are accepted too, so nobody has to rename a
column by hand after an export.

Yaesu gains antenna selection (AN), remembered per band — the antenna picked on
a band comes back with it, with no table to fill in anywhere. Rigs with one
socket never answer AN and never show the row; the log says which case it is.

And a serial port that is refused now names its likely holder. OmniRig stays
resident once activated and keeps the port of the rig configured in it, so a
native backend never gets it — "Serial port busy" alone accused nobody, and an
FTDX10 spent a morning being blamed for it.
2026-08-23 12:18:27 +02:00
rouggy c31ab05c80 fix(awards): "no field" leaves no rule running behind the panel
Choosing "no field" cleared the primary field and hid the matching controls —
but the fallback OR rules stayed in the definition and went on scanning their
own fields. An RDA award declared to match nothing still found a district in the
QTH, and the panel no longer showed the rule doing it. Only a manual override on
the same QSO kept the wrong reference out of the log.

So the choice now clears the fallbacks too, which is what its label promises,
and a rule that survives — from an imported definition, a shared template — is
rendered even in "no field" mode. Nothing that still runs may be invisible.

No catalogue award pairs an empty field with OR rules, so nothing shipped
changes behaviour.
2026-08-21 14:35:54 +02:00
rouggy e3b7a35e2c fix: stop losing decodes, hanging on exit, and wedging the rig link
Three faults an operator's log finally made visible, plus the interface
work that came out of the same session.

Reliability:

- UDP events were dropped on backpressure without a word. A period hands
  over twenty-odd decodes at once, and one slow write to the radio was
  enough to fill the queue — so a decode simply never appeared, and the
  only detector was the operator comparing the panel with JTDX. The drop
  is now counted and logged, panadapter spots went to their own goroutine
  so the radio can no longer hold the decode stream up, and the queue is
  deep enough for a full period.

- The CAT manager waited for its poll loop with a bare <-done. A loop
  wedged in a serial read then blocked every later restart inside Start,
  before it could even try to connect: the rig stayed dead, no line was
  written anywhere, and only killing the process recovered it. The wait
  is bounded at ten seconds and says what it abandoned and why the next
  connect may fail.

- Shutdown had no logging at all, so a hang left nothing to go on and a
  process the operator had to kill — which then blocked the restart after
  an update. Every step is logged, and a watchdog forces the exit if one
  of them never returns.

Auto-call:

- A QSO in progress is now held by OpsLog itself rather than inferred
  from the sender's Status. The moment WSJT-X/JTDX dropped the DX call or
  the Enable-Tx flag between overs, the exchange looked finished and the
  next CQ was answered, interleaving two and then three QSOs on one
  slice. Released on log, on halt, on taking over, and by a watchdog.

Cluster console:

- Replies to a command were buried under the spot flood; a Replies
  toggle hides the DX spots, which the list above already shows.
- Twelve named command buttons beside the input, configured in
  Settings -> Cluster; a button with no command is not drawn.
- Following the tail is now an explicit switch, and sending a command
  re-arms it. It used to measure "am I at the bottom" AFTER committing
  the new lines, so a ten-line reply looked like the operator had
  scrolled up and was never followed — the one case it exists for.

Awards:

- An award can name NO field. The matching controls disappear with it
  and only hand-assigned references count, which is the only thing that
  can feed a reference like WWBOTA. A test pins that nothing else is
  scanned.
- WWBOTA added to the catalogue with its 31 342 references.

Elsewhere: the rotor widget's Stop button acknowledges the press like
the direction presets already did, and the docked band map can be
switched to fit-to-band from its own header.
2026-08-21 01:07:10 +02:00
rouggy 21a0d560de feat(awards): a reference's number can be corrected in the editor
The one field the editor would not let you touch, and the one that was wrong on
WAJA. Every other property of a reference — its name, pattern, entity list,
validity window — was editable; the code was rendered readOnly, so correcting a
number meant deleting all 47 references and importing a new list, throwing away
anything the operator had adjusted in it.

A rename in the store, not a delete plus an insert: everything the reference
carries travels with it, which is the whole point of correcting a number rather
than replacing an entry. A number already in use is refused — REPLACE INTO would
have let one reference silently swallow another, discovered much later as a
prefecture quietly missing from the list.

The typed code is held apart from the selection. The list and every field patch
key off the selected code, so editing it in place made the editor lose the
reference mid-edit.

SaveAwardReference now recomputes the log like Delete and Replace already did. A
reference's name is what the award column SHOWS for awards displaying by name,
and its pattern is part of what matches at all — so editing one changes rows,
and the grid was left showing the old label until something else happened to
trigger a pass.

Changelog: the three TCI-sharing lines are merged into one. The server and the
two fixes made to it while building are one unreleased feature, and an operator
only ever meets the finished thing. The TCI-client PTT line stays separate — it
is OpsLog driving a SunSDR, the other direction entirely.
2026-08-17 10:26:13 +02:00
rouggy dd7b63c059 fix(awards): stack the reference validity dates, and prove the award fallback
Two dates side by side put each one in a half-width Field2, which spends 120px
on its label column — the second label overlapped the first input and the row
ran off the panel. The comment ten lines above says exactly this about the
group/subgroup fields; one per row, as everything else in this editor.

Also shows a far-future end date as open-ended. RDA carries 9999-12-31 as "no
end" and printing it back reads like a real deadline.

The claim that an empty per-reference window inherits the award's is now a
test rather than a comment: a QSO before the award's own ValidFrom does not
count for a reference that has no window of its own, and a narrower reference
window still applies on top.
2026-08-12 10:51:12 +02:00
rouggy 8fc6673611 fix(awards): apply the per-reference validity window
References are not forever: a park is delisted, a district merged, a castle
loses its number. A QSO made while the reference existed is a valid contact
and must keep counting; one made afterwards must not.

The JSON format did not need to change — ValidFrom/ValidTo were already on
awardref.Ref, already columns in award_references, already round-tripping
through export and import. They were simply never read: awardRefMetas dropped
them on the way into the engine, so nothing downstream could enforce them.
This carries them through and checks them in keepRefs.

Empty means the award's own window governs, which inScope already enforces for
every QSO in the award. That fallback is deliberately NOT duplicated per
reference — two places enforcing the same dates is two places for them to
disagree. The editor shows the award's dates as the hint under the boxes so
the operator can see what empty inherits.

Dates are compared as ISO strings rather than parsed times: the stored shape
is "2006-01-02", lexical order on it IS chronological, and this cannot fail on
a malformed value the way a parse can — a reference with a typo in its window
keeps counting instead of silently vanishing from an operator's totals.

The Explain trace names the date and the cutoff, because "did not count" on a
contact the operator remembers making is exactly when they need to be told it
is the reference that has a window, not their log that is wrong.
2026-08-12 10:43:23 +02:00
rouggy d33291b521 feat(awards): wire up the single-award export
Only the whole-catalogue bundle was reachable from the UI, so sharing one
award meant handing over every award you have — including the ones you edited
for yourself.

Nothing new was needed underneath: ExportAward(code) already existed and
already reads the definition AND its references from the database rather than
from the embedded catalog, which is the point (a WAPC is only worth sharing
because of the province list and city regexes the operator added). The English
and French strings existed too. Only the button was missing.

Kept distinct from the catalog publish next to it: that one stamps a version
and clears user_edited to seed a release, this one is a plain share and leaves
both alone, so the recipient's copy is correctly marked as someone else's work
instead of a pristine built-in that future catalog updates would overwrite.
2026-08-12 10:23:55 +02:00
rouggy 40f5960c76 feat(awards): implement the QRZ.com and Custom confirmation sources
The award editor offered five confirmation sources and Def's own doc comment
named five, but confirmed() had cases for three. "qrzcom" and "custom" fell
through the switch, so ticking either marked nothing as confirmed — the exact
failure the GrantCodes comment in this struct warns about: a checkbox that does
nothing is worse than no checkbox, because it is trusted.

QRZ.com reads qrzcom_qso_download_status, not the upload one: uploading a QSO
is us telling QRZ about it, which confirms nothing.

Custom names a field. Rather than a checkbox per external source, the Def gains
ConfirmField + ConfirmValue: any QSO field or ADIF extras key, and optionally
the comma-separated values that count. That one shape covers the three cases
asked for — the OpsLog card marker (APP_OPSLOG_QSL_RCVD), an arbitrary ADIF
tag, and a tag stamped by an imported club list — because all three end up as a
field on the QSO.

An empty ConfirmValue means any non-empty content confirms: the OpsLog marker
stores the date the card arrived, not a Y/N flag. A custom source naming NO
field confirms nothing, deliberately — the opposite default would silently mark
a whole logbook confirmed.
2026-08-09 02:11:24 +02:00
rouggy b202d98ae5 fix(awards): add a Prefix field to the primary QSOFIELDS search
Only OrRule had a Prefix ("prepended to each found reference", e.g. postal 74 →
D74); the primary search passed "" for prefix, so an award whose references are
D01/D02… couldn't prepend the D on its main rule — only on OR fallbacks. Add
Def.Prefix, pass it into the primary run(), and expose a Prefix input next to the
primary Leading/Trailing fields in the award editor.
2026-08-07 14:23:41 +02:00
rouggy a4623e9ea3 feat(awards): refuse an ambiguous match on one-reference awards
Two DARC DOKs are both called "Gießen" — two clubs share the town. Exact
matching finds both and both are right as far as the matcher can tell, so
it kept both and the operator got a QSO credited to a DOK that may well
have been the other one.

Picking one is not an option: it writes a reference into the log with no
evidence behind it. So a Def can now be marked one reference per QSO, and
an ambiguous match on such an award assigns none, names the candidates in
the trace and leaves the contact under missing references — where the
operator's choice now sticks (06e3437).

Off by default, and deliberately NOT a revival of the old `Multi` flag: a
field holding several references (an n-fer POTA activation, a VUCC grid
line) is several references, correctly, and stays that way.
2026-08-01 01:04:17 +02:00
rouggy ad02583ef7 fix: recognise the microwave bands — 10 GHz resolved to no band at all
Reported on 3 cm. cat.BandFromHz stopped at 23 cm, so a 10 GHz frequency came
back EMPTY — and an empty band is not cosmetic: the QSO is logged without one,
counts in no award slot, and exports with no BAND field. The low end was short
too (2190m / 630m / 560m).

Four band tables had to be extended because four exist: the CAT one, the award
plan in app.go, the cluster spot classifier, and the frontend's. Plus the places
that LIST bands — the QSO editor and award-definition pickers (you could not set
3 cm by hand either), the statistics axis, and the award band ORDER, where a
missing band sorts to the end instead of in frequency order.

Ranges and names are ADIF 3.1.7, which is what an export has to carry.

A test now pins one frequency per band across the Go tables and asserts they
agree — that is what was missing, four hand-maintained copies with nothing
checking them. It also pins that an out-of-band frequency stays empty rather
than snapping to the nearest band, which would file a QSO under a band the
operator never used.
2026-07-28 14:50:17 +02:00
rouggy 91b5af1c7b chore: release v0.21.3 2026-07-26 16:57:19 +02:00
rouggy 1b2da95ad4 ui: widen the Award management modal (max-w-6xl, 95vw) so the fuller footer fits 2026-07-20 14:35:18 +02:00
rouggy 8538f48259 feat: Publish-to-catalog export for awards (edit in UI, version, ship to team)
Adds ExportAwardForCatalog(code, version): writes the selected award as a
catalog-format JSON ({"def":…,"references":…}) stamped with a version and with
user_edited cleared, ready to paste over internal/award/catalog/<code>.json. A
new release then propagates the change to the whole team via mergeCatalog —
unedited copies auto-upgrade, edited ones are offered the update.

UI: a version input + "Publish to catalog…" button in the award editor footer,
defaulting to one past the award's current version.
2026-07-20 14:20:30 +02:00
rouggy 04b6431726 fix: Improved the code for awards 2026-07-14 16:42:48 +02:00
rouggy 0c6f8e2d68 feat: Added a test tab in awards to test the matching 2026-07-14 16:32:49 +02:00
rouggy 4fe0405432 feat: Allow updation of award catalog 2026-07-14 16:22:54 +02:00
rouggy 7f95a71426 feat: added Worked All Italian Provinces award and FFMA 2026-07-14 00:03:10 +02:00
rouggy 08f4b61523 feat: added FFMA award support 2026-07-13 22:18:25 +02:00
rouggy 656e238a59 feat: awards folder in the data folder, anybody can create its own awards. 2026-07-13 18:03:06 +02:00
rouggy c170d6091e feat: Reworked the awards logic so it is easy to add new ones. 2026-07-13 17:38:18 +02:00
rouggy 96390110f8 fix: Improved awards matches 2026-07-10 15:28:01 +02:00
rouggy daf38554a5 feat: Award column can now show either reference or description 2026-07-07 20:23:18 +02:00
rouggy 06183bd5d4 feat: Themes added, 4 themes available (3 dark, 1 light) 2026-07-06 09:08:47 +02:00
rouggy 2d742be7df feat: Complete translation in French 2026-07-05 10:44:40 +02:00
rouggy 69d0780bac feat: added versionning & About window 2026-06-16 19:36:56 +02:00
rouggy 16c04fc12b awards 2026-06-07 01:11:37 +02:00
rouggy 17f7a00bd7 up 2026-06-06 14:16:30 +02:00
rouggy 922a185208 up 2026-06-06 00:02:56 +02:00
rouggy 51d3a734e8 award 2026-06-05 22:35:28 +02:00
rouggy 88623f55df awards 2026-06-05 17:22:38 +02:00