M0LTE.Flex
0.2.0
See the version list below for details.
dotnet add package M0LTE.Flex --version 0.2.0
NuGet\Install-Package M0LTE.Flex -Version 0.2.0
<PackageReference Include="M0LTE.Flex" Version="0.2.0" />
<PackageVersion Include="M0LTE.Flex" Version="0.2.0" />
<PackageReference Include="M0LTE.Flex" />
paket add M0LTE.Flex --version 0.2.0
#r "nuget: M0LTE.Flex, 0.2.0"
#:package M0LTE.Flex@0.2.0
#addin nuget:?package=M0LTE.Flex&version=0.2.0
#tool nuget:?package=M0LTE.Flex&version=0.2.0
M0LTE.Flex
A dependency-free .NET client for FlexRadio 6000-series SDRs over the SmartSDR TCP/UDP API. It gives you the radio as three simple seams — audio in, audio out, and PTT — so a modem, a paging encoder, or any DSP can drive a Flex the way it would drive a sound card, plus the discovery, command/status session and VITA-49 DAX plumbing underneath.
┌──────────────┐ discover / connect ┌───────────────────────────┐
│ your app │ ────────────────────────▶│ FlexClient (TCP :4992) │
│ (modem, DSP, │ IAudioInput (RX) ◀────│ FlexStation (slice+DAX) │──▶ FLEX-6000
│ paging, …) │ IAudioOutput (TX) ────▶│ VITA-49 DAX (UDP :4991) │
│ │ IPttControl ─────────▶│ slice PTT (xmit 1/0) │
└──────────────┘ └───────────────────────────┘
- Targets
net10.0. One dependency:M0LTE.Radio.Audio— the sharedIAudioInput/IAudioOutput/IPttControlseam. - Two bring-up modes: headless (this client creates its own slice — no SmartSDR running) and attach (bind a slice a running SmartSDR already owns).
- Both DAX transports: reduced-bandwidth 24 kHz s16 and full-bandwidth 48 kHz float32.
- Hardware-free tests: an in-process
MockFlexRadiospeaks enough of the protocol to loop transmit audio back as receive audio.
Install
dotnet add package M0LTE.Flex
Quick start
using M0LTE.Flex;
// 1. Find a radio on the LAN and open the session (or FlexClient.ConnectAsync("192.168.1.50")).
await using FlexClient client = await FlexClient.DiscoverAndConnectAsync(
spec: null, timeout: TimeSpan.FromSeconds(10));
// 2. Pick a DAX transport for your sample rate, then bring up a slice + DAX streams.
// SetUpHeadlessAsync creates our own slice; SetUpAsync attaches to a running SmartSDR's.
DaxStreamFormat format = DaxStreamFormat.FullBandwidth; // 48 kHz float32 (or .ReducedBandwidth for 24 kHz s16)
var options = new FlexStationOptions
{
SliceLetter = "A",
Frequency = "14.100000",
SliceMode = "DIGU",
DaxChannel = "1",
};
await using FlexStation station = await FlexStation.SetUpHeadlessAsync(client, format, options);
// 3. Receive, transmit and key through the seams (M0LTE.Radio.Audio).
using M0LTE.Radio.Audio;
IAudioInput rx = station.CreateAudioInput();
IAudioOutput tx = station.CreateAudioOutput();
IPttControl ptt = station.CreatePtt();
Span<float> buffer = new float[1024];
int got = rx.Read(buffer); // normalised floats (−1..1) at format.SampleRate
ptt.Key();
tx.Write(mySamples); // your modulated audio at format.SampleRate
tx.Drain(); // block until the audio has left the radio…
ptt.Unkey(); // …then release
DaxStreamFormat.ForDspRate(rate) picks the transport that bridges your DSP rate with an
integer ratio (48000 → full-bandwidth 1:1; 12000/24000 → reduced-bandwidth). The audio seams
always present samples at format.SampleRate; resample to your own rate on the way in/out.
Testing without a radio
using M0LTE.Flex;
await using var mock = new MockFlexRadio(DaxStreamFormat.FullBandwidth, MockRxMode.Loopback, MockSetupMode.Headless);
mock.Start();
await using FlexClient client = await FlexClient.ConnectAsync("127.0.0.1", mock.TcpPort, mock.UdpPort);
mock.RxDelivery = client.DeliverVitaPacket; // deliver the mock's DAX in-process (lossless)
client.VitaSendHook = mock.DeliverTxPacket; // capture what we transmit
See the test project for full loopback examples exercising the reorder ring, the headless and attach bring-up sequences, and the VITA-49 codec.
Stability & versioning
The public API is locked by a build-time test (PublicApiTests compares the surface to a
committed snapshot), and the package follows Semantic Versioning. Any
change to the public surface shows up in the diff and must be paired with the right version
bump — see docs/versioning.md.
Licence & provenance
AGPL-3.0-or-later (see LICENSE). Parts of the wire implementation are ports of
the MIT-licensed Go reference clients by Andrew Rodland (KC2G) and Frank Werner-Häcker
(HB9FXQ); the attributions are in PROVENANCE.md. Not affiliated with or
endorsed by FlexRadio Systems.
| 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
- M0LTE.Radio.Audio (>= 0.1.0)
NuGet packages (1)
Showing the top 1 NuGet packages that depend on M0LTE.Flex:
| Package | Downloads |
|---|---|
|
pdn-soundmodem
Headless soundcard packet modem core: IL2P/AX.25 framing and FEC now; demodulators, KISS TCP and DCD to follow. |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 0.14.1 | 0 | 8/14/2026 |
| 0.14.0 | 0 | 8/14/2026 |
| 0.13.2 | 34 | 8/14/2026 |
| 0.13.1 | 44 | 8/13/2026 |
| 0.13.0 | 53 | 8/13/2026 |
| 0.12.0 | 159 | 8/6/2026 |
| 0.11.0 | 237 | 8/3/2026 |
| 0.10.0 | 223 | 8/2/2026 |
| 0.9.2 | 180 | 8/2/2026 |
| 0.9.1 | 106 | 8/2/2026 |
| 0.9.0 | 104 | 8/2/2026 |
| 0.8.2 | 165 | 7/27/2026 |
| 0.8.1 | 96 | 7/27/2026 |
| 0.8.0 | 103 | 7/26/2026 |
| 0.7.0 | 96 | 7/26/2026 |
| 0.5.0 | 99 | 7/25/2026 |
| 0.4.0 | 99 | 7/25/2026 |
| 0.3.0 | 125 | 7/18/2026 |
| 0.2.0 | 100 | 7/17/2026 |
| 0.1.0 | 98 | 7/17/2026 |