TomNewChao opened a new pull request, #2656:
URL: https://github.com/apache/plc4x/pull/2656

   Revives `plc4net`, which the README currently lists as *"not ready for usage 
- abandoned"*, to the point where it builds on all three platforms, has an 
executing test suite, and has a driver runtime aligned with SPI3.
   
   Relates to #2655. Follows the `dev@` thread from 2026-07-24 where Christofer 
suggested a draft PR as the way to get started.
   
   ## This is a draft — I am asking for direction, not for a merge
   
   It is deliberately larger than a normal PR because it is the whole picture 
of where the port stands. I would rather show it once and be told "this shape 
is wrong" than land five PRs in the wrong shape. Once the direction is 
confirmed I am happy to split it into merge-sized pieces in whatever grouping 
you prefer.
   
   **The single most useful thing you can tell me is the answer to the 
generator question at the bottom.**
   
   ## Reviewing this
   
   The six commits are independent and each stands alone. Reviewing commit by 
commit is much easier than reviewing the combined diff.
   
   | Commit | Change | Size |
   |---|---|---|
   | `fade923` | Retarget `net452` → `net8.0`; hoist shared properties into 
`Directory.Build.props`; add `Microsoft.NET.Test.Sdk` | 61+/37− |
   | `d3b4632` | Make `IPlcValue` dispatch reach the concrete value types; add 
missing accessors | 466+/148− |
   | `f95f216` | Replace `Ayx.BitIO` with an in-house `BitReader`/`BitWriter`; 
repair `ReadBuffer`/`WriteBuffer`; fix `ParseException` | 693+/146− |
   | `76cfe5b` | Add `.github/workflows/dotnet-platform.yml` 
(ubuntu/macos/windows) | 120+ |
   | `7285a3f` | Align the API with SPI3: `PlcField` → `PlcTag`, synchronous 
`Connect`, `ConnectionString` | 322+/177− |
   | `7486c4d` | Implement the driver runtime and a TCP transport | 2082+ |
   
   ### Why each one is needed
   
   **`fade923` — net8.0.** `net452` builds fine on Windows but cannot build on 
Linux or macOS runners, which is why plc4net was never in the CI matrix. This 
commit also adds `Microsoft.NET.Test.Sdk` to the test projects; without it the 
suites compiled but **never executed**. That single omission is why everything 
below went unnoticed.
   
   **`d3b4632` — the value model was dead through its own interface.** 
