Build a publish-subscribe design pattern

From TASTE
Jump to: navigation, search

Introduction

In this tutorial we will implement a "publish-subscribe" design pattern with TASTE to support an event manager service.

The idea is the following: the system is made of multiple applications (functions) that do some random processing (guidance, power management, name it). When they run these application can send events to an event manager. An event can have parameters and a criticality level.

At the same time it is possible for an application to subscribe (or unsubscribe) dynamically to the events of another function. The event manager shall be responsible for the forwarding of events to all subscribers of a publisher.

The event manager will also forward all events to a GUI that will display them as they come in a table. Critical events will be highlighted.


The purpose of this case study is to discover some of TASTE more advanced concepts such as:

  • use of PID for selective multicast
  • advanced data manipulation in SDL
  • customized user GUI
  • layout management in Space Creator to make better diagrams

Before diving in this example we advise you to get familiar with TASTE and have basic understanding of SDL. Make sure you have been through the main tutorial before starting!

Interface view: identify the main components of the system

Our system will be made of 3 applications:

  • Guidance, Navigation and Control (GNC)
  • Power Manager
  • Reaction Wheels manager

These components are arbitrary - their behavior and algorithms are irrelevant here. What counts is their interface, as they have to be able to:

  • send and receive events
  • subscribe and unsubscribe to another function's events


ClipCapIt-221210-145401.PNG


On the other side the Event Mangager will provide a matching interface. It is also connected to a "Housekeeping" function that will report all events to the end user.

ClipCapIt-221210-145813.PNG


Once everything is connected, the system looks like this:

ClipCapIt-221210-150029.PNG


At this point you may think that on a larger system the diagram could become unreadable and that the events interface could be hidden to focus on the main applications. We will come back on this below, keep reading!

Data structures

Data structures allow to specify what an event is, and define all the events that all applications can send, with their parameters.

We'll keep it very simple:

ClipCapIt-221210-150823.PNG

Events have a criticality, a sender identifier (the PID type is provided by TASTE, you do not have to define it), and an actual event together with an optional parameter In this example, the events sent by the GNC function have a text string parameter.

Sending an event

From the point of view of an application, sending an event is straightforward. This is the syntax used by the GNC function to send a critical event:

ClipCapIt-221210-151849.PNG


Note the use of the self keyword. It is a constant of PID type and serves to identify the current function.

Subscribing to the events from another function

If for instance the power manager application wants to receive the events sent by the GNC function it can simply register to it like this:

ClipCapIt-221210-152349.PNG

Receiving events from other functions

Add a transition to receive the events from the functions you registered to:

ClipCapIt-221210-153157.PNG


The Event Manager

The event manager is the core function of this system. We will design it as a generic component that is independent from the number or name of the system applications. It basically has to implement the 3 interfaces we identified earlier:

ClipCapIt-221210-153935.PNG


Local data structures

The event manager will hold a lookup table that will list the subscribers of every application.

We need to create two data structures:

  • a variable-size list of PIDs (to store a list of subscribers)
  • a fixed-size table indexed by a PID with each element being the variable-size list of PIDs

It is possible in SDL to create these types locally and avoid "polluting" the main ASN.1 data model used by the TASTE system. Custom data types are defined in text boxes:

ClipCapIt-221210-154620.PNG

A single variable of the second data type is declared, and will be used to manage the list of subscribers.

The Subscribe procedure

The subscription procedure consists of adding the subscriber (via the sender keyword that identifies the caller of the procedure) to the list.

ClipCapIt-221210-155122.PNG


The Unsubscribe procedure

Unsubscribing is a bit more complex as there are no direct operators to remove an element from a list. The technique consists in appending the part of the list before the element with the part after the element. The implementation is left as an exercise to the reader!

The Event procedure

When an event is received, is it forwarded to all the subscribers of the sender, and to the Housekeeping function. This is achieved using a simple loop and using the selective multicast feature of TASTE.

ClipCapIt-221210-195836.PNG

Creating a nice GUI to visualize the events (the Housekeeping function)

When an event is received we want to display it as a log in a table, and highlight critical events in red. TASTE generate defaults GUIs that allow to interact with the system and plot data ; however only the last received message is visible on this GUI. We will now explain how to create this interface to replace the default GUI:

ClipCapIt-221210-200811.PNG

Edit the User-defined Python component

In the Interface view right-click on the Housekeeping function (for which implementation language is set to GUI) and choose Edit Implementation. The Python editor will open with a skeleton function providing an interface to interact with the rest of the system.

ClipCapIt-221210-201630.PNG


Design the user interface with Qt Designer

You may create widgets directly in the Python code ; but Qt provides a tool allowing to design properly the GUI. In the work/housekeeping/GUI/src folder, run the following command:


   $ pyside6-designer


For this example, create a table widget and add the columns corresponding to what we need:

ClipCapIt-221210-202022.PNG


Save the file as "housekeeping.ui" and go back to the Python editor in Space Creator.


Implement the Python GUI

Refer to the PySide6 and Qt documentation for help. To load the .ui file and retrieve the table we have just created, you can add this code to the initialization function:

ClipCapIt-221210-202414.PNG

Then you need to fill in code called when an event is received: fill in the table like this:

ClipCapIt-221210-202611.PNG


Enable the new widget

To activate your widget, these two functions shall return True:

ClipCapIt-221210-202709.PNG


Done!

Go back to the Interface view and click on the Run button to build and execute the system

Simplify the Interface View layout

As we spotted in the beginning, the interface view could easily become hard to read if every single function has to be connected to the Event Manager. To help with this topic, Space Creator allows to create what is called "Connection Layers":

ClipCapIt-221210-203112.PNG

When you right click in this window you can add a new layer (call it Events for this example).

Then when you edit the interfaces of the Event Manager, you can associate this connection layer:

ClipCapIt-221210-203239.PNG

You then have groups of interfaces that you can hide or show all at once.

If you unselect the "Events" connections, the digram will look much lighter:

ClipCapIt-221210-203407.PNG