![]() |
VOOZH | about |
dotnet add package Oakrey.Guru.Handlers --version 4.0.4
NuGet\Install-Package Oakrey.Guru.Handlers -Version 4.0.4
<PackageReference Include="Oakrey.Guru.Handlers" Version="4.0.4" />
<PackageVersion Include="Oakrey.Guru.Handlers" Version="4.0.4" />Directory.Packages.props
<PackageReference Include="Oakrey.Guru.Handlers" />Project file
paket add Oakrey.Guru.Handlers --version 4.0.4
#r "nuget: Oakrey.Guru.Handlers, 4.0.4"
#:package Oakrey.Guru.Handlers@4.0.4
#addin nuget:?package=Oakrey.Guru.Handlers&version=4.0.4Install as a Cake Addin
#tool nuget:?package=Oakrey.Guru.Handlers&version=4.0.4Install as a Cake Tool
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.
ReplayHandler<TSelf, TReply> � async request/reply command with 500 ms timeout, CancellationToken support, and TaskCompletionSource-based response correlationEventHandler<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 resultsHandlerCollection � 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, FalseclassDiagram
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
}
dotnet add package Oakrey.Guru.Handlers
Or via Package Manager Console:
Install-Package Oakrey.Guru.Handlers
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);
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);
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}"));
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>();
Run in ReplayHandler acquires an AsyncLock over the supplied SemaphoreSlim before sending, ensuring one in-flight request per handler at a time.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.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>.| 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 |
This project is licensed under the MIT License. See the LICENSE file for details.
Contributions are welcome! Feel free to open issues or submit pull requests to improve the package.
This project is licensed under the MIT License. See the LICENSE file for details.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0-windows7.0 net10.0-windows7.0 is compatible. |
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. |
This package is not used by any popular GitHub repositories.