Commit Graph
39 Commits
Author SHA1 Message Date
rouggy 0cd243fe00 chore: release v0.26.2 2026-08-21 18:21:33 +02:00
rouggy 0bab7f05b9 feat(relays): accept a self-signed certificate on a generic HTTP board
HTTPS to a relay board could not work. Nearly every board that offers it signs
its own certificate — there is no authority anywhere that could have signed it —
so the request failed verification before it left.

A checkbox, per board, off by default. Not a blanket switch, because the other
HTTPS case is real and opposite: a board reached from outside through a proxy
with a genuine certificate, where verification is the only thing standing
between an antenna switch and the internet. Same setting, two boards, different
answers.

Off by default is only safe if the failure explains itself, so a certificate
error now names the box to tick. Go's own "x509: certificate signed by unknown
authority" is accurate and tells an operator nothing about what to do next.

Shown only once an https:// URL is actually in the board's configuration. A
board on plain HTTP has no certificate to argue about, and an option that cannot
matter yet is one more thing to wonder about.

The flag joins the driver cache key: ticking it has to rebuild the driver, or
the cached one would go on refusing the certificate with the verifying client it
already holds.

The boards that take a bare host — WebSwitch, KMTronic — keep verification. An
https:// typed there is the proxy case by construction, since they default to
plain HTTP on the LAN.

Three tests against a real self-signed TLS server: accepted with the box,
refused with a message naming it without the box, and one board's setting not
leaking into another's.
2026-08-17 10:57:29 +02:00
rouggy 191e92ad62 perf(rotator): one adaptive heading poll for every controller type
Asked whether the faster poll applies to all the rotator backends. It does —
GetRotatorHeading is one binding over PstRotator, Rotator Genius, GS-232/ARCO,
DCU-1 and SPID alike, and it reads only the ACTIVE rotor, so two towers do not
double it. But counting what that costs turned up two things worth fixing.

Every backend builds a fresh client per call — spid.New, gs232.NewSerial,
dcu1.NewSerial, rotgenius.New — so one poll is one OPEN and CLOSE of a serial
port or a TCP connection, not a read on a link already up. And the status bar
and the Station Control compass each ran their own interval against that same
binding, so with the tab open the controller was asked twice over. At the 700 ms
I had just set, that was nearly three port opens a second on a 600-baud line.

Both now share one loop, and it adapts: 500 ms while the position is changing,
3 s once it has been still for six seconds. These controllers do not report
"moving" — a SPID answers a position and nothing else — so it is inferred from
the position itself, and held briefly after the last change so the tail of a
movement stays smooth. Commanding a move, a stop, or switching rotor polls at
once, so the needle starts sweeping on the click.

A slow controller cannot stack requests behind itself either: at 600 baud a SPID
reply takes a fifth of a second on the wire alone, and a port still open from
the last poll cannot be opened again.
2026-08-16 13:39:23 +02:00
rouggy f405e71d7d fix(spid): a Rot1Prog takes three digits, so every target went the wrong way
Field report from a tower: on a RAK/RAU in Rot1Prog, every commanded heading
made the antenna want to turn nearly a full circle ANTICLOCKWISE — 0°, 90°, any
of them — while the heading readout, the stop button and everything else worked.

BuildSet framed the four-digit Rot2Prog azimuth for both dialects. A Rot1Prog
reads three: its replies are three digits in a five-byte frame, and its command
field matches. So 90° went out as "0450" and was read as 045 — 45 − 360 = −315°.
Every target landed 360° low, which is why it was always anticlockwise and
always nearly a full turn. The operator's own guess, that OpsLog was in 720°
mode, was the right instinct in the wrong place: the fault is a decimal shift,
not a range.

The round-trip test added here is the one that would have caught it without a
tower — every degree of the circle through the command builder and back through
the reply parser, which must return the degree that went in. The frame tests
pinned the Rot2Prog form against the reference and said nothing about the other
dialect.

