2.6 Tutorial Ping Pong (Java and C)

2.6.1 Scope

This tutorial describes how to create a simple hierarchical actor system of actors communicating via ports and bindings. Additionally you will use the Timing Service from the eTrice model library. This tutorial can be done for the target languages Java or C. For the Ping Pong scenario we want to create a model with a sender and a reveiver of a message. The receiver has to wait for the ping message from the sender, wait for a second and respond with a pong message.

The resulting Message Sequence Chart (MSC) at the ende of this tutorial should look like this:

PIC

We will take this MSC as specification for the desired behavior.

You will perform the following steps:

  1. create a new model from scratch
  2. define a protocol
  3. create an actor structure
  4. create finite state machines
  5. use the predefined TimingService
  6. build and run the model
  7. open the message sequence chart

2.6.2 Create a new model from scratch

Create a new eTrice project according to HelloWorld for Java or C and name it PingPong.

Your ROOM model should look like this:

1RoomModel PingPong_Model { 
2 LogicalSystem LogSys1 { 
3   SubSystemRef subSysRef1:SubSysClass1 
4 } 
5 SubSystemClass SubSysClass1 { 
6   ActorRef actorRef1:PingPongTop 
7   LogicalThread defaultThread 
8 } 
9 ActorClass PingPongTop { 
10 } 
11}

2.6.3 Create a new protocol

First we define a protocol for the communication between the Sender and the Receiver. From the specification MSC above we can derive that the Sender sends a ping message to the receiver and the receiver responds with a pong message.

In ROOM the ProtocolClass specifies interfaces. In this case we go for an asynchronous, bidirectional messaging interface (eventdriven) which is the standard communication type for a ProtocolClass. With the help of Content Assist (Ctrl+Space) we create a ProtocolClass and name it PingPongProtocol. Inside the brackets use the Content Assist to create two incoming messages called ping and pong.

The resulting code should look like this:

1 ProtocolClass PingPongProtocol { 
2   incoming { 
3    Message ping() 
4   } 
5   outgoing { 
6    Message pong() 
7   } 
8 }

With Ctrl-Shift+F or selecting Format from the context menu you can format the ROOM model. Note that the new ProtocolClass is displayed in the outline view.

2.6.4 Create the Actor Structure

Add two additional actor classes

Position the cursor outside any class definition and call the Content Assist with Ctrl+Space. Select ActorClass - actor class skeleton or ActorClass and name the ActorClass Sender.

PIC

Repeat the described procedure and name the new actor Receiver.

With Ctrl+Shift+F you can format your textual model.

The Result:

1RoomModel PingPong_Model { 
2 
3 LogicalSystem LogSys1 { 
4   SubSystemRef subSysRef1: SubSysClass1 
5 } 
6 
7 SubSystemClass SubSysClass1 { 
8   ActorRef actorRef1: PingPongTop 
9   LogicalThread defaultThread 
10 } 
11 
12 ActorClass PingPongTop { } 
13 
14 ActorClass Sender { } 
15 
16 ActorClass Receiver { } 
17 
18}

You can should also see the new ActorClasses in the outline view.

Add ports to the actors

To open the graphical structure editor, right click Receiver in the Outline View and select Edit Structure. Drag and Drop an Interface Port from the Palette to the border of the Receiver actor. Note that an Interface Port can only be placed on the border of the actor. Name the port sender and select PingPongProtocol as Protocol from the drop down list. The checkboxes Conjugated and Is Relay Port stay unchecked. Click ok. The resulting structure should look like this:

PIC

Repeat the steps above for the sender. Create a port named receiver with the same Protocol and make it Conjugated.

Keep in mind that the protocol defines ping as incoming message and pong as outgoing message. Receiver receives ping and sends pong. Therefore the Receivers port must be a regular port. The Sender has to send ping and receive pong. Therefore the Senders port must be a conjugated port.

Build hierarchical actor structure

Now we want to add the new actors to the structure of ActorClass PingPongTop.

From the outline view right click PingPongTop and select Edit Structure. Remember that you can only see the outline view if the textual editor with the .room file is active.

Drag and Drop an ActorRef inside the PingPongTop actor. Name it sender. From the actor class drop down list select Sender. Do the same for Receiver. Connect the ports via the binding tool int the Palette. The resulting structure should look like this:

PIC

We have build the structure of a hierarchical actor system with two actors that send each other messages.

Import the Timing Service

In order to implement the waiting time of the Receiver we need a timing service. The timing service is provided by the model library and must be imported before it can be used in your model.


______________________________________________ ______________________________________________         

room model for Java

