DeviceRecorder.Core 0.1.0

There is a newer version of this package available.
See the version list below for details.
dotnet add package DeviceRecorder.Core --version 0.1.0
                    
NuGet\Install-Package DeviceRecorder.Core -Version 0.1.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="DeviceRecorder.Core" Version="0.1.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="DeviceRecorder.Core" Version="0.1.0" />
                    
Directory.Packages.props
<PackageReference Include="DeviceRecorder.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 DeviceRecorder.Core --version 0.1.0
                    
#r "nuget: DeviceRecorder.Core, 0.1.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 DeviceRecorder.Core@0.1.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=DeviceRecorder.Core&version=0.1.0
                    
Install as a Cake Addin
#tool nuget:?package=DeviceRecorder.Core&version=0.1.0
                    
Install as a Cake Tool

DeviceRecorder.Core

Reusable serial device session and UI state helpers for device recorder applications.

What is included

  • SerialDeviceClient for serial port lifecycle and recovery handling
  • RecordingSessionController<TClient, TReadResult> for reusable session orchestration
  • IRecordableDeviceClient<TReadResult> for device-specific recording clients
  • IRecordingSessionState for UI-facing session state
  • FormViewState for simple connect/record UI state mapping
  • AsyncFormsTimer for non-overlapping async WinForms timer callbacks
  • TimedDeviceRecorder<TState> and PumaRecorder<TState> for reusable recording pipelines
  • ReplayDeviceClient<TState, TReadResult> and DeviceReplayEntry<TReadResult> for log-based device emulation
  • IPortProvider implementations for real or emulated port enumeration

Target framework

  • .NET 10 (net10.0-windows)

Basic usage

1. Create a device client

Your device client inherits SerialDeviceClient and implements IRecordableDeviceClient<TReadResult>.

using DeviceRecorder.Core.Controllers;
using DeviceRecorder.Core.Serial;

public sealed class SampleReadResult
{
    public string RawResponse { get; init; } = string.Empty;
}

public sealed class SampleSerialClient : SerialDeviceClient, IRecordableDeviceClient<SampleReadResult>
{
    public SampleSerialClient(string portName, int baudRate = 9600)
        : base(portName, baudRate)
    {
    }

    public bool IsRecording { get; private set; }
    public bool IsRecordingPaused { get; private set; }
    public string? RecordingFilePath { get; private set; }

    public Task<SampleReadResult> ReadAsync()
    {
        return Task.Run(Read);
    }

    public SampleReadResult Read()
    {
        var raw = ReadLine();
        SetConnectedState();
        return new SampleReadResult { RawResponse = raw };
    }

    public void StartRecording(string? directoryPath = null)
    {
        IsRecording = true;
        IsRecordingPaused = false;
        RecordingFilePath ??= Path.Combine(directoryPath ?? AppContext.BaseDirectory, "sample.txt");
    }

    public void PauseRecording()
    {
        if (IsRecording)
        {
            IsRecordingPaused = true;
        }
    }

    public void StopRecording()
    {
        IsRecording = false;
        IsRecordingPaused = false;
        RecordingFilePath = null;
    }

    public void SetRecordingTimeStep(TimeSpan recordingTimeStep)
    {
    }
}

2. Create a session controller

using DeviceRecorder.Core.Controllers;

public sealed class SampleSessionController : RecordingSessionController<SampleSerialClient, SampleReadResult>
{
    protected override SampleSerialClient CreateClient(string selectedPort)
    {
        return new SampleSerialClient(selectedPort, 9600);
    }
}

3. Use it from an application

using DeviceRecorder.Core.UI;

var controller = new SampleSessionController();
controller.SetSelectedPort("COM3");

var firstResult = await controller.ConnectAsync(TimeSpan.FromSeconds(1));
Console.WriteLine(firstResult.RawResponse);

controller.ToggleRecording(TimeSpan.FromSeconds(1), Path.Combine(AppContext.BaseDirectory, "data"));

var viewState = FormViewState.Create(controller);
Console.WriteLine(viewState.ConnectionText);
Console.WriteLine(viewState.RecordButtonText);

Notes

  • FormViewState depends only on IRecordingSessionState, so it can be reused with any compatible controller.
  • RecordingSessionController<TClient, TReadResult> contains the reusable connect/disconnect/read/record orchestration.
  • SerialDeviceClient includes serial port recovery behavior used by the sample app.

Emulation

You can emulate a device by deriving from ReplayDeviceClient<TState, TReadResult> and providing replay entries. The common replay-file support assumes only:

  • the first column is a timestamp in yyyy-MM-dd HH:mm:ss.fff
  • columns are tab-separated

Everything after that is device-specific and parsed by the device implementation.

using DeviceRecorder.Core.Emulation;
using DeviceRecorder.Core.Recording;

public sealed class SampleState
{
    public float Value { get; set; }
}

public readonly record struct SampleResult(string RawResponse, float Value);

public sealed class SampleReplayClient : ReplayDeviceClient<SampleState, SampleResult>
{
    public SampleReplayClient(IReadOnlyList<DeviceReplayEntry<SampleResult>> entries)
        : base(entries)
    {
    }

    protected override SampleState CreateState() => new();

    protected override TimedDeviceRecorder<SampleState> CreateRecorder(SampleState state)
    {
        throw new NotImplementedException();
    }

    protected override void ApplyResult(SampleResult result, SampleState state)
    {
        state.Value = result.Value;
    }
}

You can also load replay entries from a generic tab-separated replay file:

var entries = ReplayFileLoader.Load("sample-replay.txt", row =>
{
    var rawResponse = row.Columns[1];
    var value = float.Parse(row.Columns[2], CultureInfo.InvariantCulture);
    return new SampleResult(rawResponse, value);
});

Set ReplayDeviceClientOptions.RestartFromBeginningOnOpen to restart playback from the first replay entry each time the emulated device is opened.

Product Compatible and additional computed target framework versions.
.NET net10.0-windows7.0 is compatible. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
0.5.0 29 5/6/2026
0.1.0 30 5/6/2026