Previous: , Up: Expanding the AlarmSystem   [Contents]


3.5.2 Handling data: password entry

The Alarm System you created in the introductory section assumed that the keypad the user entered their password with could assert whether the password was correct. This sounds like an awfully smart component, providing not completely related functionalities in capturing input and assessing the correctness of input. An easy way to split that up would be to separate these two actions; on the IController interface, change the validPassword event to a passwordEntered event with a string parameter and create a component that can be used to assess the validity of a given password.

The new IController interface would look like this:

interface IController {
  in void passwordEntered(String pw);
  in void sensorTriggered();

  behaviour {
    on passwordEntered: {}
    on sensorTriggered: {}
  }
}

The interface for a password management component would look like this:

extern String $std::string$;

interface IPWManager {
	in bool verifyPassword(String pw);

	behaviour {
		on verifyPassword: reply(true);
		on verifyPassword: reply(false);
	}
}

As checking the validity of a password cannot be done in Dezyne, create a component without behavior that provides the IPWManager interface so this can be implemented in foreign code. Additionally, extend the behavior of the Controller component to make use of this new PWManager component by replacing the on iController.validPincode(): event statements with on iController.passwordEntered(pw): statements. The parameter to this function, pw, can then be verified with the new IPWManager port on the Controller component as follows:

    [state.Unarmed] {
      on iController.passwordEntered(pw): {
      	bool valid = iPWManager.verifyPassword(pw);
      	if(valid) {
	        state = State.Armed;
	        iLed.setYellow();
        }
      }
      on iController.sensorTriggered(): {}
      on iTimer.timeout(): illegal;
    }

Implement these changes for the other two state behavior blocks as well (Armed, Alarming). Lastly, update the System component to reflect the new interfaces and components. Re-generate code from the updated Dezyne models and create the necessary files for the foreign implementation of the password manager.

As you were previously capturing user input to trigger events on the AlarmSystem, some changes will need to be made to how the user input was being processed. Instead of mapping ‘v’ to the validPassword event like we did earlier, the simplest way to accommodate for the change is to treat every user input that is not an event trigger as a password entry, like such:

  std::string input;
  while(std::cin >> input) {
    if(input.compare("s") == 0) {
      as.iController.in.sensorTriggered();
    }
    else /*user input counts as password*/ {
      as.iController.in.passwordEntered(input);
    }
  }

Note that the function prototype in C++ for the passwordEntered event accepts std::string as parameter, just like declared in the Dezyne model by using extern String $std::string$;. By calling the passwordEntered event with the input string, the data object is sent to the AlarmSystem. Within the System, the data object is passed to another component; the PWManager component in this case. Although this data object has no meaning for Dezyne model code, Dezyne can transport such data objects across components. Of course, this is a trivially easy example but it should give you an idea of how data gathered from one component can be handled in another component.

The last thing that needs to be done is the foreign implementation of the PWManager component’s behaviour. As an exercise, define and implement the PWManager. The correct password should be “Dezyne” and should only be accessible to the PWManager class itself.

Hint: in C++, you can use string::compare or the operator== to compare strings with one another (http://www.cplusplus.com/reference/string/string/compare/).

Solution:

PWManager.hh:

#include <string>
#include "skel_PWManager.hh"

class PWManager : public skel::PWManager {
  const std::string password = "Dezyne";

  bool iPWManager_verifyPassword(std::string pw);
public:
  PWManager(const dzn::locator& loc);
};

PWManager.cc:

#include "PWManager.hh"

PWManager::PWManager(const dzn::locator& loc) : skel::PWManager(loc) {
  //no op
}

bool PWManager::iPWManager_verifyPassword(std::string pw) {
  return pw.compare(this->password) == 0;
}

Previous: , Up: Expanding the AlarmSystem   [Contents]