FB无法扩展时如何访问VAR_IN_OUT变量?

how to access VAR_IN_OUT variable when FB cannot be extended?

我一直在尝试访问 AXIS_REF_SM3,即 SM3_Basic.MC_MoveAbsoluteAxis,以便 return 轴的 wDriveId

由于 Axis 被声明为 VAR_IN_OUT 变量,我无法使用 .Axis 语法在 FB 外部访问它,因为它会导致编译器抛出

C0178:  No external access to VAR_IN_OUT parameter 'Axis' of 'MC_MOVEABSOLUTE'."

错误是有道理的,因为 VAR_IN_OUT 变量不应该可以远程访问。

然后我尝试用 FUNCTION_BLOCK FB_MoveAbsolute EXTENDS SM3_Basic.MC_MoveAbsolute 扩展 FB 并将我自己的方法写入 return PRG 调用 FB_MoveAbsolute 中的 Axis 但我得到以下信息编译器错误

C0283:  Function block 'FB_MoveAbsolute': No override possible on Method MC_MoveAbsolute.FB_Init with access specifier FINAL

相反。

有人知道从 SM3_Basic.MC_MoveAbsolute 获取 AxiswDriveId 值的更好方法吗?
或者其他检查 FB 使用哪个轴的方法?

您可以尝试对功能块进行包装:

FUNCTION_BLOCK FINAL FinalBlock
VAR_IN_OUT
    someVar: DINT;
END_VAR
FUNCTION_BLOCK Wrapper
VAR_IN_OUT
    someVar: DINT;
END_VAR
VAR
    _wrapped_obj: POINTER TO FinalBlock;
END_VAR

_wrapped_obj^(someVar := someVar);

//////

METHOD FB_Init: BOOL
VAR_INPUT
    bInitRetains: BOOL;
    bInCopyCode: BOOL;
END_VAR
VAR_IN_OUT
    wrappedObj: FinalBlock;
END_VAR

THIS^._wrapped_obj := ADR(wrappedObj);

//////

METHOD GetSomeVarMethod : DINT

GetSomeVarMethod := THIS^.someVar;

//////

METHOD GetWrappedObjP : POINTER TO FinalBlock

GetWrappedObjP := THIS^._wrapped_obj;
PROGRAM SR_Main
VAR
    original: FinalBlock;
    someVar: DINT := 5;
    wrap: Wrapper(original);
    getVar: DINT;
END_VAR

wrap(someVar := someVar); // use this instead of "original(someVar := someVar);"
getVar := wrap.GetSomeVarMethod(); // getVar = 5

编辑:如果您要使用引用(或指针),需要注意的一件事是无效引用异常。在这两种情况下你会得到它们:

  1. 如果在设置之前访问变量:
getVar := wrap.GetSomeVarMethod(); // calling this'll try to access someVar
wrap(someVar := someVar);
  1. 您忘记了应该使用包装器而不是包装对象:
original(someVar := someVar); // should have called "wrap(someVar := someVar);" instead!
getVar := wrap.GetSomeVarMethod();

要避免这种情况,您可以尝试:

  1. 访问前检查引用:
METHOD GetSomeVarMethod : DINT

IF __ISVALIDREF(THIS^.someVar) THEN
    GetSomeVarMethod := THIS^.someVar;
ELSE
    GetSomeVarMethod := -1;
END_IF

TYPE OPTIONAL
STRUCT
    value: DINT;
    error: BOOL;
END_STRUCT
END_TYPE

METHOD GetSomeVarMethod : OPTIONAL

IF __ISVALIDREF(THIS^.someVar) THEN
    GetSomeVarMethod.value := THIS^.someVar;
ELSE
    GetSomeVarMethod.error := TRUE;
END_IF

然而,如果用户忘记调用 wrap(someVar := someVar); 而只调用 original(someVar := someVar); 那么 someVar 将永远无效。

  1. 不是将对象传递给包装器,而是让包装器完全创建和管理对象:
FUNCTION_BLOCK Wrapper
VAR_IN_OUT
    someVar: DINT;
END_VAR
VAR
        // with the 'no_init' attribute, we can let our FB_Init method initialize this object using user given arguments.
        // If FinalBlock doesn't have any custom initialization arguments, you can skip this attribute and the FB_init code below.
        {attribute 'no_init'}
    _wrapped_obj: FinalBlock;
END_VAR

_wrapped_obj(someVar := someVar);

//////

METHOD FB_Init: BOOL
VAR_INPUT
    bInitRetains: BOOL;
    bInCopyCode: BOOL;
    // FinalBlock initialization arguments
END_VAR

THIS^._wrapped_obj.FB_Init( (* initialization arguments *) );

无论哪种方式,我都建议您准备好有关如何正确使用包装器并避免错误的文档。

或者,如果您想要将功能块传递给一个函数并访问该函数内的 VAR_IN_OUT 变量的值,您可以将该值与功能块一起传递(因为如果它是 VAR_IN_OUT,无论如何你应该可以访问原始文件):

VAR
    original: FinalBlock;
    someVar: DINT := 5;
END_VAR

original(someVar := someVar);
getVar := SomeFunction(obj := original, someVar := someVar);

或:

TYPE Bundle :
STRUCT
    obj: REFERENCE TO FinalBlock;
    someVar: REFERENCE TO DINT;
END_STRUCT
END_TYPE

//////

VAR
    original: FinalBlock;
    someVar: DINT := 5;
    bun: Bundle(obj := original, someVar := someVar);
END_VAR

original(someVar := someVar);
getVar := SomeFunction(bundle := bun);