URGENT : Système de vote

gribouillex Messages postés 172 Date d'inscription lundi 10 octobre 2005 Statut Membre Dernière intervention 16 mai 2011 - 7 janv. 2008 à 14:19
cs_Jack Messages postés 14006 Date d'inscription samedi 29 décembre 2001 Statut Modérateur Dernière intervention 28 août 2015 - 9 janv. 2008 à 01:04
Je change ma question de catégorie, je m'étais trompé...désolé...


Bonjour,
En tant qu'autodidacte en visual basic, j'ai besoin d'aide concernant un point sur lequel je bute depuis quelque temps.
J'ai acquis un système de vote à fréquence radio. Il s'agit de plusieurs émetteurs sans fil et un récepteur connecté en USB (port COM émulé).
Ce système a l'avantage de proposer un SDK, ce qui m'a permis de créer mon propre programme, en reprenant les codes et la .dll fournis par le constructeur.
Etant encore débutant en vb6 à l'époque, je me suis fait aider par l'assistance technique du constructeur (aux US) afin d'avoir un programme « de base » qui tient la route (ils étaient pas obligés de le faire).
Seulement voilà : le système supposé pouvoir recevoir plus de 1000 votes à la seconde ne réagit pas super bien avec le petit programme qu'on m'a fourni : dans le cas de votes simultanés il arrive très fréquemment  que cela génère un conflit et que les informations n'arrivent pas.
J'ai envoyé un mail au type qui m'a aidé pour lui signaler ce qui m'est arrivé et il m'a répondu ceci : 
If you are using the MSComm control you may have better results if you configure it to interrupt on each character and in the OnComm Event store the received character in a FIFO.<?xml:namespace prefix o ns "urn:schemas-microsoft-com:office:office" /??>

Then from a timer Event load an array from the FIFO to be passed to hitt_inspect, if hitt_inspect returns HITT_ERROR then shift your array elements up by one and add one value from the FIFO to the end of the array and call hitt_inspect again.  You may want to do this in a "While Loop", until hitt_inspect returns HITT_OK.

If you are using the CommIO from here... http://www.thescarms.com/VBasic/CommIO.asp you would do basically the same thing, except you would load the FIFO from a separate timer Event to read the comm.

The example FIFO uses the variant data type, so you should probably change this to the proper type depending on which Com I/O setup you are using, for best performance.

I hope this helps.


Je vois à peu près ce qu'il veut dire, mais je ne sais absolument pas écrire un programme de ce genre ou même adapter celui existant, quelqu'un peut-il m'aider svp  ??? Je vous remercie d'avance.. 


PS : voici le code du programme que j'utilise actuellement.





Dans main.frm (un objet Textbox appelé Text1, un objet Listbox appelé List1, un objet MSComm appelé MSComm2) :





Option Explicit
Dim RecData() As Byte
Dim Key As Long
Dim Id As Long
Dim Result As Long





Private Sub Form_Load()
  With MSComm2
    .CommPort = 5 'Adjust as needed
    .Handshaking = 0
    .RThreshold = 10 ' ici ce qui doit poser problème, non ??
    .RTSEnable = False
    .Settings = "19200,n,8,1" 'Adjust as needed
    .SThreshold = 1
    .InputMode = comInputModeBinary
    .PortOpen = True
  End With
 
  Text1.Text = ""
  List1.Text = ""
End Sub

Private Sub Form_Unload(Cancel As Integer)
    MSComm2.PortOpen = False
End Sub





Private Sub MSComm2_OnComm()
  Select Case MSComm2.CommEvent
      Case comEvReceive
          RecData = MSComm2.Input
          Result = hitt_inspect(RecData(0), Id, Key)
          If Result = HITT_OK Then
            Text1.Text = "Remote ID: " & CStr(Id) & ", Key: " & CStr(Key)
            List1.AddItem "Remote ID: " & CStr(Id) & ", Key: " & CStr(Key)
          Else
            List1.AddItem "not received"
          End If
  End Select
End Sub







Dans Module1 (h-ittsdk.vb) :



Public Const HITT_ERROR As Long = 1
Public Const HITT_OK As Long = 0
Declare Function hitt_inspect Lib "h-ittsdk.dll" (ByRef Bytes As Byte, ByRef Id As Long, ByRef key_code As Long) As Long

9 réponses

cs_Jack Messages postés 14006 Date d'inscription samedi 29 décembre 2001 Statut Modérateur Dernière intervention 28 août 2015 79
8 janv. 2008 à 02:17
Salut
Comme pour les Winsock, les ports Comm (virtuels ou pas) possèdent un buffer.
Si plusieurs émetteurs envoyent des infos pratiquement en même temps, il est possible que le PC n'ait pas le temps de générer un OnComm pour chaque boitier.
A la lecture du buffer (MSComm2.Input), les infos des boitiers se retrouvent donc à la queue-leu-leu.
Entre cette instruction et le traitement par la fonction de la DLL, il te faut vérifier le contenu de ton tableau de bytes RecData.
Insère simplement ceci entre le .Input et le Result =
   Debug.Print UBound(RecData)
Tu verras défiler des chiffres dans la fenêtre de Debug (Ctrl-G) à chaque réception
A mon avis, quand les votes merdouillent, ce tableau est plus grand que d'habitude.

Il te faut donc :
- Déterminer la taille standard d'une réponse = Taille du tableau lorsqu'un seul vote (exemple 10 bytes, de 0 à 9)
- Détecter après le .Input si le tableau ne renferme qu'un seul vote.
Si oui, pas de souci, tu continues
Si non, il faut :
- transférer les 10 premiers bytes dans un nouveau tableau de byte et donner ce nouveau tableau à manger à la DLL
- transférer les 10 bytes suivants dans ce même nouveau tableau direction la DLL
- etc jusqu'à ce qu'il n'y ait plus de donnée.

Le plus simple donc serait de faire une boucle Do-While
   Dim RecData2() As Byte
   Dim TailleRéponse As Integer
   TailleRéponse = 10   ' Exemple avec une réponse qui fait 10 bytes, de 0 à 9)
   ReDim RecData(TailleRéponse - 1)
   Dim x As Integer, y As Integer
   ...
         RecData = MSComm2.Input
         For x = 0 To UBound(RecData) Step TailleRéponse
            For y = x To (x + TailleRéponse)
               RecData2(y) = RecData(x)
            Next y
         Result = hitt_inspect(RecData2(0), Id, Key)   ' modif RecData en RecData2
         If Result = HITT_OK Then
            Text1.Text = "Remote ID: " & CStr(Id) & ", Key: " & CStr(Key)
            List1.AddItem "Remote ID: " & CStr(Id) & ", Key: " & CStr(Key)
         Else
            List1.AddItem "not received"
         End If
         Next x

Si les réponses des boitiers ne sont pas de taille fixe, il faudra parcourrir chaque byte lors de la réception pour détecter quel est le byte de fin, traditionnellement 13 ou 10 (vbCr ou vbLf) ou les deux.
Après détection, il te suffira d'envoyer les trames ainsi découpée selon le même principe sauf que le tableau RecData2 n'aura pas toujours la même taille.

Vala
Jack, MVP VB
NB : Je ne répondrai pas aux messages privés

<hr />Le savoir est la seule matière qui s'accroit quand on la partage (Socrate)
0
cs_Jack Messages postés 14006 Date d'inscription samedi 29 décembre 2001 Statut Modérateur Dernière intervention 28 août 2015 79
8 janv. 2008 à 02:19
lol, boucle Do-Loop qui s'est transformée en double For-Next
0
gribouillex Messages postés 172 Date d'inscription lundi 10 octobre 2005 Statut Membre Dernière intervention 16 mai 2011
8 janv. 2008 à 12:14
Merci jack, j'ai essayé de comprendre tout ça mais j'ai encore un peu de mal.
Je bataille avec mon ignorance et je bute sur des détails. Si je n'arrive pas à mes fins avec l'avancée que j'ai faite ci-dessous, je me pencherai encore sur ta solution.

Car de mon côté j'ai un peu avancé, un piochant et en adaptant des codes trouvés sur le web.
Je pense que je ne suis pas loin de la solution, mais j'ai encore besoin qu'on m'aide....
Le FIFO semble bien géré, le problème c'est que j'ai l'impression que chaque Byte est traité individuellement, alors que j'ai besoin qu'un array (comme le dit le type des US) de 10 bytes soit examiné et passé dans h-itt_inspect.
Le code complet ci-joint

MERCI POUR TOUTE AIDE A CE SUJET

Dim RecData() As Byte
Dim Key As Long
Dim Id As Long
Dim Result As Long
Dim ListFifo() As Byte
Dim donnée As Byte


Function fill_FIFO(MyDonnee As Byte)
''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'Ajout d'une donnée a notre liste FIFO, des qu'elle est ajoutée, on décale toute notre
'liste de 1 pour que ListFifo(0) soit disponible pour recevoir une nouvelle donnée
''''''''''''''''''''''''''''''''''''''''''''''''''''''''
    ListFifo(0) = MyDonnee 'met la donnée en premiere position de la pile
    ReDim Preserve ListFifo(UBound(ListFifo()) + 1) 'ajoute un element a la pile
    For i = UBound(ListFifo()) - 1 To 0 Step -1 'boucle pour décaler les données de la pile
        ListFifo(i + 1) = ListFifo(i) 'décalage de + 1 pour rendre dispo la premiere position de la pile
    Next
    DoEvents
