Lo
stato della comunicazione |
Proprio
com'è possibile determinare le impostazioni di una
porta seriale attraverso la funzione GetCommState, così
le si può assegnare i parametri principali attraverso
la funzione SetCommState. Parametri che, come nel caso
della prima funzione, non sono altro che i membri della struttura
DCB.
Declare
Function
SetCommState Lib "kernel32"
(ByVal hCommDev As
Long, lpDCB As _ DCB)
As Long |
dove
il primo parametro rappresenta l'intero identificatore della
porta (quello che nel codice d'esempio sviluppato nello scorso
articolo avevamo chiamato 'nPorta') ed il secondo rappresenta
invece la variabile 'Situazione_Porta'.
Facciamo già da subito un esempio pratico: se volessimo
impostare il numero di volte in cui il segnale della connessione
modifica la frequenza nel periodo della trasmissione di un
bit (quindi il Baud Rate) a 57600 non dovremo far altro che
assegnare tale valore alla variabile di tipo DCB che nell'esempio
dello scorso articolo avevamo chiamato 'Situazione_Porta':
Situazione_Porta.BaudRate
= 57600
|
in
questo modo la porta "COM2" viene impostata per
la comunicazione a velocità di trasmissione 9600 La
stessa cosa può naturalmente essere fatta per altre
proprietà che intervengono nella comunicazione seriale:
il numero di bit di parità, d'interruzione e così
via.
Ad esempio si può impostare il bit di parità
sul valore 0 utilizzando il gruppo di costanti visto nello
scorso articolo: NOPARITY, EVENPARITY, ODDPARITY, SPACEPARITY,
MARKPARITY:
Situazione_Porta.Parity
= NOPARITY |
Una
volta recuperati i parametri di comunicazione ed eventualmente
modificati come abbiamo visto sopra, è necessario ancor
prima di avviare la comunicazione, determinare le impostazioni
di time-out. Si ha un time-out nella comunicazione seriale
quando i tempi di lettura e/o di scrittura dei dati da parte
di una periferica superano i limiti di tempo stabiliti, se
questi sono stati espressamente indicati. Tali impostazioni
incideranno sulla comunicazione tanto quanto quelle legate
alla struttura DCB.
La struttura che indica le possibili configurazioni è
la COMMTIMEOUTS:
Type
COMMTIMEOUTS
ReadIntervalTimeout As Long
ReadTotalTimeoutMultiplier As Long
ReadTotalTimeoutConstant As Long
WriteTotalTimeoutMultiplier As Long
WriteTotalTimeoutConstant As Long
End Type
|
Il
primo membro, ReadIntervalTimeout indica in millisecondi
l'intervallo che intercorre tra l'invio di due caratteri.
Nel caso in cui il tempo di trasmissione superi il limite
indicato, l'invio dei dati e la lettura vengono interrotti
e la lettura dei dati restituirà qualsiasi valore presente
nella memoria della periferica ossia i dati fino ad allora
accumulati in memoria.
Assegnare a tale parametro la costante MAXDWORD e 0 ai parametri
successivi significa ritornare in tempo reale i caratteri
ricevuti nella trasmissione dei dati anche se la memoria periferica
non si è ancora riempita.
Il valore 0 per questo parametro significa invece non utilizzare
i parametri di time-out e quindi non impostare alcun tempo
limite.
Il secondo membro, ReadTotalTimeoutMultiplier (WriteTotalTimeoutMultiplier),
moltiplicato per il numero totale di byte da leggere (scrivere)
e sommato al parametro successivo ritorna in millisecondi
il limite massimo di tempo accettabile prima di interrompere
la lettura (scrittura) dei dati.
ReadTotalTimeoutConstant (WriteTotalTimeoutConstant)
indica invece una costante che sommata al numero totale di
byte da leggere (scrivere) ed al valore indicato dal parametro
precedente, restituisce il limite massimo di tempo accettabile
prima di interrompere la lettura (scrittura) dei dati.
Impostare il valore 0 per questi due ultimi parametri significa
non impostare un limite massimo di attesa nella lettura (scrittura)
dei dati.
Vista la struttura COMMTIMEOUTS è quindi notevolmente
più semplice comprendere la funzione GetCommTimeouts
che ottiene le impostazioni di time-out predefiniti per una
determinata periferica.
La struttura della funzione è la seguente:
Declare
Function
GetCommTimeouts Lib "kernel32"
(ByVal hFile As
Long, lpCommTimeouts As
COMMTIMEOUTS) As Long |
che
necessita del solito intero ('nPorta' nell'esempio iniziato
negli articoli precedenti) che identifica la porta seriale
dalla quale recuperare le impostazioni di time-out, come primo
parametro e una variabile del tipo COMMTIMEOUTS come secondo.
Alla chiamata della funzione GetCommTimeouts tale variabile
verranno assegnate le caratteristiche di time-out della porta
sotto forma di membri della struttura COMMTIMEOUTS. Andando
quindi ad analizzare la variabile si potrà comprendere
quali sono le impostazioni predefinite per la porta indicata.
Prima però la variabile dev'essere dichiarata nel seguente
modo:
Dim
Tempi_Limite As COMMTIMEOUTS
|
Una
volta dichiarata la variabile, si richiama la GetCommTimeouts
per assegnarle i valori di time-out, in questo modo:
GetCommTimeouts
nPorta, Tempi_Limite |
Nel
caso in cui la funzione abbia successo il valore ritornato
sarà diverso da 0.
Ora che la variabile è stata riempita, possiamo analizzarla
nel dettaglio:
With
Tempi_Limite
MsgBox "ReadIntervalTimeout : " & .ReadIntervalTimeout
& vbCrLf & _
"ReadTotalTimeoutConstant : " & .ReadTotalTimeoutConstant
& vbCrLf & _
"ReadTotalTimeoutMultiplier : " & .ReadTotalTimeoutMultiplier
& vbCrLf & _
"WriteTotalTimeoutConstant : " & .WriteTotalTimeoutConstant
& vbCrLf & _
"WriteTotalTimeoutMultiplier : " & .WriteTotalTimeoutMultiplier
End With |
Il
risultato sarà simile al seguente:
dove
le impostazioni qui visualizzate mostrano una situazione nella
quale non viene imposto alcun limite alla lettura ed alla
scrittura dei dati.
Queste impostazioni predefinite però possono essere
modificate a piacimento attraverso una funzione molto simile
a quella appena vista, la SetCommTimeouts, la cui dichiarazione
corrisponde a:
Declare
Function
SetCommTimeouts Lib "kernel32"
(ByVal hFile As
Long, _
lpCommTimeouts As COMMTIMEOUTS)
As Long |
I
parametri richiesti dalla funzione sono gli stessi della GetCommTimeouts
con l'unica differenza che questa volta la variabile Tempi_Limite
dev'essere riempita prima di passarla alla funzione come secondo
parametro.
Ed è proprio quello che faremo adesso. Ognuno è
in ogni caso libero di impostare i tempi limite a piacimento,
comunque per evitare problemi, reimposteremo la situazione
classica ossia nessun limite alle operazioni di lettura e
scrittura e per ottenere di volta in volta i caratteri trasmessi
alla periferica. Questo codice può essere inserito
nel listato dell'applicazione per assicurarsi che la porta
non sia configurata in modo differente:
With
Tempi_Limite
.ReadIntervalTimeout = MAXDWORD
.ReadTotalTimeoutMultiplier = 0
.ReadTotalTimeoutConstant = 0
.WriteTotalTimeoutConstant = 0
.WriteTotalTimeoutMultiplier = 0
End With
SetCommTimeouts nPorta, Tempi_Limite |
Ed
ancora prima di iniziare una nuova trasmissione di dati è
conveniente introdurre due nuovi concetti: il buffer di ricezione
e quello di trasmissione. Quando infatti viene aperta una
porta nella memoria del dispositivo vengono create due partizioni,
una destinata alla ricezione dei dati dalla periferica ed
un'altra destinata alla trasmissione dei dati. Maggiore è
la capacità dei buffer, minore è la quantità
di memoria disponibile per l'applicazione. Se le dimensioni
delle partizioni sono troppo piccole, potrebbe però
verificarsi un overflow del buffer. Le dimensioni predefinite
per il buffer di trasmissione è 512 mentre per il buffer
di ricezione 1024.
Prima
di cominciare una sessione di trasmissione è conveniente
svuotare completamente queste due partizioni attraverso la
funzione PurgeComm che ha la seguente sintassi:
Declare
Function
PurgeComm Lib "kernel32"
(ByVal hFile As
Long, ByVal dwFlags
_ As Long) As
Long |
dove
il primo parametro è rappresentato dall'identificatore
della porta ('nPorta' per intenderci) ed il secondo da un
valore costante scelto tra i seguenti:
PURGE_TXABORT:
termina tutte le operazioni di scrittura, anche quelle ancora
in corso;
PURGE_RXABORT:
termina tutte le operazioni di lettura, anche quelle ancora
in corso;
PURGE_TXCLEAR:
svuota completamente la memoria assegnata ai dati in entrata;
PURGE_RXCLEAR:
svuota completamente la memoria assegnata ai dati in uscita;
|