diff --git a/StgSharp.Device/ICommand.cs b/StgSharp.Device/ICommand.cs new file mode 100644 index 00000000..bae62457 --- /dev/null +++ b/StgSharp.Device/ICommand.cs @@ -0,0 +1,8 @@ +namespace EM.LowLevel +{ + /// + /// Marker interface for command types that can be built into bytes by an ICommandBuilder. + /// Implement this on record/struct command shapes. + /// + public interface ICommand { } +} diff --git a/StgSharp.Device/ICommandBuilder.cs b/StgSharp.Device/ICommandBuilder.cs new file mode 100644 index 00000000..396f7ea1 --- /dev/null +++ b/StgSharp.Device/ICommandBuilder.cs @@ -0,0 +1,30 @@ +namespace EM.LowLevel +{ + /// + /// Builds device/peripheral commands from C#-friendly types (enums, records, structs, etc.). + /// + public interface ICommandBuilder + { + + /// + /// Build a command payload (already framed or raw depending on implementation contract) from a + /// strongly-typed command description. + /// + /// + /// Command type (e.g., an enum or a record/struct) + /// + /// + /// Command value to build + /// + /// + /// Command bytes + /// + ReadOnlyMemory Build(TCommand command) where TCommand: notnull; + + /// + /// Try-build variant to avoid throwing and allow buffer reuse strategies. + /// + bool TryBuild(TCommand command, out ReadOnlyMemory bytes) where TCommand: notnull; + + } +} diff --git a/StgSharp.Device/IDataDecoder.cs b/StgSharp.Device/IDataDecoder.cs new file mode 100644 index 00000000..ae834d8a --- /dev/null +++ b/StgSharp.Device/IDataDecoder.cs @@ -0,0 +1,29 @@ +namespace EM.LowLevel +{ + /// + /// Decodes device-specific binary responses into C#-friendly models. + /// + public interface IDataDecoder + { + + /// + /// Decode a response of a known type into a model. + /// + /// + /// Target model type + /// + /// + /// Raw or deframed payload depending on transport contract + /// + /// + /// Decoded model + /// + TModel Decode(ReadOnlySpan payload); + + /// + /// Try-decode variant to avoid throwing on partial/bad frames. + /// + bool TryDecode(ReadOnlySpan payload, out TModel model); + + } +} diff --git a/StgSharp.Device/IPortController.cs b/StgSharp.Device/IPortController.cs new file mode 100644 index 00000000..53e47ff3 --- /dev/null +++ b/StgSharp.Device/IPortController.cs @@ -0,0 +1,54 @@ +using System.Threading; +using System.Threading.Tasks; + +namespace EM.LowLevel +{ + /// + /// Generic high-level controller that composes a PortStream, an ICommandBuilder and an + /// IDataDecoder to provide a complete peripheral control workflow. + /// + /// + /// Concrete transport deriving from PortStream + /// + /// + /// Concrete command builder + /// + /// + /// Concrete data decoder + /// + public interface IPortController where TPort: PortStream where TBuilder: ICommandBuilder + where TDecoder: IDataDecoder + { + + TBuilder CommandBuilder { get; } + + TDecoder Decoder { get; } + + TPort Port { get; } + + /// + /// Close the underlying port. + /// + void Close(); + + /// + /// Ensure the underlying port is opened and ready (delegates to Port.OpenAsync). + /// + ValueTask OpenAsync(CancellationToken cancellationToken = default); + + /// + /// Build a command, send it via the port and decode the response into a model. + /// + ValueTask RoundTripAsync( + TCommand command, + CancellationToken cancellationToken = default) + where TCommand: notnull; + + /// + /// Build a command and send it without expecting a typed response. + /// + ValueTask WriteAsync(TCommand command, CancellationToken cancellationToken = default) + where TCommand: notnull; + + } +} diff --git a/StgSharp.Device/IResponse.cs b/StgSharp.Device/IResponse.cs new file mode 100644 index 00000000..5a9cc3a2 --- /dev/null +++ b/StgSharp.Device/IResponse.cs @@ -0,0 +1,7 @@ +namespace EM.LowLevel +{ + /// + /// Marker interface for decoded response models returned by IDataDecoder. + /// + public interface IResponse { } +} diff --git a/StgSharp.Device/PortStream.cs b/StgSharp.Device/PortStream.cs new file mode 100644 index 00000000..ecdc31c0 --- /dev/null +++ b/StgSharp.Device/PortStream.cs @@ -0,0 +1,35 @@ +using System; +using System.IO; +using System.Threading; +using System.Threading.Tasks; + +namespace EM.LowLevel +{ + /// + /// High-level transport abstraction for device communication. Derives from Stream and + /// encapsulates initialization/handshake and frame (header/tail/checksum) handling as needed + /// by the device. Implementations may wrap SerialPort, Sockets, USB, etc. + /// + public abstract class PortStream : Stream + { + + /// + /// Optional bytes available hint if the transport can provide it. + /// + public virtual long? BytesAvailable => null; + + /// + /// Close the underlying transport and release resources. + /// + public abstract override void Close(); + + /// + /// Ensure the port is opened and ready. Idempotent. May perform device-specific + /// handshakes. + /// + public abstract ValueTask OpenAsync(CancellationToken cancellationToken = default); + + // Concrete transports must implement Stream's abstract members. + // Seek-related members are typically not supported and should throw NotSupportedException. + } +}