Two more from the same report. A rotator test that only READS the heading — SPID,
ARCO, DCU-1 — said "Packet sent, the antenna should swing to north, check
PstRotator's UDP listener", naming a program not in the path for a move never
commanded; it now says the controller answered and nothing was moved. And the
compass polled every three seconds, so a turning antenna moved the needle in
steps of about thirteen degrees; the heading now has its own 700 ms tick while
the relay boards and the antenna controller stay at three seconds.
2026-08-16 13:31:00 +02:00
rouggy 8683a450a7 feat(psu): switch a Modbus RTU bench supply from OpsLog
The manufacturer's document arrived, so this is no longer guesswork: 9600 8N1,
function codes 03 and 06 only, and a register map with the output on/off at
0x0001, the measurements at 0x0010…0x0013 and the set points at 0x0030/0x0031.

ONE REGISTER IS WRITTEN — 0x0001, the output. The map also exposes the voltage
and current set points and the three protection trip levels as writable, and
none of them belong to a logbook: a wrong value there is 30 V where a radio
expected 13.8, or a trip level lifted on a supply feeding an amplifier. They are
read and displayed instead, next to the measured values, which is also how an
operator sees at a glance that the supply is on and the radio is drawing nothing.

The wire layer is tested where it can be. CRC-16/MODBUS is pinned against its
published check value — the CRC of "123456789" is 0x4B37 — which fixes the
polynomial, the initial value, the reflection and the absence of a final xor all
at once; the rest of the protocol is checked frame by frame against the manual,
including the byte order of the CRC, an exception reply told apart from a broken
line, and a reply from another slave on the bus refused. The write echo must
match the value sent: it is the only confirmation the output really switched,
and accepting the frame without it is how a radio ends up dark behind a green
light.

Framing follows the manual's own rules: 3.5 character times of silence between
frames (4 ms at 9600), and a frame is over when the line falls quiet — Modbus
RTU has no terminator, and a serial read that times out returns (0, nil) here,
so the reader is built on a deadline and a quiet-time rather than on an error
that never comes.

Untested against hardware — nobody here has the supply.
2026-08-16 13:15:55 +02:00
rouggy 480d24384b fix(relays): {value} is the relay's label, not a per-relay value
It was built the other way round on a misreading of two screenshots: the pattern
held {value} and the per-relay boxes held numbers to drop into it. The ask was
simpler and better — {value} is the name typed in Relay labels, so a switch
addressed by antenna name is one pattern instead of eight URLs:

  http://10.10.10.100/relay?on={value}   relay 1 named Ant1  →  ?on=Ant1

Renaming the antenna re-addresses it, and the name on the button and the name on
the wire cannot drift apart because they are the same string. It works in the
per-relay URLs and in the patterns alike, so the per-relay boxes go back to
holding URLs and nothing about them changes meaning any more.

The label is percent-encoded with %20 rather than "+" for a space: "+" is a
space only in a query string and a literal plus in a path, and this can land in
either half of a URL.

{value} on a relay with no label would send "?on=", an empty parameter that most
boards answer with a cheerful 200 and no movement. The driver refuses it and
names the label as what is missing; the editor warns while it is being typed,
beside the empty box rather than after an antenna fails to switch. The labels
also join the driver's cache key — they are part of the wire format now.
2026-08-16 00:09:18 +02:00
rouggy fe2affc72f fix(relays): the generic HTTP board never sent its URLs; cluster filters start off
buildDeviceDriver had no case for "httpgen", so the generic board fell through
to the WebSwitch driver: it polled an address it had never been given, reported
itself offline, greyed out every relay button, and sent none of the configured
URLs. Nothing in the interface said so — the board was configured, saved and
listed, and simply did nothing. deviceKey did not cover the URLs either, so once
that is fixed, correcting a typo in one would still have handed back the cached
driver holding the old address until a restart.

