This is an old revision of the document!
Dans l'exemple précédent, nous appelons une fonction externe à la classe Button
. En fait, nous aimerions avoir une classe Button
à laquelle nous pourrions ajouter le comportement que doit avoir l'objet quand un événement se produit, comme par exemple appuyer sur le bouton ou relâcher le bouton.
===== Question n°1 =====
Ajouter trois méthodes virtuelles à votre classe
Button
qui correspondent à :
* OnPressed()
: on appuie sur le bouton.
* OnReleased()
: on relâche le bouton.
* OnChanged()
: soit le bouton a été appuyé, soit le bouton a été rélâché.
ces méthodes sont vides.
===== Question n°2 =====
La difficulté vient du fait que la méthode attachInterupt
ne passe aucune information à la méthode ISR
qui est appelé. En conséquence, c'est le nom de la méthode qui est associé avec l'interruption qui permet de savoir quel est le port et qu'elles sont les actions à effectuer.
Si nous supposons monitoré l'ensemble des 13 ports de la carte DUE, nous devrions écire trois fonctions pour chacun des ports :
<code cpp>
void OnPressedPort1();
void OnReleasedPort1();
void OnChangedPort1();
</code>
et de même pour le port 2, 3, ….
On va profite des objets pour simplifier l'écriture. Pour ce faire, nous allons définir une classe interne de la classe button
qui va permetter de fournir les trois fonctions de base Pressed
corresspondant à l'événement le bouton a été pressé, Released
que le bouton a été relâché, Changed
que l'état du bouton a changé. Ces fonctions vont simplement appelé pour le bouton si un bouton est présent sur le port donné la méthode virtuelle OnPressed()
, (resp. OnReleased()
ou OnChanged()
) défini dans la classe Button
.
<code cpp>
class Button
{
private:
struct EventHandler
{
public:
static Button* MonitoredButton;
static void Pressed()
{
if(MonitoredButton != NULL)
MonitoredButton→OnPressed();
}
static void Released()
{
if(MonitoredButton != NULL)
MonitoredButton→OnReleased();
}
static void Changed()
{
if(MonitoredButton != NULL)
MonitoredButton→OnReleased();
}
};
</code>
Ceci va donc nous créer nos 3 fonctions Pressed
, Released
et Changed
de type void interruptHandler()
que nous pouvons passer à la fonction attachInterupt
.
Maintenant, il faut en créer 13. Comment faire ? Simplement en ajoutant un tableau statique correspondant aux 13 ports que nous pouvons monitorer et créant pour chacun des port une classe de type EventHandler
.
<code cpp>
public class Button
{
class Button
{
private:
struct EventHandler
{
public:
static Button* MonitoredButton;
static void Pressed()
{
if(MonitoredButton != NULL)
MonitoredButton→OnPressed();
}
static void Released()
{
if(MonitoredButton != NULL)
MonitoredButton→OnReleased();
}
static void Changed()
{
if(MonitoredButton != NULL)
MonitoredButton→OnReleased();
}
};
static EventHandler m_EventHandlers[14];
}
</code>
Un champ static
est un champ qui est partagé par tous les objets Button
, il n'y a qu'un seul m_EventHandlers
qui est commun à tous les les objets Button
.
Modifier le constructeur pour que chaque fois que l'on crée un nouveau Button
qui est associé au port portNumber
, on pense à modifier le tableau m_EventHandlers
pour qu'il sache que le nouveau Button
créé est associé au port portNumber
, donc que l'objet situé à l'indice désigne par le portNumber
sache qu'il doit appelé les actions définies dans l'objet nouvellement créé.
Typiquement, nous allons avoir un constructeur de type suivant :
<code cpp>
public class Button
{
private:
struct EventHandler
{
public:
static Button* MonitoredButton;
static void Pressed()
{
if(MonitoredButton != NULL)
MonitoredButton→OnPressed();
}
static void Released()
{
if(MonitoredButton != NULL)
MonitoredButton→OnReleased();
}
static void Changed()
{
if(MonitoredButton != NULL)
MonitoredButton→OnChanged();
}
};
static EventHandler m_EventHandlers[14];
public:
Button(uint32_t thePortNumber, const char* theName, bool isDebug = false):
CustomComponent(theName, isDebug)
{
…
mRegistredButtons[thePortNumber].MonitoredButton = this;
}
…
};
</code>
===== Question n°3 =====
Nous considérons les deux événements que nous définissons dans le type enum
suivant qui définit deux valeurs PRESSED
indiquant que le bouton vient d'être enfoncé et RELEASED
indiquant que le bouton est relâché.
<code cpp>
enum button_event { PRESSED = 0x1, RELEASED = 0x2 };
</code>
Nous souhaitons créer une fonction qui active l'interruption ou les interruptions nécessaires pour chacun des événements identifiés par PRESSED
et RELEASED
.
Typiquement, l'action de MonitorEvents(PRESSED)
d'activer le moniteur d'interruption suivant :
<code cpp>
attachInterrupt(m_PortNumber, mEventHandles[m_PortNumber].Pressed, RISING);
</code>
Compléter le code de la classe.
<code cpp>
class Button
{
public:
void MonitorEvents(button_event theEvents)
{
…
}
}
</code>
===== Question n°4 =====
Pour définir un bouton qui implante une action quand l'utilisateur appuie sur le bouton, il suffit de surcharger désormais dans une classe dérivée la méthode OnPressed()
.
Vous pouvez désormais écrire :
class LedButton: Button
{
private:
Led mLed;
public:
LedButton(uint32_t thePortNumber, Led& theLed): Button(thePortNumber, “LedButton”, false)
{
MonitorEvents(PRESSED);
}
void OnPressed()
{
if(mLed.IsSwitchOn())
mLed.SwitchOff();
else
mLed.SwitchOn();
}
};