feat: added APF for CW in Icom

This commit is contained in:
2026-07-07 17:10:42 +02:00
parent 1cadefd207
commit ab06673854
11 changed files with 493 additions and 38 deletions
+300
View File
@@ -0,0 +1,300 @@
# OpsLog
Un logiciel de log radioamateur moderne et rapide pour Windows — saisie façon
Log4OM, CAT en temps réel pour **OmniRig**, **FlexRadio/SmartSDR** natif,
**Icom CI-V** natif (USB **et** à distance par internet, en remplacement de
RS-BA1) et **TCI** (SunSDR / Expert Electronics), cluster DX avec alertes de
spots, suivi des diplômes, cartes, log de concours, gestion des QSL et un
concepteur de cartes QSL. Construit avec **Wails v2** (backend Go + frontend
React/TypeScript), **100 % Go** (sans CGO) : SQLite pour la configuration,
**MySQL partagé** optionnel pour le journal afin que plusieurs opérateurs
partagent un même log. Entièrement thémable et bilingue (anglais / français).
Développé par **F4BPO**.
---
## Compilation / développement
- **Dev :** `wails dev` (rechargement à chaud Vite ; méthodes Go accessibles sur http://localhost:34115).
- **Build :** `wails build` (utiliser la version wails v2.11 du projet — `~/go/bin/wails.exe`).
- **Régénérer les bindings Go↔TS** après modification des méthodes `App`
exportées : `wails generate module`.
- **Release :** `.vscode/release.ps1` (Ctrl+Maj+P → *Tasks: Run Task*
*Release OpsLog*) — incrémente la version, pousse le source sur Gitea, compile
l'exe et le publie sur les releases Gitea + GitHub.
---
## Journalisation
- **Bandeau de saisie façon Log4OM :** indicatif, RST émis/reçu, nom/QTH/locator,
bande/mode, fréquence TX/RX (split), heure de début/fin, commentaire/note. Le
**drapeau** de l'entité contactée est affiché en grand à côté des champs RST.
- **Recherche d'indicatif** (QRZ.com / HamQTH) avec photo, pré-remplissage du
nom/QTH/locator et onglet QRZ.com.
- **Résolution DXCC hors ligne** depuis `cty.dat` (pays, zones CQ/ITU,
continent), avec gestion des `/MM` `/AM` `/B` (balise) et des changements de
district (`/8`, `/W6`), plus les dérogations DXpédition de ClubLog par dates.
- **QSO récents**, matrice **déjà contactés** (par créneau bande/mode),
re-résolution en masse depuis cty/QRZ/ClubLog, envoi en masse vers les services
QSL.
- **Constructeur de filtres QSO avancé** (champ / opérateur / valeur, ET / OU,
préréglages enregistrés) avec **export ADIF** des lignes filtrées ou
sélectionnées.
- **Recherche de doublons** (Outils) — regroupe les QSO par même indicatif +
bande + mode (optionnellement même jour / minute) et permet de choisir lesquels
supprimer.
- **Conforme ADIF 3.1.7** en import/export : dictionnaire complet des champs,
30 colonnes promues, éditeur générique de « champs supplémentaires » et modes
d'export standard/complet.
- **Profils :** chaque réglage est par profil ; chaque profil peut pointer son
journal vers le fichier SQLite local ou une base **MySQL partagée**
(multi-opérateur).
## Cartes & antenne
- **Vue principale = deux volets configurables** (par profil, Réglages → Général
*Vue principale*) : carte grand-cercle, carte locator (rue), la grille du
cluster, la grille des déjà-contactés, les QSO récents, les **commandes
FlexRadio**, la **console Icom** ou le panneau **Net control**.
- **Carte grand-cercle** avec distance & azimut trajet court/long, fonds de carte
sélectionnables (Light / Voyager / Street / Satellite, tous sans clé et
légendés) et le(s) **lobe(s) du faisceau d'antenne** tracés depuis l'azimut du
rotor.
- **Compas de rotor** (azimutal équidistant, clic pour tourner) piloté par
PstRotator.
- **Support Ultrabeam** (Normal / inversé 180° / bidirectionnel) : la direction
rayonnée est en vert et le **boom mécanique** en gris, à la fois sur le compas
et sur la carte, pour toujours savoir où pointe l'antenne.
## Cluster DX
- Plusieurs serveurs de cluster avec reconnexion auto, un maître pour les
commandes.
- **Barre latérale de filtres** (recherche d'indicatif, masquer-déjà-contactés,
grouper les doublons, bande / mode / statut / source) partagée entre l'onglet
Cluster et le volet cluster de la vue principale, avec bascule affichage/masquage.
- **Statut** par spot (nouveau / nouvelle bande / nouveau créneau / contacté),
clic pour accorder la radio, et une **bandmap** multi-bandes (bandes façon
panadapter).
- Les spots **POTA** sont étiquetés avec leur référence de parc (via
`api.pota.app`).
- **Alertes de spots** (façon Log4OM) : règles sur indicatif / pays / bande /
mode / spotter, avec notification sonore, visuelle et e-mail (Outils →
*Gestion des alertes*).
## Contrôle CAT
Quatre backends natifs (Réglages → CAT), chacun avec reconnexion auto et une
connexion rapide non bloquante — une radio éteinte ne fige jamais l'application :
- **OmniRig** (Rig 1/2, changement à chaud) — fonctionne avec toute radio
supportée par OmniRig.
- **FlexRadio (SmartSDR)** via l'API TCP de la radio — fréquence / mode / split
de la slice en temps réel, découverte UDP, et **spots panadapter** (les spots
du cluster poussés sur l'écran Flex, clic → remplir l'indicatif).
- **Icom CI-V** — natif, via le port **USB** de la radio *ou* par internet via le
**serveur LAN intégré** de la radio (voir *Icom à distance* ci-dessous). Ni
RS-BA1 ni Remote Utility nécessaires.
- **TCI** (WebSocket) — SunSDR / ExpertSDR2 et tout serveur compatible TCI :
fréquence / mode / PTT / split, plus spots panorama optionnels.
Le mode est lu depuis la radio ; le sous-mode numérique (FT4 vs FT8) est déduit
de la fréquence. Les **antennes RX/TX Flex par bande** sont configurables et
appliquées automatiquement au changement de bande.
### Onglet de commande FlexRadio (façon SmartSDR)
Affiché uniquement quand le backend CAT est une FlexRadio :
- **Émission :** puissance RF, puissance d'accord, TUNE, MOX, processeur de
parole (NOR/DX/DX+), VOX (+ niveau + délai), moniteur (+ niveau), gain micro.
- **Réception (slice active) :** mode/seuil AGC, niveau audio, NB / NR / ANF.
- **Coupleur d'antenne (ATU) :** accord / bypass / mémoires.
- **Amplificateur :** PowerGenius XL operate/standby + défaut.
- **Mesures en direct** via le flux UDP VITA-49 : S-mètre (unités S), puissance
directe (W), ROS, ALC, température PA, tension, plus les mesures de l'ampli.
### Onglet de commande Icom
Affiché quand le backend CAT est Icom (USB ou réseau). Une console complète façon
RS-BA1 :
- **Double afficheur VFO** (MAIN / SUB) avec la grande fréquence tabulaire, le
badge de mode, la bande et l'offset RIT/ΔTX, et une **rangée de boutons de
mode** (SSB / CW / RTTY / PSK / AM / FM).
- **Scope de spectre + waterfall** (panadapter) : ON/OFF, CTR/FIX, double-clic
pour accorder, et boutons **◀ ⊙ ▶** pour centrer le scope sur la fréquence
actuelle (±50 kHz) et le décaler à gauche/droite.
- **Mesures en direct** toujours visibles : S-mètre (clic → remplir le RST),
puissance en watts, ROS.
- **DSP réception :** gain AF / RF, squelch, AGC, préampli, atténuateur, filtre
(FIL1/2/3), NB, NR, ANF et — **en CW seulement** — l'**APF** (filtre de pic
audio).
- **Passe-bande / notch :** Twin PBT (intérieur / extérieur), notch manuel +
position.
- **Émission :** puissance RF, MOX, TUNE, **split avec offset automatique**
(+5 kHz en SSB, +1 kHz en CW), et moniteur. **En phonie seulement** : gain
micro, processeur de parole, VOX (+ gain + anti-VOX). Les commandes qui ne
s'appliquent pas au mode courant sont masquées automatiquement.
- **Bandes & antenne :** boutons de bande en un clic et sélection ANT1/ANT2.
- **Clarificateurs :** RIT et ΔTX avec accord molette / ± (Ctrl+←/→ décale le
RIT).
- Boutons **Marche / Arrêt** (manuels par choix — l'application ne réveille
jamais la radio à la connexion).
- La **manipulation CW** peut passer par le keyer intégré de la radio (voir
*Keyers* ci-dessous).
### Icom à distance (par internet, sans RS-BA1)
OpsLog parle directement le protocole réseau intégré de l'IC-7610 — il
**remplace à la fois l'Icom Remote Utility et RS-BA1**. Saisissez l'IP de la
radio, le nom/mot de passe Network User1 et l'adresse CI-V, et toute la console
Icom fonctionne sur le LAN/internet : login + token (renouvelé automatiquement),
tunnel CI-V, retransmission côté réception pour une liaison très stable même
avec le panadapter en flux, et Marche/Arrêt manuel. (L'audio est hors périmètre
— utilisez la radio en USB + une liaison voix comme Mumble.)
## Keyers & audio
- **Keyer CW** avec macros et macros sur touches F. Le moteur du keyer est
sélectionnable : **WinKeyer** (K1EL WK1/2/3 sur port COM), **Icom** (le keyer
intégré de la radio via CI-V — sans matériel supplémentaire, fonctionne aussi à
distance) ou **TCI**.
- **Keyer vocal numérique** (DVK) : enregistrer les messages vocaux F1F6 et les
émettre.
- **Enregistrement audio des QSO :** capture continue en tampon glissant ; au
*Log QSO* le contact est sauvegardé dans un WAV par QSO
(`INDICATIF_AAAAMMJJ_HHMMSS.wav`) ; mixe RX + micro.
## Amplis & commutateurs
- Amplificateur **PowerGenius XL** (4O3A) — TCP direct : operate/standby,
sélecteur de mode ventilateur et affichage des défauts.
- Commutateur d'antenne **Antenna Genius** (4O3A) via TCP/GSCP — un widget de
commutation A/B ancré.
## QSL & diplômes
- **Moteur de diplômes :** définitions intégrées + personnalisées (partagées
**globalement** entre profils) — DXCC, WAS / WAZ / WAC, WPX,
IOTA / POTA / SOTA / WWFF, **DDFM**, contacté/confirmé/validé par bande & mode,
règles OU et affectation manuelle de références, détection de référence en
direct à la saisie de l'indicatif, **import de listes de références** pour les
totaux/noms, et un **Rescan** qui relit le journal (récupère les nouvelles
confirmations LoTW/QRZ).
- **Services QSL :** ClubLog (upload ADIF par lots), LoTW, QRZ.com, eQSL —
upload et **téléchargement des confirmations** (qui rafraîchit automatiquement
les stats de diplômes).
- **Concepteur de cartes QSL** (voir ci-dessous).
- **eQSL par e-mail :** clic droit sur un QSO → *Envoyer l'eQSL par e-mail* via
le compte SMTP configuré. (Outlook/Hotmail désactivent le SMTP basic-auth —
utilisez Gmail avec un mot de passe d'application, ou un mot de passe
d'application Microsoft.)
## Log de concours
- **Onglet Contest :** choisissez un concours (liste ADIF `CONTEST_ID` intégrée)
et un échange (numéro de série courant ou échange fixe). OpsLog remplit
automatiquement `CONTEST_ID` et les numéros émis/reçus (`STX` / `SRX`), impose
un début/fin de fenêtre, signale les doublons et tient un tableau de score en
direct.
## Statut opérateur en direct (événements spéciaux)
Pour un indicatif d'événement spécial multi-op sur un journal MySQL partagé (ex.
**TM74TFR**) : Réglages → Général → *Publier le statut opérateur en direct*.
Chaque instance OpsLog envoie un battement de cœur de son activité (indicatif de
l'opérateur, bande, fréquence, mode) dans une table `live_status` toutes les
~15 s. Un petit rendu PHP
([`docs/livestatus/tm74-status.php`](docs/livestatus/tm74-status.php)) sur votre
propre serveur web lit cette table et produit une page/image en direct que vous
pouvez intégrer sur la bio **QRZ.com** de la station
(`<img src="…/tm74-status.php?img=1">`). OpsLog écrit seulement dans la base —
ce n'est pas un serveur web.
## Net control
- **Log de net dirigé** (Outils → Net) : un roster global (`nets.json`) plus une
session active en mémoire — pointez les stations présentes, puis loguez tout le
net d'un coup en utilisant la fréquence CAT.
## Apparence & langue
- **Thèmes :** quatre thèmes complets (Clair chaud, Sombre chaud, Graphite
sombre, Contraste élevé) plus **Auto** (suit la préférence clair/sombre du
système), sélectionnables dans Réglages → Général. Chaque panneau et chaque
table AG-Grid suit le thème.
- **Bilingue :** interface complète **anglais / français**, avec un choix de
drapeau au premier lancement et un sélecteur dans Réglages → Général.
## Sécurité
- **Coffre à secrets :** chiffrement optionnel par phrase de passe des mots de
passe stockés (AES-GCM + PBKDF2). Les valeurs chiffrées sont portables ; une
seule invite de déverrouillage au lancement les déchiffre pour la session.
## Intégrations (sortantes)
- **Émetteurs UDP :** pousser la fréquence actuelle vers **PstRotator**, les
infos radio au format **N1MM `RadioInfo`**, ou un **enregistrement ADIF à
chaque QSO logué** — pour que les outils externes (contrôle de rotor,
applications numériques, autres logiciels de log) restent synchronisés.
## Divers
- **Démarrage automatique :** lancer des programmes externes (WSJT-X, JTAlert,
contrôle de rotor…) au démarrage d'OpsLog, en sautant ceux déjà lancés.
- **Sauvegarde :** sauvegarde optionnelle base + ADIF à la fermeture.
- **Vérification de mise à jour** au démarrage avec un toast (désactivable).
- **Télémétrie d'usage anonyme** (un battement de cœur quotidien : ID
d'installation aléatoire + version + OS — aucune donnée d'indicatif ou de QSO ;
désactivable dans les Préférences).
---
## Concepteur de cartes QSL
Outils → *Concepteur de cartes QSL…* transforme quelques photos en une carte
eQSL soignée :
1. Choisissez 1 à 6 photos (jpeg/png). OpsLog les analyse hors ligne (grille de
détail/luminance) et propose **3 designs** — indicatif dans la zone la plus
calme de la meilleure photo, nom de l'opérateur, zones CQ/ITU + ligne locator,
drapeau du pays, les autres photos en inserts encadrés, et un encart de
confirmation par QSO.
2. Choisissez une proposition et affinez-la : cliquez un élément pour le
sélectionner, glissez pour déplacer, changez la police / le préréglage de
style (gel or, gel argent, contour blanc classique, script, plat) et les
réglages par préréglage dans le panneau de droite.
3. Enregistrez le modèle (les photos sont copiées dans
`data/qsl/templates/<id>/`, les originaux peuvent donc être déplacés). Un
modèle peut être le défaut par profil.
Envoi : clic droit sur un QSO → *Envoyer l'eQSL par e-mail*. La carte est rendue
avec les données de ce QSO, matricée en JPEG ≤ 800 Ko, archivée dans
`data/qsl/outbox/` et envoyée via le compte SMTP configuré à l'adresse trouvée
par la recherche QRZ/HamQTH. En cas de succès le QSO est marqué `EQSL_SENT=Y`
(ADIF). Les modèles de sujet/corps de l'e-mail sont dans le concepteur (variables
`{CALL} {DATE} {BAND} {MODE} {MYCALL}`).
Polices : Archivo Black, Lilita One, Baloo 2, Oswald, Great Vibes, Allura
(toutes OFL, embarquées — licences dans `internal/qslcard/assets/fonts/`) ;
Cooper Black est proposée si MS Office l'a installée. Drapeaux : flag-icons
(MIT), embarqués pour les entités DXCC couramment contactées.
---
## Données & stockage
- La **config** (réglages, profils, radios/antennes, nœuds de cluster, cache de
recherche, listes de diplômes, modèles QSL) réside toujours dans le fichier
SQLite local sous `data/` — instantané même quand le journal est sur un MySQL
lointain.
- Le **journal** (QSO) réside là où pointe le profil actif : le fichier SQLite
local ou une base **MySQL** partagée par profil.
---
*An English version of this document is available in [README.md](README.md).*
+125 -18
View File
@@ -1,10 +1,13 @@
# OpsLog # OpsLog
A modern, fast ham-radio logger for Windows — Log4OM-style entry, real-time CAT A modern, fast ham-radio logger for Windows — Log4OM-style entry, real-time CAT
(OmniRig **and** native FlexRadio/SmartSDR), DX cluster, awards tracking, maps, for **OmniRig**, native **FlexRadio/SmartSDR**, native **Icom CI-V** (USB **and**
QSL management and a QSL-card designer. Built with **Wails v2** (Go backend + remote-over-internet, replacing RS-BA1) and **TCI** (SunSDR / Expert Electronics),
DX cluster with spot alerts, awards tracking, maps, contest logging, QSL
management and a QSL-card designer. Built with **Wails v2** (Go backend +
React/TypeScript frontend), **pure Go** (no CGO): SQLite for configuration, React/TypeScript frontend), **pure Go** (no CGO): SQLite for configuration,
optional **shared MySQL** for the logbook so several operators can run one log. optional **shared MySQL** for the logbook so several operators can run one log.
Fully themeable and bilingual (English / French).
Developed by **F4BPO**. Developed by **F4BPO**.
@@ -30,10 +33,16 @@ Developed by **F4BPO**.
- **Callsign lookup** (QRZ.com / HamQTH) with photo, auto-fill of name/QTH/grid - **Callsign lookup** (QRZ.com / HamQTH) with photo, auto-fill of name/QTH/grid
and the QRZ.com tab. and the QRZ.com tab.
- **Offline DXCC** resolution from `cty.dat` (country, CQ/ITU zones, continent), - **Offline DXCC** resolution from `cty.dat` (country, CQ/ITU zones, continent),
with `/MM` `/AM` and call-area (`/8`, `/W6`) handling, plus ClubLog DXpedition with `/MM` `/AM` `/B` (beacon) and call-area (`/8`, `/W6`) handling, plus
date overrides. ClubLog DXpedition date overrides.
- **Recent QSOs**, **Worked-before** matrix (per band/mode slot), bulk re-resolve - **Recent QSOs**, **Worked-before** matrix (per band/mode slot), bulk re-resolve
from cty/QRZ/ClubLog, bulk send to QSL services. from cty/QRZ/ClubLog, bulk send to QSL services.
- **Advanced QSO filter builder** (field / operator / value, AND / OR, saved
presets) with filtered- and selected-row **ADIF export**.
- **Find duplicates** (Tools) — groups QSOs by same call + band + mode (optionally
same day / minute) and lets you pick which to delete.
- **ADIF 3.1.7 compliant** import/export: a full field dictionary, 30 promoted
columns, a generic "extra fields" editor and standard/all export modes.
- **Profiles:** every setting is per-profile; each profile can point its logbook - **Profiles:** every setting is per-profile; each profile can point its logbook
at the local SQLite file or a **shared MySQL** database (multi-operator). at the local SQLite file or a **shared MySQL** database (multi-operator).
@@ -41,7 +50,8 @@ Developed by **F4BPO**.
- **Main view = two configurable panes** (per profile, Settings → General → - **Main view = two configurable panes** (per profile, Settings → General →
*Main view*): great-circle map, locator (street) map, the cluster grid, the *Main view*): great-circle map, locator (street) map, the cluster grid, the
worked-before grid, or the **FlexRadio controls**. worked-before grid, recent QSOs, the **FlexRadio controls**, the **Icom
console** or the **Net control** panel.
- **Great-circle map** with short/long-path distance & azimuth, selectable - **Great-circle map** with short/long-path distance & azimuth, selectable
basemaps (Light / Voyager / Street / Satellite, all key-free and labelled) and basemaps (Light / Voyager / Street / Satellite, all key-free and labelled) and
the **antenna beam lobe(s)** drawn from the rotor azimuth. the **antenna beam lobe(s)** drawn from the rotor azimuth.
@@ -58,15 +68,29 @@ Developed by **F4BPO**.
pane, with a show/hide toggle. pane, with a show/hide toggle.
- Per-spot **status** (new / new-band / new-slot / worked), click-to-tune the - Per-spot **status** (new / new-band / new-slot / worked), click-to-tune the
rig, and a multi-band **Band Map** (panadapter-style strips). rig, and a multi-band **Band Map** (panadapter-style strips).
- **POTA** spots are tagged with their park reference (via `api.pota.app`).
- **Spot alerts** (Log4OM-style): rules on call / country / band / mode /
spotter, with sound, visual and e-mail notification (Tools → *Alert
management*).
## CAT control ## CAT control
- **OmniRig** backend (Rig 1/2, hot-swap), and a native **FlexRadio (SmartSDR)** Four native backends (Settings → CAT), each with auto-reconnect and a fast,
backend over the radio's TCP API — real-time slice freq/mode/split, auto non-blocking connect so a powered-off radio never freezes the app:
reconnect, UDP discovery, and **panadapter spots** (cluster spots pushed to the
Flex display, click → fill the call). - **OmniRig** (Rig 1/2, hot-swap) — works with any OmniRig-supported rig.
- Mode is taken from the radio; the digital sub-mode (FT4 vs FT8) is inferred - **FlexRadio (SmartSDR)** over the radio's TCP API — real-time slice freq /
from the frequency. mode / split, UDP discovery, and **panadapter spots** (cluster spots pushed to
the Flex display, click → fill the call).
- **Icom CI-V** — native, over the radio's **USB** port *or* over the internet
via the radio's **built-in LAN server** (see *Remote Icom* below). No RS-BA1 or
Remote Utility needed.
- **TCI** (WebSocket) — SunSDR / ExpertSDR2 and any TCI-compatible server:
freq / mode / PTT / split, plus optional panorama spots.
Mode is taken from the radio; the digital sub-mode (FT4 vs FT8) is inferred from
the frequency. **Per-band Flex RX/TX antennas** can be configured and are applied
automatically on band change.
### FlexRadio control tab (SmartSDR-style) ### FlexRadio control tab (SmartSDR-style)
@@ -80,19 +104,64 @@ Shown only when the CAT backend is a FlexRadio:
- **Live meters** over the UDP VITA-49 stream: S-meter (S-units), forward power - **Live meters** over the UDP VITA-49 stream: S-meter (S-units), forward power
(W), SWR, ALC, PA temperature, voltage, plus the amplifier's meters. (W), SWR, ALC, PA temperature, voltage, plus the amplifier's meters.
### Icom control tab
Shown when the CAT backend is Icom (USB or network). A full RS-BA1-style console:
- **Twin VFO readout** (MAIN / SUB) with the big tabular frequency, mode badge,
band and RIT/ΔTX offset, and a **mode-button row** (SSB / CW / RTTY / PSK /
AM / FM).
- **Spectrum scope + waterfall** (panadapter): ON/OFF, CTR/FIX, double-click to
tune, and **◀ ⊙ ▶** buttons to centre the scope on the current frequency
(±50 kHz) and pan left/right.
- **Live meters** always visible: S-meter (click → fill RST), power in watts, SWR.
- **Receive DSP:** AF / RF gain, squelch, AGC, preamp, attenuator, filter
(FIL1/2/3), NB, NR, ANF and — **on CW only** — the **APF** (audio peak filter).
- **Passband / notch:** Twin PBT (inner / outer), manual notch + position.
- **Transmit:** RF power, MOX, TUNE, **split with an automatic offset**
(+5 kHz on SSB, +1 kHz on CW), and monitor. On **voice modes only**: mic gain,
speech compressor, VOX (+ gain + anti-VOX). Controls that don't apply to the
current mode are hidden automatically.
- **Bands & antenna:** one-touch band buttons and ANT1/ANT2 selection.
- **Clarifiers:** RIT and ΔTX with wheel / ± tuning (Ctrl+←/→ nudges RIT).
- **Power ON / OFF** buttons (manual by design — the app never wakes the rig on
connect).
- **CW keying** can run through the radio's own keyer (see *Keyers* below).
### Remote Icom (over the internet, no RS-BA1)
OpsLog speaks the IC-7610's built-in network protocol directly — it **replaces
both the Icom Remote Utility and RS-BA1**. Enter the radio's IP, the Network
User1 name/password and the CI-V address, and the whole Icom console works over
the LAN/internet: login + token (auto-renewed), CI-V tunnel, receive-side
retransmit for a rock-solid link even with the panadapter streaming, and manual
power ON/OFF. (Audio is out of scope — use the radio in USB + a voice link such
as Mumble.)
## Keyers & audio ## Keyers & audio
- **WinKeyer** CW keyer (macros, F-key macros, auto-call repeat). - **CW keyer** with macros and F-key macros. The keyer engine is selectable:
- **Digital Voice Keyer** (DVK) message playback. **WinKeyer** (K1EL WK1/2/3 over a COM port), **Icom** (the radio's own keyer
- **QSO audio recording** (SSB/DAX) archived per QSO; disabled for CW (no DAX over CI-V — no extra hardware, works over the remote link too) or **TCI**.
audio in CW). - **Digital Voice Keyer** (DVK): record F1F6 voice messages and transmit them.
- **QSO audio recording:** continuous rolling capture; on *Log QSO* the contact
is saved to a per-QSO WAV (`CALL_YYYYMMDD_HHMMSS.wav`); mixes RX + mic.
## Amplifiers & switches
- **PowerGenius XL** (4O3A) amplifier — direct TCP: operate/standby, fan-mode
selector and fault display.
- **Antenna Genius** (4O3A) antenna switch over TCP/GSCP — a docked A/B
antenna-switch widget.
## QSL & awards ## QSL & awards
- **Awards engine:** built-in + custom award definitions (shared **globally** - **Awards engine:** built-in + custom award definitions (shared **globally**
across profiles), worked/confirmed/validated by band & mode, OR rules and across profiles) — DXCC, WAS / WAZ / WAC, WPX, IOTA / POTA / SOTA / WWFF,
manual reference assignment, live reference detection on call entry, and a **DDFM**, worked/confirmed/validated by band & mode, OR rules and manual
**Rescan** that re-pulls the logbook (picks up fresh LoTW/QRZ confirmations). reference assignment, live reference detection on call entry, **reference-list
import** for totals/names, and a **Rescan** that re-pulls the logbook (picks up
fresh LoTW/QRZ confirmations).
- **QSL services:** ClubLog (batched ADIF upload), LoTW, QRZ.com, eQSL — upload - **QSL services:** ClubLog (batched ADIF upload), LoTW, QRZ.com, eQSL — upload
and **confirmation download** (which auto-refreshes the award stats). and **confirmation download** (which auto-refreshes the award stats).
- **QSL Card Designer** (see below). - **QSL Card Designer** (see below).
@@ -100,6 +169,13 @@ Shown only when the CAT backend is a FlexRadio:
SMTP account. (Outlook/Hotmail disable basic-auth SMTP — use Gmail with an app SMTP account. (Outlook/Hotmail disable basic-auth SMTP — use Gmail with an app
password, or a Microsoft app password.) password, or a Microsoft app password.)
## Contest logging
- **Contest tab:** pick a contest (built-in ADIF `CONTEST_ID` list) and an
exchange (running serial or a fixed exchange). OpsLog auto-fills `CONTEST_ID`
and the sent/received serials (`STX` / `SRX`), enforces a window start/end,
flags dupes and keeps a live scoreboard.
## Multi-operator live status (special events) ## Multi-operator live status (special events)
For a multi-op special-event call on a shared MySQL logbook (e.g. **TM74TFR**): For a multi-op special-event call on a shared MySQL logbook (e.g. **TM74TFR**):
@@ -111,10 +187,37 @@ own web server reads that table and produces a live page/image you can embed on
the station's **QRZ.com** bio (`<img src="…/tm74-status.php?img=1">`). OpsLog the station's **QRZ.com** bio (`<img src="…/tm74-status.php?img=1">`). OpsLog
only writes to the DB — it is not a web server. only writes to the DB — it is not a web server.
## Net control
- **Directed-net logging** (Tools → Net): a global roster (`nets.json`) plus an
in-memory active session — check stations in, then log the whole net at once
using the CAT frequency.
## Appearance & language
- **Themes:** four complete themes (Warm light, Warm dark, Graphite dark, High
contrast) plus **Auto** (follows the OS light/dark preference), selectable in
Settings → General. Every panel and every AG-Grid table follows the theme.
- **Bilingual:** full **English / French** UI, with a first-run flag chooser and
a switcher in Settings → General.
## Security
- **Secret vault:** opt-in passphrase encryption of the stored passwords
(AES-GCM + PBKDF2). Encrypted values are portable; a single unlock prompt at
launch decrypts them for the session.
## Integrations (outbound)
- **UDP emitters:** push the current frequency to **PstRotator**, radio info in
**N1MM `RadioInfo`** format, or an **ADIF record on each logged QSO** — so
external tools (rotator control, digital apps, other loggers) stay in sync.
## Other ## Other
- **Autostart:** launch external programs (WSJT-X, JTAlert, rotator control…) at - **Autostart:** launch external programs (WSJT-X, JTAlert, rotator control…) at
OpsLog startup, skipping any already running. OpsLog startup, skipping any already running.
- **Backup:** optional database + ADIF backup at shutdown.
- **Update check** at startup with a toast (toggleable). - **Update check** at startup with a toast (toggleable).
- **Anonymous usage telemetry** (a once-a-day heartbeat: random install ID + - **Anonymous usage telemetry** (a once-a-day heartbeat: random install ID +
version + OS — no callsign or QSO data; opt-out in Preferences). version + OS — no callsign or QSO data; opt-out in Preferences).
@@ -156,3 +259,7 @@ commonly-worked DXCC entities.
`data/` — instant even when the logbook is on a far-away MySQL. `data/` — instant even when the logbook is on a far-away MySQL.
- **Logbook** (QSOs) lives where the active profile points it: the local SQLite - **Logbook** (QSOs) lives where the active profile points it: the local SQLite
file or a per-profile shared **MySQL** database. file or a per-profile shared **MySQL** database.
---
*A French version of this document is available in [README.fr.md](README.fr.md).*
+7
View File
@@ -7843,6 +7843,13 @@ func (a *App) IcomSetANF(on bool) error {
return a.cat.IcomDo(func(ic cat.IcomController) error { return ic.SetANF(on) }) return a.cat.IcomDo(func(ic cat.IcomController) error { return ic.SetANF(on) })
} }
func (a *App) IcomSetAPF(on bool) error {
if a.cat == nil {
return fmt.Errorf("cat not initialized")
}
return a.cat.IcomDo(func(ic cat.IcomController) error { return ic.SetAPF(on) })
}
func (a *App) IcomSetAGC(mode string) error { func (a *App) IcomSetAGC(mode string) error {
if a.cat == nil { if a.cat == nil {
return fmt.Errorf("cat not initialized") return fmt.Errorf("cat not initialized")
+37 -18
View File
@@ -3,7 +3,7 @@ import { Radio, AudioLines, Mic, Activity, SlidersHorizontal, Antenna, Filter, P
import { import {
GetIcomState, IcomRefresh, GetIcomState, IcomRefresh,
IcomSetAFGain, IcomSetRFGain, IcomSetNB, IcomSetNBLevel, IcomSetNR, IcomSetNRLevel, IcomSetAFGain, IcomSetRFGain, IcomSetNB, IcomSetNBLevel, IcomSetNR, IcomSetNRLevel,
IcomSetANF, IcomSetAGC, IcomSetPreamp, IcomSetAtt, IcomSetFilter, IcomSetANF, IcomSetAPF, IcomSetAGC, IcomSetPreamp, IcomSetAtt, IcomSetFilter,
IcomSetRFPower, IcomSetMicGain, IcomSetSplit, IcomTune, IcomSetPTT, IcomSetRFPower, IcomSetMicGain, IcomSetSplit, IcomTune, IcomSetPTT,
IcomSetScope, IcomScopeData, IcomSetScopeMode, IcomSetScopeEdges, GetCATState, SetCATFrequency, SetCATMode, IcomSetScope, IcomScopeData, IcomSetScopeMode, IcomSetScopeEdges, GetCATState, SetCATFrequency, SetCATMode,
IcomSetRIT, IcomSetRITOn, IcomSetXITOn, IcomSetRIT, IcomSetRITOn, IcomSetXITOn,
@@ -21,7 +21,7 @@ type IcomState = {
s_meter: number; power_meter: number; swr_meter: number; s_meter: number; power_meter: number; swr_meter: number;
rf_power: number; mic_gain: number; rf_power: number; mic_gain: number;
af_gain: number; rf_gain: number; af_gain: number; rf_gain: number;
nb: boolean; nb_level: number; nr: boolean; nr_level: number; anf: boolean; nb: boolean; nb_level: number; nr: boolean; nr_level: number; anf: boolean; apf: boolean;
agc?: string; preamp: number; att: number; filter: number; agc?: string; preamp: number; att: number; filter: number;
rit_hz: number; rit_on: boolean; xit_on: boolean; rit_hz: number; rit_on: boolean; xit_on: boolean;
antenna: number; antenna: number;
@@ -35,7 +35,7 @@ const ZERO: IcomState = {
available: false, transmitting: false, split: false, available: false, transmitting: false, split: false,
s_meter: 0, power_meter: 0, swr_meter: 0, rf_power: 0, mic_gain: 0, s_meter: 0, power_meter: 0, swr_meter: 0, rf_power: 0, mic_gain: 0,
af_gain: 0, rf_gain: 0, af_gain: 0, rf_gain: 0,
nb: false, nb_level: 0, nr: false, nr_level: 0, anf: false, nb: false, nb_level: 0, nr: false, nr_level: 0, anf: false, apf: false,
preamp: 0, att: 0, filter: 1, preamp: 0, att: 0, filter: 1,
rit_hz: 0, rit_on: false, xit_on: false, rit_hz: 0, rit_on: false, xit_on: false,
antenna: 1, antenna: 1,
@@ -615,6 +615,11 @@ export function IcomPanel({ onReportRST }: { onReportRST?: (rst: string) => void
const mainHz: number = split ? (cat?.freq_rx_hz || 0) : (cat?.freq_hz || 0); const mainHz: number = split ? (cat?.freq_rx_hz || 0) : (cat?.freq_hz || 0);
const subHz: number = split ? (cat?.freq_hz || 0) : 0; const subHz: number = split ? (cat?.freq_hz || 0) : 0;
const curMode: string = cat?.mode || st.mode || ''; const curMode: string = cat?.mode || st.mode || '';
// Mode-dependent controls: VOX / speech-comp / mic are voice-only (hidden on
// CW and data); APF (audio peak filter) is CW-only. Fold USB/LSB into phone.
const um = curMode.toUpperCase();
const isCW = um === 'CW' || um === 'CWR';
const isPhone = um === 'SSB' || um === 'USB' || um === 'LSB' || um === 'AM' || um === 'FM';
return ( return (
<div className="h-full min-h-0 overflow-auto bg-background"> <div className="h-full min-h-0 overflow-auto bg-background">
@@ -735,10 +740,12 @@ export function IcomPanel({ onReportRST }: { onReportRST?: (rst: string) => void
<Slider value={st.rf_power} accent="#ef4444" onChange={(v) => set({ rf_power: v }, () => IcomSetRFPower(v))} /> <Slider value={st.rf_power} accent="#ef4444" onChange={(v) => set({ rf_power: v }, () => IcomSetRFPower(v))} />
<span className="w-8 text-right text-xs font-mono tabular-nums text-muted-foreground">{st.rf_power}</span> <span className="w-8 text-right text-xs font-mono tabular-nums text-muted-foreground">{st.rf_power}</span>
</Row> </Row>
<Row label={t('icmp.mic')}> {isPhone && (
<Slider value={st.mic_gain} accent="#ef4444" onChange={(v) => set({ mic_gain: v }, () => IcomSetMicGain(v))} /> <Row label={t('icmp.mic')}>
<span className="w-8 text-right text-xs font-mono tabular-nums text-muted-foreground">{st.mic_gain}</span> <Slider value={st.mic_gain} accent="#ef4444" onChange={(v) => set({ mic_gain: v }, () => IcomSetMicGain(v))} />
</Row> <span className="w-8 text-right text-xs font-mono tabular-nums text-muted-foreground">{st.mic_gain}</span>
</Row>
)}
<div className="flex items-center gap-2 pt-1"> <div className="flex items-center gap-2 pt-1">
<button type="button" onClick={toggleMox} <button type="button" onClick={toggleMox}
className={cn('flex-1 px-3 py-1.5 rounded-md text-xs font-bold border transition-colors', className={cn('flex-1 px-3 py-1.5 rounded-md text-xs font-bold border transition-colors',
@@ -752,21 +759,26 @@ export function IcomPanel({ onReportRST }: { onReportRST?: (rst: string) => void
TUNE TUNE
</button> </button>
</div> </div>
{/* Speech processor / monitor / VOX. */} {/* Monitor (all modes) + speech processor / VOX (voice modes only —
they don't exist on CW or data). */}
<div className="pt-2 mt-1 border-t border-border/60 space-y-3"> <div className="pt-2 mt-1 border-t border-border/60 space-y-3">
<LevelRow label="COMP" on={st.comp} value={st.comp_level}
onToggle={() => set({ comp: !st.comp }, () => IcomSetComp(!st.comp))}
onLevel={(v) => set({ comp_level: v }, () => IcomSetCompLevel(v))} />
<LevelRow label="MON" on={st.monitor} value={st.mon_level} <LevelRow label="MON" on={st.monitor} value={st.mon_level}
onToggle={() => set({ monitor: !st.monitor }, () => IcomSetMonitor(!st.monitor))} onToggle={() => set({ monitor: !st.monitor }, () => IcomSetMonitor(!st.monitor))}
onLevel={(v) => set({ mon_level: v }, () => IcomSetMonLevel(v))} /> onLevel={(v) => set({ mon_level: v }, () => IcomSetMonLevel(v))} />
<LevelRow label="VOX" on={st.vox} value={st.vox_gain} {isPhone && (
onToggle={() => set({ vox: !st.vox }, () => IcomSetVOX(!st.vox))} <>
onLevel={(v) => set({ vox_gain: v }, () => IcomSetVOXGain(v))} /> <LevelRow label="COMP" on={st.comp} value={st.comp_level}
<Row label="Anti-VOX"> onToggle={() => set({ comp: !st.comp }, () => IcomSetComp(!st.comp))}
<Slider value={st.anti_vox} disabled={!st.vox} onChange={(v) => set({ anti_vox: v }, () => IcomSetAntiVOX(v))} /> onLevel={(v) => set({ comp_level: v }, () => IcomSetCompLevel(v))} />
<span className="w-8 text-right text-xs font-mono tabular-nums text-muted-foreground">{st.anti_vox}</span> <LevelRow label="VOX" on={st.vox} value={st.vox_gain}
</Row> onToggle={() => set({ vox: !st.vox }, () => IcomSetVOX(!st.vox))}
onLevel={(v) => set({ vox_gain: v }, () => IcomSetVOXGain(v))} />
<Row label="Anti-VOX">
<Slider value={st.anti_vox} disabled={!st.vox} onChange={(v) => set({ anti_vox: v }, () => IcomSetAntiVOX(v))} />
<span className="w-8 text-right text-xs font-mono tabular-nums text-muted-foreground">{st.anti_vox}</span>
</Row>
</>
)}
</div> </div>
</Card> </Card>
@@ -837,6 +849,13 @@ export function IcomPanel({ onReportRST }: { onReportRST?: (rst: string) => void
<Chip label="ANF" on={st.anf} onClick={() => set({ anf: !st.anf }, () => IcomSetANF(!st.anf))} /> <Chip label="ANF" on={st.anf} onClick={() => set({ anf: !st.anf }, () => IcomSetANF(!st.anf))} />
<span className="text-xs text-muted-foreground">{t('icmp.autoNotch')}</span> <span className="text-xs text-muted-foreground">{t('icmp.autoNotch')}</span>
</div> </div>
{/* APF (audio peak filter) — CW only: peaks the CW tone. */}
{isCW && (
<div className="flex items-center gap-2">
<Chip label="APF" on={st.apf} onClick={() => set({ apf: !st.apf }, () => IcomSetAPF(!st.apf))} />
<span className="text-xs text-muted-foreground">{t('icmp.apf')}</span>
</div>
)}
</Card> </Card>
</div> </div>
</div> </div>
+2 -2
View File
@@ -193,7 +193,7 @@ const en: Dict = {
'agp.portDeselect': 'Port {letter} — click to deselect', 'agp.portSelect': 'Select on port {letter}', 'agp.online': 'online', 'agp.offline': 'offline', 'agp.close': 'Close', 'agp.connecting': 'Connecting…', 'agp.noAntennas': 'No antennas configured.', 'agp.portDeselect': 'Port {letter} — click to deselect', 'agp.portSelect': 'Select on port {letter}', 'agp.online': 'online', 'agp.offline': 'offline', 'agp.close': 'Close', 'agp.connecting': 'Connecting…', 'agp.noAntennas': 'No antennas configured.',
'flxp.smartsdrRemote': 'SmartSDR remote control', 'flxp.offline': 'OFFLINE', 'flxp.waiting': 'Waiting for the FlexRadio… (set CAT to FlexRadio and connect)', 'flxp.transmit': 'Transmit', 'flxp.rfPower': 'RF Power', 'flxp.tunePwr': 'Tune Pwr', 'flxp.splitHint': 'Split: RX/TX on separate slices. ON creates a TX slice +1 kHz (CW) / +5 kHz (SSB) up, like SmartSDR.', 'flxp.voxDly': 'VOX Dly', 'flxp.speed': 'Speed', 'flxp.pitch': 'Pitch', 'flxp.delay': 'Delay', 'flxp.smartsdrRemote': 'SmartSDR remote control', 'flxp.offline': 'OFFLINE', 'flxp.waiting': 'Waiting for the FlexRadio… (set CAT to FlexRadio and connect)', 'flxp.transmit': 'Transmit', 'flxp.rfPower': 'RF Power', 'flxp.tunePwr': 'Tune Pwr', 'flxp.splitHint': 'Split: RX/TX on separate slices. ON creates a TX slice +1 kHz (CW) / +5 kHz (SSB) up, like SmartSDR.', 'flxp.voxDly': 'VOX Dly', 'flxp.speed': 'Speed', 'flxp.pitch': 'Pitch', 'flxp.delay': 'Delay',
'flxp.receiveActive': 'Receive (active slice)', 'flxp.muted': 'Muted — click to unmute', 'flxp.mute': 'Mute RX audio', 'flxp.filter': 'Filter', 'flxp.amplifier': 'Amplifier', 'flxp.ampInLine': 'Amplifier is in line (transmitting through PA).', 'flxp.ampBypassed': 'Amplifier bypassed (standby).', 'flxp.pgConnected': 'PowerGenius connected', 'flxp.pgOffline': 'PowerGenius offline', 'flxp.fan': 'Fan', 'flxp.fanStandard': 'Standard', 'flxp.fanContest': 'Contest', 'flxp.fanBroadcast': 'Broadcast', 'flxp.fault': 'FAULT', 'flxp.meters': 'Meters', 'flxp.noMeters': "No meters yet — waiting for the radio's UDP stream…", 'flxp.amplifierHdr': 'AMPLIFIER', 'flxp.receiveActive': 'Receive (active slice)', 'flxp.muted': 'Muted — click to unmute', 'flxp.mute': 'Mute RX audio', 'flxp.filter': 'Filter', 'flxp.amplifier': 'Amplifier', 'flxp.ampInLine': 'Amplifier is in line (transmitting through PA).', 'flxp.ampBypassed': 'Amplifier bypassed (standby).', 'flxp.pgConnected': 'PowerGenius connected', 'flxp.pgOffline': 'PowerGenius offline', 'flxp.fan': 'Fan', 'flxp.fanStandard': 'Standard', 'flxp.fanContest': 'Contest', 'flxp.fanBroadcast': 'Broadcast', 'flxp.fault': 'FAULT', 'flxp.meters': 'Meters', 'flxp.noMeters': "No meters yet — waiting for the radio's UDP stream…", 'flxp.amplifierHdr': 'AMPLIFIER',
'icmp.spectrum': 'Spectrum', 'icmp.scopeFixed': 'Fixed — double-click / wheel to tune', 'icmp.scopeCenter': 'Center — follows VFO', 'icmp.scopeOff': 'Scope off', 'icmp.scopePanDown': 'Shift scope 50 kHz', 'icmp.scopePanUp': 'Shift scope +50 kHz', 'icmp.scopeCenterVfo': 'Center scope on the current frequency (±50 kHz)', 'icmp.notConnected': "Icom not connected. Enable the Icom CI-V backend in Settings → CAT and connect the radio's USB port.", 'icmp.refresh': 'Refresh', 'icmp.meters': 'Meters', 'icmp.transmit': 'Transmit', 'icmp.power': 'Power', 'icmp.mic': 'Mic', 'icmp.receive': 'Receive', 'icmp.preamp': 'Preamp', 'icmp.filter': 'Filter', 'icmp.noiseNotch': 'Noise / Notch', 'icmp.autoNotch': 'Auto notch filter', 'icmp.clarifiers': 'RIT / ΔTX', 'icmp.ritHint': 'Wheel or ± to shift · Ctrl+←/→ shifts RIT when active', 'icmp.bandsAntenna': 'Bands & Antenna', 'icmp.antenna': 'Antenna', 'icmp.passband': 'Passband / Notch', 'icmp.pbtCenter': 'Center PBT', 'icmp.manualNotch': 'Manual notch — MN on, then set position', 'icmp.squelch': 'Squelch', 'icmp.powerOnHint': 'Power the radio ON (boots ~15 s)', 'icmp.powerOffHint': 'Power the radio OFF', 'icmp.powerOffConfirm': 'Switch the radio OFF?', 'icmp.spectrum': 'Spectrum', 'icmp.scopeFixed': 'Fixed — double-click / wheel to tune', 'icmp.scopeCenter': 'Center — follows VFO', 'icmp.scopeOff': 'Scope off', 'icmp.scopePanDown': 'Shift scope 50 kHz', 'icmp.scopePanUp': 'Shift scope +50 kHz', 'icmp.scopeCenterVfo': 'Center scope on the current frequency (±50 kHz)', 'icmp.notConnected': "Icom not connected. Enable the Icom CI-V backend in Settings → CAT and connect the radio's USB port.", 'icmp.refresh': 'Refresh', 'icmp.meters': 'Meters', 'icmp.transmit': 'Transmit', 'icmp.power': 'Power', 'icmp.mic': 'Mic', 'icmp.receive': 'Receive', 'icmp.preamp': 'Preamp', 'icmp.filter': 'Filter', 'icmp.noiseNotch': 'Noise / Notch', 'icmp.autoNotch': 'Auto notch filter', 'icmp.apf': 'Audio peak filter (CW)', 'icmp.clarifiers': 'RIT / ΔTX', 'icmp.ritHint': 'Wheel or ± to shift · Ctrl+←/→ shifts RIT when active', 'icmp.bandsAntenna': 'Bands & Antenna', 'icmp.antenna': 'Antenna', 'icmp.passband': 'Passband / Notch', 'icmp.pbtCenter': 'Center PBT', 'icmp.manualNotch': 'Manual notch — MN on, then set position', 'icmp.squelch': 'Squelch', 'icmp.powerOnHint': 'Power the radio ON (boots ~15 s)', 'icmp.powerOffHint': 'Power the radio OFF', 'icmp.powerOffConfirm': 'Switch the radio OFF?',
'rst.clickToFill': 'Click to set RST tx from the signal', 'rst.clickToFill': 'Click to set RST tx from the signal',
'qrz.openTitle': 'Open {call} on QRZ.com', 'qrz.openTitle': 'Open {call} on QRZ.com',
// Misc panels/modals (alerts / send-spot / net / udp / filter / details) // Misc panels/modals (alerts / send-spot / net / udp / filter / details)
@@ -379,7 +379,7 @@ const fr: Dict = {
'agp.portDeselect': 'Port {letter} — clic pour désélectionner', 'agp.portSelect': 'Sélectionner sur le port {letter}', 'agp.online': 'en ligne', 'agp.offline': 'hors ligne', 'agp.close': 'Fermer', 'agp.connecting': 'Connexion…', 'agp.noAntennas': 'Aucune antenne configurée.', 'agp.portDeselect': 'Port {letter} — clic pour désélectionner', 'agp.portSelect': 'Sélectionner sur le port {letter}', 'agp.online': 'en ligne', 'agp.offline': 'hors ligne', 'agp.close': 'Fermer', 'agp.connecting': 'Connexion…', 'agp.noAntennas': 'Aucune antenne configurée.',
'flxp.smartsdrRemote': 'Contrôle à distance SmartSDR', 'flxp.offline': 'HORS LIGNE', 'flxp.waiting': 'En attente du FlexRadio… (règle le CAT sur FlexRadio et connecte)', 'flxp.transmit': 'Émission', 'flxp.rfPower': 'Puissance RF', 'flxp.tunePwr': 'Puiss. TUNE', 'flxp.splitHint': 'Split : RX/TX sur des slices séparées. ON crée une slice TX +1 kHz (CW) / +5 kHz (SSB) au-dessus, comme SmartSDR.', 'flxp.voxDly': 'Délai VOX', 'flxp.speed': 'Vitesse', 'flxp.pitch': 'Tonalité', 'flxp.delay': 'Délai', 'flxp.smartsdrRemote': 'Contrôle à distance SmartSDR', 'flxp.offline': 'HORS LIGNE', 'flxp.waiting': 'En attente du FlexRadio… (règle le CAT sur FlexRadio et connecte)', 'flxp.transmit': 'Émission', 'flxp.rfPower': 'Puissance RF', 'flxp.tunePwr': 'Puiss. TUNE', 'flxp.splitHint': 'Split : RX/TX sur des slices séparées. ON crée une slice TX +1 kHz (CW) / +5 kHz (SSB) au-dessus, comme SmartSDR.', 'flxp.voxDly': 'Délai VOX', 'flxp.speed': 'Vitesse', 'flxp.pitch': 'Tonalité', 'flxp.delay': 'Délai',
'flxp.receiveActive': 'Réception (slice active)', 'flxp.muted': 'Coupé — clic pour rétablir', 'flxp.mute': "Couper l'audio RX", 'flxp.filter': 'Filtre', 'flxp.amplifier': 'Amplificateur', 'flxp.ampInLine': 'Amplificateur en ligne (émission via le PA).', 'flxp.ampBypassed': 'Amplificateur en bypass (standby).', 'flxp.pgConnected': 'PowerGenius connecté', 'flxp.pgOffline': 'PowerGenius hors ligne', 'flxp.fan': 'Ventilo', 'flxp.fanStandard': 'Standard', 'flxp.fanContest': 'Contest', 'flxp.fanBroadcast': 'Diffusion', 'flxp.fault': 'DÉFAUT', 'flxp.meters': 'Mesures', 'flxp.noMeters': 'Aucune mesure — en attente du flux UDP de la radio…', 'flxp.amplifierHdr': 'AMPLIFICATEUR', 'flxp.receiveActive': 'Réception (slice active)', 'flxp.muted': 'Coupé — clic pour rétablir', 'flxp.mute': "Couper l'audio RX", 'flxp.filter': 'Filtre', 'flxp.amplifier': 'Amplificateur', 'flxp.ampInLine': 'Amplificateur en ligne (émission via le PA).', 'flxp.ampBypassed': 'Amplificateur en bypass (standby).', 'flxp.pgConnected': 'PowerGenius connecté', 'flxp.pgOffline': 'PowerGenius hors ligne', 'flxp.fan': 'Ventilo', 'flxp.fanStandard': 'Standard', 'flxp.fanContest': 'Contest', 'flxp.fanBroadcast': 'Diffusion', 'flxp.fault': 'DÉFAUT', 'flxp.meters': 'Mesures', 'flxp.noMeters': 'Aucune mesure — en attente du flux UDP de la radio…', 'flxp.amplifierHdr': 'AMPLIFICATEUR',
'icmp.spectrum': 'Spectre', 'icmp.scopeFixed': 'Fixe — double-clic / molette pour accorder', 'icmp.scopeCenter': 'Centré — suit le VFO', 'icmp.scopeOff': 'Scope éteint', 'icmp.scopePanDown': 'Décaler le scope 50 kHz', 'icmp.scopePanUp': 'Décaler le scope +50 kHz', 'icmp.scopeCenterVfo': 'Centrer le scope sur la fréquence actuelle (±50 kHz)', 'icmp.notConnected': 'Icom non connecté. Active le backend CI-V Icom dans Réglages → CAT et connecte le port USB de la radio.', 'icmp.refresh': 'Rafraîchir', 'icmp.meters': 'Mesures', 'icmp.transmit': 'Émission', 'icmp.power': 'Puissance', 'icmp.mic': 'Micro', 'icmp.receive': 'Réception', 'icmp.preamp': 'Préampli', 'icmp.filter': 'Filtre', 'icmp.noiseNotch': 'Bruit / Notch', 'icmp.autoNotch': 'Filtre notch auto', 'icmp.clarifiers': 'RIT / ΔTX', 'icmp.ritHint': 'Molette ou ± pour décaler · Ctrl+←/→ décale le RIT si actif', 'icmp.bandsAntenna': 'Bandes & Antenne', 'icmp.antenna': 'Antenne', 'icmp.passband': 'Passe-bande / Notch', 'icmp.pbtCenter': 'Centrer PBT', 'icmp.manualNotch': 'Notch manuel — active MN, puis règle la position', 'icmp.squelch': 'Squelch', 'icmp.powerOnHint': 'Allumer la radio (démarre en ~15 s)', 'icmp.powerOffHint': 'Éteindre la radio', 'icmp.powerOffConfirm': 'Éteindre la radio ?', 'icmp.spectrum': 'Spectre', 'icmp.scopeFixed': 'Fixe — double-clic / molette pour accorder', 'icmp.scopeCenter': 'Centré — suit le VFO', 'icmp.scopeOff': 'Scope éteint', 'icmp.scopePanDown': 'Décaler le scope 50 kHz', 'icmp.scopePanUp': 'Décaler le scope +50 kHz', 'icmp.scopeCenterVfo': 'Centrer le scope sur la fréquence actuelle (±50 kHz)', 'icmp.notConnected': 'Icom non connecté. Active le backend CI-V Icom dans Réglages → CAT et connecte le port USB de la radio.', 'icmp.refresh': 'Rafraîchir', 'icmp.meters': 'Mesures', 'icmp.transmit': 'Émission', 'icmp.power': 'Puissance', 'icmp.mic': 'Micro', 'icmp.receive': 'Réception', 'icmp.preamp': 'Préampli', 'icmp.filter': 'Filtre', 'icmp.noiseNotch': 'Bruit / Notch', 'icmp.autoNotch': 'Filtre notch auto', 'icmp.apf': 'Filtre de pic audio (CW)', 'icmp.clarifiers': 'RIT / ΔTX', 'icmp.ritHint': 'Molette ou ± pour décaler · Ctrl+←/→ décale le RIT si actif', 'icmp.bandsAntenna': 'Bandes & Antenne', 'icmp.antenna': 'Antenne', 'icmp.passband': 'Passe-bande / Notch', 'icmp.pbtCenter': 'Centrer PBT', 'icmp.manualNotch': 'Notch manuel — active MN, puis règle la position', 'icmp.squelch': 'Squelch', 'icmp.powerOnHint': 'Allumer la radio (démarre en ~15 s)', 'icmp.powerOffHint': 'Éteindre la radio', 'icmp.powerOffConfirm': 'Éteindre la radio ?',
'rst.clickToFill': 'Clic pour remplir le RST tx depuis le signal', 'rst.clickToFill': 'Clic pour remplir le RST tx depuis le signal',
'qrz.openTitle': 'Ouvrir {call} sur QRZ.com', 'qrz.openTitle': 'Ouvrir {call} sur QRZ.com',
'altm.filterPh': 'Filtrer…', 'altm.noMatch': 'aucun résultat', 'altm.noneAll': 'aucune sélection = TOUT', 'altm.nSelected': '{n} sélectionné(s)', 'altm.giveName': 'Donne un nom à la règle', 'altm.deleteConfirm': "Supprimer l'alerte « {name} » ?", 'altm.title': 'Gestion des alertes', 'altm.desc': 'Alerte quand un spot correspond à une règle. Filtres vides = TOUT ; les filtres définis sont combinés par ET (ex. France + 20m = stations françaises sur 20m).', 'altm.rules': 'Règles', 'altm.noRules': 'Aucune règle — clique sur +', 'altm.emailTo': "E-mail d'alerte à", 'altm.selectOrCreate': 'Sélectionne ou crée une règle.', 'altm.tabDef': 'Définition', 'altm.tabCall': 'Indicatif / DXCC', 'altm.tabBandMode': 'Bande / Mode', 'altm.tabOrigin': 'Origine', 'altm.ruleName': 'Nom de la règle', 'altm.alertEnabled': 'Alerte activée', 'altm.againAfter': 'Réalerter après (min)', 'altm.againHint': '0 = une fois/session · -1 = toujours', 'altm.actions': 'Actions', 'altm.visual': 'Visuel', 'altm.sound': 'Son', 'altm.email': 'E-mail', 'altm.skipWorked': 'Ignorer les indicatifs déjà contactés (même bande + mode)', 'altm.callsigns': 'Indicatifs (un par ligne, jokers : IW3*, */P)', 'altm.countries': 'Pays (DXCC)', 'altm.continents': 'Continents', 'altm.bands': 'Bandes', 'altm.modes': 'Modes', 'altm.spotterCall': 'Indicatif du spotteur (joker)', 'altm.spotterCallPh': 'ex. F* ou DL1ABC', 'altm.spotterContinents': 'Continents du spotteur', 'altm.spotterCountries': 'Pays du spotteur', 'altm.delete': 'Supprimer', 'altm.saveRule': 'Enregistrer la règle', 'altm.close': 'Fermer', 'altm.filterPh': 'Filtrer…', 'altm.noMatch': 'aucun résultat', 'altm.noneAll': 'aucune sélection = TOUT', 'altm.nSelected': '{n} sélectionné(s)', 'altm.giveName': 'Donne un nom à la règle', 'altm.deleteConfirm': "Supprimer l'alerte « {name} » ?", 'altm.title': 'Gestion des alertes', 'altm.desc': 'Alerte quand un spot correspond à une règle. Filtres vides = TOUT ; les filtres définis sont combinés par ET (ex. France + 20m = stations françaises sur 20m).', 'altm.rules': 'Règles', 'altm.noRules': 'Aucune règle — clique sur +', 'altm.emailTo': "E-mail d'alerte à", 'altm.selectOrCreate': 'Sélectionne ou crée une règle.', 'altm.tabDef': 'Définition', 'altm.tabCall': 'Indicatif / DXCC', 'altm.tabBandMode': 'Bande / Mode', 'altm.tabOrigin': 'Origine', 'altm.ruleName': 'Nom de la règle', 'altm.alertEnabled': 'Alerte activée', 'altm.againAfter': 'Réalerter après (min)', 'altm.againHint': '0 = une fois/session · -1 = toujours', 'altm.actions': 'Actions', 'altm.visual': 'Visuel', 'altm.sound': 'Son', 'altm.email': 'E-mail', 'altm.skipWorked': 'Ignorer les indicatifs déjà contactés (même bande + mode)', 'altm.callsigns': 'Indicatifs (un par ligne, jokers : IW3*, */P)', 'altm.countries': 'Pays (DXCC)', 'altm.continents': 'Continents', 'altm.bands': 'Bandes', 'altm.modes': 'Modes', 'altm.spotterCall': 'Indicatif du spotteur (joker)', 'altm.spotterCallPh': 'ex. F* ou DL1ABC', 'altm.spotterContinents': 'Continents du spotteur', 'altm.spotterCountries': 'Pays du spotteur', 'altm.delete': 'Supprimer', 'altm.saveRule': 'Enregistrer la règle', 'altm.close': 'Fermer',
+2
View File
@@ -350,6 +350,8 @@ export function IcomSetAGC(arg1:string):Promise<void>;
export function IcomSetANF(arg1:boolean):Promise<void>; export function IcomSetANF(arg1:boolean):Promise<void>;
export function IcomSetAPF(arg1:boolean):Promise<void>;
export function IcomSetAntenna(arg1:number):Promise<void>; export function IcomSetAntenna(arg1:number):Promise<void>;
export function IcomSetAntiVOX(arg1:number):Promise<void>; export function IcomSetAntiVOX(arg1:number):Promise<void>;
+4
View File
@@ -662,6 +662,10 @@ export function IcomSetANF(arg1) {
return window['go']['main']['App']['IcomSetANF'](arg1); return window['go']['main']['App']['IcomSetANF'](arg1);
} }
export function IcomSetAPF(arg1) {
return window['go']['main']['App']['IcomSetAPF'](arg1);
}
export function IcomSetAntenna(arg1) { export function IcomSetAntenna(arg1) {
return window['go']['main']['App']['IcomSetAntenna'](arg1); return window['go']['main']['App']['IcomSetAntenna'](arg1);
} }
+2
View File
@@ -690,6 +690,7 @@ export namespace cat {
nr: boolean; nr: boolean;
nr_level: number; nr_level: number;
anf: boolean; anf: boolean;
apf: boolean;
agc?: string; agc?: string;
preamp: number; preamp: number;
att: number; att: number;
@@ -736,6 +737,7 @@ export namespace cat {
this.nr = source["nr"]; this.nr = source["nr"];
this.nr_level = source["nr_level"]; this.nr_level = source["nr_level"];
this.anf = source["anf"]; this.anf = source["anf"];
this.apf = source["apf"];
this.agc = source["agc"]; this.agc = source["agc"];
this.preamp = source["preamp"]; this.preamp = source["preamp"];
this.att = source["att"]; this.att = source["att"];
+2
View File
@@ -415,6 +415,7 @@ type IcomTXState struct {
NR bool `json:"nr"` NR bool `json:"nr"`
NRLevel int `json:"nr_level"` NRLevel int `json:"nr_level"`
ANF bool `json:"anf"` ANF bool `json:"anf"`
APF bool `json:"apf"` // audio peak filter (CW only)
AGC string `json:"agc,omitempty"` // FAST | MID | SLOW AGC string `json:"agc,omitempty"` // FAST | MID | SLOW
Preamp int `json:"preamp"` // 0=off, 1=P.AMP1, 2=P.AMP2 Preamp int `json:"preamp"` // 0=off, 1=P.AMP1, 2=P.AMP2
Att int `json:"att"` // dB attenuation, 0=off Att int `json:"att"` // dB attenuation, 0=off
@@ -450,6 +451,7 @@ type IcomController interface {
SetNR(bool) error SetNR(bool) error
SetNRLevel(int) error SetNRLevel(int) error
SetANF(bool) error SetANF(bool) error
SetAPF(bool) error
SetAGC(string) error SetAGC(string) error
SetPreamp(int) error SetPreamp(int) error
SetAtt(int) error SetAtt(int) error
+1
View File
@@ -110,6 +110,7 @@ const (
SubSwVOX = 0x46 // VOX on/off SubSwVOX = 0x46 // VOX on/off
SubSwBreakIn = 0x47 // CW break-in: 0=OFF, 1=SEMI, 2=FULL (needed so 0x17 CW keys TX) SubSwBreakIn = 0x47 // CW break-in: 0=OFF, 1=SEMI, 2=FULL (needed so 0x17 CW keys TX)
SubSwMN = 0x48 // manual notch on/off SubSwMN = 0x48 // manual notch on/off
SubSwAPF = 0x32 // audio peak filter on/off (CW only)
) )
// CW break-in modes (CmdSwitch 0x47). // CW break-in modes (CmdSwitch 0x47).
+11
View File
@@ -1166,6 +1166,9 @@ func (b *IcomSerial) readDSP() {
if v, ok := b.readSwitch(civ.SubSwANF); ok { if v, ok := b.readSwitch(civ.SubSwANF); ok {
st.ANF = v != 0 st.ANF = v != 0
} }
if v, ok := b.readSwitch(civ.SubSwAPF); ok {
st.APF = v != 0
}
if v, ok := b.readSwitch(civ.SubSwAGC); ok { if v, ok := b.readSwitch(civ.SubSwAGC); ok {
st.AGC = agcName(v) st.AGC = agcName(v)
} }
@@ -1357,6 +1360,14 @@ func (b *IcomSerial) SetANF(on bool) error {
return nil return nil
} }
func (b *IcomSerial) SetAPF(on bool) error {
if err := b.exec(civ.CmdSwitch, civ.SubSwAPF, boolByte(on)); err != nil {
return err
}
b.setCache(func(s *IcomTXState) { s.APF = on })
return nil
}
func (b *IcomSerial) SetAGC(name string) error { func (b *IcomSerial) SetAGC(name string) error {
v := agcValue(name) v := agcValue(name)
if v == 0 { if v == 0 {