Files
BasicComponents/PLC/POUs/Unittests/AOTests/FB_AnalogOutputTest.TcPOU
2025-11-13 09:19:39 +01:00

469 lines
13 KiB
XML

<?xml version="1.0" encoding="utf-8"?>
<TcPlcObject Version="1.1.0.1">
<POU Name="FB_AnalogOutputTest" Id="{ebe472aa-270b-4ff7-b47b-01e41ab792c6}" SpecialFunc="None">
<Declaration><![CDATA[FUNCTION_BLOCK FB_AnalogOutputTest EXTENDS TcUnit.FB_TestSuite
VAR_INPUT
END_VAR
VAR_OUTPUT
END_VAR
VAR
END_VAR
]]></Declaration>
<Implementation>
<ST><![CDATA[// test invalid parameter
TestConfigErrorDivisionByZero();
TestConfigErrorNegativMaxMinusMin();
// test HMI
TestHMIOutput();
// test functionality itself
TestOutputScaling();
// test clamping
TestSetpointUpperCap();
TestSetpointLowerCap();
// test unused
TestUnused();]]></ST>
</Implementation>
<Method Name="TestConfigErrorDivisionByZero" Id="{eb0c63a7-066d-4e01-b0f9-aedc1022b328}">
<Declaration><![CDATA[{warning disable C0394}
METHOD TestConfigErrorDivisionByZero
VAR
// analog output instance
_fbAnalogOutput : FB_AnalogOutput('');
// analog output config
_stAnalogOutputConfig : ST_ANALOG_IO_CONFIG;
// analog output hmi data
_stHMIInterface : ST_HMI_ANALOG_VALUE;
// conversion result
_iAnalogOutput : INT;
// fb error
_xError : BOOL;
END_VAR]]></Declaration>
<Implementation>
<ST><![CDATA[TEST('TestConfigErrorDivisionByZero');
// denom = udiAIMax - udiAIMin
// Test if no crash occurs when denom equals zero
_stAnalogOutputConfig.iAIMax := 4095;
_stAnalogOutputConfig.iAIMin := 0;
_stAnalogOutputConfig.rPVMax := 0;
_stAnalogOutputConfig.rPVMin := 0;
// run analog scaling
_fbAnalogOutput(
rSetpoint := 100,
stAnalogIOConfig := _stAnalogOutputConfig,
xReleaseErrors := ,
xConfirmAlarms := ,
stHMIInterface := _stHMIInterface,
iAnalogValue => _iAnalogOutput,
xError => _xError,
xInUnitTestMode := TRUE);
// evaluate Error and result to zero
AssertTrue(_xError, 'There should be an error when trying to divide by zero.');
AssertEquals_INT(Expected := 0, Actual := _iAnalogOutput, 'Output is expected to be zero when trying to divide by zero');
TEST_FINISHED();]]></ST>
</Implementation>
</Method>
<Method Name="TestConfigErrorNegativMaxMinusMin" Id="{6f3e2737-a3ba-4909-b974-955bc0e635c3}">
<Declaration><![CDATA[{warning disable C0394}
METHOD TestConfigErrorNegativMaxMinusMin
VAR
// analog output instance
_fbAnalogOutput : FB_AnalogOutput('');
// analog output config
_stAnalogOutputConfig : ST_ANALOG_IO_CONFIG;
// analog output hmi data
_stHMIInterface : ST_HMI_ANALOG_VALUE;
// conversion result
_iAnalogOutput : INT;
// fb error
_xError : BOOL;
END_VAR
]]></Declaration>
<Implementation>
<ST><![CDATA[TEST('TestConfigErrorNegativMaxMinusMin');
// denom = udiAIMax - udiAIMin
// Test if no crash occurs when denom is smaller than zero
_stAnalogOutputConfig.iAIMax := 4095;
_stAnalogOutputConfig.iAIMin := 0;
_stAnalogOutputConfig.rPVMax := 0;
_stAnalogOutputConfig.rPVMin := 1;
// run analog scaling
_fbAnalogOutput(
rSetpoint := 100,
stAnalogIOConfig := _stAnalogOutputConfig,
xReleaseErrors := ,
xConfirmAlarms := ,
stHMIInterface := _stHMIInterface,
iAnalogValue => _iAnalogOutput,
xError => _xError,
xInUnitTestMode := TRUE);
// evaluate Error and result to zero
AssertTrue(_xError, 'There should be an error when trying to divide by zero.');
AssertEquals_INT(Expected := 0, Actual := _iAnalogOutput, 'Output is expected to be zero when trying to divide by negative number.');
TEST_FINISHED();]]></ST>
</Implementation>
</Method>
<Method Name="TestHMIOutput" Id="{6b0d589b-625b-471a-8f08-48db4bd05305}">
<Declaration><![CDATA[{warning disable C0394}
METHOD TestHMIOutput
VAR
// analog output instance
_fbAnalogOutput : FB_AnalogOutput('Name');
// analog output config
_stAnalogOutputConfig : ST_ANALOG_IO_CONFIG;
// analog output hmi data
_stHMIInterface : ST_HMI_ANALOG_VALUE;
// conversion result
_iAnalogOutput : INT;
// fb error
_xError : BOOL;
END_VAR
VAR CONSTANT
// expected hmi values
sName : STRING := 'Name';
sUnit : STRING := 'm/s';
iOk : INT := 1;
iError : INT := 2;
// delta for assertion
rDelta : REAL := 0.01;
END_VAR]]></Declaration>
<Implementation>
<ST><![CDATA[TEST('TestHMIOutput');
// some example settings
_stAnalogOutputConfig.iAIMax := 4095; //12 bit max
_stAnalogOutputConfig.iAIMin := 0;
_stAnalogOutputConfig.rPVMax := 100;
_stAnalogOutputConfig.rPVMin := 50;
_stAnalogOutputConfig.sUnit := sUnit;
// run analog scaling
_fbAnalogOutput(
rSetpoint := 60, //60 * 81,9 - 4095 = 819
stAnalogIOConfig := _stAnalogOutputConfig,
xReleaseErrors := ,
xConfirmAlarms := ,
stHMIInterface := _stHMIInterface,
iAnalogValue => _iAnalogOutput,
xError => _xError,
xInUnitTestMode := TRUE);
// due to only moving real, a delta of 0.01 should be sufficient.
// testing all HMI values
AssertEquals_REAL(Expected := _stAnalogOutputConfig.rPVMax, Actual := _stHMIInterface.rMax, Delta := rDelta,'rMax was not passed to HMI correctly.');
AssertEquals_REAL(Expected := _stAnalogOutputConfig.rPVMin, Actual := _stHMIInterface.rMin, Delta := rDelta,'rMin was not passed to HMI correctly.');
// rValue from HMI Interface functions as an Input to the FB. If the FB would write it back we would have a loop!
{analysis -140}
//AssertEquals_REAL(Expected := rExpected, Actual := stHMIInterface.rValue, Delta := rDelta,'rValue was not passed to HMI correctly.');
{analysis +140}
AssertEquals_STRING(Expected := sName, Actual := _stHMIInterface.sName, 'sName was not passed to HMI correctly.');
AssertEquals_STRING(Expected := sUnit, Actual := _stHMIInterface.sUnit, 'sUnit was not passed to HMI correctly.');
AssertTrue(_stHMIInterface.xUsed, 'xUsed is not passed to HMI correctly.');
AssertEquals_INT(Expected := iOk, Actual := _stHMIInterface.iStatus, 'Status is Error when OK was expected.');
// testing error passtrough (div by zero)
_stAnalogOutputConfig.rPVMax := 0;
_stAnalogOutputConfig.rPVMin := 0;
// run analog scaling
_fbAnalogOutput(
rSetpoint := 0,
stAnalogIOConfig := _stAnalogOutputConfig,
xReleaseErrors := ,
xConfirmAlarms := ,
stHMIInterface := _stHMIInterface,
iAnalogValue => _iAnalogOutput,
xError => _xError);
// reading error from HMI interface
AssertEquals_INT(Expected := iError, Actual := _stHMIInterface.iStatus, 'Status is OK when Error was expected.');
TEST_FINISHED();]]></ST>
</Implementation>
</Method>
<Method Name="TestOutputScaling" Id="{60f43e92-2d83-42da-8c76-29a4e23f243d}">
<Declaration><![CDATA[{warning disable C0394}
METHOD TestOutputScaling
VAR
// analog output instance
_fbAnalogOutput : FB_AnalogOutput('');
// analog output config
_stAnalogOutputConfig : ST_ANALOG_IO_CONFIG;
// analog output hmi data
_stHMIInterface : ST_HMI_ANALOG_VALUE;
// conversion result
_iAnalogOutput : INT;
// fb error
_xError : BOOL;
END_VAR
VAR CONSTANT
// expected conversion results
iExpected1 : INT := 819;
iExpected2 : INT := 3071;
iExpected3 : INT := 354;
iExpected4 : INT := 4013;
iExpected5 : INT := 2058;
END_VAR]]></Declaration>
<Implementation>
<ST><![CDATA[TEST('TestOutputScaling');
// some example settings
_stAnalogOutputConfig.iAIMax := 4095; //12 bit max
_stAnalogOutputConfig.iAIMin := 0;
_stAnalogOutputConfig.rPVMax := 100;
_stAnalogOutputConfig.rPVMin := 50;
// run first value
_fbAnalogOutput(
rSetpoint := 60, //60 * 81,9 - 4095 = 819
stAnalogIOConfig := _stAnalogOutputConfig,
xReleaseErrors := ,
xConfirmAlarms := ,
stHMIInterface := _stHMIInterface,
iAnalogValue => _iAnalogOutput,
xError => _xError,
xInUnitTestMode := TRUE);
// and evaluate result
AssertFalse(_xError, 'There should not be an error here.');
AssertEquals_INT(Expected := iExpected1, Actual := _iAnalogOutput,'Result was not calculated correctly.');
// run second value
_fbAnalogOutput(
rSetpoint := 87.5, //87,5 * 81,9 - 4095 = 3071
stAnalogIOConfig := _stAnalogOutputConfig,
xReleaseErrors := ,
xConfirmAlarms := ,
stHMIInterface := _stHMIInterface,
iAnalogValue => _iAnalogOutput,
xError => _xError);
// and evaluate result
AssertFalse(_xError, 'There should not be an error here.');
AssertEquals_INT(Expected := iExpected2, Actual := _iAnalogOutput,'Result was not calculated correctly.');
// run third value
_fbAnalogOutput(
rSetpoint := 54.321, //54,321 * 81,9 - 4095 = 354
stAnalogIOConfig := _stAnalogOutputConfig,
xReleaseErrors := ,
xConfirmAlarms := ,
stHMIInterface := _stHMIInterface,
iAnalogValue => _iAnalogOutput,
xError => _xError);
// and evaluate result
AssertFalse(_xError, 'There should not be an error here.');
AssertEquals_INT(Expected := iExpected3, Actual := _iAnalogOutput,'Result was not calculated correctly.');
// run forth value
_fbAnalogOutput(
rSetpoint := 99, //99 * 81,9 - 4095 = 4013
stAnalogIOConfig := _stAnalogOutputConfig,
xReleaseErrors := ,
xConfirmAlarms := ,
stHMIInterface := _stHMIInterface,
iAnalogValue => _iAnalogOutput,
xError => _xError);
// and evaluate result
AssertFalse(_xError, 'There should not be an error here.');
AssertEquals_INT(Expected := iExpected4, Actual := _iAnalogOutput,'Result was not calculated correctly.');
// run fifth value
_fbAnalogOutput(
rSetpoint := 75.12345, // 75,12345 * 81,9 - 4095 = 2058
stAnalogIOConfig := _stAnalogOutputConfig,
xReleaseErrors := ,
xConfirmAlarms := ,
stHMIInterface := _stHMIInterface,
iAnalogValue => _iAnalogOutput,
xError => _xError);
// and evaluate result
AssertFalse(_xError, 'There should not be an error here.');
AssertEquals_INT(Expected := iExpected5, Actual := _iAnalogOutput,'Result was not calculated correctly.');
TEST_FINISHED();]]></ST>
</Implementation>
</Method>
<Method Name="TestSetpointLowerCap" Id="{807912d5-bba1-425b-bbaa-8753f0659a61}">
<Declaration><![CDATA[{warning disable C0394}
METHOD TestSetpointLowerCap
VAR
// analog output instance
_fbAnalogOutput : FB_AnalogOutput('');
// analog output config
_stAnalogOutputConfig : ST_ANALOG_IO_CONFIG;
// analog output hmi data
_stHMIInterface : ST_HMI_ANALOG_VALUE;
// conversion result
_iAnalogOutput : INT;
// fb error
_xError : BOOL;
END_VAR
VAR CONSTANT
// expected lower cap result
iExpected : INT := 0;
END_VAR
]]></Declaration>
<Implementation>
<ST><![CDATA[TEST('TestSetpointLowerCap');
// some example settings
_stAnalogOutputConfig.iAIMax := 4095; //12 bit max
_stAnalogOutputConfig.iAIMin := 0;
_stAnalogOutputConfig.rPVMax := 100;
_stAnalogOutputConfig.rPVMin := 50;
// run with setpoint lower than lower cap
_fbAnalogOutput(
rSetpoint := 30,
stAnalogIOConfig := _stAnalogOutputConfig,
xReleaseErrors := ,
xConfirmAlarms := ,
stHMIInterface := _stHMIInterface,
iAnalogValue => _iAnalogOutput,
xError => _xError,
xInUnitTestMode := TRUE);
// evaluate wethere the result is the equivalent of lower cap or not
AssertFalse(_xError, 'There should not be an error here.');
AssertEquals_INT(Expected := iExpected, Actual := _iAnalogOutput,'Setpoint was expected to be capped.');
TEST_FINISHED();]]></ST>
</Implementation>
</Method>
<Method Name="TestSetpointUpperCap" Id="{286c1c76-f998-4c94-9225-155b9dc5d782}">
<Declaration><![CDATA[{warning disable C0394}
METHOD TestSetpointUpperCap
VAR
// analog output instance
_fbAnalogOutput : FB_AnalogOutput('');
// analog output config
_stAnalogOutputConfig : ST_ANALOG_IO_CONFIG;
// analog output hmi data
_stHMIInterface : ST_HMI_ANALOG_VALUE;
// conversion result
_iAnalogOutput : INT;
// fb error
_xError : BOOL;
END_VAR
VAR CONSTANT
// expected upper cap result
iExpected : INT := 4095;
END_VAR]]></Declaration>
<Implementation>
<ST><![CDATA[TEST('TestSetpointUpperCap');
// some example settings
_stAnalogOutputConfig.iAIMax := 4095; //12 bit max
_stAnalogOutputConfig.iAIMin := 0;
_stAnalogOutputConfig.rPVMax := 100;
_stAnalogOutputConfig.rPVMin := 50;
// run with setpoint higher than upper cap
_fbAnalogOutput(
rSetpoint := 110,
stAnalogIOConfig := _stAnalogOutputConfig,
xReleaseErrors := ,
xConfirmAlarms := ,
stHMIInterface := _stHMIInterface,
iAnalogValue => _iAnalogOutput,
xError => _xError,
xInUnitTestMode := TRUE);
// evaluate wethere the result is the equivalent of upper cap or not
AssertFalse(_xError, 'There should not be an error here.');
AssertEquals_INT(Expected := iExpected, Actual := _iAnalogOutput,'Setpoint was expected to be capped.');
TEST_FINISHED();]]></ST>
</Implementation>
</Method>
<Method Name="TestUnused" Id="{5c9c0209-9c4b-4d43-90e6-a77c731cebf3}">
<Declaration><![CDATA[{warning disable C0394}
METHOD TestUnused
VAR
// analog output instance
_fbAnalogOutput : FB_AnalogOutput('');
// analog output config
_stAnalogOutputConfig : ST_ANALOG_IO_CONFIG;
// analog output hmi data
_stHMIInterface : ST_HMI_ANALOG_VALUE;
// conversion result
_iAnalogOutput : INT;
// fb error
_xError : BOOL;
END_VAR
]]></Declaration>
<Implementation>
<ST><![CDATA[TEST('TestUnused');
// some example settings
_stAnalogOutputConfig.xUsed := FALSE;
// run analog output
_fbAnalogOutput(
rSetpoint := 100,
stAnalogIOConfig := _stAnalogOutputConfig,
xReleaseErrors := ,
xConfirmAlarms := ,
stHMIInterface := _stHMIInterface,
iAnalogValue => _iAnalogOutput,
xError => _xError,
xInUnitTestMode := TRUE);
// test for error and output (should not be present and 0 when unused)
AssertFalse(_xError, 'There should not be an error when unused.');
AssertEquals_INT(Expected := 0, Actual := _iAnalogOutput, 'Output is expected to be zero when unused');
TEST_FINISHED();]]></ST>
</Implementation>
</Method>
</POU>
</TcPlcObject>