Application note

DPI to DPI communication in Process-Pascal

When more than one DPI is involved in a control system, the individual DPIs normally need to communicate with each other in order to synchronize the controls.

Communicating with other DPIs is done in the same way as accessing IO modules, but due to the flexibility in user data structure in a DPI, the user has to specify the data location and definition.
This example consists of two DPIs: One DPI defines and contains the data. This one is called the server. The other DPI accesses the data in the server using P-NET communication. This one is called the client.
Access to external data can be achieved in different ways. This example shows three ways to make the client program:

1. External data definition
2. Access by Pointer to structured data, using NodeList
3. Access by Pointer to simple data within a data structure, using NodeList

NOTE for P-NET on Ethernet:


The server address definition examples in this document do not apply to P-NET on Ethernet.
Except for that part, the remaining text in the examples is the same for all P-NET variants.

When using Ethernet, the address consists of 3 elements:

– Port No.
– Net Index
– Destination node address.

When using all other network types, the address consists of 2 elements:

– Port No.
– Destination node address.

The server application is exactly the same for all three examples. Only the way of accessing data is different. Data must be defined at a fixed SoftWire number in the server.

DosingRecordType = Record
                                  DosingTime: Real;
                                  DosingPumps: Bit8;
                                  DosingState: Integer;
                               End;

Server Application Program:

(*$I’ \Data.inc’*)

VAR
  BlenderRecord: DosingRecordType PLACE: 800; (* Use static SoftWire No. *)
  DosingHeads : Bit8 PLACE: 812;                        (* Use static Softwire No. *)

TASK TestCommunicationToPD600;
  BEGIN
    Loop
      ChangeTask;
    End;
END;

Example 1: External data declaration:

Data must be declared with the same format in the client as was used to create the data in the server.
By defining the data to be external with the “AT NET” command, the data is not physically stored in this DPI, only the path to, and the declaration of the data is stored.
If the data structure is changed in the server, all clients having a reference to this data must be recompiled.
In VIGO, data is shown in both the client and the server. Both refer to the same data structure in the server.
Note: Data of a sub-type e.g. Timer or Bit8, cannot be shown in VIGO if they are used in a structured variable.

(*$I ’ \data.inc’*)

VAR
  Blender : DosingRecordType [DeviceType:602] AT NET: (2,2) SoftWire : 800;
  DozingNozzles : Bit8 [DeviceType:602] AT NET: (2,2) SoftWire : 812;
  MasterPump -> Blender.DosingPumps[3];

Task TestCommunicationToPD602;
Begin
  Loop
    IF Blander.DosingState = 6 Then   (* reading status from external DPI *)
      Blender.DosingTime := 8            (* writing data to external DPI *)
    Else
      Blender.DosingTime := 25.8;      (* writing data to external DPI *)

    MasterPump := True;                   (* access external data via pointer *)
    Blender.DosingPumps[5] := True; (* access external record structure *)
    DosingNozzles[5] := True;            (* access external data variable *)
    ChangeTask;
  End;
End;

Variable names in the client and in the server are different in these examples. This has only been done to highlight the external data definition. Identical variable names may be used in both applications if required.

Example 2: Access by pointer to structured data using NodeList:

A pointer is defined to point to the data structure in the server DPI. The client contains a number of pointers that can point to specific data in the server.
The data pointer is initialised at runtime. The same pointer can be used to point to different data of the same type, at different times.
In VIGO, only the data pointers are shown in the client. Data can only be accessed in the server.
If the data structure is changed in the server, all clients having a reference to this data must be recompiled.

Client application using pointers to structured data types:

*$I ’..\data.inc’*)

VAR
  DosingPointer : Pointer to DosingRecordType;
  NozzlePointer : Pointer to Bit8;

Task TestCommunicationByNodelist;
Begin
  Nodelist[1].code:= 32;                 (* target type = PD602 *)
  Nodelist[1].nodeaddr[0]:= chr(2); (* path length = 2 *)
  Nodelist[1].nodeaddr[1]:= chr(2); (* output in this DPI = 2 *)
  Nodelist[1].Nodeaddr[2]:= chr(2); (* node address of external DPI = 2 *)
  Loop
    DosingPointer -> PointerToNode(1,800,0); (* SW = 800 Offset = 0 *)
    IF DosingPointer.DosingState = 6 Then       (* reading status from external DPI *)
      DosingPointer.DosingTime := 8                (* writing data to external DPI *)
    Else
      DosingPointer.DosingTime := 25.8;          (* writing data to external DPI *)
    DosingPointer.DosingPumps[3] := True;     (* access external data via pointer *)
    NozzlePointer -> PointerToNode(1,812,0); (* SW = 812 Offset = 0 *)
    NozzlePointer[5] := True;                          (* access external data variable *)
   ChangeTask;
  End;
End;

When choosing between the use of pointers to data structures and using external variable references, both have certain advantages:
The external variable reference is a more structured way of defining data, as the declarations are made together with the data definition, whereas with pointers, the reference may be scattered throughout the application program. If multiple structures of the same type have to be referenced, e.g. a list of recipes, a single pointer can be initialised inside a loop to access each recipe one by one.

Example 3: Access by pointer to simple data using NodeList:

In this example, the data structure is not declared in the client. The single data is referenced directly.
Referring to simple data inside a structure e.g. a record implies addressing the data by both the structure’s Softwire number and the offset inside the structure.
If the data structure is changed in the server, all clients having a reference to this data must be recompiled, because the offsets to specific data within the structure are likely to have changed.

Client application using pointers to simple data types:

VAR
  DosingTime: Pointer to Real;
  DosingState: Pointer to Integer;
  PumpPointer: Pointer to boolean;

Task TestCommunicationByNodelist;
Begin
  Nodelist[1].code:= 32;                  (* target type = PD602 *)
  Nodelist[1].nodeaddr[0]:= chr(2); (* path length = 2 *)
  Nodelist[1].nodeaddr[1]:= chr(2); (* outport in this DPI = 2 *)
  Nodelist[1].nodeaddr[2]:= chr(2); (* node address of external DPI = 2 *)

  Loop
    DosingState -> PointerToNode(1,800,6); (* SW = 800 Offset = 6 *)
    IF DosingState = 6 Then                         (* reading status from external DPI *)
    Begin
      DosingTime -> PointerToNode(1,800,0); (* SW = 800 Offset = 0 *)
     DosingTime := 8                                     (* writing data to external DPI *)
    End
    Else
    Begin
      DosingTime -> PointerToNode(1,800,0); (* SW = 800 OffSet = *)
      DosingTime := 25.8;                              (* writing data to external DPI *)
    End;

  (* Blender.DosingPumps[3] := True *)
  PumpPointer -> PointerToNode(1,800,4,3);  (* SW = 800 OffSet = 4 Bit = 3 *)
  PumpPointer := True;                                  (* access external data via pointer *)
  (* DosingNozzles[5] := True *)
  PumpPointer -> PointerToNode(1,812,0,5); (* SW = 812 OffSet = 0 Bit = 5 *)
  PumpPointer := True;                                 (* access external data variable *)
  ChangeTask;
  End;
End;

If the pointer is used to point out single bits, a bit number can be specified after the offset.
See PumpPointer example above.