Oakrey.Guru.Handlers 4.0.4

dotnet add package Oakrey.Guru.Handlers --version 4.0.4
                    
NuGet\Install-Package Oakrey.Guru.Handlers -Version 4.0.4
                    
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="Oakrey.Guru.Handlers" Version="4.0.4" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Oakrey.Guru.Handlers" Version="4.0.4" />
                    
Directory.Packages.props
<PackageReference Include="Oakrey.Guru.Handlers" />
                    
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 Oakrey.Guru.Handlers --version 4.0.4
                    
#r "nuget: Oakrey.Guru.Handlers, 4.0.4"
                    
#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 Oakrey.Guru.Handlers@4.0.4
                    
#: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=Oakrey.Guru.Handlers&version=4.0.4
                    
Install as a Cake Addin
#tool nuget:?package=Oakrey.Guru.Handlers&version=4.0.4
                    
Install as a Cake Tool

Oakrey.Guru.Handlers

Handler framework for Oakrey Guru USB hardware devices. Provides async request/reply command execution with configurable timeout, typed Rx event stream handlers, status-reply dispatch, and a thread-safe handler collection keyed by packet ID.

Builds on Oakrey.Guru.Adapter for the underlying packet transport.

Main features

  • ReplayHandler<TSelf, TReply> � async request/reply command with 500 ms timeout, CancellationToken support, and TaskCompletionSource-based response correlation
  • EventHandler<TSelf, TEvent> � typed push-based event stream via IObservable<TEvent> backed by an Rx Subject<TEvent>
  • StatusHandler<TSelf> � specialised ReplayHandler that decodes a one-byte Status response and throws GuruException on non-OK results
  • HandlerCollection � thread-safe dictionary keyed by ushort packet ID; lazy-creates handlers on first access via GetHandler<T>()
  • GuruException � domain exception with static guard helpers (ThrowIfDataLengthMismatch, ThrowIfDataLengthIsInsufficient, ThrowIfInvalidDataCount)
  • Status enum � standard device response codes: Ok, Await, Error, InvalidArg, Busy, NotPermitted, NotImplemented, False

Architecture

classDiagram
    direction TB

    class IHandler {
        +Id ushort
        +Handler Action~byte[]~
        +ProcessReplay(byte[])
    }

    class HandlerBase~TSelf~ {
        #logger ILogger
        +ProcessReplay(byte[])
    }
    HandlerBase ..|> IHandler

    class ReplayHandler~TSelf,TReply~ {
        #taskCompletionSource TaskCompletionSource~TReply~
        #Run(transmitter, deviceLock, payload, ct) Task~TReply~
        #CheckExpectedReply()
    }
    ReplayHandler --|> HandlerBase

    class StatusHandler~TSelf~ {
        +Handler Action~byte[]~
    }
    StatusHandler --|> ReplayHandler

    class EventHandler~TSelf,TEvent~ {
        +Subscribe(IObserver~TEvent~) IDisposable
        #Publish(TEvent)
    }
    EventHandler --|> HandlerBase
    EventHandler ..|> IObservable~TEvent~

    class HandlerCollection {
        +AddCommand(IHandler)
        +TryGetCommand(ushort, out IHandler) bool
        +GetHandler~T~() T
    }

Requirements

Installation

dotnet add package Oakrey.Guru.Handlers

Or via Package Manager Console:

Install-Package Oakrey.Guru.Handlers

Usage

Async request/reply handler

Derive from ReplayHandler<TSelf, TReply> and implement Id, Handler, and a public Execute method that calls Run:

using Oakrey.Guru.Handlers;
using Oakrey.Guru.Adapter;

public class PingHandler : ReplayHandler<PingHandler, uint>
{
    public override ushort Id => 0x0000;
    public override Action<byte[]> Handler => HandlePingReply;

    public Task<uint> Execute(ITransmitter transmitter, SemaphoreSlim deviceLock, uint data, CancellationToken ct)
    {
        return Run(transmitter, deviceLock, BitConverter.GetBytes(data), ct);
    }

    private void HandlePingReply(byte[] data)
    {
        GuruException.ThrowIfInvalidDataCount(data);
        taskCompletionSource?.SetResult(BitConverter.ToUInt32(data, 0));
    }
}

