Tutto ciò che occorre è:
Nella figura è raffigurato lo schema del collegamento Null Modem usato in laboratorio
Nella tabella è riportato il collegamento dei pin dei due connettori.
DTE 1 | DTE 2 | ||
---|---|---|---|
Receive Data | 2 | 3 | Transmit Data |
Transmit Data | 3 | 2 | Receive Data |
DTR | 4 | 6+1 | DSR + CD |
System Ground | 5 | 5 | System Ground |
DSR + CD | 6+1 | 4 | DTR |
RTS | 7 | 8 | CTS |
CTS | 8 | 7 | RTS |
L'API per le comunicazioni di Win32 è un una libreria di funzioni(incluse nella libreria run-time di Windows) che fa da interfaccia software fra il programma utente e il driver di un dispositivo I/O, come l'UART, il controller per la parallela, la scheda di rete.
In figura è rappresentata l'architettura di comunicazione
La trasmissione dei dati avviene con la seguente modalità:
Analogamente la ricezione:
Il driver di Windows permette di effettuare in maniera relativamente semplice le operazioni tipiche della comunicazione:
Il controllo di flusso viene effettuato o da hardware utilizzando i segnali RTS/CTS o da software. Nella seconda modalità, si utilizza un protocollo chiamato Xon/Xoff, dal nome dei due caratteri ASCII usati: Xon =17 e Xoff= 19.
Il protocollo opera nel seguente modo:
Sono previsti due tipi di timeout: quello che intercorre fra la ricezione di due caratteri e quello relativo alla lettura/scrittura di un blocco di n bytes.
Si effettua chiamando la funzione CreateFile:
Createfile |
HANDLE CreateFile(
DWORD dwFlagsAndAttribute, |
L’attributo programma l’interfaccia nella modalità Overlapped I/O.
I parametri della comunicazione sono numerosi. Per ora ci interessano i seguenti:
Ad essi si accede tramite una struct chiamata DCB (Device Control Block).
DCB |
typedef struct _DCB{ DWORD BaudRate BYTE ByteSize BYTE Parity BYTE StopBits <altri campi> } DCB |
CBR_110 | CBR_19200 |
CBR_300 | CBR_38400 |
CBR_600 | CBR_56000 |
CBR_1200 | CBR_57600 |
CBR_2400 | CBR_115200 |
CBR_4800 | CBR_128000 |
CBR_9600 | CBR_256000 |
CBR_14400 |
ONESTOPBIT | 1 bit di stop |
ONE5STOPBITS | 1.5 bit di stop |
TWOSTOPBITS | 2 bit di stop |
Per leggere la configurazione corrente della porta si usa GetCommState, per impostare una nuova configurazione SetCommState. Entrambe le funzioni hanno gli stessi parametri
SetCommState |
BOOL SetCommState( HANDLE hcom; LPDCB lpDCB; ) |
Esempio di uso GetCommState/SetCommState
HANDLE hcom2;
hcom2=CreateFile(.........); GetCommState(hcom2, &dbc); dbc.BaudRate = CBR_9600;
dbc.ByteSize = 8;
dbc.Parity = NOPARITY;
dbc.StopBits = ONESTOPBIT;
resultset=SetCommState(hcom2,&dbc); Per ricevere dati dalla porta seriale si usa la funzione ReadFile, per inviare dati si usa
WriteFile.
Le due funzioni hanno gli stessi parametri.
ReadFile
BOOL ReadFile(
HANDLE hFile,
LPVOID lpBuffer,
DWORD NumerodiBytesDaLeggere,
LPDWORD lpNumerodiBytesLetti,
LPOVERLAPPED lpOverlapped }
Notare che il puntatore lpbuffer è di tipo void. Questo significa che si può passare qualunque tipo di dato.
DBC dbc;
Implementazione delle procedure di ricezione/invio dati
struct prova{
tipo1 campo1;
tipo2 campo2;
}
si crea un puntatore prova *punt= new prova oppure una variabile prova pv;
nel primo caso:
ReadFile(hcom2, (prova *)punt, sizeof(prova),&nletti,NULL)
nel secondo caso:
ReadFile(hcom2, (prova *)&pv, sizeof(prova),&nletti,NULL);
E’ importante tenere presente il comportamento di ReadFile (WriteFile). La funzione ritorna solo quando il numero di bytes da leggere (scrivere) richiesti è stato prelevato dal buffer (scritto nel buffer).
Un 'operazione di lettura infatti potrebbe tenere occupato il thread per un tempo lungo sei dati tardano ad arrivare nel buffer.
Un modo per risolvere il problema è usare la funzione ClearCommError. Questa funzione restituisce come parametro una variabile di tipo COMSTAT, una struct che contiene una serie di campi che danno informazioni sullo stato corrente della comunicazione, in particolare:
DWORD cbInQue //bytes presenti nel buffer di input
DWORD cbOutQue; // bytes presenti nel buffer di output.
Esempio: lettura in polling di N bytes
#define N = 10;
HANDLE hcom2;
char BufferIn |
//la funzione ritorna true se ci sono bytes da leggere nel buffer BOOL LeggiNBytes(DWORD *numletti) DWORDerrors; COMSTAT stc; BOOL result; ClearCommError(hcom2,&errors,&StatComm); if (errors>0){ //gestione errori return FALSE; }if (StatComm.cbInQue>0){ ReadFile(hcom2,BufferIn,StatComm.cbInQue,numletti,NULL)) return TRUE; } return FALSE; } |
void main(){ DWORD nletti=0; //è obbligatorio inizializzare a 0 .............. .............. while (LeggiNBytes(&nletti)); ............... } |
I timeout vengono impostati riempiendo la stuttura COMMTIMEOUTS con la funzione SetCommTimeouts.
La COMMTIMEOUTS è definita così:
COMMTIMEOUTS |
typedef struct _COMMTIMEOUTS{
DWORD ReadIntervalTimeout; DWORD ReadTotalTimeoutMultiplier; DWORD ReadTotalTimeoutConstant; DWORD WriteTotalTimeoutMultiplier; DWORD WriteTotalTimeoutConstant; } COMMTIMEOUTS,*LPCOMMTIMEOUTS; |
Il campo RTTM (WTTM) è un moltiplicatore usato per adattare il timeout totale al numero di caratteri.
Generalmente si una questa formula:
TimeoutTotale = (Moltiplicatore * numero_di
bytes)+ COSTANTE
in cui Moltiplicatore o Costante possono essere posti a 0
Nella tabella seguente è riassunto il comportamento delle operazioni di scrittura o lettura rispetto ai timeouts
Totale |
Intervallo |
Modalità di ritorno di ReadFile o WriteFile |
---|---|---|
0 | 0 | Quando il buffer è completamente riempito. I Timeouts non sono usati |
T | 0 | Quando il buffer è completamente riempito o sono trascorsi T ms dall'inizio dell'operazione |
0 | Y | Quando il buffer è completamente riempito o sono trascorsi Y ms fra la ricezione di due caratteri consecutivi. |
T | Y | Quando il buffer è completamente riempito o uno dei timeouts è scaduto . |
Per impostare i timeouts si chiama SetCommTimeouts
SetCommTimeouts |
BOOL SetCommTimeouts( HANDLE hfile LPCOMMTIMEOUTS lpCommTimeouts ) |