![]() |
guill.net
-
La page des réseaux
|
![]() |
|
![]() ![]() ![]() |
Première partie : Gestion des entrées/Sorties de périphériques
L’une des grandes force Windows
NT et de Windows 95 réside dans le nombre de périphériques
que ces environnements savent gérer. D’un façon générale,
nous pouvons définir un périphérique comme quelque
chose permettant une communication. Voici une liste décrivant leur
usage habituel :
Périphériques | Usage |
Fichier | Stockage de données |
Répertoire | Attributs et compression de fichiers |
Disque logique | Formatage |
Disque physique | Table de partitionnement |
Port série | Transmission de données en série |
Port parallèle | Envoi de données en parallèle |
Console | Une fenêtre texte |
Win32 tente de masquer les différences entre périphériques afin de faciliter la tâche du développeur d’application. Ainsi, lorsque vous avez ouvert un périphérique, les fonctions Win32 qui permettent de lire ou d’écrire des données, sont les même quel que soit le mode de communication employé.
Cette partie présente les différents mécanismes disponibles pour lire et écrire des données sur un périphérique. Nous nous intéresserons plus particulièrement à la manipulation de ces fonctions pour des périphérique de type port série.
Il faut noter que bien que les fonctions utilisées soient communes à tout type de périphérique leur utilisation et paramétrage diffère d’un périphérique à l’autre. Par exemple nous pouvons régler la vitesse de transmission sur une ligne série, mais ce paramètre n’a aucun sens pour un fichier.
Ouvrir et fermer un périphérique
Avant de pouvoir effectuer une quelconque opération d’entrée/sortie, vous devez ouvrir le périphérique et obtenir un handle. D’une façon générale la plupart des périphériques sont ouvert avec la fonction CreateFile, dont la description est donnée ci après :
HANDLE CreateFile(
LPCTSTR
lpFileName,
DWORD
dwDesiredAccess,
DWORD
dwShareMode,
LPSECURITY_ATTRIBUTES
lpSecurityAttributes,
DWORD
dwCreationDistribution,
DWORD
dwFlagsAndAttributes,
HANDLE
hTemplateFile
);
Le paramètre lpFileName identifie le type de périphérique ainsi que l’instance spécifique de ce périphérique. LpFileName aura pour valeur :
Valeur | Signification |
0 | Vous ne souhaitez
ni Lire ni écrire sur le périphérique.
Vous souhaitez juste changer sa configuration et ses réglages |
GENERIC_READ | Permet des accès en lecture seule sur le périphérique |
GENERIC_WRITE | Permet des accès en écriture seule sur le périphérique. |
GENERIC_READ| GENERIC_WRITE | Permet des accès en lecture et en écriture sur le périphérique |
Le paramètre dwShareMode
détermine les privilèges de partage. Sous Windows 95 et Windows
NT, un périphérique peut être employé par plusieurs
ordinateurs à la fois ou par plusieurs processus en même temps.
Il devient alors important de pouvoir réduire les droits d’accès
des autres systèmes et processus sur le périphérique
que vous utilisez. Les différentes valeurs possibles pour dwShareMode
sont :
Valeur | Signification |
0 | Vous souhaitez
un accès exclusif à ce périphérique. S’il est
déjà ouvert, CreateFile échoue.
Si vous l’ouvrez et qu’un autre appel CreateFile est effectué ensuite, cet appel échouera. |
FILE_SHARE_READ | Vous souhaitez
utiliser le périphérique en lecture seul. S’il est déjà
ouvert en écriture, CreateFile échouera.
Si vous l’ouvrez et qu’un autre appel CreateFile est effectué en écriture, cet appel échouera. |
FILE_SHARE_WRITE | Vous souhaitez
uniquement écrire dans le périphérique. S’il est déjà
ouvert en lecture, CreateFile échouera.
Si vous l’ouvrez et qu’un autre appel CreateFile est effectué en lecture, cet appel échouera. |
FILE_SHARE_READ| FILE_SHARE_WRITE | Vous souhaitez
utiliser le périphérique en lecture et en écriture.
Si le périphérique est déjà ouvert pour un accès exclusif, CreateFile échouera. Si vous l’ouvrez et qu’un autre appel CreateFile est effectué en lecture ou en écriture, cet appel échouera. |
Le paramètre lpSecurityAttributes, pointe sur une structure SECURITY_ATTRIBUTES qui vous permet de préciser les informations de sécurité de l’objet du noyau associé au périphérique. Vous définissez également si le handle obtenu en retour sera héritable ou non ( permettant ainsi à des processus enfant d’accéder au périphérique). Le paramètre est NULL si vous souhaiter mettre en œuvre la sécurité par défaut et un handle non héritable.
Le paramètre dwCreationDistribution
est utile lorsque CreateFile ouvre un fichier. Les différentes valeurs
dwCreationDistribution sont :
Valeur | Signification |
CREATE_NEW | Demande à CreateFile de créer un nouveau fichier. Echec si un fichier de même nom existe. |
CREATE_ALWAYS | Demande à CreateFile de créer un fichier sans vérification de l’existance ou non de l’existance d’un fichier de même nom. |
OPEN_EXISTING | Demande à CreateFile d’ouvrir un fichier existant. Erreur si le fichier n’existe pas. |
OPEN_ALWAYS | Demande à CreateFile d’ouvrir un fichier s’il existe ou de le créer s’il n’existe pas encore. |
TRUNCATE_EXISTING | Demande à
CreateFile
d’ouvrir un fichier existant et de ramener sa taille à 0 octet.
Echec si le fichier n’existe pas déjà. Le drapeau GENERIC_WRITE doit être également utilisé. |
Lorsque vous appelez CreateFile pour ouvrir un périphérique qui n’est pas un fichier, vous devez utiliser OPEN_EXISTING pour le paramètre dwCreationDistribution.
Le paramètre dwFlagsAndAttributes
vous permet de définir des drapeaux affinant la communication avec
le périphérique et si le périphérique est un
fichier vous obtenez ses attributs. Dans le cas de la communication qui
nous intéresse nous n’utiliserons pas ce paramètre : valeur
= 0. Il faut noter que si vous souhaitez utiliser le périphérique
de manière asynchrone, il faut utiliser le drapeau FILE_FLAG_OVERLAPPED.
Ce drapeau indique au système que vous voulez accéder au
fichier de manière asynchrone ( par défaut l’ouverture est
synchrone).
Si vous communiquer en mode
synchrone, le programme est suspendu dans l’attente des informations devant
être lues. Une fois la lecture terminée, le programme reprend
le contrôle et continue sont exécution.
Théoriquement les
entrées/sorties sur les périphériques étant
très lentes par rapport à la plupart des opérations
du processeur, il est préférable de communiquer avec un périphérique
de façon asynchrone. Dans le principe, vous appelez une fonction
demandant au système d’exploitation de lire ou d’écrire des
données mais cette fonction rend la main immédiatement, sans
attendre la fin de l’opération. Le système d’exploitation
traite votre demande de façon autonome et vous renvoie un message
lorsque le traitement est terminé. Pendant ce temps votre application
a continué à s’exécuter. Nous ne traiterons pas ce
cas dans notre exemple.
Le paramètre hTemplateFile permet de spécifier les attributs du fichier. Il aura pour valeur NULL dans notre cas
Nous allons maintenant aborder la lecture et l’écriture de donnée synchrone sur un périphérique
Lecture et écriture synchrone sur un périphérique :
Cette section aborde les fonctions de Win32 qui permettent des lectures et des écritures synchrones sur des périphériques ( nous ne traiterons pas les lecture asynchrones ). Rappel un périphérique peut être un fichier, un canal, un port …
La méthode la plus simple et la plus facile à mettre en œuvre pour lire et écrire des fichiers passe par les deux fonctions :
BOOL ReadFile(
HANDLE
hFile, // handle of file to read
LPVOID
lpBuffer, // address of buffer that receives data
DWORD
nNumberOfBytesToRead, // number of bytes to read
LPDWORD
lpNumberOfBytesRead, // address of number of bytes read
LPOVERLAPPED
lpOverlapped // address of structure for data
);
BOOL WriteFile(
HANDLE
hFile, // handle to file to write to
LPCVOID
lpBuffer, // pointer to data to write to file
DWORD
nNumberOfBytesToWrite, // number of bytes to write
LPDWORD
lpNumberOfBytesWritten, // pointer to number of bytes written
LPOVERLAPPED
lpOverlapped // pointer to structure needed for overlapped I/O
);
bien que chacune de ces fonctions possèdent le mot File dans son nom, elles peuvent être utilisées avec n’importe quel type de périphérique.
Le paramètre hFile identifie le handle du périphérique auquel vous souhaitez accéder.
Le paramètre lpBuffer pointe sur une mémoire tampon qui servira lors des échanges d’écriture/lecture entre le périphérique et l’application.
Le paramètre nNumberOfBytesToWrite et nNumberOfBytesToRead indique à ReadFile et WriteFile combien d’octets doivent être lus ou écrits sur le périphérique.
Le paramètre lpNumberOfBytesRead et lpNumberOfBytesWritten indique l’adresse d’un DWORD contenant le nombre d’octets réellement transmis.
Le paramètre lpOverlapped doit être NULL lors d’opération synchrone.
Les fonctions ReadFile et WriteFile renvoient TRUE en cas de succès. ReadFile ne peut être utilisée qu’avec des périphériques ouvert avec le drapeau GENERIC_READ. De même WriteFile ne peut être utilisée que si le périphérique est ouvert avec le drapeau GENERIC_WRITE.
Configuration du périphérique de communication
Le fichier étant ouvert il ne nous reste plus qu’à configurer le port de communication. Pour cela nous utilisons la fonction SetCommSate :
BOOL SetCommState(
HANDLE
hFile, // handle of communications device
LPDCB
lpDCB // address of device-control block structure
);
Le paramètre hFile identifie le handle de communication retourné par la fonction CreateFile
Le paramètre lpDCB indique l’adresse de la structure DCB contenant les informations de configuration spécifique au port de communication.
Description de la structure DCB
La structure DCB permet de configurer le port serie. Cette structure est définie comme suit :
typedef struct _DCB {
// dcb
DWORD
DCBlength;
// sizeof(DCB)
DWORD
BaudRate;
// current baud rate
DWORD
fBinary: 1; // binary
mode, no EOF check
DWORD
fParity: 1; // enable
parity checking
DWORD
fOutxCtsFlow:1; // CTS output flow control
DWORD
fOutxDsrFlow:1; // DSR output flow control
DWORD
fDtrControl:2; // DTR flow control
type
DWORD
fDsrSensitivity:1; // DSR sensitivity
DWORD
fTXContinueOnXoff:1; // XOFF continues Tx
DWORD
fOutX: 1;
// XON/XOFF out flow control
DWORD
fInX: 1;
// XON/XOFF in flow control
DWORD
fErrorChar: 1; // enable error replacement
DWORD
fNull: 1;
// enable null stripping
DWORD
fRtsControl:2; // RTS flow control
DWORD
fAbortOnError:1; // abort reads/writes on error
DWORD
fDummy2:17; // reserved
WORD
wReserved;
// not currently used
WORD
XonLim;
// transmit XON threshold
WORD
XoffLim;
// transmit XOFF threshold
BYTE
ByteSize;
// number of bits/byte, 4-8
BYTE
Parity;
// 0-4=no,odd,even,mark,space
BYTE
StopBits;
// 0,1,2 = 1, 1.5, 2
char
XonChar;
// Tx and Rx XON character
char
XoffChar;
// Tx and Rx XOFF character
char
ErrorChar;
// error replacement character
char
EofChar;
// end of input character
char
EvtChar;
// received event character
WORD
wReserved1;
// reserved; do not use
} DCB;
Le paramètre DCBlength donne la taille en octets de la structure.
Le paramètre BaudRate spécifie la vitesse de transmission sur le port série. La valeur peut être n’importe quelle valeur ou une des valeurs standards définies ci après :
CBR_110
CBR_300 CBR_600 CBR_1200 CBR_2400 CBR_4800 CBR_9600 CBR_14400 |
CBR_19200
CBR_38400 CBR_56000 CBR_57600 CBR_115200 CBR_128000 CBR_256000 |
FBinary doit être à TRUE pour des application Windows.
Le paramètre fParity spécifie la vérification ou non de la parité. TRUE la parité est vérifiée et une erreur est générée si nécessaire.
Les paramètres suivants ne sont pas utilisés en communication 3 fils. Il sont uniquement à configurer dans le cas de protocole XON/XOFF et permettent de contrôler les signaux DTR ( terminal prêt), CTS(Voie Libre), DSR ( jeu de donnée prêt), RTS (demande pour émettre) . Nous ne rentrerons donc pas dans le détail de ces paramètres. De façon générale, et dans le cadre de cette présentation, nous leur affecterons la valeur 0.
FOutxCtsFlow
Specifies whether the CTS
(clear-to-send) signal is monitored for output flow control. If this member
is TRUE and CTS is turned off, output is suspended until CTS is sent again.
fOutxDsrFlow
Specifies whether the DSR
(data-set-ready) signal is monitored for output flow control. If this member
is TRUE and DSR is turned off, output is suspended until DSR is sent again.
fDtrControl
Specifies the DTR (data-terminal-ready)
flow control. This member can be one of the following values:
Value | Meaning |
DTR_CONTROL_DISABLE | Disables the DTR line when the device is opened and leaves it disabled. |
DTR_CONTROL_ENABLE | Enables the DTR line when the device is opened and leaves it on.. |
DTR_CONTROL_HANDSHAKE | Enables DTR handshaking.
If handshaking is enabled, it is an error for
the application to adjust the line by using the EscapeCommFunction function. |
fDsrSensitivity
Specifies whether the communications
driver is sensitive to the state of the DSR signal. If this member is TRUE,
the driver ignores any bytes received, unless the DSR modem input line
is high.
fTXContinueOnXoff
Specifies whether transmission
stops when the input buffer is full and the driver has transmitted the
XoffChar character. If this member is TRUE, transmission continues after
the input buffer has come within XoffLim bytes of being full and the driver
has transmitted the XoffChar character to stop receiving bytes. If this
member is FALSE, transmission does not continue until the input buffer
is within XonLim bytes of being empty and the driver has transmitted the
XonChar character to resume reception.
fOutX
Specifies whether XON/XOFF
flow control is used during transmission. If this member is TRUE, transmission
stops when the XoffChar character is received and starts again when the
XonChar character is received.
fInX
Specifies whether XON/XOFF
flow control is used during reception. If this member is TRUE, the XoffChar
character is sent when the input buffer comes within XoffLim bytes of being
full, and the XonChar character is sent when the input buffer comes within
XonLim bytes of being empty.
fErrorChar
Specifies whether bytes
received with parity errors are replaced with the character specified by
the ErrorChar member. If this member is TRUE and the fParity member is
TRUE, replacement occurs.
fNull
Specifies whether null bytes
are discarded. If this member is TRUE, null bytes are discarded when received.
fRtsControl
Specifies the RTS (request-to-send)
flow control. If this value is zero, the default is RTS_CONTROL_HANDSHAKE.
This member can be one of the following values:
Value | Meaning |
RTS_CONTROL_DISABLE | Disables the RTS line when the device is opened and leaves it disabled. |
RTS_CONTROL_ENABLE | Enables the RTS line when the device is opened and leaves it on. |
RTS_CONTROL_HANDSHAKE | Enables RTS handshaking.
The driver raises the RTS line when the "type-ahead" (input)
buffer is less than one-half full and lowers the RTS line when the buffer is more than three-quarters full. If handshaking is enabled, it is an error for the application to adjust the line by using the EscapeCommFunction function. |
RTS_CONTROL_TOGGLE | Specifies that
the RTS line will be high if bytes are available for transmission.
After all buffered bytes have been sent, the RTS line will be low. |
fAbortOnError
Specifies whether read and
write operations are terminated if an error occurs. If this member is TRUE,
the driver terminates all read and write operations with an error status
if an error occurs. The driver will not accept any further communications
operations until the application has acknowledged the error by calling
the ClearCommError function.
fDummy2
Reserved; do not use.
wReserved
Not used; must be set to
zero.
XonLim
Specifies the minimum number
of bytes allowed in the input buffer before the XON character is sent.
XoffLim
Specifies the maximum number
of bytes allowed in the input buffer before the XOFF character is sent.
The maximum number of bytes allowed is calculated by subtracting this value
from the size, in bytes, of the input buffer.
XonChar
Specifies the value of the
XON character for both transmission and reception.
XoffChar
Specifies the value of the
XOFF character for both transmission and reception.
ErrorChar
Specifies the value of the
character used to replace bytes received with a parity error.
EofChar
Specifies the value of the
character used to signal the end of data.
EvtChar
Specifies the value of the
character used to signal an event.
wReserved1
Reserved; do not use.
Le paramètre ByteSize définit le nombre de bits de l’octet
Le paramètre Parity
définit le type de parité utilisé dans le protocole.
Les valeurs possibles sont :
Valeur | Description |
EVENPARITY | Parité paire |
NOPARITY | Pas de parité |
ODDPARITY | Parité impaire |
Le paramètre StopBits
définit le nombre de stop bit. Les valeurs possibles sont :
Valeur | Description |
ONESTOPBIT | 1 stop bit |
ONE5STOPBITS | 1.5 stop bits |
TWOSTOPBITS | 2 stop bits |
Définition des TimeOut de communication
La définition des timeouts de communication est utilisée pour arrêter le process de communication au bout de x (ms). Dans notre cas un timeout sera utilisé pour sortir de la boucle de réception étant donnée que l’on ne veut pas gérer la taille des trames reçue. Nous fixerons donc une taille de buffer de réception fixe que nous traiterons en fin de time out.
La gestion des timeouts se fait à l’aide des commandes SetCommTimeouts pour la configuration, GetCommTimeouts pour la lecture de la configuration et de la structure COMMTIMEOUTS contenant la description des timeouts :
Fonction SetCommTimeouts : utilisée pour configurer les timeOuts
BOOL SetCommTimeouts(
HANDLE
hFile,
// handle of communications device
LPCOMMTIMEOUTS
lpCommTimeouts // address of communications time-out structure
);
Le paramètre hFile identifie le port de communication retourné par la fonction CreateFile
Le paramètre lpCommTimeouts pointe sur une structure COMMTIMEOUTS qui contient les nouvelles valeurs de time out
La valeur de retour est différente de 0 en cas de succès.
Fonction GetCommTimeouts : utilisée pour lire les timeouts
BOOL GetCommTimeouts(
HANDLE
hFile,
// handle of communications device
LPCOMMTIMEOUTS
lpCommTimeouts // address of comm. time-outs structure
);
Le paramètre hFile identifie le port de communication retourné par la fonction CreateFile
Le paramètre lpCommTimeouts pointe une structure contenant la configuration actuelle des timeouts.
La valeur de retour est différente de 0 en cas de succès.
La structure COMMTIMEOUTS : utilisée pour définir les timeouts
typedef struct _COMMTIMEOUTS
{ // ctmo
DWORD
ReadIntervalTimeout;
DWORD
ReadTotalTimeoutMultiplier;
DWORD
ReadTotalTimeoutConstant;
DWORD
WriteTotalTimeoutMultiplier;
DWORD
WriteTotalTimeoutConstant;
} COMMTIMEOUTS,*LPCOMMTIMEOUTS;
ReadIntervalTimeout
Specifies the maximum time,
in milliseconds, allowed to elapse between the arrival of two characters
on the communications line. During a ReadFile operation, the time period
begins when the first character is received. If the interval between the
arrival of any two characters exceeds this amount, the ReadFile operation
is completed and any buffered data is returned. A value of zero indicates
that interval time-outs are not used.
A value of MAXDWORD, combined
with zero values for both the ReadTotalTimeoutConstant and ReadTotalTimeoutMultiplier
members, specifies that the read operation is to return immediately with
the characters that have already been received, even if no characters have
been received.
ReadTotalTimeoutMultiplier
Specifies the multiplier,
in milliseconds, used to calculate the total time-out period for read operations.
For each read operation, this value is multiplied by the requested number
of bytes to be read.
ReadTotalTimeoutConstant
Specifies the constant,
in milliseconds, used to calculate the total time-out period for read operations.
For each read operation, this value is added to the product of the ReadTotalTimeoutMultiplier
member and the requested number of bytes.
A value of zero for both
the ReadTotalTimeoutMultiplier and ReadTotalTimeoutConstant members indicates
that total time-outs are not used for read operations.
WriteTotalTimeoutMultiplier
Specifies the multiplier,
in milliseconds, used to calculate the total time-out period for write
operations. For each write operation, this value is multiplied by the number
of bytes to be written.
WriteTotalTimeoutConstant
Specifies the constant,
in milliseconds, used to calculate the total time-out period for write
operations. For each write operation, this value is added to the product
of the WriteTotalTimeoutMultiplier member and the number of bytes to be
written.
A value of zero for both
the WriteTotalTimeoutMultiplier and WriteTotalTimeoutConstant members indicates
that total time-outs are not used for write operations.
Remarks
If an application sets ReadIntervalTimeout
and ReadTotalTimeoutMultiplier to MAXDWORD and sets ReadTotalTimeoutConstant
to a value greater than zero and less than MAXDWORD, one of the following
occurs when the ReadFile function is called:
- If there are any characters
in the input buffer, ReadFile returns immediately with the characters in
the buffer.
- If there are no characters
in the input buffer, ReadFile waits until a character arrives and then
returns immediately.
- If no character arrives
within the time specified by ReadTotalTimeoutConstant, ReadFile times out.