TomNewChao commented on PR #2656:
URL: https://github.com/apache/plc4x/pull/2656#issuecomment-5103845018
> Now that I had the time to catch up with everything else after my holiday
yesterday, now I had the time to thorougly read your initial
message.在昨天假期过后,我有时间重新整理了一下其他的事情,现在我有时间仔细阅读了你们发来的原始消息。
>
> So the PLC4Net doesn't have to be identical to the Java version. It was
allways our goal to make the libratries feel natural in their normal ecosystem.
With Java we're using CompletableFutures, with Go we're using channels ...
whatever is the best way to do things in the target language.因此,PLC4Net 不必与
Java 版本完全相同。我们的目标始终是让这些库在各自的生态系统中能够自然融合。对于 Java 语言,我们使用 CompletableFutures;而对于
Go 语言,则使用通道……无论哪种方式都能达到目标语言的最佳效果。
>
> What we do try to keep, is the general usage pattern: So if connections
are synchronous in Java, it would sort of be bad if it wasn't in other
languages. Also if the naming of things was kept ... like the usage of "Tag"
and "Query" and that you can add a Tag or a TagString,
....我们努力保留的是这些通用的使用模式:如果在 Java
中连接是同步的,那么在其他语言中这种特性就可能会变得不好用。另外,如果能够保持一些命名规范的话……比如继续使用“Tag”和“Query”这样的命名方式,并且可以添加“Tag”或“TagString”这样的元素……
>
> Admittedly I don't quite understand what you mean with your first
divergence: "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." Could you please explain
that?诚然,我不太理解你所说的“第一次分歧”是什么意思。你的意思是:“ConnectionString 是 API 中的公共类型,而不是 SPI
中的类型。它没有任何 SPI 依赖关系,而位于 API 中的 PlcDriverManager 则需要使用它来配置协议代码。”请能解释一下这一点吗?
>
> I think when I did the first work on PLC4Net, I chose KNX as this used the
most of our mspec-functionality ... I thought if I get this driver working, the
rest will most probably also work. Usually when starting on a new language I
started with Modbus as this is the simplest one of them all for which a
test-bench is cheaply available. KNX also had this super odd encoding for 16
bit float which isn't really a full half-precision-iec float. In the new SPI3
java version, I think I used a dedicated float implementation:我记得在第一次开发 PLC4Net
项目时,我选择了 KNX 作为协议选择,因为 KNX 利用了我们 MSpec
功能的最多部分……我认为,如果我能让这个驱动程序正常工作,那么其他协议也很有可能会顺利实现。通常,在开始使用一种新的协议时,我会从 ModBus
开始尝试,因为 ModBus 是最简单的协议之一,相关的测试平台也很便宜。而 KNX 则采用了一种非常特殊的 16 位浮点�
��方式,实际上并不是真正的半精度 IEC 浮点编码。在新的 SPI3 Java 版本中,我认为我们使用了专门的浮点实现方式来处理这种编码问题。
>
> ```
> ['PDT_KNX_FLOAT' REAL
> [simple float 16 value floatEncoding='"KNXFloat"']
> ]
> ```
>
> The implementation is here:实施工作已经开始了:
plc4j/spi/buffers/byte/src/main/java/org/apache/plc4x/java/spi/buffers/bytebased/encoding/EncodingKnxFloat.java
>
> However, I built things in SPI3 so theoretically a protocol module could
bring along it's own Encoding implementation by putting the class in the driver
module and registering it via a
org.apache.plc4x.java.spi.buffers.bytebased.encoding.Encoding property
file.不过,我使用的是 SPI3 框架来构建应用程序。因此,理论上,一个协议模块可以通过在驱动模块中引入自己的编码实现,并通过
org.apache.plc4x.java.spi.buffers.bytebased.encoding.Encoding 属性文件来注册该编码实现。
>
> As you could see I never really got very far with the .Net version as the
person that claimed to want to help decided to go away. Usually my process was
that I hand wrote some types from Modbus in the target language, then I copied
the java templates and started adjusting them till the output matched the
hand-written one. the data-io template you found was simply one copied but
never touched by me as the work stopped before I had time to do
that.如您所见,那个.NET 版本的工作我并没有取得太大进展。那个声称愿意帮忙的人后来就离开了。通常我的工作流程是:先用目标语言手动编写一些 Modbus
协议的数据类型,然后复制 Java
模板,并不断调整它们,直到输出结果与手动编写的结果一致。您看到的那个数据输入输出模板就是直接复制过来的,但我并没有对其进行任何修改,因为在我完成之前,工作就停止了。
>
> As you saw on the discussion list, we're currently considering splitting
out Go and also creating go-native code generators. Possibly this is something
you would also like to do. Initially the idea was to have one system for
generating code. One system anyone would understand and maintaining would
therefore be easier. Also is it one thing to understand a programming language,
but it's a totally different thing to understand the tooling available in a
language, the best practices and how to nicely integrate this into a smoothly
running build. For java and maven we knew how to do this, for the others not so
much ;-) So the current template+maven approch was simply a quick win that we
knew how to do.正如你在讨论帖中看到的,我们目前正在考虑将 Go 语言分离出来,同时开发专门针对 Go
语言的代码生成工具。也许这也是你希望做的事情。最初的想法是建立一个统一的代码生成系统,这样大家就能更容易理解和维护
这个系统。不过,理解一种编程语言是一回事,而了解该语言提供的工具、最佳实践以及如何将它们很好地整合到流畅运行的构建过程中则是另一回事。对于 Java 和
Maven 来说,我们懂得如何做到这一点,但对于其他语言来说则不太容易哦;-)所以,目前采用模板+Maven 的方法只是我们能够成功实现的一个例子而已。
>
> However, have I found out with my own closed-source work, that there are
huge benefits for running this in a tool-native fashion ... then I guess only
the resolution of the protocol modules would need to be implemented and the
code-gen is built per language. The mspec format is documented in an Antlr4
grammar for which there should be tooling in most languages. The core mspec
format is described
here:不过,通过我自己使用开源框架进行开发的经验来看,以工具原生的方式来实现这一功能确实有着巨大的优势……我认为,只需要实现协议模块的相关功能,然后针对每种语言分别生成相应的代码即可。mspec
格式有相应的文档说明,它遵循 Antlr4 语法规范,因此大多数语言都应该有相应的工具来支持这种格式。关于 mspec 核心格式的描述可以在这里找到:
code-generation/protocol-base-mspec/src/main/antlr4/org/apache/plc4x/plugins/codegenerator/language/mspec/MSpec.g4代码
生成/协议基础 MSpec 源码目录结构如下: src/main/antlr4/ org/apache/plc4x/plugins/代码生成器/
language/MSpec/MSpec.g4 The expression syntax used in the little expression
blocks inside are documented here:这些小表达式块中使用的表达式语法在这里有详细说明:
code-generation/protocol-base-mspec/src/main/antlr4/org/apache/plc4x/plugins/codegenerator/language/mspec/expression/Expression.g4代码生成/协议基础
MSpec 源码目录结构如下: src/main/antlr4/ org/apache/plc4x/plugins/代码生成器 ->
language/MSpec -> expression/Expression.g4
>
> I hope I manged to answer your questions ... if not ... don't hesitate to
ask ... ideally here ... if it has to be quickly and you see I'm online in
Slack, just ask there.希望我已经回答了你的问题……如果没有回答到的话,请随时提问。如果情况需要快速处理,而且你看到我正在 Slack
上在线,那就直接在那里提问吧。
Thanks — knowing the goal is to make the libraries feel natural in their
normal
ecosystem while keeping the usage pattern and the naming settles several
things I
was unsure about. Let me answer your question first, then lay out where I
would
like to take this.
On the ConnectionString divergence — it does not hold up
The three states side by side:
(*) = the full connection-string parser
protocol code + transport code + host + port + query params + URL
decoding
(1) and (2) are the same shape. I broke that in (3).
What happened: I read "Uri cannot parse the whole s7:cotp://host form" —
which
is true, Host comes back empty and Port -1 — as "Uri cannot be used here"
the manager only ever needs the protocol code, and I had never checked what
Java
actually does there. Both behave identically:
java.net.URI System.Uri
scheme / host Scheme / Host
s7://192.168.0.1 s7 / 192.168.0.1 s7 / 192.168.0.1
s7:cotp://10.0.0.5:102 s7 / null s7 / ""
modbus-tcp://10.0.0.9:502?u=1 modbus-tcp / 10.0.0.9 modbus-tcp /
10.0.0.9
opcua:tcp://localhost:4840/milo opcua / null opcua / ""
Java has exactly the same limitation on the two-scheme form and lives with
it,
because DefaultPlcDriverManager only ever takes the scheme. So the thing I
treated as a blocker was never one.
Counting the consumers settles which module the type belongs in:
api/PlcDriverManager.cs:60 ConnectionString.Parse(..) 1 site <- the
line I added
spi/drivers/DriverBase.cs:83 ConnectionString parameter 3 sites <-
genuine; these
spi/drivers/DriverBase.cs:101 ConnectionString.Parse(..) need
transport code,
spi/drivers/DriverBase.cs:130 ResolveTransportCode(..) host,
port, params
Revert that one line and the type has no consumers left in the api module.
So it
moves down next to DriverBase and the manager goes back to Uri.Scheme. I will
fix that.
On the general approach
My intent throughout has been to follow how the Go and Java modules are u
the project keeps one consistent shape. Your point about the usage pattern
and
the naming is a fair hit — IPlcReadRequestBuilder still exposes
AddItem(name, fieldQuery), which is both the old "field" wording and missing
the Tag/TagString pair. I will align it with addTag/addTagAddress. Query I
would rather leave until there is browse support behind it — plc4net
currently
has no PlcBrowser and no browse request at all, so adding the type on its own
would be the name without the capability.
On KNX
I did not choose it, I inherited it — plc4net/drivers/knxnetip/src already
carries the generated model, so finishing that capability looked like the
first step. My own roadmap is different: Modbus, then S7, then OPC UA,
because
what I actually need is to reach PLCs from several vendors and feed them
into an
IoT platform. Your note that you normally start with Modbus matches where
heading anyway.
On tool-native code generation
I agree with building it per language. Each language has its own idioms,
tooling
and best practices, and a tool-native generator fits that far better than one
shared toolchain. Thanks for the two grammar pointers — I have looked at
them and
they seem very tractable from .NET, so the part left to work out is the
resolution of the protocol modules you mentioned.
Where I would like to go next
1. Get the CLA filed.
2. Start with Modbus and prove the path end to end.
3. Extend outwards to the protocols the PLCs I work with actually speak.
One request
This PR is really me probing for direction rather than proposing something
finished, and properly absorbing this project is going to take me a while
you consider creating a feature/plc4net branch I could target instead of
develop? contributing.adoc already describes feature branches with that
prefix, and it would let this land in reviewable increments without any o
touching the 1.0.0 release — which I think also answers @sruehl's question
above.
Happy to work that way if it suits you.
--
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]