Next: , Previous: , Up: Implementing and integrating foreign components   [Contents]


3.3.2 Implementation of events on interfaces

It’s time to put the information we gathered from the System view in the previous section to use. To get a feel for interacting with the generated System, let’s start with the ‘easy’ method of integrating handwritten code: binding unbound ports. The port that is currently not bound on the AlarmSystem is of type IController. From the perspective of the System, this is a provides port. The IController interface consists of two in-events, namely validPincode and sensorTriggered. If you have a look at the generated IController.hh file, you can see how this translates to generated code:

struct IController
{

  struct
  {
    std::function<void()> validPincode;
    std::function<void()> sensorTriggered;
  } in;

  struct
  {

  } out;
  // Dezyne meta information
}

For every interface in a Dezyne System, such a file is generated. As you can imagine, in-events on an interface can be found in the in struct and out-events in the out struct. These structs contain std::function objects, which can be invoked or assigned to.

In the intoduction, four event types were mentioned. These four types are the cross product of in- and out-events on provides and requires ports. There are two distinct integration steps that can be performed to cover the integration of the four event types. The following table serves as an overview of when to apply what integration step:

Port typeEvent typeUser action
Provides interface (on top of a component)InCall Dezyne function from handwritten code
OutAssign handwritten code to system function
Requires interface (on the bottom of a component)InAssign handwritten code to system function
OutCall Dezyne function from handwritten code

In case of the IController port, a provides port, both of its events are in-events. Therefore, we must call the Dezyne functions from handwritten code. You may recall that earlier in the section we examined the generated AlarmSystem and noted that its IController port can be accessed on the AlarmSystem object (Inspecting the generated system). Then, on the IController port, we can access events from the in and out structs. The calling of events should take place in the event loop which you created.

Let’s make the event loop a bit smarter, so we can use it to process some user input. If we then map the user input to triggers for the validPincode and sensorTriggered events, we can control the AlarmSystem. The following code snippet is sufficient for processing simple user input:

 std::string input;
  while(std::cin >> input) { // Loop is executed upon every newline from user input
    if(input.compare("s") == 0) {
      // s == sensorTriggered
    }
    else if(input.compare("v") == 0) {
      // v == validPincode
    }
  }

If you replace the comments with the corresponding function calls on the AlarmSystem object, the integration steps for the IController port are complete. As an exercise, replace the comments with the help of the information in this section.

Solution:

int
main(int argc, char* argv[])
{
  dzn::locator loc;
  dzn::runtime rt;

  loc.set(rt);

  AlarmSystem as(loc);

  as.check_bindings();

  std::string input;
  while(std::cin >> input) {
    if(input.compare("s") == 0) {
      as.iController.in.sensorTriggered();
    }
    else if(input.compare("v") == 0) {
      as.iController.in.validPincode();
    }
  }
}

At this stage, the AlarmSystem has no unbound ports that contain provides/out or requires/in events. Later in the section, when we add timer functionality to the AlarmSystem, you will see how this integration step is performed (Timer and Siren integration). First, let’s have a look at implementing the LED component.


Next: , Previous: , Up: Implementing and integrating foreign components   [Contents]