Subclasses declared `public new bool GetBool()` rather than `override`. In C# 
`new` is compile-time name hiding and does not participate in virtual dispatch, 
so a caller holding an `IPlcValue` — which is how the API hands values out — 
landed on `PlcValueAdapter`'s defaults. `((IPlcValue) new 
PlcDINT(42)).GetInt()` returned `0`. `PlcBOOL`, `PlcSTRING`, `PlcCHAR`, 
`PlcWCHAR` and `PlcWSTRING` additionally stored a value but never exposed it at 
all.
   
   **`f95f216` — the bit codec.** `Ayx.BitIO` is net45-only and unmaintained 
since 2016; internally it round-trips reads through a `StringBuilder` of 
`'0'`/`'1'` characters and throws on a 32-bit field, so plc4net could not read 
a float. It is replaced with an MSB-first `BitReader`/`BitWriter` (~240 lines, 
no dependencies). Fixing the codec then exposed the layer above it: 
`ReadUlong`/`ReadLong` consumed `2*bitLength-32` bits, 
`WriteFloat`/`WriteDouble` passed arguments in the wrong order, the 16-bit 
float branch was an empty block, `ReadDouble(32)` always threw, and 
`ReadString`/`ReadByteArray`/`WriteString` were `NotImplementedException`. 
`ParseException` did not derive from `Exception`.
   
   The KNX DPT 9.x 16-bit format is implemented explicitly rather than as 
IEEE-754 half. One test documents that the format is coarse at the top of its 
range (step 327.68 at exponent 15) so the next person does not read it as a 
rounding bug.
   
   **`7285a3f` — SPI3 alignment.** `PlcField` → `PlcTag`, `ConnectAsync` → 
synchronous `Connect`, and a `ConnectionString` parser whose grammar is 
character-for-character the Java `DriverBase.URI_PATTERN`.
   
   **`7486c4d` — the driver runtime.** `DriverBase` (connection-string 
dispatch, transport selection, supported-transport enforcement), 
`ConnectionBase`, `MessageCodecBase<T>`, the transport abstraction, and a TCP 
transport.
   
   ## Relationship to the Java SPI3 contracts
   
   | plc4net | plc4j |
   |---|---|
   | `spi/drivers/DriverBase.cs` | 
`plc4j/spi/drivers/.../spi/drivers/DriverBase.java` |
   | `spi/drivers/MessageCodecBase.cs` | 
`plc4j/spi/drivers/.../spi/drivers/MessageCodecBase.java` |
   | `spi/transports/ITransportInstance.cs` | 
`plc4j/transports/api/.../spi/transports/api/TransportInstance.java` |
   | `api/api/ConnectionString.cs` | `DriverBase.URI_PATTERN` plus parameter 
parsing |
   
   ### Four places I deliberately diverged
   
   Flagging these because they are the most likely thing to be objected to, and 
I would rather discuss them than have them found in review.
   
   1. **`ConnectionString` is a public type in the API, not the SPI.** It has 
no SPI dependency, and `PlcDriverManager` — which lives in the API — needs it 
to route the protocol code.
   2. **Getters became C# properties** (`IsOpen`, `ProtocolCode`). .NET 
convention.
   3. **`ITransportInstance` extends `IDisposable`.** .NET resource convention; 
enables `using`.
   4. **The TCP read loop is `async`/`await`, not a virtual thread.** .NET has 
no virtual threads; the async socket path is the equivalent.
   
   If you would rather have a literal transliteration of the Java API, say so 
and I will change these — but the .NET ecosystem expectations argued for the 
above.
   
   ## What is not here
   
   - **Generated code has no parse/serialize** — see the question below. This 
is the reason there is still no real driver.
   - No request/response correlation or timeouts.
   - Only a TCP transport. No UDP, serial, TLS, or COTP (S7 needs COTP).
   - Request builders are interfaces only; no implementations yet.
   - No tag-address parsing framework.
   - KNXnet/IP is still generated models only, not a driver.
   
   ## Verification
   
   - `dotnet build plc4net/plc4net.sln` — 0 errors, 0 warnings
   - `dotnet test plc4net/plc4net.sln` — 77 passing (76 SPI, 1 KNX)
   - The C# generator was re-run against `knxnetip.mspec`; output is 
byte-for-byte identical to the checked-in `.cs`, so this PR does not drift from 
the protocol descriptions
   
   Value-model tests assert exclusively through `IPlcValue` rather than the 
concrete types. That is deliberate: the `new`/`override` defect was invisible 
to tests bound to concrete types and only visible through the interface.
   
   CI is the one thing I cannot verify from here — `dotnet-platform.yml` has 
never run in this repository's environment. If it fails I will fix it on the 
branch.
   
   ## The question I would most like answered
   
   `CsLanguageOutput.getComplexTypeTemplates()` registers only 
`model-template.cs.ftlh`. An `io-template.cs.ftlh` exists beside it but is not 
registered, and its body is still verbatim Java (`implements MessageInput<>`, 
`@Override`, `throws ParseException`). So generating a protocol for C# yields 
data classes and nothing that can parse or serialize a frame.
   
   Java has since moved to the code-based generators under 
`org.apache.plc4x.codegeneration.language.java`; go, c and python are still on 
freemarker.
   
   **Should C# stay on freemarker and get a real `io-template.cs.ftlh`, or 
follow Java to a code-based generator?**
   
   I will do either. If freemarker is acceptable as an interim, I would start 
with a minimal KNXnet/IP round-trip as proof — which doubles as the 
specification for a code-based generator later, so neither path wastes the 
other's work.
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to