Two shapes of home-made switch could not be described at all:

  - a bit-mask board whose four URLs differ by one character
    (/Set0/1, /Set0/2, /Set0/4, /Set0/8) — {value} in the pattern now takes the
    number from the per-relay box, keeping the address in one place;
  - a board numbering its channels from zero — {relay-1}, since giving up the
    pattern for eight hand-typed URLs was the only alternative.

The pattern decides what the per-relay boxes hold, and the grid says which as
soon as {value} is typed: guessing per box ("does this look like a URL?") would
change meaning on a typo, which is not a thing to do to something wired to an
antenna. A URL typed without a scheme gets http:// like the named boards get
from relayBase; https:// is passed through untouched.

Host and the connection test are gone for this type. It has no address of its
own — its relays may each live on a different box — and no status to read, so a
test could only ever answer "OK, 4 relays". Save was greyed out without a host,
which made a complete configuration of four full URLs impossible to store.

Cluster filters no longer persist across launches. A band lock set weeks earlier
is invisible to whoever set it: the counter reads 76 spots live, the grid is
empty, and the search goes to the cluster instead. Nobody loses work by
re-ticking a chip. Grouping and the panel state still persist — they change how
spots look, never whether they appear.
2026-08-15 23:53:32 +02:00
rouggy 5c958572dc fix(relays): let the HTTP board's channel count be chosen
The selector offered 1, 2, 4, 8 and 16 and none of them took: the board stayed
at four relays.

The count is decided in three places — deviceRelayCount in Go, chanCount in the
Station Control panel, relayCountUI in Settings. The new type was added to the
first and the dropdown, and to neither of the others, so the panel resized the
labels from a helper that had never heard of it and fell straight through to
its fixed default. The Go side was right the whole time, which is why the
driver would have been built correctly for a count the operator could not set.

All three now know the type. A test pins the Go side against every count the
dropdown offers, and against the fixed boards, whose hardware decides and which
must keep ignoring the field.
2026-08-15 02:35:14 +02:00
rouggy 26b8dade20 feat(relays): generic HTTP relay board, and point band switching at it
An operator was about to build band→relay mapping into the custom URL rows.
It already exists, and better: relay auto-control has a per-relay "band" rule
driving webswitch, KMTronic, Dingtian, Denkovi and USB boards. It holds state
so a relay is only commanded when its wanted position changed, reads the
boards live before the first apply so it does not re-command one already in
place, and carries per-relay labels. A URL fired on a band change has none of
that, and would have been a second definition of "which antenna on which band"
— the drift that cost us a week on counties.

So the gap was only the hardware: a hand-made switch is none of the five named
types. It is now the sixth, "HTTP relay": an ON URL and an OFF URL, either as
one pattern with {relay} substituted, or one pair per relay. The per-relay
form is the reason it exists — these boxes often have URLs with nothing in
common between channels (…/FF0101 and …/FF0201), which no pattern can express.

Status is remembered rather than read: most have no endpoint worth trusting.
The cost is stated in the code and the panel — after a restart every relay is
re-commanded once, which is harmless on a board with no memory and far better
than assuming an antenna is already selected.

And the Connections panel now says so, exactly where the wrong choice is made:
picking a band change with a URL transport shows a note pointing at Station
Control. The URL transport stays — a lookup pushed to a webhook or a QSO to a
dashboard is an event, not a state, and Station Control has no place for it.
2026-08-15 02:23:03 +02:00
rouggy 784d809290 fix(rotator): put the SP/LP readout inside the compass itself
It went under the Station Control rotator; the compass that wanted it is the
docked one beside the entry strip. Both are the same RotorCompass, so the
readout moves INTO that component: every compass in the app carries it, and no
caller draws its own.

The bezel already showed the short path as a red marker, but a marker is a
direction, not a number — and the numbers in the status bar are 10px, which is
what prompted this.

Clickable only when the caller passed onGoto, since a compass rendered without
one cannot turn anything and a button that does nothing is worse than a label.
2026-08-13 11:45:49 +02:00
rouggy 700b688fc0 feat(rotator): short and long path headings under the compass
The same pair already sits in the status bar, where it is 10px and several
operators reported not being able to read it. Repeated under the compass at a
size that can be read across a shack.

