在TwinCAT和CodeSys IEC-61131编程环境中,可以使用VAR_INPUT
作为类型规范声明POU INTERFACE
。我相信TwinCAT和CoDeSys对接口的支持是对标准IEC-61131语言定义的扩展。
问题1:调用POU时,接口VAR_INPUT
是否具有传递值(即在每次执行FB时复制输入FB的状态)或传递引用语义?
问题2:在哪里指定或记录此行为?
答案 0 :(得分:1)
接口类型本身是一个值,但是它不包含它所引用的功能块。它被实现为指向实例的vtable-pointer的指针。如果它是对实现接口的功能块的引用,则使用它,但是返回的地址是功能块的地址 NOT (这是关键的区别)。那是因为实现了:
FB Instance
|
interface (PVOID) ------+ * PVOID vtable 1 +----> VTABLE 3
+------> * PVOID vtable 2 -----+ |
* ... * method 1
* PVOID vtable n * ...
* data fields * method m
因此,如果您读取接口的内容,则会在功能块实例内的某个位置获得一个地址,该地址就是该实例内vtable指针的地址。特定的vtable是实现接口方法(即与接口兼容)的那个。
对于某些类型的FB_MyFB,我们可以检查是否是如此:
INTERFACE I_Derived EXTENDS __SYSTEM.QueryInterface
END_INTERFACE
FUNCTION_BLOCK FB_MyFB IMPLEMENTS I_Derived
...
END_FUNCTION_BLOCK
FUNCTION F_CheckInterfaceRange(fb : REFERENCE TO FB_MyFB) : BOOL
VAR
ifc : I_Derived := fb;
ifcval : POINTER TO PVOID := ADR(ifc);
END_VAR
ifcval := ifcval^;
F_CheckInterfaceRange :=
ifcval >= ADR(fb)
AND_THEN ifcval <= (ADR(fb) + SIZEOF(FB_MyFB) - SIZEOF(PVOID));
END_FUNCTION
似乎不可能直接获取实例的地址。这很可能是一个任意限制:所有vtable指针都必须是有效的,并且可能属于某个内存区域,因此您可以想象从指向该接口的任何地方开始,然后从该接口向后走,直到停止获取有效的指针为止。这些就是界限。该实例以vtable指针开头,因此您将找到其中一个指针。然后检查指针在各种库FB类型的实例中的外观,然后查看指向vtables的外观,我确定会弹出一些有效的启发式方法,甚至可能不及{{1 }}。 CoDeSys 3代码生成器非常糟糕。
支持的方法是让FB实现扩展__QUERYINTERFACE
的接口。然后,使用SYSTEM.__QueryInterface
访问该接口以获取FB的__QUERYPOINTER
的值。
您可以想象THIS
看起来像:
__QUERYPOINTER
FUNCTION __QUERYPOINTER
VAR_INPUT
ifc : __SYSTEM.QueryInterface;
ptr : REFERENCE TO PVOID;
END_VAR
ptr := ifc.__QUERYTHIS();
END_FUNCTION
接口实现了一种在FB实现的接口之间强制转换的方法,只要这两个接口都从__SYSTEM.QueryInterface
派生,还可以实现一种方法(将其称为__SYSTEM.QueryInterface
)返回__QUERYTHIS
。
该方法由编译器生成。
想象其余的实现有点像:
THIS
您可以类似地实现INTERFACE __SYSTEM.QueryInterface
PROPERTY _This_ : POINTER TO BYTE
METHOD _This__GET : POINTER TO BYTE // that's how CoDeSys 3 implements getters/setters
END_PROPERTY
...
END_INTERFACE
FUNCTION BLOCK FB_Queryable IMPLEMENTS I_Queryable
PROPERTY _This_ : POINTER TO BYTE
METHOD _This__GET : POINTER TO BYTE
_This_GET := THIS;
END_METHOD
END_FUNCTION_BLOCK
(这并不容易,因为F_QueryInterface
从编译器获得帮助):
__QUERYINTERFACE
答案 1 :(得分:0)