如何在 codesys/twincat3 中传递扩展类型的数组?

How do I pass an array of an extended type in codesys/twincat3?

假设我有一个抽象功能块 AValve,我为各种类型的阀门进行了扩展。我扩展了 AValve 以便将其实现为 BasicValve。我还有一个函数块,它接受一个 AValve 的数组,看起来像这样

FUNCTION_BLOCK ValveDispatch
VAR_IN_OUT
   valves : ARRAY[*] OF AVALVE;
END_VAR

如果我尝试将 BasicValve 的数组传递到此功能块中,我会遇到:

Cannot convert type 'ARRAY [0..5] OF BasicValve' to type 'ARRAY [*] OF AVALVE' of VAR_IN_OUT 'valves'

考虑到 codesys 可能无法同时处理扩展类型和可变长度数组,我尝试将设置长度数组作为输入,只是为了测试,因为我需要可变长度。这样做会给出一个略有不同的错误,但似乎意思相同:

Type `ARRAY[0..5] of BasicValve' is not equal to type 'ARRAY [0..5] OF AVALVE' of VAR_IN_OUT 'valves'

有什么方法可以让我完成这项工作吗?将单个扩展对象传递到期望其基本类型的输入中工作正常,但似乎不支持使用数组这样做。

简短的回答:使用 Var_In_Out 这是不可能的。 Var_in_out 是一种引用调用。在 TwinCAT 中,引用始终具有严格的类型绑定。

我的第一个方法是使用一个简单的接口指针来解决这个问题var_input。该界面包含您移交的字段的大小和类型(Array[*] 也是如此)。但是我不确定派生的接口指针是否允许切换。也许你必须交出基础接口并手动在某处与__TCQUERYINTERFACE进行接口转换。

我要在这里添加一个我自己的问题的答案,但暂时不要接受它以防有人泄露秘密,哈哈。

基本上,据我所知,将 Array of Derived Type 传递给 Array of BasicType 的模式根本不受支持。通过 VAR_IN_OUT 或其他输入类型。您甚至不能将一个分配给另一个。最好的我可以告诉 Codesys 在将数组相互比较时不尊重继承,但如果您将数组的特定索引与 object 进行比较,则会这样做。我提出了两个我不喜欢但应该可行的解决方法。

如果要传递接口,则可以在调用函数块的 header 中构建数组,如下所示:

VAR
aFB : ARRAY[0..2] of ExtendedFB;//implements IExtended, which extends IBasic
aInterface : ARRAY[0..2] OF IBasic := [aFB[0], aFB[1],aFB[2]];
END_VAR

当涉及到扩展的 fb 而不是接口时,这将不太有效。在那种情况下我不得不使用指针,像这样:

VAR
aFB: ARRAY[0..2] of ExtendedFB;//extends AbstractFB
apFB : Array[0..2] of Pointer to AbstractFB := [ADR(afb[0]), ADR(afb[1]), ADR(afb[2])];
END_VAR

TL;DR 无需将 Array of ExtendedType 传递到期望 Array of BasicTypeReference to Array of BasicType 的输入中,您可以使用 ExtendedType objects 并传递它,编译器不会抱怨。不幸的是,如果不使用接口,你就会被指针所困,因为你不能在不实例化它们的情况下创建功能块数组。

您看到的问题实际上归结为一个非常简单的问题,数组是值数据类型

也就是说,当您试图通过 VAR_IN_OUT 传递 ARRAY [*] OF FB_Ext 时,您实际上正在做的是创建一个全新的数据类型 ARRAY [*] OF FB_Ext,它不会扩展 ARRAY [*] OF FB_Base.

如果您在 ST 的位级别查看数组,问题就会变得非常清楚,数组本身的大小为 ElementSize * ElementCount,因此尝试将更大的数据类型 FB_Ext 强制放入FB_Base 的较小数据空间如果不弄乱一切就无法工作。

因此您将不得不使用指针或接口来进行此处理。


TLDR: 你想做的事在 ST 中是不可能的。

所以这本来是要评论的,但是有点超出了大小限制。改为作为 wiki 发布。