Clickable, like the ones in the status bar: a heading you can see and not act
on would be a step backwards from what is already there. Disabled and dashed
when no station is entered, rather than showing a heading to nowhere.
2026-08-13 11:34:00 +02:00
rouggy 1b32b1ddec feat(antenna): per-band tune frequency for Ultrabeam and SteppIR
The band buttons in Station Control tuned to a fixed mid-band frequency baked
into the frontend. An operator who lives in the CW segment, or in the FT8
window, got the antenna resonant somewhere he never operates and had to nudge
it every time. The SteppIR's own controller has a Frequency (KHz) column per
band for exactly this; this is that column.

Stored sparsely: a band with no entry uses its default, so nothing migrates
and an operator sets only the bands he cares about. Left empty the Settings
box shows the default as its placeholder, which makes clearing it the obvious
way back.

The value is checked against the band plan before it is kept, because it goes
to the antenna as a tune command — a lost digit (1450 for 20 m) or kHz typed
as MHz would send the elements travelling to a length wrong for the band the
operator is on, and on a SteppIR that journey inhibits transmit the whole way.
A rejected entry is logged and the band falls back to its default.

Resolution happens in the backend and rides on the existing status poll, so
the widget no longer decides where a band button goes and cannot drift from
what Settings shows. Its own table stays only as a floor for the first poll.
2026-08-12 08:58:01 +02:00
rouggy 65bbaa85f3 feat(antenna): three tracking modes for Ultrabeam and SteppIR
The follow loop only ever had one behaviour — re-tune once the rig moved
further than a fixed step. The SteppIR's own controller software offers three,
and operators arrive with that mental model: every frequency change, past a
threshold, or only on a band change. They are real operating trade-offs, not
preferences: "always" keeps resonance perfect at the cost of motors running
constantly (and on a SteppIR every move inhibits transmit while the elements
travel), "band" moves them a handful of times a day.

"Always" is implemented as the threshold mode with a 1 kHz threshold rather
than as a separate branch, so all modes keep the one deadband reference that
matters: the rig frequency last commanded for, NOT the antenna's own reported
frequency — a SteppIR flips its reported frequency between the commanded value
and its home value, which would re-issue a SET on nearly every poll and leave
the operator permanently unable to transmit.

Band mode compares against the band last COMMANDED for, not the rig's previous
band, so the first move after startup and any move made by hand still get
reconciled. It applies to the immediate spot-click path too: a click inside the
band the antenna is already resonant in moves nothing.

An unset or unrecognised mode resolves to the step mode, so every config
written before this option behaves exactly as it did.

Also routes the antenna settings block through t() — it was hardcoded English.
2026-08-12 08:31:44 +02:00
rouggy c4d90e6880 feat(station): drive the motorized antenna from its widget
It showed pattern, elements and Retract — everything except where the antenna
is pointed, which is the thing an operator changes most. Tuning it meant opening
Settings or moving the rig.

A button per band, taken from the bands configured in Settings rather than a
list invented here: a band dropped there cannot be clicked here. They point at
where people actually work, not the arithmetic centre — 20 m centres on 14175
and nobody lives there, 10 m spans 1.7 MHz of which the top half is empty.

Up and down move 25 kHz, which is also the finest tracking threshold: a smaller
nudge would be undone by the next poll while tracking is on. They work from the
ANTENNA's frequency, not the rig's, or walking the antenna across a band while
the rig stays put would be undone on the first press.

Tracking moved within reach because it is an operating decision — off to park
the antenna, on to resume — not something set up once. Its step only appears
when it is on: a threshold for something switched off is a question the operator
cannot act on.

MotorTuneKHz carries the CURRENT direction rather than resetting it. Both
controllers set frequency and pattern in one command, so a bare frequency would
silently drop a 180° or bidirectional pattern — a beam turning round is not an
acceptable side effect of clicking a band.
2026-08-11 15:45:02 +02:00
rouggy 62cdabe114 feat(relay): accept a full URL host so relays work behind an HTTPS proxy
Network relay boards (WebSwitch/KMTronic/Dingtian) were always reached at
http://<host>, so a board on the LAN behind a reverse proxy — the common remote
setup where the operator's 80/443 already go to Nginx Proxy Manager — couldn't be
reached from outside. relayBase() now keeps a scheme the operator supplies
(https://relay.example.com, optional sub-path) and only defaults to http:// for a
bare host/host:port. UI hint + test added.
2026-08-06 09:26:16 +02:00
rouggy b3fdd0b7fa feat(rotator): multiple rotors of any type, plus a CAT PTT hotkey
Settings -> Rotator is now a list like the amplifiers: add/remove rotors,
mix PstRotator / Rotator Genius / ARCO, and a Rotator Genius can drive both
its ports (one entry = two rotors). The compass gains a rotor selector, and
a per-rotor motorized-antenna flag so the boom/pattern paths show only for
the rotor carrying the Ultrabeam/SteppIR.

Also in this batch: a keyboard PTT hotkey (hold-to-talk or toggle, reusing
the audio PTT method with a CAT fallback), and TCI spot push to the
panadapter with click-to-fill of the callsign.
2026-08-04 09:01:21 +02:00
rouggy 72f692aa04 chore: release v0.23.0 2026-08-02 20:03:16 +02:00
rouggy f6cd6e999a chore: release v0.22.9 2026-08-02 06:40:10 +02:00
rouggy 91b5af1c7b chore: release v0.21.3 2026-07-26 16:57:19 +02:00
rouggy 3a9dda13c4 feat: collapsible Flex/amp/tuner cards, matched meter sizes, faster + distinct-icon TGXL
Addresses three points of feedback on the Tuner Genius work:

- Meter sizes: the amplifier meters were rendered `compact` (smaller than the
  FlexRadio meters). Dropped compact so the amp, tuner and Flex meters are all
  the same size.
- Collapsible cards: the FlexRadio panel Card, AmpCard and TunerCard now fold
  from a chevron in the header, state persisted per card (opslog.cardOpen.*).
  The amplifier cards share the "amplifier" collapse key across their SPE/ACOM/
  PGXL variants so folding sticks regardless of the shown model.
- TGXL responsiveness: the tuner's device poll dropped 1500ms→400ms and the
  three UI pollers 1500ms→500ms, so the SWR/power meters track TX without the
  2–3s lag behind the amplifier the user saw.
- Icon: the Tuner Genius top-bar toggle used Zap, same as the CW keyer — changed
  the tuner's icon (top bar + widget + card) to Gauge so the two are distinct.
2026-07-25 11:22:56 +02:00
rouggy 9b677c6b35 feat: Tuner Genius XL — A/B channels, plus FlexRadio panel + Station Control cards
Push the tuner control further so it mirrors the native 4O3A app and the way the
PowerGenius XL is surfaced.

Backend (internal/tunergenius):
- Status now carries both RF channels A and B (source/mode, band, frequency,
  bound Flex nickname, per-channel bypass, antenna, PTT), the active channel,
  the C1/L/C2 relay-network positions, and the 3-way-vs-SO2R hardware variant
  (learned once from the `info` reply). Flat freq/antenna still mirror the active
  channel for the compact widget.
- New TunerGeniusActivate(ch) binding → `activate ch=N` (or `ant=N` on 3-way).

Frontend:
- New shared TunerCard, styled exactly like AmpCard (PWR/SWR meter bars,
  A/B channel selector with source+freq+antenna, Tune/Bypass/Operate). Used in
  BOTH the FlexRadio panel (its own card, like the PGXL) and Station Control.
- Docked TunerGeniusPanel widget now shows the two channels A/B with their
  source/frequency/antenna and lets you click to make one active — the missing
  A/B state the user flagged.
- i18n EN/FR for the new labels (channels, antenna, in-line/bypassed, title).

Still UNTESTED on hardware — verify the per-channel field names/units and the
activate behaviour on the real box.
2026-07-25 10:47:11 +02:00
rouggy 88202efddb ui: Station Control masonry layout — pack cards into balanced columns
flex-wrap with fixed-width cards started each new row below the TALLEST card of
the previous row, leaving big gaps under short panels (e.g. the amplifier alone
on a second line). Switch the dashboard to balanced CSS columns (column-width
430px, break-inside-avoid): cards flow top-to-bottom and pack tightly by height.
"Auto" fits as many columns as the window allows; 1-4 cap the column count via
the container max-width. Grip-drag reorder unchanged. Changelog 0.21.1.
2026-07-25 01:49:18 +02:00
rouggy 2823f3e401 feat: Station Control amp parity + all amps, Help→Send log to F4BPO, bulk-edit frequency, fix Cluster midnight sort
- Station Control: the amplifier panel is now the exact same card as the FlexRadio panel (extracted shared AmpCard: OPERATE/STANDBY, ON/OFF, power level, output-power bar, live FWD/ID/temp meters). Every configured amp gets its own card — no dropdown.
- Help → "Send log to F4BPO" (only when SMTP is configured): e-mails opslog.log + previous session + crash log to the developer. New email.SendFiles for multi-attachment.
- Bulk edit: new "Frequency (MHz)" field sets freq_hz AND recomputes band; out-of-band values rejected. Fixes a run logged on a stale/default freq after CAT dropped.
- Cluster: Time column sorted lexically on the HHMMZ string, so spots after 0000Z sorted below 2359Z and looked frozen at the UTC rollover. Now sorts by real arrival time.
- Also folds in the DVK auto-CQ/2-column layout and Station Control dashboard batch (changelog 0.20.10, EN+FR).
2026-07-23 13:22:02 +02:00
rouggy 1070637c40 feat+fix batch: Station Control dashboard (fixed-width panels, grip-handle drag reorder, amp meters from the Flex stream, compact relays), Ultrabeam element list capped to 3 (READ_BANDS over-read), spot-click on Flex panadapter now sets mode, DAX TX toggle, DVK panel state persists across relaunch, duplicate amp meters cleared on power-cycle, QSO audio recording snapshot taken synchronously at log time (was racing the form-clear cancel), Flex COMP meter max -20->-25 and MIC scale to 0; changelog 0.20.10 2026-07-23 01:08:47 +02:00
rouggy b7dd8d4852 feat: multiple amplifiers + SmartSDR v4 DSP filters
Multi-amp: Settings->Amplifier becomes a list (amps.json, legacy single-amp keys auto-migrate to entry #1); one client per enabled amp with per-id bindings (GetAmplifiers/SaveAmplifiers/GetAmpStatuses/AmpOperate/AmpPower/AmpPowerLevel/AmpFanMode); legacy a.pgxl/a.spe/a.acom point at the first enabled amp of each family. Amp cards in FlexPanel and Station Control gain a dropdown to pick the amp; the status bar shows one clickable chip per amp. Use case: two SPEs run in parallel.

Flex v4 DSP (8000/Aurora): NRL/ANFL (lms_nr/lms_anf), NRS (speex_nr), NRF (nrf) with level sliders, RNN (rnnoise) and ANFT on/off — keys per the FlexLib slice docs; the section only shows when the radio reports these keys (dsp_v4 flag), so 6000-series panels are unchanged.
2026-07-22 17:25:10 +02:00
rouggy 5aac28f564 fix: PGXL status-bar chip and Station Control widget read OPERATE from the Flex when it reports the amp (the direct GSCP status doesn't carry operate state) — toggle then goes through FlexAmpOperate like the Flex panel; direct TCP link stays as fallback; log distinct raw PGXL status payloads to map unknown fields 2026-07-22 09:33:39 +02:00
rouggy 968da5488c chore: release v0.20.8 2026-07-21 21:48:23 +02:00
rouggy 0385aed760 feat: amplifier controls without a Flex/Icom panel — Station Control widget (SPE/ACOM full control, PGXL fan) + status-bar chip (green OPERATE / orange STANDBY / red offline, click opens Settings); warn with a toast when activating a profile whose MySQL is unreachable instead of silently staying on the old logbook 2026-07-21 18:47:31 +02:00
rouggy 880ecdbbb5 fix: cache relay-board drivers so Denkovi/USB-serial boards stay connected
The station-control code rebuilt a fresh driver on every status poll and every
relay set. Stateful boards (Denkovi FTDI D2XX, USB-serial) hold an OS handle only
one opener can own, so the first poll opened the board and leaked the handle, and
every poll after failed with 'device in use' — the relays greyed out a second
after Save and auto-control never switched. Drivers are now cached per device and
reused, closed on config change. Adds a Test-connection button + detect feedback
in the device editor (reported by VK4MA).
2026-07-21 09:31:08 +02:00
rouggy def59da748 ui: label both USB relay backends as 'Denkovi USB' (FT245/D2XX vs serial/COM) 2026-07-20 17:33:02 +02:00
rouggy fe69bc308c feat: Denkovi USB 4/8 (selectable) + generic USB-serial relay board (CH340/LCUS)
- Denkovi (FT245 D2XX) now selectable as 4 or 8 relays (a 4-relay board just uses
  the low nibble); NewDenkovi takes a count, driven by the device's Channels.
- New 'usbrelay' backend: cheap CH340/LCUS USB-serial boards over a COM port
  using the common A0 protocol ([0xA0][relay][state][checksum]); write-only, so
  Status is a shadow. Channel count configurable (1/2/4/8/16).
- StationDevice gains Channels; deviceRelayCount() drives label/relay counts for
  the variable-size types. Device editor: channel selector + COM-port picker
  (usbrelay) / FTDI-serial (denkovi).

Both untested on hardware; the A0 command set / Denkovi bit order may need a tweak
after a live test.
2026-07-20 17:23:38 +02:00
rouggy c07a17dc47 feat: Denkovi USB 8-relay board (FT245 D2XX bit-bang)
Third relay device alongside WebSwitch and KMTronic. Despite enumerating as a
COM port, this board is driven via FTDI D2XX synchronous bit-bang (one byte = 8
relays, bit 0 = relay 1), not serial ASCII — so we load ftd2xx.dll at runtime
(no CGO) and call FT_OpenEx/FT_SetBitMode/FT_Write, addressing the board by its
FTDI serial (e.g. DAE0006K), exactly like the vendor tool. Windows-only (stub
elsewhere); ListDenkoviDevices enumerates connected serials for the picker.

Wired into relaydev (Count/Status/Set), app.go (deviceDriver/relayCountFor/type
whitelist + ListDenkoviDevices binding), and the Station device editor (new type
+ FTDI-serial field with Detect). Untested on hardware; bit order / on-polarity
may need a flip after a live test.
2026-07-20 16:50:04 +02:00
rouggy 6322a425d8 feat: Added columns selection in the Net Control 2026-07-17 20:21:29 +02:00
rouggy 9f08df1c39 fix: fix a bug adjusting the length of Ultrabeam 2026-07-17 20:19:54 +02:00
rouggy dcf006905c fix: QTH field is wider to see the full city names 2026-07-16 22:47:24 +02:00
rouggy 7cf2dfeaf9 feat: For steppir & Ultrabeam,possibility to change each element length 2026-07-16 22:32:29 +02:00
rouggy 69229964f4 fix: bug 2026-07-16 22:13:21 +02:00
rouggy 09848adddc feat: Added Ultrabeam/Steppir to Station Control with function to retract elements. 2026-07-16 22:10:36 +02:00
rouggy 829c236d6c feat: New Station Control, allow to control Webswitch 1216H or KMTronic 2026-07-16 22:01:07 +02:00