CosmoSerialPort 0.1.1
See the version list below for details.
dotnet add package CosmoSerialPort --version 0.1.1
NuGet\Install-Package CosmoSerialPort -Version 0.1.1
<PackageReference Include="CosmoSerialPort" Version="0.1.1" />
<PackageVersion Include="CosmoSerialPort" Version="0.1.1" />
<PackageReference Include="CosmoSerialPort" />
paket add CosmoSerialPort --version 0.1.1
#r "nuget: CosmoSerialPort, 0.1.1"
#:package CosmoSerialPort@0.1.1
#addin nuget:?package=CosmoSerialPort&version=0.1.1
#tool nuget:?package=CosmoSerialPort&version=0.1.1
CosmoSerialPort
A modern, cross-platform serial port library for .NET 10 — a semantic port of serialport-rs built for industrial automation, robotics, SCADA, telemetry and other long-running, latency-sensitive workloads.
- Windows (Win32 overlapped I/O + IOCP), Linux (termios2/
BOTHER, poll), macOS (termios +IOSSIOSPEED, IOKit enumeration) SerialPortderives fromStream: works withStreamReader,System.IO.Pipelines, etc.- Real async: pooled
IValueTaskSourceoperations over a poll reactor (Unix) / IOCP (Windows) — noTask.Runwrappers, zero steady-state allocations - Deterministic disposal:
Dispose()wakes blocked readers, even with infinite timeouts - Port enumeration with USB VID/PID, serial number, manufacturer and product strings
- Modem pin control (RTS/DTR out, CTS/DSR/RI/CD in), break, buffer discard, XON/XOFF and RTS/CTS flow control
- Opt-in text layer (
ReadLine/WriteLine,NewLine,Encoding) and a race-freeDataReceivedevent — the binary hot path stays untouched until you use them - Nullable, analyzer-clean, AOT- and trimming-compatible
- Targets
net10.0andnetstandard2.0— usable from .NET Framework 4.7.2+, validated on .NET Framework 4.8 (seesamples/CosmoSerialPort.Probe48). The ns2.0 build uses classicDllImportinterop and a small polyfill layer; behavior is identical, though async continuations there always dispatch via the thread pool
Quick start
using CosmoSerialPort;
// Discover ports
foreach (SerialPortInfo info in SerialPort.GetPortInfos())
Console.WriteLine($"{info.PortName} [{info.PortType}] {info.UsbInfo?.Product}");
// Open with the builder (an immutable record — share and reconfigure freely)
using SerialPort port = SerialPort.Create("/dev/ttyUSB0", 115200)
.WithParity(Parity.None)
.WithStopBits(StopBits.One)
.WithFlowControl(FlowControl.None)
.WithReadTimeout(TimeSpan.FromSeconds(2))
.Open();
// Sync: returns as soon as at least one byte is available,
// throws SerialPortTimeoutException after ReadTimeout.
byte[] buffer = new byte[256];
int read = port.Read(buffer);
// Async with cancellation
int n = await port.ReadAsync(buffer.AsMemory(), cancellationToken);
await port.WriteAsync("AT\r\n"u8.ToArray());
// Pipelines for protocol parsing
var reader = port.CreatePipeReader();
// Control surface
port.SetRts(true);
ModemPins pins = port.GetModemPins();
port.DiscardBuffers(ClearBuffer.Input);
// Text layer (opt-in; UTF-8 and "\n" by default)
port.WriteLine("AT");
string? reply = port.ReadLine();
string? reply2 = await port.ReadLineAsync(cancellationToken);
// DataReceived: a background watcher owns the receive side while subscribed,
// so reading inside the handler is safe (unlike System.IO.Ports).
port.DataReceived += (_, e) =>
{
if (!e.IsEndOfStream && port.ReadLine() is { } line)
Console.WriteLine($"got: {line}");
};
Timeouts
| Value | Sync behavior | Async behavior |
|---|---|---|
Timeout.Infinite (default) |
Block until data | Wait until data or cancellation |
> 0 |
SerialPortTimeoutException after the timeout |
Same |
0 |
Fail immediately if nothing buffered (the serialport-rs default) | Same |
SerialPortTimeoutException derives from TimeoutException for System.IO.Ports
compatibility; all other errors derive from SerialPortException (an IOException) with the
native error code preserved.
Thread safety
One thread may read while another writes on the same instance. Multiple concurrent readers (or writers) are rejected. Control operations are individually thread-safe.
CosmoSerialPort vs System.IO.Ports
How this library compares to the classic System.IO.Ports.SerialPort:
| Feature | System.IO.Ports | CosmoSerialPort |
|---|---|---|
| API model | Mutable component: set properties, then Open() |
Immutable SerialPortBuilder record → Open() returns the port |
| Stream integration | Indirect, via the BaseStream property |
SerialPort is a Stream |
| Async I/O | BaseStream.ReadAsync wraps the old APM pattern; not truly asynchronous |
Real async: ValueTask + CancellationToken; poll reactor on Unix, IOCP on Windows |
| Cancellation | Not supported — close the port to abort | CancellationToken on every async operation |
| Allocations | Internal buffering and event machinery allocate per operation | Zero steady-state allocations; Span/Memory overloads |
| Dispose while reading | Notorious hangs and ObjectDisposedException crashes on hot unplug |
Deterministic: Dispose() wakes blocked readers; hot-unplug tested |
DataReceived event |
Fires on a pool thread; reading from the handler races other reads | Serialized invocations; a watcher owns the receive side, so handler reads are race-free with natural backpressure |
| Text layer | ReadLine/WriteLine/NewLine/Encoding (ASCII default) |
Same surface, opt-in with zero cost when unused (UTF-8 default) |
| Port enumeration | GetPortNames() — names only (registry SERIALCOMM) |
Names plus USB VID/PID, serial number, manufacturer, product, transport type (SetupAPI / sysfs / IOKit) |
| Baud rates | Standard rates; non-standard rates fail on Linux/macOS | Arbitrary rates: BOTHER (Linux), IOSSIOSPEED (macOS), any DCB value (Windows) |
| Exclusive access | None on Unix — two processes can open the same tty | flock + TIOCEXCL by default, opt-out via WithExclusive(false) |
| Modem pins | CtsHolding/DsrHolding/CDHolding — three calls, no Ring Indicator |
GetModemPins() — all four input pins in one native call |
| Error model | Mixed IOException/InvalidOperationException/UnauthorizedAccessException; native codes lost |
Typed hierarchy (PortNotFound, AccessDenied, PortInUse, InvalidConfiguration, NativeIO) with NativeErrorCode preserved |
| Timeout exception | TimeoutException |
SerialPortTimeoutException : TimeoutException — existing catch blocks keep working |
| Pipelines | Manual wiring over BaseStream |
CreatePipeReader() / CreatePipeWriter() built in |
| Parity options | Also Mark/Space parity, ParityReplace, DiscardNull |
None/Odd/Even only (serialport-rs semantics) |
| Handshake options | Extra RequestToSendXOnXOff combined mode |
None/Software (XON/XOFF)/Hardware (RTS/CTS) |
PinChanged/ErrorReceived events |
Available | Not offered — poll GetModemPins(), errors surface as typed exceptions |
| AOT / trimming | Not annotated | AOT- and trim-compatible (net10.0 target) |
| Frameworks | .NET Framework and .NET (Windows focus; limited Unix fidelity) | net10.0 + netstandard2.0 (.NET Framework 4.7.2+), first-class Windows/Linux/macOS |
Migration notes. Most call sites map one-to-one: IsOpen → CanRead/CanWrite, Close() → Dispose(), DiscardInBuffer()/DiscardOutBuffer() → DiscardBuffers(ClearBuffer.…), DtrEnable/RtsEnable → WithDtrOnOpen(…)/SetRts(…). Two things have no direct equivalent: Write(string) (encode explicitly and write the bytes — the old default was ASCII) and ReadExisting() (check BytesToRead, then Read that many bytes — or better, use ReadLine/ReadAsync). Ports open at construction time via the builder, so code that configured a closed port and opened it later should defer creation to the point of first use.
Repository layout
| Path | Contents |
|---|---|
src/CosmoSerialPort |
The library |
tests/CosmoSerialPort.Tests |
xunit suite; loopback tests run against kernel pseudo-terminals on Unix |
bench/CosmoSerialPort.Benchmarks |
BenchmarkDotNet loopback benchmarks |
samples/CosmoSerialPort.Probe |
Hardware smoke test / enumeration demo for a real or virtual port |
ARCHITECTURE.md |
Analysis of serialport-rs and the porting decisions |
dotnet build -c Release # warning-clean, analyzers on
dotnet test -c Release # 31 tests; PTY loopback suite on macOS/Linux
dotnet run --project samples/CosmoSerialPort.Probe -c Release -- COM1 # against an echo peer
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. 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. |
| .NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.0 is compatible. netstandard2.1 was computed. |
| .NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
| MonoAndroid | monoandroid was computed. |
| MonoMac | monomac was computed. |
| MonoTouch | monotouch was computed. |
| Tizen | tizen40 was computed. tizen60 was computed. |
| Xamarin.iOS | xamarinios was computed. |
| Xamarin.Mac | xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.0
- System.IO.Pipelines (>= 10.0.9)
- System.Memory (>= 4.6.3)
- System.Runtime.CompilerServices.Unsafe (>= 6.1.2)
- System.Threading.Tasks.Extensions (>= 4.6.3)
-
net10.0
- No dependencies.
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.