CallAndResponse.Transport.Serial 2.0.0-alpha.6

This is a prerelease version of CallAndResponse.Transport.Serial.
dotnet add package CallAndResponse.Transport.Serial --version 2.0.0-alpha.6
                    
NuGet\Install-Package CallAndResponse.Transport.Serial -Version 2.0.0-alpha.6
                    
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="CallAndResponse.Transport.Serial" Version="2.0.0-alpha.6" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="CallAndResponse.Transport.Serial" Version="2.0.0-alpha.6" />
                    
Directory.Packages.props
<PackageReference Include="CallAndResponse.Transport.Serial" />
                    
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 CallAndResponse.Transport.Serial --version 2.0.0-alpha.6
                    
#r "nuget: CallAndResponse.Transport.Serial, 2.0.0-alpha.6"
                    
#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 CallAndResponse.Transport.Serial@2.0.0-alpha.6
                    
#: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=CallAndResponse.Transport.Serial&version=2.0.0-alpha.6&prerelease
                    
Install as a Cake Addin
#tool nuget:?package=CallAndResponse.Transport.Serial&version=2.0.0-alpha.6&prerelease
                    
Install as a Cake Tool

CallAndResponse

A .NET library for structured call-and-response communication over byte-oriented transports. Swap between serial, BLE, and USB without touching your protocol code.

The library is pure framing and protocol logic. It never opens, closes, or manages transport connections — you provide an active IDuplexPipe from System.IO.Pipelines, and CallAndResponse handles message framing on top of it.

Getting Started

Prerequisites

  • .NET SDK 9.0.200 or later (required by the .slnx solution format; all projects target net8.0)

Install

dotnet add package CallAndResponse
dotnet add package CallAndResponse.Protocol.Modbus

Quick Example — Modbus over Serial

using System.IO.Ports;
using System.IO.Pipelines;
using CallAndResponse;
using CallAndResponse.Protocol.Modbus;

// You own the serial port lifecycle
using var port = new SerialPort("COM3", 9600, Parity.Even);
port.Open();

// Bridge to pipes — two lines
var transceiver = new Transceiver(
    PipeReader.Create(port.BaseStream),
    PipeWriter.Create(port.BaseStream));

// Use it with a protocol client
var modbus = new ModbusRtuClient(transceiver);

var registers = await modbus.ReadHoldingRegisters(
    unitIdentifier: 1,
    startingAddress: 0x0000,
    numRegisters: 10,
    cancellationToken);

Quick Example — Custom Framing

// Receive until a specific header + footer pattern is found
var payload = await transceiver.SendReceiveHeaderFooter(
    writeBytes: new byte[] { 0x01, 0x02 },
    header: new byte[] { 0xAA },
    footer: new byte[] { 0x55 },
    token: cancellationToken);

// Or use temporal framing for unsolicited data (e.g., barcode scanners)
var burst = await transceiver.ReceiveUntilIdle(
    idleTimeout: TimeSpan.FromMilliseconds(100),
    token: cancellationToken);

Quick Example — STM32 Firmware Update

using CallAndResponse.Protocol.Stm32Bootloader;

var bootloader = new Stm32BootloaderClient(transceiver);

if (await bootloader.Ping(cancellationToken))
{
    var info = await bootloader.GetSupportedCommands(cancellationToken);
    var chipId = await bootloader.GetId(cancellationToken);

    // Read 1024 bytes of flash
    var flash = await bootloader.ReadMemory(
        Stm32BootloaderClient.Stm32BaseAddress, 1024, cancellationToken);
}

Packages

Package Description
CallAndResponse Core library — ITransceiver, Transceiver, framing extensions, exceptions
CallAndResponse.Protocol.Modbus Modbus RTU client (read/write holding registers)
CallAndResponse.Protocol.Stm32Bootloader STM32 system bootloader commands (read/write/erase flash)

Architecture

The library has two layers that only depend downward:

