View Full Version : [C++] Come creare un ciclo di attesa per leggere su una porta
DomusP45
16-04-2012, 09:54
Salve a tutti.
Devo fare la lettura di un buffer su una porta seriale, usando una libreria di comunicazione seriale (RS232.h) che ho trovato in rete, gratuita.
Funziona bene, ma l'unica cosa che gli manca è un timer di scadenza per la lettura sulla porta, nel senso che quando faccio la lettura deve attendere un tot di secondi e poi dichiarare il timeout, un timeout che gli assegno io.
Avevo pensato di fare una sorta di ciclo while o for, ma non saprei come comportarmi. Insomma, vorrei ottenereu una cosa del tipo
Do {
legge sulla porta;
incrementa un contatore del tempo;
}
while (timeout) || (lettura>0)
solo che con la libreria time.h o ctime.h non ci ho mai avuto a che fare...e quindi volevo chiedere se qualcuno sa darmi una dritta su come fare in modo che questa cosa funzioni: del tipo, assegnato un time out di 3 secondi, tale ciclo attenda di avere una lettura (byte letti>0) oppure attenda massimo 3 secondi e poi esca e dichiari il timeout.
Come posso fare?
[Kendall]
16-04-2012, 10:12
Salve a tutti.
Devo fare la lettura di un buffer su una porta seriale, usando una libreria di comunicazione seriale (RS232.h) che ho trovato in rete, gratuita.
Funziona bene, ma l'unica cosa che gli manca è un timer di scadenza per la lettura sulla porta, nel senso che quando faccio la lettura deve attendere un tot di secondi e poi dichiarare il timeout, un timeout che gli assegno io.
Avevo pensato di fare una sorta di ciclo while o for, ma non saprei come comportarmi. Insomma, vorrei ottenereu una cosa del tipo
Do {
legge sulla porta;
incrementa un contatore del tempo;
}
while (timeout) || (lettura>0)
solo che con la libreria time.h o ctime.h non ci ho mai avuto a che fare...e quindi volevo chiedere se qualcuno sa darmi una dritta su come fare in modo che questa cosa funzioni: del tipo, assegnato un time out di 3 secondi, tale ciclo attenda di avere una lettura (byte letti>0) oppure attenda massimo 3 secondi e poi esca e dichiari il timeout.
Come posso fare?
la libreria ctime contiene delle funzioni interessanti a riguardo. Ti permette per esempio di utilizzare un tick counter che restituisce il numero di clock della cpu dall'avvio del programma. Essendo i clock strettamente legati al tempo (c'è proprio una costante definita per ogni sistema, CLOCKS_PER_SEC) puoi crearti facilmente un semplice timer. Io ne avevo creato uno tempo fa, anche se implementava caratteristiche che a te decisamente non servono (nel senso che ti basterebbe una cosa ben più semplice).
clockover
16-04-2012, 11:22
Oppure postresti gestire il tutto con un SIGALRM.
Fai inviare il segnale dopo il tuo timeout e con sigaction (http://www.manpagez.com/man/2/sigaction/) lo gestisci
DomusP45
16-04-2012, 11:26
Oppure postresti gestire il tutto con un SIGALRM.
Fai inviare il segnale dopo il tuo timeout e con sigaction (http://www.manpagez.com/man/2/sigaction/) lo gestisci
ma questo cos'è? una gestione a thread per caso?
Forse è un pò troppo per leggere semplicemente su una porta...è un timer che mi serve...il "tick" come faccio poi a renderlo vincolato al timeout oppure al fatto che abbia letto qualcosa? Il ciclo Do-While è corretto in tal caso? Oppure è meglio un FOR su una variabile di tipo TIME ad esempio?
clockover
16-04-2012, 11:33
ma questo cos'è? una gestione a thread per caso?
No sono dei semplici segnali... servono a far comunicare i processi tra di loro e tu potresti sfruttarli per creare il tuo timeout
http://it.wikipedia.org/wiki/Segnale_(informatica)
forse però non ho ben capito io il meccanismo del tuo algoritmo
DomusP45
16-04-2012, 11:45
A me serve un controllo sulla lettura che sia vincolato al tempo e ai byte che la funzione di lettura restituisce.
Se ha letto (byte >0) oppure è passato il tempo "timeout" deve uscire e comunicare "Timeout".
Ora, se il timeout lo fisso all'avvio del programma, esempio 3 secondi, come posso fare per fare in modo che quando chiamo la funzione di lettura, un ciclo di controllo me la gestisca in questo modo?
[Kendall]
16-04-2012, 11:50
ma questo cos'è? una gestione a thread per caso?
Forse è un pò troppo per leggere semplicemente su una porta...è un timer che mi serve...il "tick" come faccio poi a renderlo vincolato al timeout oppure al fatto che abbia letto qualcosa? Il ciclo Do-While è corretto in tal caso? Oppure è meglio un FOR su una variabile di tipo TIME ad esempio?
Puoi fare una cosa del genere:
long endValue = clock() + CLOCKS_PER_SEC * timeOutValue;
while (clock() < endValue || lettura > 0) {
// Codice per la lettura dalla porta
Sleep(waitTime);
}
La funzione di Sleep() serve per temporizzare la lettura, per evitare che venga ripetuta costantemente ma solo dopo tot millisecondi (così da alleggerire la cpu). Per la sintassi precisa del comando Sleep() meglio che guardi in internet, io son andato "a ricordo" ;)
clockover
16-04-2012, 11:54
A me serve un controllo sulla lettura che sia vincolato al tempo e ai byte che la funzione di lettura restituisce.
Se ha letto (byte >0) oppure è passato il tempo "timeout" deve uscire e comunicare "Timeout".
Ora, se il timeout lo fisso all'avvio del programma, esempio 3 secondi, come posso fare per fare in modo che quando chiamo la funzione di lettura, un ciclo di controllo me la gestisca in questo modo?
Io probabilmente imposterei un flag che sarà controllato dal ciclo. Questo flag viene impostato dalla funzione sigaction al momento della ricezione del segnale SIGALRM.
un piccolo esempio qui --> http://publib.boulder.ibm.com/infocenter/iseries/v5r3/index.jsp?topic=%2Fapis%2Fsigalarm.htm
DomusP45
16-04-2012, 11:56
;37287564']Puoi fare una cosa del genere:
long endValue = clock() + CLOCKS_PER_SEC * timeOutValue;
while (clock() < endValue || lettura > 0) {
// Codice per la lettura dalla porta
Sleep(waitTime);
}
La funzione di Sleep() serve per temporizzare la lettura, per evitare che venga ripetuta costantemente ma solo dopo tot millisecondi (così da alleggerire la cpu). Per la sintassi precisa del comando Sleep() meglio che guardi in internet, io son andato "a ricordo" ;)
beh, sleep() la conosco...insomma fino ad ora l'ho usata proprio per attendere prima di leggere 2 secondi, poi faceva la lettura e comunicava l'output. Ma mi è stato chiesto che il tempo di attesa deve essere specificato dall'utente del programma in fase di avvio e che la lettura deve durare anche meno del timeout se la risposta sulla porta arriva prima dei 3 secondi ad esempio.
In pratica: o attende 3 secondi o attende di avere un buffer di lettura, se legge qualcosa entro un secondo, può smettere di "attendere" ecco perchè servirebbe un timer vincolato al tempo si ma anche all'esito della lettura..per non far attendere per forza 3 secondi se la risposta è già pervenuta a 2 secondi ad esempio...
lorenzo001
16-04-2012, 12:29
Ma lavori su Linux o Windows?
P.S. I file .h sono semplici include non librerie ...
DomusP45
16-04-2012, 13:09
Ma lavori su Linux o Windows?
P.S. I file .h sono semplici include non librerie ...
in linux...
[Kendall]
16-04-2012, 14:05
beh, sleep() la conosco...insomma fino ad ora l'ho usata proprio per attendere prima di leggere 2 secondi, poi faceva la lettura e comunicava l'output. Ma mi è stato chiesto che il tempo di attesa deve essere specificato dall'utente del programma in fase di avvio e che la lettura deve durare anche meno del timeout se la risposta sulla porta arriva prima dei 3 secondi ad esempio.
In pratica: o attende 3 secondi o attende di avere un buffer di lettura, se legge qualcosa entro un secondo, può smettere di "attendere" ecco perchè servirebbe un timer vincolato al tempo si ma anche all'esito della lettura..per non far attendere per forza 3 secondi se la risposta è già pervenuta a 2 secondi ad esempio...
Pensavo che la variabile lettura fosse utilizzata proprio per fare la verifica di lettura. Infatti nel mio esempio la mettevo come seconda condizione di uscita dal while. Per quanto concerne lo Sleep(), non lo utilizzavo per bloccare il ciclo, ma con valori molto bassi (dell'ordine del decimo di secondo) per evitare che quel ciclo venisse ripetuto per migliaia e migliaia di volte, caricando inutilmente la cpu. Pertanto lo sleep non temporizza nulla, ma semplicemente scandisce la frequenza di check del loop (non so se mi son fatto capire). Se sei sotto linux mi sembra che lo sleep ci sia, ma in una forma leggermente diversa sintatticamente.
tomminno
16-04-2012, 15:47
Per fare quello che chiedi hai bisogno di aprire la seriale in modalità asincrona. Altrimenti la lettura rimarrà bloccata fino a che non arriva qualcosa e non avrai modo di sbloccarla.
Dovresti aprire la seriale con il parametro O_NONBLOCK.
DomusP45
16-04-2012, 15:53
Per fare quello che chiedi hai bisogno di aprire la seriale in modalità asincrona. Altrimenti la lettura rimarrà bloccata fino a che non arriva qualcosa e non avrai modo di sbloccarla.
Dovresti aprire la seriale con il parametro O_NONBLOCK.
la seriale è così che viene aperta...a me interessa come fare a vincolare la lettura che duri massimo 3 secondi e poi comunichi il timeout se non arriva niente entro il tempo di timeout...
è un timer fissato su tot secondi che devo associare, che parte quando avvio la lettura e finisce dopo tot secondi...
[Kendall]
16-04-2012, 16:57
la seriale è così che viene aperta...a me interessa come fare a vincolare la lettura che duri massimo 3 secondi e poi comunichi il timeout se non arriva niente entro il tempo di timeout...
è un timer fissato su tot secondi che devo associare, che parte quando avvio la lettura e finisce dopo tot secondi...
Il codice che ti ho scritto qualche post più sopra fa proprio questo.
DomusP45
16-04-2012, 18:08
;37289749']Il codice che ti ho scritto qualche post più sopra fa proprio questo.
Intendi questo?
long endValue = clock() + CLOCKS_PER_SEC * timeOutValue;
while (clock() < endValue || lettura > 0) {
// Codice per la lettura dalla porta
Sleep(waitTime);
}
Allora dimmi: endValue cosa sarebbe? CLOCKS-PER-SEC cos'è?
immagino che timeoutvalue sia quello che imposto io in millisecondi, giusto? pertanto 3000, o no? e waittime? dove lo piglia?
grazie ancora per la disponibilità.
[Kendall]
16-04-2012, 19:44
Intendi questo?
long endValue = clock() + CLOCKS_PER_SEC * timeOutValue;
while (clock() < endValue || lettura > 0) {
// Codice per la lettura dalla porta
Sleep(waitTime);
}
Allora dimmi: endValue cosa sarebbe? CLOCKS-PER-SEC cos'è?
immagino che timeoutvalue sia quello che imposto io in millisecondi, giusto? pertanto 3000, o no? e waittime? dove lo piglia?
grazie ancora per la disponibilità.
Ho usato delle variabili che fossero più chiare possibili:
endValue è il valore del clock finale, dopo il quale uscire dal ciclo. Lo trovi leggendo il valore dei clock prima di entrare nel ciclo, aggiungendo il tempo che vuoi far attendere prima di uscire dal while. CLOCKS_PER_SEC è una costante definita nel sistema, e indica il numero di clock per secondo nel sistema utilizzato. Questo di conseguenza devi moltiplicarlo per il numero di secondi che vuoi far attendere (3 nel caso precedente).
waitTime è il valore (solitamente in millisecondi, ma devi vedere la funzione precisa in linux che valore richiede) di attesa ad ogni ciclo. Lo imposti tu! Come ti dicevo non serve a scandire il tempo (non sarebbe un indicatore preciso), ma a fissarti la frequenza di "check" per la lettura della porta. Se per esempio lo imposti a un decimo di secondo automaticamente quel ciclo verrà temporizzato ed eseguito una volta ogni decimo di secondo (diminuendo il carico sulla cpu).
DomusP45
16-04-2012, 19:55
;37290821']Ho usato delle variabili che fossero più chiare possibili:
endValue è il valore del clock finale, dopo il quale uscire dal ciclo. Lo trovi leggendo il valore dei clock prima di entrare nel ciclo, aggiungendo il tempo che vuoi far attendere prima di uscire dal while. CLOCKS_PER_SEC è una costante definita nel sistema, e indica il numero di clock per secondo nel sistema utilizzato. Questo di conseguenza devi moltiplicarlo per il numero di secondi che vuoi far attendere (3 nel caso precedente).
waitTime è il valore (solitamente in millisecondi, ma devi vedere la funzione precisa in linux che valore richiede) di attesa ad ogni ciclo. Lo imposti tu! Come ti dicevo non serve a scandire il tempo (non sarebbe un indicatore preciso), ma a fissarti la frequenza di "check" per la lettura della porta. Se per esempio lo imposti a un decimo di secondo automaticamente quel ciclo verrà temporizzato ed eseguito una volta ogni decimo di secondo (diminuendo il carico sulla cpu).
ok...ora mi fermo un pò...domani provo e ti aggiorno...
Puoi usare la select(2) (http://www.kernel.org/doc/man-pages/online/pages/man2/select.2.html) con il parametro di timeout.
Oppure, come ti suggerisce clockover, usare un SIGALRM.
DomusP45
18-04-2012, 11:01
;37290821']Ho usato delle variabili che fossero più chiare possibili:
endValue è il valore del clock finale, dopo il quale uscire dal ciclo. Lo trovi leggendo il valore dei clock prima di entrare nel ciclo, aggiungendo il tempo che vuoi far attendere prima di uscire dal while. CLOCKS_PER_SEC è una costante definita nel sistema, e indica il numero di clock per secondo nel sistema utilizzato. Questo di conseguenza devi moltiplicarlo per il numero di secondi che vuoi far attendere (3 nel caso precedente).
waitTime è il valore (solitamente in millisecondi, ma devi vedere la funzione precisa in linux che valore richiede) di attesa ad ogni ciclo. Lo imposti tu! Come ti dicevo non serve a scandire il tempo (non sarebbe un indicatore preciso), ma a fissarti la frequenza di "check" per la lettura della porta. Se per esempio lo imposti a un decimo di secondo automaticamente quel ciclo verrà temporizzato ed eseguito una volta ogni decimo di secondo (diminuendo il carico sulla cpu).
mi spiace ma non funziona.. non aspetta...:muro:
[Kendall]
18-04-2012, 11:20
mi spiace ma non funziona.. non aspetta...:muro:
Dal punto di vista dell'attesa del tempo fidati che deve funzionare.
Per farti un esempio, questo codice funziona (e non è nient'altro che la stessa cosa che ti avevo indicato prima, senza la parte di lettura della porta). Se lo compili vedrai che attenderà giusto 5 secondi.
#include <ctime>
#include <iostream>
using namespace std;
int main() {
cout << "START!" << endl;
long endValue = clock() + CLOCKS_PER_SEC * 5;
while (clock() < endValue) {}
cout << "END!" << endl << "Premere un tasto per concludere";
cin.get();
}
DomusP45
18-04-2012, 15:52
;37300258']Dal punto di vista dell'attesa del tempo fidati che deve funzionare.
Per farti un esempio, questo codice funziona (e non è nient'altro che la stessa cosa che ti avevo indicato prima, senza la parte di lettura della porta). Se lo compili vedrai che attenderà giusto 5 secondi.
#include <ctime>
#include <iostream>
using namespace std;
int main() {
cout << "START!" << endl;
long endValue = clock() + CLOCKS_PER_SEC * 5;
while (clock() < endValue) {}
cout << "END!" << endl << "Premere un tasto per concludere";
cin.get();
}
Kendall sei gentilissimo, infatti funziona da solo lo so e l'ho provato..ma nel caso con la lettura no...evidentemente quello che restituisce la lettura lo fa inceppare o falsare come test "lettura>0"...vedrò cosa riesco a fare...
[Kendall]
18-04-2012, 16:44
Kendall sei gentilissimo, infatti funziona da solo lo so e l'ho provato..ma nel caso con la lettura no...evidentemente quello che restituisce la lettura lo fa inceppare o falsare come test "lettura>0"...vedrò cosa riesco a fare...
Eh, a questo punto allora bisognerebbe vedere come interagisce la lettura della porta con il loop di attesa.
DomusP45
19-04-2012, 09:09
Io uso per la comunicazione seriale questa libreria
http://www.teuniz.net/RS-232/
la funzione di lettura è "PollComport"...e quello che restituisce sono i byte letti...ma col ciclo crea problemi...:muro:
vBulletin® v3.6.4, Copyright ©2000-2026, Jelsoft Enterprises Ltd.