// Usage
PingHandler ping = handlers.GetHandler<PingHandler>();
uint echo = await ping.Execute(transceiver, deviceLock, 0xDEADBEEF, CancellationToken.None);

Status-reply handler

Derive from StatusHandler<TSelf> when the device replies with a single Status byte. The base class decodes the byte and throws GuruException for any non-Ok result:

using Oakrey.Guru.Handlers;
using Oakrey.Guru.Adapter;

public class ResetHandler : StatusHandler<ResetHandler>
{
    public override ushort Id => 0x00FF;

    public Task<Status> Execute(ITransmitter transmitter, SemaphoreSlim deviceLock, CancellationToken ct)
    {
        return Run(transmitter, deviceLock, [], ct);
    }
}

// Usage - throws GuruException if device returns anything other than Status.Ok
Status result = await reset.Execute(transceiver, deviceLock, CancellationToken.None);

Push-based event handler

Derive from EventHandler<TSelf, TEvent> to expose an IObservable<TEvent> stream from incoming packets:

using Oakrey.Guru.Handlers;

public record ErrorEvent(uint TimeStamp, byte Id, int ErrorCode);

public class ErrorEventHandler : EventHandler<ErrorEventHandler, ErrorEvent>
{
    public override ushort Id => 0x0D0F;
    public override Action<byte[]> Handler => HandleEvent;

    private void HandleEvent(byte[] data)
    {
        GuruException.ThrowIfDataLengthIsInsufficient(data, 7);
        Publish(new ErrorEvent(
            BitConverter.ToUInt32(data, 1),
            data[5],
            data[6]));
    }
}

// Usage
ErrorEventHandler errorHandler = handlers.GetHandler<ErrorEventHandler>();
using IDisposable sub = errorHandler.Subscribe(e =>
    Console.WriteLine($"Error on channel {e.Id} at {e.TimeStamp}: {e.ErrorCode}"));

Handler collection

HandlerCollection manages all handlers for a device instance. Pass it the IObservable<ReceivedPacket> stream from ITransceiver.Received to route incoming packets:

using Oakrey.Guru.Handlers;
using Oakrey.Guru.Adapter;

HandlerCollection handlers = new();

// Wire incoming packets to the collection
using IDisposable routing = transceiver.Received.Subscribe(packet =>
{
    if (handlers.TryGetCommand(packet.CommandId, out IHandler? handler))
    {
        handler.ProcessReplay(packet.Data);
    }
});

// Lazy handler creation on first use
PingHandler ping = handlers.GetHandler<PingHandler>();

Development notes

  • Run in ReplayHandler acquires an AsyncLock over the supplied SemaphoreSlim before sending, ensuring one in-flight request per handler at a time.
  • The default reply timeout is 500 ms. It is set via the replyTimeout field in ReplayHandler; override it in a derived class if needed.
  • HandlerCollection.GetHandler<T>() requires T to have a public parameterless constructor. If a handler needs constructor arguments, use AddCommand directly.
  • Duplicate handler IDs throw ArgumentException from AddCommand � each ushort ID must be unique per collection instance.
  • EventHandler is IDisposable. Always dispose it (or the owning HandlerCollection) to complete the underlying Subject<TEvent>.

Project information

Author Oakrey
License MIT
Repository https://dev.azure.com/oakrey/OpenPackages/_git/Drivers
Project URL http://www.oakrey.cz/opkg_drivers_guru
Target framework net10.0-windows

License

This project is licensed under the MIT License. See the LICENSE file for details.

Contributing

Contributions are welcome! Feel free to open issues or submit pull requests to improve the package.

License

This project is licensed under the MIT License. See the LICENSE file for details.

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 (1)

Showing the top 1 NuGet packages that depend on Oakrey.Guru.Handlers:

Package Downloads
Oakrey.Guru.Base

Base device library for Oakrey Guru USB hardware devices. Provides DeviceBase, IDevice, and ILicense abstractions over the Guru packet protocol, including async firmware update from Intel HEX files, bootloader entry, multi-slot license key retrieval, and connection verification.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
4.0.4 0 5/22/2026
4.0.3 102 5/15/2026
4.0.2 101 5/14/2026
4.0.1 146 2/2/2026
4.0.0 130 1/7/2026
3.0.0 302 11/14/2025
2.1.0 264 6/18/2025
2.0.0 229 6/4/2025
1.0.0 286 4/17/2025