M0LTE.Rig
0.2.1
dotnet add package M0LTE.Rig --version 0.2.1
NuGet\Install-Package M0LTE.Rig -Version 0.2.1
<PackageReference Include="M0LTE.Rig" Version="0.2.1" />
<PackageVersion Include="M0LTE.Rig" Version="0.2.1" />
<PackageReference Include="M0LTE.Rig" />
paket add M0LTE.Rig --version 0.2.1
#r "nuget: M0LTE.Rig, 0.2.1"
#:package M0LTE.Rig@0.2.1
#addin nuget:?package=M0LTE.Rig&version=0.2.1
#tool nuget:?package=M0LTE.Rig&version=0.2.1
M0LTE.Rig
Two abstractions over an amateur-radio transceiver, both dependency-free and capability-probed: IRigControl, the station-control (CAT) seam, and IRadioControl, the channel-sensing seam. Pick IRigControl for anything an operator drives (a logger, a digimode app); pick IRadioControl for anything that reacts to channel activity (a MAC layer, a CSMA gate). RigRadioControl bridges a live IRigControl into IRadioControl when you have the former and need the latter.
Station control - IRigControl
Get/set frequency and mode, PTT, SWR / RF-power metering, and receive-side DCD / signal-strength reads, all behind capability probes.
IRigControl rig = await RigctldRig.ConnectAsync(); // M0LTE.Rig.Hamlib
// IRigControl rig = await FlrigRig.ConnectAsync(); // M0LTE.Rig.Flrig
await rig.SetFrequencyAsync(14_074_000);
await rig.SetModeAsync(RigMode.PktUsb);
if (rig.Capabilities.HasFlag(RigCapabilities.SwrMeter))
{
var swr = await rig.ReadSwrAsync(); // dimensionless ratio, 1.0 = perfect
}
if (rig.Capabilities.HasFlag(RigCapabilities.DcdRead))
{
var busy = await rig.ReadDcdAsync(); // true = carrier present / channel busy
}
Channel sensing - IRadioControl
Push carrier-sense (DCD) edges, RSSI, and transmitter keying - what a MAC layer or CSMA gate wants, because a hardware carrier-sense edge leads the modem's decoded frame by a whole preamble.
IRadioControl radio = new RigRadioControl(rig, ownsRig: true); // bridge from any IRigControl
// or a native implementation, e.g. M0LTE.Tait.Ccdi's TaitCcdiRadio
radio.CarrierSenseChanged += (_, e) => Console.WriteLine($"channel {(e.Busy ? "busy" : "clear")} at {e.At:O}");
if (radio.Capabilities.HasFlag(RadioCapabilities.RssiRead))
{
Console.WriteLine($"{await radio.ReadRssiDbmAsync():F1} dBm");
}
A driver can also offer IRadioSideChannel - a small-datagram control plane the radio itself provides (Tait SDM over the radio's internal FFSK modem, for instance), riding the radio's own signalling modem rather than the audio-path modem/TNC. Because it bypasses the audio modem it is mode- and deviation-agnostic, which makes it the natural place to renegotiate the very link it sits beside. Drivers advertise the machinery via RadioCapabilities.SideChannel; consumers must still probe that it is enabled in the radio's programming before gating features on it.
Design
IRigControlis the cross-backend common subset for CAT control. Everything a backend might lack is gated byRigCapabilitiesflags discovered at connect time; calling an unadvertised member throwsNotSupportedException.IRadioControlis the cross-driver common subset for channel sensing, gated the same way byRadioCapabilities. The {RSSI-get, busy-get, PTT-set} subset has held across four implementations without an interface change; reserved flags (channel change, frequency, TX power) exist so richer radios can be described before the interface grows those members - that control belongs toIRigControlinstead.RigModewraps a canonical token (hamlib vocabulary:USB,LSB,CW,PKTUSB, ...) with pass-through for backend-native names (RigMode.From("DATA-U")) - mode vocabularies genuinely diverge across backends, so this is not a closed enum.- Receive-side reads on
IRigControl-ReadDcdAsync(true = carrier present / channel busy) andReadSignalStrengthDbmAsync(dBm) - exist soRigRadioControlcan serveIRadioControl's carrier-sense seam from any CAT rig. RigRadioControlis poll-synthesised, not push. CAT backends have no notification channel, so DCD is sampled by an owned loop and carrier-sense edges are synthesised from consecutive samples; edges shorter than the poll interval are invisible. A failed read fails open (ChannelBusy = null, so a CSMA gate never blocks on stale information) and backs off to a slower retry cadence until the rig self-heals.ownsRig: truehands the rig's lifetime to the adapter; the defaultfalseleaves it with the caller, and dispose best-effort unkeys anything the adapter left keyed.- Errors are typed:
RigConnectionException(link down - retry is sane),RigTimeoutException,RigCommandException(the backend said no; carries its native code),RigProtocolException(unparseable reply). - Poll-only backends. Current
IRigControlbackends (rigctld, flrig) have no push channel; callers own their polling cadence. NativeIRadioControldrivers (Tait CCDI) push real hardware edges instead.
This package is deliberately dependency-free - it does not pull in the rest of the AX.25 stack of any particular project. Implementations:
M0LTE.Rig.Hamlib-IRigControlover hamlib'srigctldnetwork protocol (any of hamlib's 200+ rigs, plus the many rigctld-protocol emulators).M0LTE.Rig.Flrig-IRigControlover flrig's XML-RPC server.M0LTE.Tait.Ccdi(repo) - a Tait TM8100/TM8200 CCDI driver implementing both seams natively:TaitCcdiRadio(IRadioControlwith push carrier-sense andIRadioSideChannel) andTaitRigControl, a partial view (PTT + relative RF-power meter) demonstrating a backend that honestly advertises only a slice of theIRigControlsurface.
AX.25-specific adapters over IRadioControl (per-frame RSSI tagging, feeding the AX.25 CSMA gate) live in packet-net/packet.net as Packet.Ax25.Radio.
Design and research notes live in packet.net, where this library was written: docs/research/rig-control-spike.md.
AGPL-3.0-licensed. Standalone; used by (among others) the Packet.NET stack.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- No dependencies.
NuGet packages (8)
Showing the top 5 NuGet packages that depend on M0LTE.Rig:
| Package | Downloads |
|---|---|
|
Packet.Tune.Core
Coordination primitives for tuning a NinoTNC + radio pair with the two ends apart: the tuning-telegram protocol (ITuningLink), an SDM flavour riding the radio's own side channel (M0LTE.Rig.IRadioSideChannel; Tait CCDI short data messages: radio-native FFSK, independent of the TNC mode/pot under tune), a WebSocket flavour with a PIN-rendezvous relay, the shared meter/tuned assistant loop, a mode-coordination protocol (propose/confirm/commit a TNC mode + radio channel switch, probe-verify, revert-to-home on failure), and a capability doctor for the whole TNC-to-radio stack. Source: github.com/packet-net/packet.net. |
|
|
M0LTE.Rig.Hamlib
Pure-managed client for hamlib's NET rigctl protocol (rigctld, TCP 4532) implementing the M0LTE.Rig IRigControl abstraction: get/set frequency and mode, PTT, SWR and RF-power metering, capability discovery via dump_caps, plus raw-command and get-level escape hatches. No native libhamlib dependency. Source: github.com/M0LTE/M0LTE.Rig. |
|
|
M0LTE.Rig.Flrig
Client for flrig's XML-RPC rig-control server (default port 12345) implementing the M0LTE.Rig IRigControl abstraction: get/set frequency and mode, PTT, SWR and RF-power metering with hamlib-compatible meter conversions, plus a raw method-call escape hatch. No dependencies beyond M0LTE.Rig. Source: github.com/M0LTE/M0LTE.Rig. |
|
|
Packet.Ax25.Radio
Brings a radio's control channel (M0LTE.Rig's IRadioControl: RSSI, hardware carrier-sense/DCD, PTT) into the AX.25 stack: RssiTaggingTransport decorates any IAx25Transport so inbound frames carry per-frame RSSI/SNR/noise-floor/airtime metadata, and RadioCarrierSense bridges hardware DCD onto the ICarrierSense seam the listener's CSMA gate consults before every keyup. Source: github.com/packet-net/packet.net. |
|
|
Packet.Ax25.Radio.Tait
An IAx25Transport whose modem IS the radio: no external TNC. Puts a Tait TM8100/TM8200 into Transparent mode (its internal FFSK modem as an 8-bit-clean byte pipe), frames AX.25 with KISS SLIP over that pipe, and de-frames inbound bytes back into whole frames. Because it owns the transmission it times it directly, so it implements ITxCompletionTransport and stamps per-frame on-air start/end and airtime. Builds on M0LTE.Tait.Ccdi. Source: github.com/packet-net/packet.net. |
GitHub repositories
This package is not used by any popular GitHub repositories.