# OPC-UA Agent for Legacy Programmable Logic Controllers +
## 3 OPC-UA Agent for Legacy Programmable Logic Controllers
### OPC-UA Client and RPC  
In IEC 61131-3-based systems, users can write OPC-UA client codes using either textual programming languages such as structured text (ST) and instruction list (IL), or graphic languages such as the ladder diagram (LD), function block diagram (FBD), and structured flow chart (SFC) [5]. Legacy PLCs usually accept a single program file for execution and require a translator to convert the IEC 61131-3 code files into a PLC-executable program. Figure 6 shows the procedure. Many legacy controllers support only numeric variable types, i.e., bool, integer, and real types, and do not support derived or complex types such as array or structure. To support the parameters of types other than numeric types, the translator in our design generates VAR_INPUT.json during the conversion process and stores input values for such non-numeric parameters of OPC-UA client functions. For example, the ServerEndPointUrl input in UA_Connect (see Figure 2) specifies the URL or IP address of the OPC-UA server the program will connect to, and the VAR_INPUT.json file stores the address value for ServerEndPointUrl. The example in Figure 7 shows (a) an OPC-UA client application written in IEC 61131-3 ST and (b) the corresponding program converted into a PLC-executable script. The program receives the target position from an external OPC-UA server and operates a single-axis motor drive connected to the legacy controller. Lines 1-11 in Figure 7 define the variables that will be used in the rest of the PLC procedure. Next, line 14 shows the program calling UA_Connect to create an OPC-UA session with an external server. During the conversion process, the address value for the server URL parameter is inserted into a table for the URL parameters in VAR_INPUT.json. The index of the table entry is stored in the converted program and later used by the UA agent to look up the argument value when UA_Connect is called. When the connection is established, UA_NodeGetHandleList is called and a new handle (_nHdls0) is created for the node that stores the target position (line 17). The legacy controller then reads the target position from the server by calling UA_ReadList and stores it in the _tarPos variable (line 20). The while loop in lines 19-24 repeats until the target position received is greater than 200. Then the UA_ReadList function is no longer called, and the connection with the server is closed using UA_Disconnect. Figure 5: Structure of gateway messages used by the gateway messaging protocol for platform-independent communication between OPC-UA agent and PLC. For the RPC of OPC-UA client functions, a handshaking between the PLC and agent has been defined using shared variables. Each client function \(\lambda\) is associated with two state variables, cmd[\(\lambda\)] and stat[\(\lambda\)] (see Figure 6). The cmd[\(\lambda\)] variable is used by the PLC to command the start and end of \(\lambda\). The stat[\(\lambda\)] shows the status of \(\lambda\) and can be modified by the agent. If cmd[\(\lambda\)] = 0 and stat[\(\lambda\)] = 0, it means that \(\lambda\) is idle and not being used by the PLC. When PLC wants to call \(\lambda\), it sets cmd[\(\lambda\)] = 1. The agent then acknowledges the call by setting stat[\(\lambda\)] = 1 and starts executing \(\lambda\). When \(\lambda\) completes, the agent sets stat[\(\lambda\)] to 2 or 3, to indicate that \(\lambda\) succeeded or failed, respectively. Then, the PLC resets cmd[\(\lambda\)] = 0 to end, calling \(\lambda\), and the agent confirms this and resets stat[\(\lambda\)] = 0. Figure 7b shows the PLC program and explains RPC handshaking. For \(\lambda_{1}\) = UA_Connect, the shared variables I100 and I128 represent cmd[\(\lambda_{1}\)] and stat[\(\lambda_{1}\)], respectively (lines 9-10). For \(\lambda_{2}\) = UA_ReadList, I117 and I145 refer to cmd[\(\lambda_{2}\)] and stat[\(\lambda_{2}\)], respectively. If cmd[\(\lambda_{2}\)] = 0 and stat[\(\lambda_{2}\)] = 0, the input parameters are stored in I277-I279 (lines 16-23).