Documentation:Tutorial:Events - MdsWiki
Navigation
Personal tools

From MdsWiki

Jump to: navigation, search

Asynchronous events in MDSplus

In MDSplus it is possible to generate asynchronous events as well as waiting for them. Events are often used to synchronize data visualization in jScope: an update event name can be defined in the jScope Setup Data pop-up window, forcing an update of the displayed signal whenever such an event is received. Data acquisition events in this case are generated by the data acquisition routines (usually the methods of the devices involved in data acquisition).

There are two MDSplus executables which can be called from a console: wfevent <Event_name> and setevent <event_name> . The former suspends until an event with that name has been received; the latter generated such an event.

In MDSplus there exist several implementations of asynchronous events: the most recent uses UDP multicast, and therefore events can be exchanged among applications residing on different machines in the same LAN. UDP multicast is the default communication for MDSplus events.
By default, MDSplus uses port 4000 and multicast address 224.0.0.175. Port and multicast address can be changed by defining environment variables mdsevent_port and mdsevent_address, respectively. In particular, a range of multicast addresses can be specified by specifying for mdsevent_address the format n.n.n.n-n (if a single address is specified, the format is n.n.n.n).

However, not always UDP messages can be transferred among subnetworks, so a different configuration is required in this case, using TCP/IP-based events. TCP/IP - based events rely on mdsip communication. In order to send events over mdsip (instead of multicast UDP) it is necessary to define environment variable mds_event_target as the mdsip address (<ip address>[:port]) of the intended target mdsip server. In this case issued events will not be sent over multicast UDP, but will be sent to the targer mdsip server via mdsip (TCP/IP based).
Every event listener running on the same machine hosting the mdsip server can then receive the events issued via mdsip (provided, of course that the event name matches). It is also possible to allow event reception by means of event listeners running on other machines not hosting a mdsip server by defining environment variable mds_event_server as the mdsip address (<ip address>[:port]) of the intended source mdsip server. In this case the receiver will no more listen to events from multicast UDP, but from the selected mdsip server.

The Classes for Event Management

MDSplus defines one class, Event, for event generation and reception. In addition to notification, MDSplus events can bring data, either raw or "packed" into Data instances. The event issuer can then optionally associate data top the event, which will be received by every listener for that event. Events can be generated by the following methods:

  • setevent(name) to generate an event with no associated data
  • seteventRaw(name, buffer) to generate an event carrying a buffer of bytes
  • setevent(name, Data) to generate an event carrying a Data instance

To handle event reception it is necessary to extend Event class by associating the actions to be executed upon event reception. Class Event in fact defines the virtual function run(), which is called after the class instantiation whenever the event with the specified name has been received. The overridden run() method can then retrieve received data by calling superclass' getData() or getRaw() methods. The following code shows how to define a new Event class called MyEvent whose action is to print the content of the received buffer. It is possible to test the programs using the command

setevent <event_name> <Data String>

which generates an event with the specified name and passing the second parameter as a string buffer.

C++

#include <mdsobjects.h>
using namespace MDSplus;
class MyEvent:public Event
{
public:
    MyEvent(char *name):Event(name){}
    void run()
    {
        int bufSize;
        char *name = getName(); //Get the name of the event
        char *date = getTime()->getDate(); //Get the event reception date in string format
        char *buf =  getRaw(&bufSize); //Get raw data
        char *str = new char[bufSize+1]; //Make it a string
        memcpy(str, buf, bufSize);
        str[bufSize] = 0;
        cout << "RECEIVED EVENT " << name << " AT " << date << " WITH DATA  " << str << "\n";
    }
};

Java:

import MDSplus.*;
class MyEvent extends Event
{
     public MyEvent(java.lang.String event)throws Exception
     {
         super(event);
    }
    public void run()
    {
        System.out.println("RECEIVED EVENT "+ getName()+" AT " + getTime().getDate()+" WITH DATA  " + new java.lang.String(getRaw()));
    }
}

Python:

import sys
import time
from MDSplus import *

class MyEvent(Event):
       def run(self):
             print("RECEIVED EVENT " + self.getName())
             print(self.getTime())
             print(self.getRaw())

def main(arg):
      eventObj=MyEvent(arg)
      time.sleep(1000000)   #wait for events

if __name__=="__main__":
      arg = str(sys.argv[1])
      main(arg)


Using the Python example, try the following. From the event receiver's terminal, you can execute the above Python code that will be listening for events (assuming the above code was saved in a file with the name "myevent.py"):

python myevent.py hi!

The receiver will be listening. Now, open a new terminal and execute:

setevent hi! my_data_string

The receiver's terminal will print on the screen something like the following:

RECEIVED EVENT hi!
1548967068.08605
Byte_Unsigned([109,121,95,100,97,116,97,95,115,116,114,105,110,103])
where the Byte_Unsigned(...) in this example is the data string received.