Skip to content

Modernize library, fix protocol and connection bugs (v2.0.0) - #1

Merged
archofthings merged 4 commits into
mainfrom
claude/wizardly-pasteur-xhktn2
Oct 1, 2026
Merged

archofthings merged 4 commits into
mainfrom
claude/wizardly-pasteur-xhktn2

Conversation

@archofthings

@archofthings archofthings commented Oct 1, 2026 •

Copy link
Copy Markdown
Owner

Summary

This brings the repository up to date: it fixes several real bugs in the Ethernet and serial protocol code, moves off the unsupported netcoreapp3.1, adds CI, and rewrites the README. The package version is bumped to 2.0.0 because a few public helpers became internal (details below)

Bug fixes

  • Ethernet read requests were malformed. ReadWordAsync and ReadBitAsync wrote the Length field as 1 byte instead of 2, which shifted the whole data block by one byte. Per the CIMON master frame layout (ID(9) · FrameNo(1) · Cmd(1) · Res(1) · Length(2) · Data · CheckSum(2)), read requests now use the same 2-byte length as writes.
  • Auto-connect failed after the first request. TcpSocket closed its socket after each request and then tried to reuse it, so with the default autoConnect: true every later call threw ObjectDisposedException. A new socket is now created for each connection.
  • Frame numbers didn't wrap correctly. After 128 requests the frame number stayed at 0 for the next 128 requests. It now cycles 0–127.
  • SerialSocket.ReceiveData could return a null task, which throws NullReferenceException when awaited.
  • Truncated or corrupted responses threw IndexOutOfRangeException. They're now validated (header, frame number, length and checksum) and return ResponseCode.WritingError.
  • Serial WriteWordAsync accepted up to 63 words, but the 2-character length field can only describe 61. Larger requests silently sent a wrong length and are now rejected.
  • Opening an already open SerialSocket threw an exception.

Improvements

  • Faster requests: responses are returned as soon as a complete frame arrives. Before, every request waited the full read timeout (1 s by default).
  • Connection handling:
    • A connection opened explicitly with Connect() now stays open. Only connections opened automatically are closed after the request.
    • Requests on one connector are sent one at a time, so a connector can be shared between tasks.
    • TcpSocket has an optional usePing parameter for networks that block ICMP.
    • Connectors and sockets implement IDisposable.
  • Refactoring: frame building and response handling are shared instead of copied into each of the 8 read/write methods.
  • Platforms: targets netstandard2.0 and net8.0 instead of the unsupported netcoreapp3.1, so the package also works on .NET Framework 4.6.1+.
  • Dependencies: removed Ardalis.GuardClauses. Its newer versions conflict with the custom extensions this project put in its namespace.
  • Packaging: dotnet pack used to fail on any machine but the author's because the package icon pointed to C:\Users\...\cimon_logo.png. Packing now works and includes the README and symbols.

Breaking changes

  • Tools and the guard extension methods are now internal.
  • The PlcConnector constructor is now protected PlcConnector(IPlcSocket socket, bool autoConnect), and the protected _timeout field was removed.
  • Serial WriteWordAsync accepts at most 61 words (was 63).

Tests and CI

  • Tests now run on .NET 10 with current versions of xUnit, the test SDK and coverlet.
  • The tests used async void, which in xUnit 2 can hide failures. They now use async Task.
  • Added 14 regression tests for the fixes above: frame numbering, the read frame layout, reconnecting after auto-disconnect, keeping explicit connections open, and truncated, corrupted and missing responses.
  • CI:
    • Replaced the two duplicate CodeQL workflows (still on v2 actions) with one current workflow.
    • Added a CI workflow that builds, tests and packs the library.

Docs

  • Rewrote the README:
    • NuGet, downloads, CI, CodeQL, framework and license badges
    • Quick start, API overview and connection handling
    • Memory type, response code and request limit tables
  • Added a LICENSE file (MIT, matching the package metadata) and a CHANGELOG.md.
  • Package URLs now point to archofthings/Cimon.Net.

Testing

  • dotnet build: no warnings for netstandard2.0 or net8.0
  • dotnet test: 149 passed, 0 failed
  • dotnet pack: the package is created, with the README and symbols
  • Not tested on a real CIMON PLC

Not changed, worth checking

Serial WriteBitAsync sends each bit as a raw 0x00/0x01 byte rather than the ASCII characters '0'/'1'. That's unusual for an ASCII protocol, but I couldn't confirm what the spec expects, so the behavior is unchanged.

claude added 4 commits October 1, 2026 18:12
Fixes:
- Ethernet read requests wrote a 1-byte Length field instead of 2 bytes
- TcpSocket reused a closed Socket, so auto-connect failed after the first request
- Frame number did not wrap correctly after 128 requests
- SerialSocket.ReceiveData could return a null Task
- Truncated/corrupt responses threw IndexOutOfRangeException
- Serial WriteWordAsync allowed word counts that overflow the length field

Improvements:
- Return as soon as a full frame arrives instead of always waiting the read timeout
- Keep explicitly opened connections open; serialize requests per connector
- Optional ping in TcpSocket, IDisposable on connectors and sockets
- Target netstandard2.0 and net8.0, drop Ardalis.GuardClauses, fix dotnet pack
- Update tests to net10.0 / current packages, use async Task tests, add regression tests
- Replace duplicate CodeQL workflows, add CI build/test/pack workflow

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DJd5JnXo2vuX9foBcTtgGQ
- Add NuGet, downloads, CI, CodeQL, target framework and license badges
- Restructure README with features, quick start, API overview, connection
  handling, address/memory type reference, response codes and limits
- Add MIT LICENSE file matching the package license

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DJd5JnXo2vuX9foBcTtgGQ
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DJd5JnXo2vuX9foBcTtgGQ
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DJd5JnXo2vuX9foBcTtgGQ
@archofthings
archofthings merged commit 39372ef into main Oct 1, 2026
1 check passed
@archofthings
archofthings deleted the claude/wizardly-pasteur-xhktn2 branch October 1, 2026 18:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants