J’ai hacké mon onduleur ou le reverse engineering de protocoles de communication (part 9)

Comme indiqué dans mon précédent post, je vais expliquer le fonctionnement d'un timer. Très utilise lorsqu'on souhaite faire une action spécifique à intervalle régulier. Je vais également en profiter pour montrer comment créer une propriété en lecture et écriture. En plus, je vais expliquer comment lever des exceptions dans son propre code.

Une bonne partie de tout cela se trouve condensé dans la fonction d'ouverture de l'onduleur. Voici donc le code avec les déclarations de variables et constantes nécessaires à la compréhension.

 

Const ERREUR_IDENTITE = "Impossible d'obtenir l'identité de l'onduleur"

Const ERREUR_ALIM_BATTERIE = "Impossible d'obtenir les informations de batterie"

Const ERREUR_ALIM_SECTEUR = "Impossible d'obtenir les informations de secteur"

Const PERIOD_APPEL = 3000 '2 secondes = 2000 milisecondes

Private myPeriodeAppel As
Integer = PERIOD_APPEL

Private myPort As SerialPort

Private myPortSerie As
String = ""
'stocke le nom du port

Private myTimer As Timer

 

Public
Function Ouvrir(ByVal StrPort As
String) As
Boolean

Try

'ouvre le port série avec le bonnes infos

myPortSerie = StrPort

myPort = New SerialPort(StrPort, 2400, Ports.Parity.None, 8, Ports.StopBits.One)

'le caractère de fin de ligne est chr(13), c'est à dire Entrée

myPort.NewLine = Chr(13)

'délais d'attente de 2 secondes

myPort.ReadTimeout = 2000

myPort.Open()

myPort.DtrEnable = True

'vérifie que l'on a bien un onduleur et rempli les bonnes fonctions

If
Not (EnvoiCommande(OnduleurCommande.Identite)) Then

Throw
New System.Exception(ERREUR_IDENTITE)

End
If

If
Not (EnvoiCommande(OnduleurCommande.Batterie)) Then

Throw
New System.Exception(ERREUR_ALIM_BATTERIE)

End
If

If
Not (EnvoiCommande(OnduleurCommande.Tension)) Then

Throw
New System.Exception(ERREUR_ALIM_SECTEUR)

End
If

'toutes les propriétés ont été remplies

'intialise le timer, récupère les infos toutes les 5 secondes

myTimer = New Timer(AddressOf VerifierStatut)

myTimer.Change(0, myPeriodeAppel)

Return
True

Catch ex As Exception

'si ça ne s'ouvre pas, répercute l'exception

Throw ex

Return
False

End
Try

End
Function

La fonction Ouvrir prend un paramètre qui doit contenir une chaîne de type COM1, COM2 ou autre permettant d'ouvrir le port série. Le tout se trouve dans un try – catch qui va permet de récupérer les exceptions qui peuvent être levées. En cas de problème, sur le port série, il est important de ne pas laisser planter l'application et de le remonter à l'appelant.

Sur le même principe, lorsque le port série est ouvert, la fonction EnvoiCommande(OnduleurCommande.Identite) renvoie True si les informations de type modèle, sous modèle, version sont récupérés. Si ce n'est pas le cas, elle renvoie False. Du coup, si un onduleur n'est pas présent, les informations ne seront pas récupérées et False sera renvoyé. Dans ce cas, nous sommes devant un problème et on lève une exception. Cela se fait simplement à l'aide le la ligne Throw New System.Exception("ce que l'on veut envoyer"). Simple et efficace.

Quand au timer, simple également. Il suffit de déclarer une variable de type Timer, ici myTimer. Ensuite, il faut créer une fonction de callback (rappel). Elle permettra au lors du déclanchement du timer de venir se brancher et d'exécuter le code de la fonction. La fonction de call back s'appelle VerifierStatut. Sa définiton est ci-dessous. L'initialisation se fait donc en indiquant myTimer = New Timer(AdressOf VerifierStatut). AdressOf renvoie un pointeur de la fonction de callback. Il ne reste plus qu'à initialiser le timer : myTimer.Change(0, myPeriodeAppel). 0 indique qu'il doit se déclencher maintenant. Le myPeriodeAppel indique l'intervalle en milli secondes d'appel de la fonction de callback.

Private
Sub VerifierStatut(ByVal stateInfo As
Object)

'pas de vérification particulière. En cas de problème, les exceptions sont trappées dans la fonction EnvoiCommande

EnvoiCommande(OnduleurCommande.Tension)

End
Sub

Dans mon cas, par défaut, lors de l'ouverture de l'onduleur, l'appel se fait toutes les 3000 milli secondes soit toutes les 3 secondes. J'ai implémenté en plus dans ma gestion d'onduleur une propriété qui permet de modifier cette valeur. Je ne sais pas encore par avance tous les combiens de temps, il est nécessaire de l'appeler. Donc, je me garde la possibilité de modifier cette valeur. Cependant, pour des questions de performances, je ne souhaite pas que l'appel soit fait à moins d'une seconde. J'exprime donc ma propriété en secondes et choisi des byte.

L'implémentation de la propriété donne cela :

Public
Property PeriodeAppel() As
Byte

Get

Return (myPeriodeAppel / 1000)

End
Get

Set(ByVal value As
Byte)

If value > 0 Then

myPeriodeAppel = value * 1000

myTimer.Change(0, myPeriodeAppel)

End
If

End
Set

End
Property

La lecture (Get) est simple, je renvoie la période d'appel divisée par 1000 car en interne ma variable est en milli secondes.

Pour l'écriture (Set), je vérifie que la valeur est bien supérieur à 0 (donc au moins égale à 1). Je la multiplie par 1000, et je change la période d'appel de mon timer.

Avec VB.NET, il est donc très facile de lever des exceptions, facile également d'implémenter et gérer un timer, de mettre en place des propriétés, en lecture et en écriture. Avec un comportement particulier qui modifie l'application dans la partie lecture ou écriture.

Le prochain post sera certainement consacré à la mise en place d'un service Windows. Seule chose qu'il me reste à faire par rapport à mon ambition d'origine ! So stay tune…