End Function


Private Sub Timer1_Timer()
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'Timer de traitement des informations contenues dans la pile
's'il y a au moins une donnée reçue on traite toute la liste FIFO
'cela permet d'optimiser le traitement et de ne pas dépendre du timer de 1 ms
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
If UBound(ListFifo()) > 0 Then  'si il y a une donnée a traiter
    For i = UBound(ListFifo()) To 1 Step -1 'parcourt la liste dans l'ordre inverse (on traite de la première info reçue a la dernière)
        ''''''''''''''''' c'est en dessous que l'on execute ce que l'on veut avec cette donnée
        donnée = UBound(ListFifo())  'lit la derniere position de la pile
       
        'ici code pour traiter la donnée ou renvoi vers une fonction
        '''''''''''''''''
         Result = hitt_inspect(donnée, Id, Key)
          If Result = HITT_OK Then
            Text1.Text = "Remote ID: " & CStr(Id) & ", Key: " & CStr(Key)
            List1.AddItem "Remote ID: " & CStr(Id) & ", Key: " & CStr(Key)
          Else
            List1.AddItem "HITT_?"
          End If
        '''''''''''''''''
        If UBound(ListFifo()) > 0 Then ReDim Preserve ListFifo(UBound(ListFifo()) - 1) 'si la pile a + d'1 enregistrement, supprime le dernier enregistrement puisque deja traité
        DoEvents 'pour ne pas prendre toutes les ressources CPU dans des traitements continus de la liste Fifo
    Next
       
End If
End Sub

Private Sub MSComm2_OnComm()
    Dim v As Variant
    Dim b() As Byte


    Select Case MSComm2.CommEvent ' event causation
        Case comEvReceive   ' received data
            MSComm2.InputLen = 1
            Do While MSComm2.InBufferCount > 0 ' get each char
                v = MSComm2.Input
                b = v
                Call fill_FIFO(b(0))   ' put into FIFO
            Loop
    End Select
End Sub


Private Sub Form_Load()
ReDim Preserve ListFifo(0) 'initialise le premier enregistrement de la pile
With MSComm2
    .CommPort = 5 'Adjust as needed
    .Handshaking = 0
    .RThreshold = 1
    .RTSEnable = False
    .Settings = "19200,n,8,1" 'Adjust as needed
    .SThreshold = 1
    .InputMode = comInputModeBinary
    .PortOpen = True
  End With
 
  Text1.Text = ""
  List1.Text = ""
End Sub

Private Sub Form_Unload(Cancel As Integer)   If MSComm2.PortOpen True Then MSComm2.PortOpen False
End Sub




 


 


 
0
gribouillex Messages postés 172 Date d'inscription lundi 10 octobre 2005 Statut Membre Dernière intervention 16 mai 2011
8 janv. 2008 à 12:34
Jack, j'ai oublié de dire que lorsque j'ai testé ta solution, j'ai eu l'erreur d'execution 9 : indice en dehors de la plage, sur cette ligne :

RecData2(y) = RecData(x)

Pour info, tu ne l'a pas précisé, mais j'ai réduit le  .RThreshold à 1 au lieu de 10, ce qui me semble être le début de la solution (traiter un caractère après l'autre) , non ?


 


merci
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
cs_Jack Messages postés 14006 Date d'inscription samedi 29 décembre 2001 Statut Modérateur Dernière intervention 28 août 2015 79
8 janv. 2008 à 20:12
Salut
Le RThreshold n'est que seuil à partir duquel le MSComm déclenchera l'évènement OnComm.
Donc, oui, tu peux jouer avec ce paramètre. Cela influencera le traitement puisque tu ne pourras plus avoir les données complètes en une seule passe (mais c'est jouable) et que tu vas générer .
L'exemple de programme avec le tableau FIFO n'est là que pour réordonner les données lors de leur arrivée.
Ceci n'est utile que lorsque tu fais le traitement plus tard. Dans ton cas, tu as décidé d'envoyer les données à la DLL lors de la réception, donc pas de risque d'intervertir les données.
Je pense qu'il faut que tu essayes de trouver quelle est la longueur standard d'une réponse.
As-tu fait l'essai de :
- remettre le RThreshold à une valeur décente (200 par exemple)
- Insérer la ligne Debug.Print dont je t'ai parlé plus haut
- de provoquer un seul vote
et de regarder le chiffre affiché dans la fenêtre de debug.
Repète l'opération de vote pour vérifier que les paquets ont toujours la même taille (pour un vote seul)

Une fois que tu auras ça, il sera facile de lire et comprendre les données contenues dans les données reçues. On en reparlera.

Une chose m'étonne dans le dernier code que tu as montré :
La première ligne bleue     Result = hitt_inspect(donnée, Id, Key)
Dans cette ligne, la variable Donnée correspond à un entier qui correspond à la taille du tableau.
Alors que dans le premier jet, cette variable était la première valeur du tableau RecData(0)
Cette dernière syntaxe me parait cohérente et classique lorsqu'on veut transmettre un tableau à une DLL : On lui envoie le premier élément afin que la DLL calcule l'adresse mémoire du tableau, puis elle se base sur une détection d'un Chr$(0) pour détecter la fin du tableau.
Je ne comprends donc pas comment la nouvelle ligne bleue peut fonctionner : On ne fait référence au tableau de byte nulle part !
Bizarre

Dernière question avant le prochain round : Es-tu familier des manoeuvres du mode "pas à pas" de VB6 ?
Ceci est très pratique pour debugger :
- Clique sur une des lignes de ton programme
- Appuie sur F9 pour lui demander de s'arrêter là quand il passera
- Lance ton programme et attend que l'IDE pointe cette ligne
- Une fois que le programme est stoppé sur cette ligne, un simple survol de la souris sur les varaibles affiche son contenu.
De plus, la fenêtre de debug (Ctrl-G) permet de lancer quelques commandes qui permet de mieux voir le contenu des variables, par exemple, tu peux lancer un    ? RecData(0)    pour lui demander d'afficher (Print) le contenu de cette varaible du tableau

Vala
Jack, MVP VB
NB : Je ne répondrai pas aux messages privés

<hr />Le savoir est la seule matière qui s'accroit quand on la partage (Socrate)
0
cs_Jack Messages postés 14006 Date d'inscription samedi 29 décembre 2001 Statut Modérateur Dernière intervention 28 août 2015 79
8 janv. 2008 à 20:14
J'oubliais une partie importante du "pas à pas" :
Quand tu es stoppé sur une ligne, tu peux :
- F8 : Avancer d'une seule instruction
- F5 : Continuer l'exécution classique du programme ... jusqu'à ce qu'il rencontre à nouveau la ligne du point d'arrêt (pointée par F9)
0
cs_Jack Messages postés 14006 Date d'inscription samedi 29 décembre 2001 Statut Modérateur Dernière intervention 28 août 2015 79
8 janv. 2008 à 20:25
Encore moi
Toute reflexion faite, le RThreshold à 1 n'est peut-être pas une mauvaise idée.
Elle garantit de récupérer les infos dès qu'elles arrivent.
Cela implique de les stocker. L'utilisation du tableau FIFO est donc utile.
Cela n'empèche qu'il faut quand même estimer la taille standard d'une réception pour savoir quand il est utile d'envoyer les infos à la DLL.
Une fois que tu auras cette info, on pouura dépouiller les données et voir :
- si on retrouve les infos renvoyées par la DLL (des fois, les DLL ne servent pas à grand chose)
- de détecter si une trame se termine bien par Chr$(0)
0
gribouillex Messages postés 172 Date d'inscription lundi 10 octobre 2005 Statut Membre Dernière intervention 16 mai 2011
8 janv. 2008 à 21:05
Merci Jack pour tous tes efforts,

J'ai pu résoudre mon problème avec l'aide de mon contact aux US.


La solution n'était pas loin en effet, il a solutionné ça grace à un Stack FIFO en module de classe.(code par Philip Bradbury First In-First Out Stack). Les données arrivant dans OnComm partent tout droit dans le magasin FIFO.

A chaque vote, il y a toujours 10 bytes qui arrivent. Donc, dans le timer, dès que le programme atteint 9, il créé un buffer de données qui lui, est balancé dans hitt_inspect...

Le RThreshold est bien à 1.

Bref la solution n'était pas loin...
 
Pour info, oui, je connais le mode "pas à pas"... j'ai commencé à apprendre le vb par nécessité. C'est le meilleur moteur pour apprendre. On chercher, on fouille, on bidouille et on essaye de comprendre les codes existants... c'est comme ça que je fais.. c'est pour ça que je bloque de temps en temps sur des choses anodines... On se refera pas.

En tout cas, merci beaucoup Jack, tes explications m'ont justement beaucoup appris.
0
cs_Jack Messages postés 14006 Date d'inscription samedi 29 décembre 2001 Statut Modérateur Dernière intervention 28 août 2015 79
9 janv. 2008 à 01:04
Bienvenu, Gribouillex
Avec mes histoires de détection de paquet, et de 10 bytes en plus, j'étais tombé plie poil !
Faut que je j'aille jouer au loto, bonne journée.
0
Rejoignez-nous