Protocol Layer       (Modbus, STM32 — depends only on ITransceiver)
    ↓
Core Abstraction     (ITransceiver, Transceiver, PipeReader + PipeWriter)
  • Transceiver takes IDuplexPipe or PipeReader + PipeWriter and provides framed message exchange. All convenience methods (SendReceiveExactly, ReceiveUntilTerminator, etc.) are extension methods on ITransceiver.
  • Protocol clients accept ITransceiver and use the convenience methods to implement protocol-specific operations.
  • Transport bridging is the caller's responsibility. See Examples/ for complete IDuplexPipe implementations for serial and BLE Nordic UART.

See docs/ARCHITECTURE.md for the full architecture document.

Adding a Transport

Bridge your transport to System.IO.Pipelines and create a Transceiver:

// For stream-based transports (serial, TCP, etc.)
var transceiver = new Transceiver(
    PipeReader.Create(stream),
    PipeWriter.Create(stream));

// For event-based transports (BLE notifications, etc.)
var rxPipe = new Pipe();
device.DataReceived += async (s, e) =>
    await rxPipe.Writer.WriteAsync(e.Data);
var transceiver = new Transceiver(rxPipe.Reader, txPipeWriter);

See Examples/Example.Transport.Serial/ and Examples/Example.Transport.Ble/ for complete working examples.

Adding a Protocol

Accept ITransceiver via constructor and use the convenience methods:

public class MyProtocolClient
{
    private readonly ITransceiver _transceiver;

    public MyProtocolClient(ITransceiver transceiver)
        => _transceiver = transceiver;

    public async Task<byte[]> ReadDeviceId(CancellationToken token)
    {
        var response = await _transceiver.SendReceiveExactly(
            new byte[] { 0x01 },
            numBytesExpected: 4,
            token);

        return response.ToArray();
    }
}

Project Structure

CallAndResponse/
├── Source/
│   ├── CallAndResponse/                          Core library
│   │   ├── ITransceiver.cs                       Protocol-facing contract
│   │   ├── Transceiver.cs                        Pipe-backed implementation
│   │   ├── TransceiverExtensions.cs              Convenience framing methods
│   │   ├── DuplexPipeExtensions.cs               AsTransceiver() extension
│   │   ├── FrameDetectionResult.cs               Frame detection return type
│   │   └── TransceiverTransportException.cs      I/O-level exception
│   │
│   ├── CallAndResponse.Protocol.Modbus/          Modbus RTU protocol
│   └── CallAndResponse.Protocol.Stm32Bootloader/ STM32 bootloader protocol
│
├── Examples/
│   ├── Example.Transport.Serial/                 Serial IDuplexPipe + Modbus
│   └── Example.Transport.Ble/                    BLE Nordic UART IDuplexPipe
│
├── Test/
│   └── CallAndResponse.Test.Unit/                Unit tests (xUnit)
│
├── docs/
│   ├── ARCHITECTURE.md
│   └── adr/                                      Architecture decision records
│
└── CallAndResponse.slnx

Building

dotnet build CallAndResponse.slnx
dotnet test CallAndResponse.slnx --filter Category!=Integration

License

MIT © Charles Lee

Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  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 was computed.  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. 
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 CallAndResponse.Transport.Serial:

Package Downloads
Datafeel.NET.Serial

Package Description

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
2.0.0-alpha.6 32 8/28/2026
1.6.1-alpha 242 9/8/2025
1.6.0-alpha 162 9/5/2025
1.5.0-alpha 301 3/7/2025
1.4.0-alpha 459 2/6/2025
1.3.1-alpha 234 2/5/2025
1.3.0-alpha 186 2/5/2025
1.2.3-alpha 231 1/19/2025
1.2.1-alpha 248 1/18/2025
1.2.0-alpha 230 1/16/2025
1.1.1 219 1/7/2025
1.1.0 340 1/2/2025
1.0.7 204 12/28/2024