fix(kpa): a settings save must not flick the KPA500's power switch — and the maps stay under the menus

startAmps tore down and rebuilt every amplifier client on any settings
save, and closing a COM port makes the Windows driver drop DTR/RTS. On a
KPA500 those lines ARE the power switch — so 'save' meant 'amplifier off
twenty seconds later', exactly F1TPL's report, and the fix that held the
lines while OPEN couldn't survive a close. An amplifier whose config is
unchanged now keeps its running client across saves; the others still
rebuild.

Also: isolate on the FT Map panel — Leaflet's z-1000 panes were painting
over the menu bar and the Preferences dialog, as the grid map's own
comment warned.
This commit is contained in:
2026-08-31 11:39:02 +02:00
parent cd5d8b503b
commit 612cb67438
3 changed files with 49 additions and 10 deletions
+39 -7
View File
@@ -18677,19 +18677,51 @@ func (a *App) startAmps() {
old := a.ampInsts
a.ampInsts = map[string]*ampInst{}
a.ampsMu.Unlock()
for _, inst := range old {
a.pgxl, a.spe, a.acom = nil, nil, nil
list, err := a.GetAmplifiers()
if err != nil {
for _, inst := range old {
go inst.stopAll()
}
return
}
// An amplifier whose configuration did not change keeps its RUNNING client
// across a settings save. Rebuilding closes the serial port, and closing a
// COM port makes the Windows driver drop DTR/RTS — which on a KPA500 is the
// POWER SWITCH: every save of any Settings page was switching the amplifier
// off (F1TPL's report). Reuse also spares the other amps a reconnect blink.
reused := map[string]bool{}
for _, c := range list {
if !c.Enabled {
continue
}
if o, ok := old[c.ID]; ok && o.cfg == c {
reused[c.ID] = true
if o.pgxl != nil && a.pgxl == nil {
a.pgxl = o.pgxl
}
if o.spe != nil && a.spe == nil {
a.spe = o.spe
}
if o.acom != nil && a.acom == nil {
a.acom = o.acom
}
a.ampsMu.Lock()
a.ampInsts[c.ID] = o
a.ampsMu.Unlock()
}
}
for id, inst := range old {
if reused[id] {
continue
}
// Stop() can block up to the dial timeout waiting for an in-progress
// connect; tear down in the background so saving Settings (this runs on
// the Wails RPC goroutine) doesn't freeze the UI.
go inst.stopAll()
}
a.pgxl, a.spe, a.acom = nil, nil, nil
list, err := a.GetAmplifiers()
if err != nil {
return
}
for _, c := range list {
if !c.Enabled {
if !c.Enabled || reused[c.ID] {
continue
}
isPGXL := c.Type == "" || c.Type == "pgxl"
+6 -2
View File
@@ -5,12 +5,16 @@
"en": [
"QSL Manager: Club Log confirmations — downloads your log matches (getmatches API) and stamps two new columns, ClubLog match status and match date, available everywhere: table columns, filters, bulk edit and the QSO editor.",
"Super Check Partial: option to merge Club Logs weekly call list (~180k calls heard on the air in the last 3 years) with MASTER.SCP.",
"Fixed: opening the app could silently stop at startup (settings showing as default, “db not initialized”) when a database migration targeted a table that database no longer holds — migrations now skip what does not apply, and a startup failure is written to the log."
"Fixed: opening the app could silently stop at startup (settings showing as default, “db not initialized”) when a database migration targeted a table that database no longer holds — migrations now skip what does not apply, and a startup failure is written to the log.",
"FT Map / Grid squares: the map no longer floats above the menus and the Preferences dialog.",
"KPA500: saving ANY settings page no longer power-cycles the amplifier. A save rebuilt every amplifier connection, and closing the COM port drops DTR/RTS — the KPA500s power switch. An unchanged amplifier now keeps its running connection across saves."
],
"fr": [
"QSL Manager : confirmations Club Log — télécharge vos matches de log (API getmatches) et remplit deux nouvelles colonnes, statut et date de match ClubLog, disponibles partout : colonnes du tableau, filtres, édition groupée et éditeur de QSO.",
"Super Check Partial : option pour fusionner la liste hebdomadaire de Club Log (~180k indicatifs entendus sur lair ces 3 dernières années) avec MASTER.SCP.",
"Corrigé : lapplication pouvait se figer silencieusement au démarrage (réglages par défaut, « db not initialized ») quand une migration visait une table absente de cette base — les migrations ignorent désormais ce qui ne sapplique pas, et un échec de démarrage est écrit dans le log."
"Corrigé : lapplication pouvait se figer silencieusement au démarrage (réglages par défaut, « db not initialized ») quand une migration visait une table absente de cette base — les migrations ignorent désormais ce qui ne sapplique pas, et un échec de démarrage est écrit dans le log.",
"FT Map / Grid squares : la carte ne passe plus au-dessus des menus et de la fenêtre Préférences.",
"KPA500 : sauvegarder nimporte quelle page des réglages n’éteint plus lampli. Une sauvegarde reconstruisait chaque connexion dampli, et fermer le port COM relâche DTR/RTS — linterrupteur dalimentation du KPA500. Un ampli inchangé garde désormais sa connexion à travers les sauvegardes."
]
},
{
+4 -1
View File
@@ -119,7 +119,10 @@ export function FTMapPanel({ decodes, myGrid }: { decodes: FTMapDecode[]; myGrid
const bands = [...new Set(decodes.map((d) => (d.band ?? '').toLowerCase()).filter(Boolean))];
return (
<div className="relative h-full w-full min-h-0">
// isolate: Leaflet stacks its panes and controls up to z-index 1000, which
// beat the app menus and the Settings dialog. A stacking context of our own
// keeps all of it inside this panel.
<div className="relative isolate z-0 h-full w-full min-h-0">
<div ref={divRef} className="absolute inset-0 rounded-lg overflow-hidden" />
{/* Basemap picker, MainMap's own vocabulary. */}
<div className="absolute top-2 left-12 z-[1000] flex gap-1 rounded-md bg-background/85 backdrop-blur px-1 py-1 border border-border">