如何在 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 BasicType
或 Reference 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 发布。
假设我有一个抽象功能块 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 BasicType
或 Reference 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 发布。