Autres articles / Other articles

COMx: transmission et réception série

publication: 19 décembre 2024 / mis à jour 19 décembre 2024

Read this page in english

 

Contrôle du délai d'attente E/S

Depuis l'écriture du précédent chapitre, le code du fichier serial.fs a évolué. Ce code est organisé en couches logiques: paramètres pour CreateFileA, contrôle time-out, paramètres port série, initialisation et fermeture port série...

Ce code est susceptible d'évoluer sans préavis. Je vous invite donc à le consulter sur le dépôt GITHUB.

Le code FORTH complet en lien avec cet article est disponible ici:
  GITHUB: eForth-Windows /serial/

Pour tous vos développements Forth, il est fortement conseillé de vous organiser de manière similaire:

Contrôle du délai d'attente E/S

Si l'appareil avec lequel on communique ne répond pas, ou répond dans un délai trop long, il se produit un blocage logiciel quand on exécute ReadFile.

Pour régler les délais d'attente, il faut utiliser le mot SetCommTimeouts dont voici la définition:

\ sets the time-out parameters for all read and write operations  
\ on a specified communications device 
z" SetCommTimeouts" 2 Kernel32 SetCommTimeouts  ( hSerial timeouts -- fl ) 

Paramètres:

Définition de la structure COMMTIMEOUTS:

\ structure control for timeouts 
struct COMMTIMEOUTS 
  i32 field ->ReadIntervalTimeout 
  i32 field ->ReadTotalTimeoutMultiplier 
  i32 field ->ReadTotalTimeoutConstant 
  i32 field ->WriteTotalTimeoutMultiplier 
  i32 field ->WriteTotalTimeoutConstant 

On construit notre structure locale timeouts:

create timeouts 
    COMMTIMEOUTS allot 

Et enfin, on définit le mot set-timeouts. Ici, on ne définit que les délais d'attente en réception de données:

\ set read timeouts 
: set-timeouts  { readInterv readTotInterv -- } 
    timeouts COMMTIMEOUTS erase 
    readInterv      timeouts !field ->ReadIntervalTimeout 
    readTotInterv   timeouts !field ->ReadTotalTimeoutConstant 
    hSerial timeouts SetCommTimeouts  0 = if 
        abort" Error: SetCommTimeouts " .error 
    then 
  ; 

Exemple d'utilisation:

\ Usage: 
50 500 set-timeouts 

Le paramétrage des délais d'attente doit s'effectuer après ouverture du port série, avant toute opération de lecture de données provenant du port série.

Définition des tampons d'entrée-sortie

Les tampons d'entrée-sorties sont simplement des espaces mémoire réservés:

La taille de chaque tampon est définie par les deux constantes dwInQueue et dwOutQueue:

\ initialise in and out buffer sizes 
256 constant dwInQueue 
256 constant dwOutQueue 
 
\ RECeiVe BUFFER used by ReadFile 
create RECV_BUFFER 
    dwInQueue allot 
     
\ SEND BUFFER used by WriteFile 
create SEND_BUFFER 
    dwOutQueue allot 

Ne réservez pas des tampons trop grands si l'application finale ne le nécessite pas. Pour communiquer avec un transmetteur LoRa, des tampons de 256 octets sont très suffisants. Pour transmettre des commandes Forth avec une carte de type Z79Forth ou toute autre carte acceptant des commandes très courtes, les tampons peuvent être ramenés à 128 octets.

Ecriture dans le tampon de sortie

Dans le chapitre précédent, nous avons vu qu'il est possible de transmettre des données avec le mot to-serial. Ce mot utilise les données provenant d'une chaîne de caractères définie par son adresse et sa longueur.

Or, SEND-BUFFER est simplement une zone mémoire. L'idée est d'exploiter cette espace comme une chaine de type z-string. Pour rappel, eForth Windows traite deux type de chaînes de caractères:

Une chaîne de caractère initiée par z" n'empile que l'adresse de début du texte. Cette chaîne se termine toujours par le code $00.

Si on remplit notre tampon SEND-BUFFER avec uniquement des octets à zéro, son contenu peut être considéré comme une chaîne z-string de taille nulle. Pour y affecter un texte, on va utiliser le mot lstrcatA dont voici la définition:

\ Appends one string to another 
z" lstrcatA" 2 Kernel32 lstrcatA  ( lpString1 lpString2 -- lpString1|0 ) 

Le mot lstrcatA concatène le contenu de deux chaînes de type z-string. Il utilise seulement deux paramètres:

On va utiliser ce mot lstrcatA dans une définition qui concatène n'importe quelle chaîne z-string vers SEND_BUFFER:

\ add string to SEND BUFFER 
: +buff!  ( zstr -- ) 
    SEND_BUFFER swap lstrcatA drop 
  ; 

Exemple:

z" AT" +buff!  \ add AT to SEND BUFFER 

On peut également concaténer une chaîne addr-len en utilisant le mot s>z pour modifier cette chaine en chaîne z-string:

s" +SEND=" s>z +buff!  \ add +SEND= to SEND BUFFER 
SEND_BUFFER z>s type   \ display: AT+SEND= 

Pour être certain d'utiliser un tampon vide, il suffit de définir le mot buff!:

\ store new string in SEND BUFFER 
: buff!  ( zstr -- ) 
    SEND_BUFFER dwOutQueue erase        \ reset content of SEND BUFFER 
    +buff! 
  ; 

Le mot buff! est à utiliser chaque fois qu'on souhaite ré-initialiser le contenu du tampon SEND_BUFFER avec une nouvelle séquence de données.

On va terminer ici avec ces trois dernières définitions:

\ compile a zstring  
: +buff"  ( --  ) 
    postpone z" 
    postpone +buff! 
  ; immediate 
 
\ CRLF in z-string format 
create zCRLF 
    $0D c, 
    $0A c, 
    $00 c, 
 
\ CR in z-string format 
create zCR 
    $0D c, 
    $00 c, 

Le mot +buff" concatène le contenu texte qui suit ce mot, délimité par ". Exemple:

: ATband 
    z" AT" buff! 
    +buff" +BAND="  ; 
ATband  SEND_BUFFER z>s type   \ display: AT+BAND= 

Les deux autres mots zCRLF et zCR sont des pseudo-chaînes contenant les codes binaires des commandes CR-LF et CR. Beaucoup de protocoles de communication série nécessitent un délimiteur. Un interpréteur Forth utilise CR. Un transmetteur LoRa utilise CRLF. Exemple:

: ATband?  ( -- ) 
    z" AT" buff! 
    +buff" +BAND=?" 
    zCRLF +buff! 
   ; 

Dans le mot ATband?, on prépare une séquence de commande AT destinée à un transmetteur LoRa. Cette séquence fait remonter l'aide simplifiée de la commande AT Band. Pour envoyer cette commande au transmetteur LoRa, il nous reste à définir ce dernier mot:

\ send content of SEND_BUFFER to serial port 
: buffer-to-serial ( -- ) 
    SEND_BUFFER z>s to-serial 
  ; 

A ce stade, nos outils pour transmettre et recevoir des données semblent satisfaisants pour une application pratique.


Legal: site web personnel sans commerce / personal site without seling