1RoomModel PingPong_Model { 
2 
3 import room.basic.service.timing.* from "../../org.eclipse.etrice.modellib.java/model/TimingService.room" 
4 (...)
___________________________________________________         

room model for C

1RoomModel PingPong_Model { 
2 
3 import room.basic.service.timing.* from "../../org.eclipse.etrice.modellib.c/model/TimingService.room" 
4 (...)

This is the first time you use an element from the modellib. Make sure that your Java Build Path or the settings for your C compiler are configured to use the modellib. Otherwise the generated code can not be built.


______________________________________________ ______________________________________________         

build settings for Java
Right click the project PingPong and select Properties -> Java Build Path -> Projects . Add the project org.eclipse.etrice.modellib.java .

PIC

________________________________________________________________________         

build settings for C

Right click the project PingPong and select Properties -> C/C++ Build -> Settings -> Includes. Add the include path org.eclipse.etrice.modellib.c/src-gen to the list.

PIC

Select Properties -> C/C++ Build -> Settings -> Libraries. Add the library org.eclipse.etrice.modellib.c and the library path org.eclipse.etrice.modellib.c/MinGWDebug to the lists. For Posix the path will be org.eclipse.etrice.modellib.c/PosixDebug.

PIC


Now the imported library can be used within your model and we will add the actor with the timing service to our model.

Right click the SubSystemClass SubSysClass1 in the outline view and select Edit Structure. The ActorClass PingPongTop is already referenced in the subsystem as actorRef1. Drag and Drop an ActorRef into the structure of SubSysClass1 and name it timingService. From the actor class drop down list select room.basic.service.timing.ATimingService. Draw a LayerConnection from actorRef1 to the service provision point (SPP) of the timingService. The resulting structure should look like this:

PIC

The layer connection between an ActorRef and a SPP enables the use of service access points (SAP) for the service provided by the SPP, in this case the timing service. SAPs and SPPs are ports with a different kind of connection. Every SAP of the type PTimer inside actorRef1 is now connected automatically by the code generator with the SPP of the timingService.

The current version of eTrice does not provide a graphical element for a service access point (SAP). Therefore the SAPs to access the timing service must be added in the .room file. Open the PingPong.room file and navigate to the Receiver actor. Add the SAP for the protocol PTimer to the structure of the actor:

1 ActorClass Receiver { 
2   Interface { 
3    Port sender: PingPongProtocol 
4   } 
5   Structure { 
6    external Port sender 
7    SAP timing : PTimer 
8   } 
9 }

Now the Receiver can use the timing service.

Inspect the Actor Structure

Before we start with the implementation of the behavior we will have a short look at the instance tree of the application we built so far:

PIC

For each instance you can see the names of the ActorRef s and in brackets the names of the ActorClasses. Starting at the subsystem level this instance tree will be implemented by the code generator. The subsystem will be implemented as process in Linux or Windows.

2.6.5 Implement the Behavior

We will implement two finite state machines (FSMs) to define the event driven behavior of the actors Sender and Receiver.

Before you start with the implementation, have a look at the MSC with the specification of the behavior.

Lets start with the Sender. Right click to Sender in the outline view or the structure editor and select Edit Behavior. Drag and Drop the Initial Point and two States into the top state. Name the states SendingPing and ReceivedPong. Use the Transition tool to draw transitions from init to SendingPing and from SendingPing to ReceivedPong. When you draw a transition, the Dialog Edit Transition opens. Here you can specify the trigger event and the action code for each transition. Note that the initial transition does not have a trigger event. The transition dialog for the Transition from SendingPing to ReceivedPong should look like this:

PIC

The transition will now be triggered by an incoming message ping at the port receiver.

Now we open the dialog Edit State of the state SendingPing by right clicking the state and selecting Edit State from the menu. We want to send the message ping in the entry code of this state. The defined ports will be generated as a member attribute of the actor class from type of the attached protocol. To send a message you must state port.message(param);. In this example receiver.ping(); sends the ping message via the receiver port. You can also use the Button Messages to select the message from the list of available ports and their available messages. Assuming that the actor Receiver is connected to this port, the message will be sent there.

The FSM of Sender should now look like this:

PIC

Now we implement the FSM of the ActorClass Receiver.

PIC

In the entry code of the state WaitingForAWhile we start the timeout:

timing.startTimeout(1000);

In the entry code of the state SentPong we send the message pong back to the Sender:

sender.pong();

Save the diagram and inspect the PingPong.room file. The Receiver should look like this:

1 ActorClass Receiver { 
2   Interface { 
3    Port sender: PingPongProtocol 
4   } 
5   Structure { 
6    external Port sender 
7    SAP timing : PTimer 
8   } 
9   Behavior { 
10    StateMachine { 
11      Transition init: initial -> WaitingForPing { } 
12      Transition tr0: WaitingForPing -> WaitingForAWhile { 
13       triggers { 
14         <ping: sender> 
15       } 
16      } 
17      Transition tr1: WaitingForAWhile -> SentPong { 
18       triggers { 
19         <timeout: timing> 
20       } 
21      } 
22      State WaitingForPing 
23      State SentPong { 
24       entry { 
25         "sender.pong();" 
26       } 
27      } 
28      State WaitingForAWhile { 
29       entry { 
30         "timing.startTimeout(1000);" 
31       } 
32      } 
33    } 
34   } 
35 }

The PingPong model is done now. You can generate, compile and run it as described in Hello World for C or Hello World for Java. The generated MSC in tmp/log should show the same MSC we used to specify the behavior at the beginning of this tutorial.

PIC

Please note that the timeout messages startTimeout and timeout might vary depending on the target language and are not displayed completely correct in the current version (red dot). The MSC logger will be extended to handle this correct in the next version.

2.6.6 Summary

Within this tutorial you have learned how to create a FSM with transitions triggered by incoming messages. You have used entry code to send messages and have used the timing service from the model library. You are now familiar with the basic features of eTrice. Further tutorials and examples will take this knowledge as a precondition.