CallAndResponse 2.0.0-alpha.6

This is a prerelease version of CallAndResponse.
dotnet add package CallAndResponse --version 2.0.0-alpha.6
                    
NuGet\Install-Package CallAndResponse -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" 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" Version="2.0.0-alpha.6" />
                    
Directory.Packages.props
<PackageReference Include="CallAndResponse" />
                    
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 --version 2.0.0-alpha.6
                    
#r "nuget: CallAndResponse, 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@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&version=2.0.0-alpha.6&prerelease
                    
Install as a Cake Addin
#tool nuget:?package=CallAndResponse&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 (4)

Showing the top 4 NuGet packages that depend on CallAndResponse:

Package Downloads
Datafeel

An API for communicating with Datafeel hardware

CallAndResponse.Transport.Ble

Package Description

CallAndResponse.Protocol.Modbus

A Modbus API using the CallAndResponse Transceiver

CallAndResponse.Protocol.Stm32Bootloader

STM32 bootloader commands implemented using the CallAndResponse Transceiver

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
2.0.0-alpha.6 35 8/28/2026
1.6.1-alpha 365 9/8/2025
1.6.0-alpha 296 9/5/2025
1.5.0-alpha 427 3/7/2025
1.4.0-alpha 910 2/6/2025
1.3.1-alpha 467 2/5/2025
1.3.0-alpha 291 2/5/2025
1.2.3-alpha 420 1/19/2025
1.2.1-alpha 413 1/18/2025
1.2.0-alpha 371 1/16/2025
1.1.1 395 1/7/2025
1.1.0 853 1/2/2025
1.0.7 334 12/28/2024