Files
DP44/enriched-qwen3-coder-next/Common/DTS.Common.IConnection/SerialConnection.md
2026-04-17 14:55:32 -04:00

9.1 KiB
Raw Blame History

source_files, generated_at, model, schema_version, sha256
source_files generated_at model schema_version sha256
Common/DTS.Common.IConnection/SerialConnection/SerialConnection.cs
2026-04-16T02:09:02.781823+00:00 Qwen/Qwen3-Coder-Next-FP8 1 4992256eaf51da73

SerialConnection

Documentation: SerialConnection Class


1. Purpose

The SerialConnection class provides a serial portbased implementation of the IConnection interface, enabling asynchronous I/O operations over a system serial port (System.IO.Ports.SerialPort). It wraps the .NET SerialPort class to expose standard connection semantics (connect, disconnect, send, receive) using the asynchronous programming model (APM) and Task-based wrappers. Despite implementing methods like SoftConnect, SoftDisconnect, Bind, Listen, and Accept, the class does not support soft disconnection or server-side listening—those methods are stubs or throw exceptions when misused. Its primary role is to allow serial communication to be used interchangeably with other connection types (e.g., TCP) via the IConnection abstraction.


2. Public Interface

All methods and properties are part of the public API unless explicitly marked protected.

Member Signature Description
IsSoftDisconnected public bool IsSoftDisconnected { get; private set; } Always false. Not used for serial connections.
SoftConnect() public void SoftConnect() No-op. Comment notes: "does nothing for serial as we don't have a soft disconnect option yet."
SoftDisconnect() public void SoftDisconnect() No-op. Comment notes: "does nothing for serial as we don't have a soft disconnect option yet."
KeepAliveErrorReceived() void IConnection.KeepAliveErrorReceived() Explicit interface implementation; no-op.
Create(string connectString, string hostIPAddress) public void Create(string connectString, string hostIPAddress) No-op. Does not assign connectString.
GetConnectionData() public string GetConnectionData() Returns "".
GetCurrentDownloadRate() public double GetCurrentDownloadRate() Returns 0D.
GetCurrentUploadRate() public double GetCurrentUploadRate() Returns 0D.
OnDisconnected public event EventHandler OnDisconnected Event declared but never raised.
Connected public bool Connected { get; } Always false. Not updated on connect.
ConnectString public string ConnectString => _PortName Returns the last-assigned port name (e.g., "COM3").
Flags public System.Net.Sockets.SocketFlags Flags { get; set; } Property inherited from IConnection; unused (no socket semantics).
Create(string PortName) public void Create(string PortName) Initializes Port with _PortName (note: bug—see Gotchas). Sets _PortName = PortName.
BeginConnect(...) public IAsyncResult BeginConnect(AsyncCallback cb, object state) Opens the SerialPort. Throws if Port == null or _PortName is null/empty. Returns null.
EndConnect(...) public void EndConnect(IAsyncResult ar) No-op. Throws if Port == null.
BeginDisconnect(...) public IAsyncResult BeginDisconnect(bool reuseSocket, AsyncCallback cb, object state) No-op. Throws if Port == null. Returns null.
EndDisconnect(...) public void EndDisconnect(IAsyncResult asyncResult) No-op. Throws if Port == null.
BeginAccept(...) public IAsyncResult BeginAccept(AsyncCallback callback, Object state) Throws if Port == null. Returns null.
EndAccept(...) public IConnection EndAccept(IAsyncResult asyncResult) Returns a new SerialConnection instance (uninitialized—no Port created). Throws if Port == null.
Bind(int port) public void Bind(int port) No-op. Throws if Port == null.
Listen(int backlog) public void Listen(int backlog) No-op. Throws if Port == null.
BeginSend(...) public IAsyncResult BeginSend(byte[] buffer, int offset, int size, AsyncCallback cb, object state) Delegates to SerialPort.BaseStream.BeginWrite(...). Throws if Port == null or cb == null.
EndSend(...) public int EndSend(IAsyncResult ar) Calls SerialPort.BaseStream.EndWrite(ar). Returns Port.BytesToWrite. Throws if Port == null.
SendAsync(...) public Task<int> SendAsync(byte[] sendBuffer, int bufferStartOffset, int bufferSizeToSend) Wraps BeginSend/EndSend using Task.Factory.FromAsync.
BeginReceive(...) public IAsyncResult BeginReceive(byte[] buffer, int offset, int size, AsyncCallback cb, object state) Delegates to SerialPort.BaseStream.BeginRead(...). Throws if Port == null or cb == null.
EndReceive(...) public int EndReceive(IAsyncResult ar) Calls SerialPort.BaseStream.EndRead(ar). Throws if Port == null.
Dispose() public void Dispose() Calls Dispose(true) and suppresses finalization.
~SerialConnection() ~SerialConnection() Finalizer calls Dispose(false).
Dispose(bool) protected virtual void Dispose(bool disposing) Closes and nulls Port if disposing is true. Sets disposed = true.

