A general template for all classes with CLSID=16#004x. Recommended class values:
Other classes can be defined as needed.
Implements functionality for working with a physical analog output on a local PLC or distributed I/O device.
The structure of the CH_CFG and CH_HMI variables is provided in the Class Structure Description.
MIN and MAX values to enable straightforward forced value control. The separation between MIN and MAX may be defined by the CHAOFN subclass.Requirements are described in the LVL0 Class Requirements.
TIA Portal example:
// Work with IOT buffer
"CHIOTFN"(CHCFG:=#CHCFG, RAWINT:=#RAWINT);
#STA := #CHCFG.STA;
#CMD := #CHCFG.CMD;
// Unpack from STA
#VRAW := #STA.VRAW;
#VAL := #STA.VALB;
#BAD := #STA.BAD; (* externally controlled *)
#PNG := #STA.PNG;
#ULNK := #STA.ULNK;
#MERR := #STA.MERR; (* externally controlled *)
#BRK := #STA.BRK; (* externally controlled *)
#SHRT := #STA.SHRT; (* externally controlled *)
#NBD := #STA.NBD; (* externally controlled *)
#INBUF := #STA.INBUF;
#FRC := #STA.FRC;
#SML := #STA.SML;
#CMDLOAD := #STA.CMDLOAD; (* bit-controlled *)
#INBUF := (#CHCFG.ID = "BUF".CHBUF.ID) AND (#CHCFG.CLSID = "BUF".CHBUF.CLSID);
#CMDLOAD := #CHHMI.STA.%X15;
#CMD := 0;
// Command handler
// Broadcast force/unforce
IF "SYS".PLCCFG.CMD=16#4301 THEN
#FRC := true; (* force one/all objects of this type *)
END_IF;
IF "SYS".PLCCFG.CMD=16#4302 THEN
#FRC := false; (* unforce object of this type *)
END_IF;
// Select command source by priority
IF #CMDLOAD THEN
#CMD := 16#0100; // write to buffer
ELSIF #INBUF AND "BUF".CHBUF.CMD <> 0 THEN
#CMD := "BUF".CHBUF.CMD;
ELSIF #CHCFG.CMD<>0 THEN
#CMD := #CHCFG.CMD;
END_IF;
// Commands
CASE #CMD OF
16#0001: (* write MAX *)
IF #FRC AND #INBUF THEN
#RAWINT := #MAX;
END_IF;
16#0002: (* write MIN *)
IF #FRC AND #INBUF THEN
#RAWINT := #MIN;
END_IF;
16#0003: (* set to mid-range *)
IF #FRC AND #INBUF THEN
#RAWINT := #MIDLE;
END_IF;
16#0100: (* read configuration into buffer *)
"BUF".CHBUF.ID := #CHCFG.ID;
"BUF".CHBUF.CLSID := #CHCFG.CLSID;
"BUF".CHBUF.STA.%X0 := #CHCFG.STA.VRAW;
"BUF".CHBUF.STA.%X1 := #CHCFG.STA.VALB;
"BUF".CHBUF.STA.%X2 := #CHCFG.STA.BAD;
"BUF".CHBUF.STA.%X3 := #CHCFG.STA.b3;
"BUF".CHBUF.STA.%X4 := #CHCFG.STA.PNG;
"BUF".CHBUF.STA.%X5 := #CHCFG.STA.ULNK;
"BUF".CHBUF.STA.%X6 := #CHCFG.STA.MERR;
"BUF".CHBUF.STA.%X7 := #CHCFG.STA.BRK;
"BUF".CHBUF.STA.%X8 := #CHCFG.STA.SHRT;
"BUF".CHBUF.STA.%X9 := #CHCFG.STA.NBD;
"BUF".CHBUF.STA.%X10 := #CHCFG.STA.b10;
"BUF".CHBUF.STA.%X11 := #CHCFG.STA.INIOTBUF;
"BUF".CHBUF.STA.%X12 := #CHCFG.STA.INBUF;
"BUF".CHBUF.STA.%X13 := #CHCFG.STA.FRC;
"BUF".CHBUF.STA.%X14 := #CHCFG.STA.SML;
"BUF".CHBUF.STA.%X15 := #CHCFG.STA.CMDLOAD;
"BUF".CHBUF.VAL := #CHCFG.VAL;
"BUF".CHBUF.VARID := #CHCFG.VARID;
16#0300: (* toggle force *)
#FRC := NOT #FRC;
16#0301: (* enable force *)
#FRC := true;
16#0302: (* disable force *)
#FRC := false;
END_CASE;
// Variable value writing
IF #FRC AND #INBUF THEN
#RAWINT := "BUF".CHBUF.VAL;
ELSIF #FRC AND NOT #INBUF THEN
; (* no change *)
ELSIF NOT #FRC THEN
#RAWINT := #CHCFG.VAL;
END_IF;
// Ping-pong mechanism
#ULNK := #PNG; (* ping received - linked to upper level *)
#PNG := false; (* reset PNG bit as pong response *)
IF NOT #ULNK THEN
#CHCFG.VARID := 0;
END_IF;
// Reset processed commands
#CMDLOAD := 0;
#CMD := 0;
// System bits and counters
IF #FRC THEN
"SYS".PLCCFG.STA.FRC0 := true;
"SYS".PLCCFG.CNTFRC := "SYS".PLCCFG.CNTFRC + 1;
END_IF;
#BAD := #BRK OR #SHRT;
// Pack into STA
#STA.VRAW := #RAWINT>0;
#STA.VALB := #CHCFG.VAL>0;
#STA.BAD := #BAD;
#STA.PNG := #PNG;
#STA.ULNK := #ULNK;
#STA.MERR := #MERR;
#STA.BRK := #BRK;
#STA.SHRT := #SHRT;
#STA.NBD := #NBD;
#STA.INBUF := #INBUF;
#STA.FRC := #FRC;
#STA.SML := #SML;
#STA.CMDLOAD := #CMDLOAD;
#CHCFG.STA := #STA;
#CHCFG.CMD := #CMD;
// Pack into INT
#STAINT.%X0 := #VRAW;
#STAINT.%X1 := #VAL;
#STAINT.%X2 := #BAD;
#STAINT.%X4 := #PNG;
#STAINT.%X5 := #ULNK;
#STAINT.%X6 := #MERR;
#STAINT.%X7 := #BRK;
#STAINT.%X8 := #SHRT;
#STAINT.%X9 := #NBD;
#STAINT.%X11 := #STA.INIOTBUF;
#STAINT.%X12 := #INBUF;
#STAINT.%X13 := #FRC;
#STAINT.%X14 := #SML;
#STAINT.%X15 := FALSE;
#CHHMI.STA := #STAINT;
#CHHMI.VAL := #RAWINT;
// Buffer update
IF #INBUF THEN
"BUF".CHBUF.STA := #STAINT;
"BUF".CHBUF.VARID := #CHCFG.VARID;
"BUF".CHBUF.CMD := 0;
IF NOT #FRC THEN
"BUF".CHBUF.VAL := #CHCFG.VAL;
END_IF;
END_IF;
Used after calling VAR.
This section describes the testing methodology for the specific functions of CHAOFN. Other tests are described in the LVL0 Class Description.
The list is provided in the LVL0 Class Description.
ID and CLSID.| Step Number | Test Action | Expected Result | Notes |
|---|---|---|---|
| 1 | Set STA.X15=1 for one of the CH_HMI variables |
The entire CH_CFG content should be loaded into CHBUF. STA.X15 in CH_HMI should reset to 0. STA.12 (INBUF) should be 1 in CH_HMI, CH_CFG, and CHBUF. |
|
| 2 | Change the variable value (e.g., RAW for DICH input) |
The updated value should appear in CH_HMI, CH_CFG, and CHBUF. |
|
| 3 | Set STA.X15=1 for another CH_HMI variable |
The entire CH_CFG content of the new variable should load into CHBUF. |
|
| 4 | Repeat step 1 using CH_CFG.CMD=16#100 |
The entire CH_CFG content should load into CHBUF. STA.X15 in CH_HMI should reset to 0. STA.12 (INBUF) should be 1 in CH_HMI, CH_CFG, and CHBUF. CH_CFG.CMD should reset to 0. |
Values should be checked in CH_HMI, CH_CFG, and CH_BUF.
| Step Number | Test Action | Expected Result | Notes |
|---|---|---|---|
| 1 | Link a test variable to the buffer | The entire CH_CFG content should load into CHBUF. |
|
| 2 | Change the variable value (e.g., RAW for DICH input) |
The live and raw values should update in CH_HMI, CH_CFG, and CHBUF (for CHDI and CHDO). |
See detailed tests for the specific class |
| 3 | Repeat step 2 with another value |
Values should be checked in CH_HMI, CH_CFG, and CH_BUF.
| Step Number | Test Action | Expected Result | Notes |
|---|---|---|---|
| 1 | Link a test variable to the buffer | The entire CH_CFG content should load into CHBUF. |
|
| 2 | Change the input value to 0 | The value should change as in test 3. | Input value: RAW for DICH/AICH, VAL for DOCH/AOCH. |
| 3 | Send the force command CHBUF.CMD=16#0301 |
The FRC bit should be 1. |
|
| 4 | Change the input value | The output value should remain unchanged. | Input value: RAW for DICH/AICH, VAL for DOCH/AOCH. |
| 5 | Send command 16#0001 (write 1/MAX) |
The value should change to 1/MAX. | |
| 6 | Send command 16#0002 (write 0/MIN) |
The value should change to 0/MIN. | |
| 7 | Send command 16#0003 (TOGGLE/set to mid-range) |
The value should toggle or change to mid-range. | |
| 8 | Change the CHBUF.VAL value |
The value should update to the specified value. | For discrete, any value >0 equals 1. |
| 9 | Send the unforce command CHBUF.CMD=16#0302 |
The FRC bit should be 0. |
|
| 10 | Send the toggle force command 16#0300 repeatedly, leaving in forced mode |
The FRC bit should toggle accordingly. |
|
| 11 | Force multiple variables into forced mode | The FRC bits for these variables should be 1. |
|
| 12 | Check PLC.STA_PERM and PLC.CNTFRC_PERM |
PLC.STA_PERM.X13 should be 1, and PLC.CNTFRC_PERM should match the number of forced variables. |
|
| 13 | Unforce all variables | PLC.STA_PERM.X13 should be 0, and PLC.CNTFRC_PERM should be 0. |
TST_CHDIPNGON for CHDI) is used to run the test.TST_CHDIPNGID.CH_CFG.PNG:IF TST_CHDIPNGON THEN
CHDI[TST_CHDIPNGID].STA.PNG := true;
CHDI[TST_CHDIPNGID].VARID := TST_CHDIPNGID;
END_IF;
| Step Number | Test Action | Expected Result | Notes |
|---|---|---|---|
| 1 | Write a value into CH_CFG.VARID |
It should reset to 0 since the variable is not linked. | |
| 2 | Set TST_CHDIPNGID within valid channel range and TST_CHDIPNGON=TRUE |
For the specified variable, CH_CFG.VARID should equal the set value, and CH_CFG.ULNK should be TRUE. |
|
| 3 | Change TST_CHDIPNGID to another valid channel and set TST_CHDIPNGON=TRUE |
The previous channel should clear CH_CFG.VARID and CH_CFG.ULNK. The new channel should match the result in step 2. |
|
| 4 | Set TST_CHDIPNGON=FALSE |
The last channel should clear CH_CFG.VARID and CH_CFG.ULNK. |
| Step Number | Test Action | Expected Result | Notes |
|---|---|---|---|
| 1 | Send a broadcast force command PLC.CMD=16#4301 |
The FRC bit for all variables should be 1; PLC.CNTFRC_PERM should match the number of variables. |
|
| 2 | Send a broadcast unforce command PLC.CMD=16#4302 |
The FRC bit for all variables should be 0; PLC.CNTFRC_PERM should be 0. |