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
<PackageReference Include="Oakrey.Guru.Handlers" Version="4.0.4" />
<PackageVersion Include="Oakrey.Guru.Handlers" Version="4.0.4" />
<PackageReference Include="Oakrey.Guru.Handlers" />
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.4
#tool nuget:?package=Oakrey.Guru.Handlers&version=4.0.4
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,CancellationTokensupport, andTaskCompletionSource-based response correlationEventHandler<TSelf, TEvent>� typed push-based event stream viaIObservable<TEvent>backed by an RxSubject<TEvent>StatusHandler<TSelf>� specialisedReplayHandlerthat decodes a one-byteStatusresponse and throwsGuruExceptionon non-OK resultsHandlerCollection� thread-safe dictionary keyed byushortpacket ID; lazy-creates handlers on first access viaGetHandler<T>()GuruException� domain exception with static guard helpers (ThrowIfDataLengthMismatch,ThrowIfDataLengthIsInsufficient,ThrowIfInvalidDataCount)Statusenum � 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
- .NET 10.0 (Windows)
- Oakrey.Guru.Adapter >= 4.0.1
- Oakrey.Async >= 2.0.0
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
RuninReplayHandleracquires anAsyncLockover the suppliedSemaphoreSlimbefore sending, ensuring one in-flight request per handler at a time.- The default reply timeout is 500 ms. It is set via the
replyTimeoutfield inReplayHandler; override it in a derived class if needed. HandlerCollection.GetHandler<T>()requiresTto have a public parameterless constructor. If a handler needs constructor arguments, useAddCommanddirectly.- Duplicate handler IDs throw
ArgumentExceptionfromAddCommand� eachushortID must be unique per collection instance. EventHandlerisIDisposable. Always dispose it (or the owningHandlerCollection) to complete the underlyingSubject<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.
- Project URL: Project Website
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 | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0-windows7.0 is compatible. |
-
net10.0-windows7.0
- Oakrey.Async (>= 2.1.0)
- Oakrey.Guru.Adapter (>= 4.0.5)
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.