FT891.Core 1.2.0

Suggested Alternatives

FT891.Core 2.0.0

Additional Details

Legacy code

There is a newer version of this package available.
See the version list below for details.
dotnet add package FT891.Core --version 1.2.0
                    
NuGet\Install-Package FT891.Core -Version 1.2.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="FT891.Core" Version="1.2.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="FT891.Core" Version="1.2.0" />
                    
Directory.Packages.props
<PackageReference Include="FT891.Core" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add FT891.Core --version 1.2.0
                    
#r "nuget: FT891.Core, 1.2.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package FT891.Core@1.2.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=FT891.Core&version=1.2.0
                    
Install as a Cake Addin
#tool nuget:?package=FT891.Core&version=1.2.0
                    
Install as a Cake Tool

FT891.Core

The library at the heart of the solution: a complete, async CAT client for the Yaesu FT-891, the protocol engine that drives it, the command table it relies on, and the transport abstraction that lets it talk to either real hardware or the simulator.

Target framework: net48 · Language: C# latest · No runtime dependencies beyond System.IO.Ports (for the serial transport).


Folder layout

FT891.Core/
├── Enums/
│   └── Enums.cs              OperatingMode, AgcMode, MeterType, TunerState,
│                             ScanMode, BreakInMode, BandSelect
├── Models/
│   ├── RadioInfo.cs          record: frequency, mode, TX, S-meter, split, channel
│   └── MeterReading.cs       record: meter type + value
├── Protocol/
│   ├── CatSpec.cs            command → reply-length table (the source of truth)
│   ├── CatSerialEngine.cs    the single byte-count-driven TransceiveAsync
│   ├── FT891Cat.cs           ICatInterface implementation (one-liners)
│   ├── ICatTransport.cs      the byte-pipe abstraction
│   ├── SerialPortTransport.cs   real radio (RS-232 / USB, 8-N-2)
│   ├── TcpCatTransport.cs    virtual serial port over TCP
│   └── Num.cs                Clamp helper (Math.Clamp is absent on net48)
├── Interface/
│   └── ICatInterface.cs      the full public surface
└── Properties/
    └── IsExternalInit.cs     polyfill so records/init compile on net48

How it fits together

1. CatSpec — the response-length table

A single dictionary maps each 2-letter command to the total number of bytes its reply contains, including the prefix and the trailing ;:

{ "FA", 12 },   // "FA014250000;"  → 2 + 9 + 1
{ "MD",  5 },   // "MD0" + 1 hex mode digit + ";"
{ "IF", 34 },   // full status frame
...

This is the only place that encodes per-command knowledge. 58 commands are described. The lengths were derived from (and kept consistent with) the exact frame formats FT891Cat builds and parses, so a count-driven read always lands on the right boundary. (A handful of lengths were corrected from the original single-file source for self-consistency — see the table at the bottom.)

2. CatSerialEngine.TransceiveAsync — the only I/O

public async Task<string> TransceiveAsync(string command, int expectedBytes = -1)
  • Ensures the command ends with ;.
  • If expectedBytes is -1, looks it up in CatSpec from the 2-char prefix.
  • expectedBytes == 0 → a set-only command; write and return immediately.
  • Otherwise it reads exactly expectedBytes bytes in a loop (handling partial TCP/serial reads) — never scanning for a delimiter.
  • A SemaphoreSlim serialises access so concurrent callers can't interleave a write/read pair.

3. ICatTransport — serial or TCP

public interface ICatTransport : IDisposable
{
    bool IsOpen { get; }
    void Open();  void Close();  void DiscardInBuffer();
    void Write(string data);
    int  Read(byte[] buffer, int offset, int count);
}
  • SerialPortTransport — wraps System.IO.Ports.SerialPort configured the way the FT-891 expects: 38400 baud, 8 data bits, no parity, two stop bits, ASCII encoding, 2000 ms read/write timeout.
  • TcpCatTransport — treats a TCP socket as a virtual serial port. A socket read-timeout is surfaced as a TimeoutException, so "the radio said nothing" always looks the same regardless of transport.

4. FT891Cat — one-liners over the engine

Every method is a single expression that builds a frame (for a set) or builds a frame, awaits the reply, and slices out the value (for a read):

public Task SetVfoAFrequencyAsync(long hz)      => Set($"FA{hz:D9};");
public async Task<long> GetVfoAFrequencyAsync() => long.Parse((await Read("FA;")).Substring(2, 9));

Three constructors let you choose the transport:

new FT891Cat("COM3");                                  // real serial port
new FT891Cat(new TcpCatTransport("127.0.0.1", 4000));  // simulator / network
new FT891Cat(existingCatSerialEngine);                 // bring your own engine

