DeviceRecorder.Core
0.1.0
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
<PackageReference Include="DeviceRecorder.Core" Version="0.1.0" />
<PackageVersion Include="DeviceRecorder.Core" Version="0.1.0" />
<PackageReference Include="DeviceRecorder.Core" />
paket add DeviceRecorder.Core --version 0.1.0
#r "nuget: DeviceRecorder.Core, 0.1.0"
#:package DeviceRecorder.Core@0.1.0
#addin nuget:?package=DeviceRecorder.Core&version=0.1.0
#tool nuget:?package=DeviceRecorder.Core&version=0.1.0
DeviceRecorder.Core
Reusable serial device session and UI state helpers for device recorder applications.
What is included
SerialDeviceClientfor serial port lifecycle and recovery handlingRecordingSessionController<TClient, TReadResult>for reusable session orchestrationIRecordableDeviceClient<TReadResult>for device-specific recording clientsIRecordingSessionStatefor UI-facing session stateFormViewStatefor simple connect/record UI state mappingAsyncFormsTimerfor non-overlapping async WinForms timer callbacksTimedDeviceRecorder<TState>andPumaRecorder<TState>for reusable recording pipelinesReplayDeviceClient<TState, TReadResult>andDeviceReplayEntry<TReadResult>for log-based device emulationIPortProviderimplementations 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
FormViewStatedepends only onIRecordingSessionState, so it can be reused with any compatible controller.RecordingSessionController<TClient, TReadResult>contains the reusable connect/disconnect/read/record orchestration.SerialDeviceClientincludes 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 | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0-windows7.0 is compatible. |
-
net10.0-windows7.0
- System.IO.Ports (>= 10.0.7)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.