Newsgroup: it.comp.programmare.win32
Titolo: [C] Usare i timer di windows per gestire un timeout

Salve a tutti.
Sto scrivendo un'applicazione console in C per ricevere e inviare dati
sulla porta COM.
Non ho mai programmato per windows, sono sempr estato un programmatore
firmware su microprocessori, quindi non conosco la terminologia e i
concetti della programmazione windows.
L'applicazione è una macchina ha stati in uno dei quali è in attesa di
una ricezione dalla seriale in cui chiama continuamente la funzione
ReadByte che aspetta e restituisce il singolo byte dalla COM.
L'analisi dei byte ricevuti permette all'applicazione di cambiare
stato ed evolvere verso la fine.
Prima di entrare nello stato di attesa ricezione mi piacerebbe
impostare un timer per gestire il timeout di ricezione in modo da
evitare che il programma resti bloccato all'infinito.
Ho visto che i timer di windows devono essere impostati e poi il
thread deve andare in uno stato di attesa in cui non fa nulla e
aspetta che il timer scatti e segnali al thread di andare avanti.
Io invece vorrei impostare il timer, continuare a fare un'operazione
(in particolare a leggere la COM in polling) e se scatta il timer
cambiare stato o se l'operazione che sto facendo si esaurisce fermare
il timer ed andare avanti.
Come scrivo tutto questo in C in windows?
Di seguito lo stato in cui leggo la seriale a cui vorrei aggiungere la
gestione del timeout.
Grazie in anticipo per qualsiasi aiuto.
[CUT]
switch(machine_state)
{
  case INIT_STATE:
    // set up a timer here for timeout
    // change state
    machine_state = READ_STATE;
    break;
  case READ_STATE:
    // read from COM
    data_from_COM = ReadByte(com_port_handler);
    RS232_read_buffer[RS232_read_element] = data_from_COM;
    RS232_read_element++;
    fprintf(stderr, "Data received: %c\n", data_from_COM);
    fSuccess = AnalizeBuffer();
    if (fSuccess == TRUE)
    {
      // end the
      RunMachine = FALSE;
    }
    machine_state = READ_STATE;
    break;
}
...
...
//===============================
char ReadByte(HANDLE com_handler)
{
  BOOL fSuccess;
  char c;
  DWORD NumberOfBytesRead;
  for(;;)
  {
    fSuccess = ReadFile(com_handler, &c, 1, &NumberOfBytesRead, NULL);
    if (NumberOfBytesRead > 0)
    {
      break;
    }
  }
  return c;
}   // ReadByte

 evitare che il programma resti bloccato all'infinito.
Se ho ben capito quello che ti serve, non complicherei la cosa 
gestendo un timer nel vero senso della parola. Ti basta usare la 
funzione API GetTickCount per controllare il passare del tempo 
ed uscire dal ciclo se hai superato il timeout.
Dai anche un'occhiata a SetCommTimeouts nel caso tu gi� non 
l'abbia utilizzata in fase di apertura della porta.
HTH,
-- 
Stefano Frosio
www.esse-effe.com

 l'abbia utilizzata in fase di apertura della porta.
Questi non li avevo visti, ora me li studio.
Grazie.

 superato il timeout.
Cosï¿œ facendo perï¿œ consumi tempo CPU. Durante il ciclo che attende che i 
tick passino, un core della cpu ï¿œ impegnato al 100% il che ï¿œ certamente 
un dato negativo.
Meglio allora usare la WaitForSingleObject con un tempo massimo 
(timeout) di uscita. Le funzioni di Wait restituiscono l'esecuzione 
allo scheduler di Windows che riattiverï¿œ il thread solo dopo il tempo 
richiesto.
Il vecchissimo esempio MTTTY ï¿œ ancora attualissimo anche se ï¿œ scritto 
in C e non in C++:
http://msdn.microsoft.com/en-us/library/ms810467.aspx
-- 
Raffaele Rialdi  
http://www.iamraf.net
Weblog: 
http://blogs.ugidotnet.org/raffaele
Microsoft .NET MVP 
http://mvp.support.microsoft.com
 -
UGIdotNET - 
http://www.ugidotnet.org

 100% il che � certamente un dato negativo.
Typo. Pensavo a "stato" e ho scritto "ciclo". Quindi il mio 
"uscire dal ciclo" va inteso come "uscire dallo stato di 
attesa". Non � di certo mia intenzione suggerire un ciclo solo 
in attesa che passi il tempo.
Tra l'altro l'OP ha gi� impostato il programma come macchina a 
stati, per cui non gli sar� difficile chiamare la GetTickCount 
in uno stato (all'inizio dell'attesa) e verificare il protocollo 
o l'eventuale timeout in un altro. Nel frattempo il programma 
pu� fare altro e la CPU di certo non � impegnata al 100%.
-- 
Stefano Frosio
www.esse-effe.com

 al 100%.
Ok, ci siamo capiti. L'importante ï¿œ che la cpu non giri 'a vuoto'.
Ad ogni modo gli suggerisco di andare sulla falsa riga di mttty che ï¿œ 
un esempio consolidato. Sulla seriale fortunatamente non c'ï¿œ nulla da 
inventare :)


 può fare altro e la CPU di certo non è impegnata al 100%.
In effetti ho fatto proprio così: nel primo stato leggo il Tick e nel
secondo attendo la ricezione, verifico il protocollo e rileggo il Tick
per controllare che non sia passato troppo tempo in attesa di un
carattere.
L'esempio indicato da Raffaele Rialdi mttty è da dove ho preso le
funzioni scrittura di un buffer e di lettura di un byte.
Non capisco però il resto e vorrei evitare di inserire gestioni di
eventi o messaggi che non capisco bene.
Il problema ora è che step a step il programma sembra funzionare, ma
se lo mando in run si inchioda da qualche parte e non riesco ad
interroperlo. Sto usando CodeBlock come IDE e GNU gcc coem toolchin di
compilazione.
La parte che mi rende più perplesso è proprio la funzione di lettura
di un byte che ho preso e modificato proprio partendo dall'esempio
mttty:
char ReadByte(HANDLE com_handler)
{
    BOOL fSuccess;
    char c;
    DWORD NumberOfBytesRead;
    for(;;)
    {
        fSuccess = ReadFile(com_handler, &c, 1, &NumberOfBytesRead,
NULL);
        if (NumberOfBytesRead > 0)
        {
            break;
        }
    }
    return c;
}   // ReadByte
Contiene un for che può diventare teoricamente infinito!
In realtà mi aspetteri di poter comunque interrompere l'esecuzione in
Codeblock, cosa che non avviene e mi fa pensare a un qualche problema
nascosto che non capisco.
Qualche idea?

 Contiene un for che pu� diventare teoricamente infinito!
Teoricamente e guardando la funzione a se stante s�, ma 
verosimilmente sar� richiamata in un thread a parte per cui 
l'applicativo non risulta bloccato.
Nel tuo caso chiamerei semplicemente la ReadFile e se ci sono 
nuovi dati si passa all'analisi del protocollo.