API surface (ICatInterface)

Group Representative members
Connection Connect, Disconnect, IsConnected, Dispose
VFO & frequency Get/SetVfoAFrequencyAsync, Get/SetVfoBFrequencyAsync, CopyVfoAToVfoBAsync, CopyVfoBToVfoAAsync, SwapVfosAsync, BandUp/DownAsync, SelectBandAsync, FrequencyUp/DownAsync, ZeroInAsync
Mode Get/SetModeAsync
Memory Get/SetMemoryChannelAsync, CopyVfoAToMemoryAsync, CopyMemoryToVfoAAsync, ChannelUpDownAsync, WriteMemoryAsync, ReadMemoryAsync, Store/RecallQuickMemoryBankAsync
TX / PTT / split IsTransmittingAsync, SetMoxAsync, Get/SetSplitAsync
Power Get/SetPowerAsync, Get/SetTxPowerAsync
Audio levels AF, RF, Mic, Squelch, Monitor — Get/Set…Async
RF / antenna Get/SetRfAttenuatorAsync, Get/SetPreampAsync, Get/SetTunerStateAsync
DSP / filters AGC, Noise Reduction (+level), Noise Blanker (+level), Auto Notch, Manual Notch, IF Shift, Bandwidth, Contour
CW Get/SetKeySpeedAsync, Get/SetKeyPitchAsync, Get/SetBreakInModeAsync, Get/SetSemiBreakInDelayAsync, Get/SetCwSpotAsync, Get/SetKeyerAsync, SendCwAsync, Get/SetKeyerMemoryAsync
VOX Get/SetVoxAsync, Get/SetVoxGainAsync, Get/SetVoxDelayAsync
Speech processor Get/SetSpeechProcessorAsync, Get/SetSpeechProcessorLevelAsync
Clarifier Get/SetClarifierAsync, ClarifierUp/DownAsync, ClarifierClearAsync
CTCSS / repeater Get/SetCtcssAsync, Get/SetCtcssDcsNumberAsync, Get/SetOffsetAsync
Scan Get/SetScanModeAsync
Meters / status GetSMeterAsync, ReadMeterAsync, GetBusyAsync, GetRadioInfoAsync, GetRadioIdAsync, GetOppositeVfoInfoAsync
Display / UI Dimmer, Lock, Fast-step, Auto-information — Get/Set…Async
Message memory PlaybackAsync, LoadMessageAsync
Escape hatch SendRawCommandAsync(command, expectedBytes = -1)

Values are clamped to the radio's valid ranges before transmission (e.g. TX power 5–100 W, key speed 4–60 WPM) via the Num.Clamp helper.


Running modern C# on .NET Framework 4.8

The original source used several APIs/syntax that don't exist on net48. They are handled so the code stays clean and idiomatic:

Modern feature net48 accommodation
record types + init setters Properties/IsExternalInit.cs polyfill + <LangVersion>latest</LangVersion>
Math.Clamp Num.Clamp(value, min, max) helper
string.EndsWith(char) EndsWith(";", StringComparison.Ordinal)
range slicing s[..2] s.Substring(0, 2) (no System.Index/Range on net48)
System.IO.Ports NuGet package System.IO.Ports 8.0.0
net48 reference assemblies Microsoft.NETFramework.ReferenceAssemblies (cross-environment build)

Reply lengths corrected from the original single-file source

Command Was Now Why
FA / FB 13 12 FA + 9 digits + ; = 12
IS 9 10 flag + sign + 4 digits needs 10
CO 11 13 flag + 4-digit level + 4-digit bias
KM 55 54 slot + 50-char message + ;
IF 30 34 status fields parsed up to index 32

These keep the count-driven reader perfectly aligned with the bytes a real radio (and the simulator) emits.


READMEs written by Claude Code Opus 4.8m Context - From CodeBase - TSGBMPPT

Product Compatible and additional computed target framework versions.
.NET Framework net48 is compatible.  net481 was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (1)

Showing the top 1 NuGet packages that depend on FT891.Core:

Package Downloads
FT891.Simulator

A virtual Yaesu FT-891 transceiver over TCP for developing and testing CAT clients without hardware. Embed SimulatorServer in-process (as FT891.Tests does) or run it standalone.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
2.1.0 310 6/7/2026
2.0.0 151 6/6/2026
1.2.1 397 6/5/2026 1.2.1 is deprecated because it is no longer maintained.
1.2.0 166 6/5/2026 1.2.0 is deprecated because it is no longer maintained.