Note

: The class implements IDisposable. Connected is never set to true, and OnDisconnected is never invoked.


3. Invariants

  • Connected is always false. It is a read-only property initialized to false and never modified.
  • _PortName is set only via Create(string PortName). ConnectString returns _PortName.
  • Port is only initialized in Create(string PortName) and EndAccept(...). In the latter case, the new SerialConnection instance has Port == null.
  • BeginConnect is the only method that actually opens the serial port (Port.Open()). No other method affects port state.
  • EndSend returns Port.BytesToWrite, which reflects the number of bytes still pending in the transmit buffer—not bytes sent.
  • SoftConnect, SoftDisconnect, Bind, Listen, and BeginAccept/EndAccept are not functional for serial connections and may throw if Port == null.
  • IsSoftDisconnected is always false and unused.

4. Dependencies

  • Depends on:

    • DTS.Common.Interface.Connection (via IConnection interface).
    • System.IO.Ports (for SerialPort).
    • System.Threading.Tasks (for Task<int>).
    • System (for EventHandler, AsyncCallback, IAsyncResult, Exception).
  • Depended on by:

    • Unknown from source alone. Presumably used by higher-level connection-handling logic that consumes IConnection.

5. Gotchas

  • Critical Bug in Create(string PortName):

    Port = new SerialPort(_PortName); // ❌ Uses uninitialized _PortName
    _PortName = PortName;             // ✅ Sets _PortName *after* use
    

    The SerialPort constructor is called with _PortName, which is null at that point. Should be new SerialPort(PortName).

  • Connected is never updated:
    Even after BeginConnect succeeds, Connected remains false. Consumers cannot rely on this property.

  • OnDisconnected is never raised:
    The event is declared but never invoked—even during Dispose or Port.Close().

  • EndAccept returns an uninitialized SerialConnection:
    The new instance has Port == null, so calling BeginConnect/Send/Receive on it will throw.

  • SoftConnect/SoftDisconnect are no-ops:
    Despite being part of IConnection, they do nothing. Do not expect disconnection behavior from them.

  • BeginDisconnect/EndDisconnect do not close the port:
    Only Dispose closes the SerialPort. EndDisconnect is a no-op.

  • GetCurrentDownloadRate() / GetCurrentUploadRate() always return 0D:
    No actual rate tracking is implemented.

  • Flags property is unused:
    It is a SocketFlags property (from IConnection) but serial ports do not use socket flags.

  • BeginSend/BeginReceive use SerialPort.BaseStream:
    This is correct for async I/O, but note that SerialPort.BaseStream is synchronous under the hood—performance may be suboptimal for high-throughput scenarios.

  • No validation of PortName in Create:
    Invalid port names (e.g., "COM999") will only fail at Port.Open() in BeginConnect.

  • ConnectString is misleading:
    It holds only the port name (e.g., "COM3"), not a full connection string. Also, the overload Create(string connectString, string hostIPAddress) ignores connectString.

  • disposed flag prevents double-dispose:
    Safe, but Port may be null after first dispose—subsequent Dispose calls are no-ops.

  • No exception handling in BeginConnect/EndConnect:
    Exceptions from Port.Open() (e.g., UnauthorizedAccessException, IOException) propagate directly.

  • No cancellation support:
    All async methods lack CancellationToken support.

  • EndSend returns BytesToWrite:
    This is the number of bytes remaining in the output buffer—not bytes sent. Likely a mistake; should be bytes written (which is implicit in EndWrites return value, but EndSend discards it and returns BytesToWrite instead).