Newsgroup: it.comp.programmare.win32
Titolo: Aiuto su timer e seriali

Ciao,
mi sposto qui da it.comp.programmare.
Sto scrivendo un programmino in Visual C++ 2010 Express.
L'applicazione è in modalità console e girerà su un PC (senza operatore) 
con Windows XP Embedded.
Il programma essenzialmente deve fare tre cose:
1) ogni x ms deve eseguire una funzione
2) deve rimanere in attesa di righe di testo sulla seriale (terminate da 
\r\n)
3) in base al comando ricevuto deve poter inviare sulla seriale file 
binari da decine di kByte
Ora, per il punto 1) ho fatto una cosa del genere nel main:
HANDLE          hTimer;
BOOL            bSuccess;
LARGE_INTEGER   liDueTime;
DWORD		dwWait;
hTimer = CreateWaitableTimer(NULL, FALSE, NULL);
liDueTime.QuadPart = 0;
SetWaitableTimer(hTimer, &liDueTime, settings.GrabPeriod, TimerAPCProc, 
NULL, FALSE);
for (;;) {
	dwWait = WaitForSingleObjectEx(hTimer, INFINITE, TRUE);
	switch (dwWait) {
	case WAIT_OBJECT_0:
	case WAIT_IO_COMPLETION:
	default:
		;
	}
	// gestione uscita dal ciclo e altre operazioni
}
CloseHandle(hTimer);
Dove la mia callback TimerAPCProc viene richiamata appunto ogni 
settings.GrabPeriod ms.
Quello che domando è:
a) per restare in attesa di eventi sulla seriale è corretta la strada di 
migrare su WaitForMultipleObjectsEx così da gestire nello stesso loop 
sia gli eventi timer che seriali? In pratica mi creo un array con gli 
handle che mi servono e vado a vedere quale ha risvegliato il thread.
b) per leggere una riga di testo terminata da /r/n non posso usare 
timeout (per via del tipo di periferica seriale) e vorrei quindi 
prelevare un carattere alla volta dal buffer seriale e gestirli a 
manina. Mi sono letto questo documento:
http://msdn.microsoft.com/en-us/library/ms810467.aspx
ma onestamente non mi è chiaro quale strada devo seguire per leggere di 
volta in volta tutti i byte presenti nella seriale senza rischiare di 
perderne qualcuno e in modo tale che siano compatibili con le Wait 
functions.
c) Come implementereste una funzione che deve inviare decine di kB su 
una seriale lenta (impiegando quindi decine di secondi) consentendo 
comunque ai punti 1) e 2) di continuare il loro lavoro?
Grazie!
Marco

 functions.
Ho provato a scrivere questo codice che funziona perfettamente se invio 
i dati seriali da terminale (cioè scrivendo a mano). Ma da risultati 
inattendibili se invio il pacchetto di dati rapidamente, senza 
intervallo tra un byte e l'altro.
Dove è l'errore?
	HANDLE hModem;
 
	hModem = CreateFile(settings.ModemComPort, GENERIC_READ | 
GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);
	if (hModem == INVALID_HANDLE_VALUE) {
		cout << "Error hModem";
	}
	DCB dcb;
	FillMemory(&dcb, sizeof(dcb), 0);
	GetCommState(hModem, &dcb);
	dcb.BaudRate = settings.ModemBaudRate;
	dcb.ByteSize = 8;
	dcb.fParity = FALSE;
	dcb.StopBits = ONESTOPBIT;
	SetCommState(hModem, &dcb);
    DWORD      dwRes;
    DWORD      dwCommEvent;
    DWORD      dwStoredFlags;
    DWORD	  dwOvRes;
    BOOL       fWaitingOnStat = FALSE;
    OVERLAPPED osStatus = {0};
    char		  chRead;
    DWORD	  dwRead;
    dwStoredFlags = EV_RXCHAR;
    SetCommMask(hModem, dwStoredFlags);
    osStatus.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
DWORD			nCount;
	HANDLE		    lpHandles[16];
	HANDLE          hTimer;
	BOOL            bSuccess;
	LARGE_INTEGER   liDueTime;
	DWORD			dwWait;
	hTimer = CreateWaitableTimer(NULL, FALSE, NULL);
	liDueTime.QuadPart = 0;
	SetWaitableTimer(hTimer, &liDueTime, settings.GrabPeriod, TimerAPCProc, 
NULL, FALSE);
 
	lpHandles[0] = hTimer;
	lpHandles[1] = osStatus.hEvent;
	nCount = 2;
	for (;;) {
		if (!fWaitingOnStat) {
			if (!WaitCommEvent(hModem, &dwCommEvent, &osStatus)) {
				if (GetLastError() == ERROR_IO_PENDING)
				fWaitingOnStat = TRUE;
			}
		}
		dwWait = WaitForMultipleObjectsEx(nCount, lpHandles, FALSE, 
POLL_TIMEOUT, TRUE);
		switch (dwWait) {
		case WAIT_OBJECT_0+0:				// hTimer
			GetLocalTime(&CallingContext.ActualTime);
			break;
		case WAIT_OBJECT_0+1:				// hModem;
			if (GetOverlappedResult(hModem, &osStatus, &dwOvRes, FALSE)) {
				do {
					ReadFile(hModem, &chRead, 1, &dwRead, &osStatus);
					rxModem[idxModem] = chRead;
					if (idxModem == BUFF_SIZE - 1 || rxModem[idxModem] == '\n' || 
rxModem[idxModem] == '\r') {
						rxModem[idxModem] = '\0';
						idxModem = 0;
						if (strlen(rxModem)) {
							strcpy(global.Modem.rx.data, rxModem);
							global.Modem.rx.fReady = TRUE;
						}
					} else idxModem++;
					cout << rxModem << ", " << idxModem << '\n';
				} while (dwRead);
			}
			fWaitingOnStat = FALSE;
			break;
		case WAIT_TIMEOUT:
			//cout << ".";
			if (global.Modem.rx.fReady) parseRxModem();
			if (global.exit) goto Exit;
			break;
//		case WAIT_IO_COMPLETION:
//			break;
		}
	}
Exit:
	CloseHandle(hTimer);
	CloseHandle(osStatus.hEvent);
	system("PAUSE");
	return 0;
}
Grazie per qualsiasi suggerimento!
Marco

 seriale file binari da decine di kByte
Potresti lanciare un thread parallelo che si occupi dell'invio.
HTH,
-- 
Stefano Frosio
www.esse-effe.com
 

 Potresti lanciare un thread parallelo che si occupi dell'invio.
Verifico anche questa strada.
Grazie!
Marco

 accettabile.
Su Windows XP difficilmente arriverai ad avere questa precisione.
Sicuramente non con i timer collegati alla UI o con delle Sleep.
Puoi provare ad utilizzare i multimedia timers, ma anche in quel caso è 
possibile che sporadicamente (magari anche solo l'1 per mille o 
diecimila delle volte) il ritardo sia significativamente più alto e al 
di fuori del range che hai indicato.
Se uscire dal range non è un problema, devi solo gestire questa 
condizione nel tuo codice evitando che possa generare problemi.
Se non rispettare i tempi è un problema, devi considerare l'utilizzo di 
estensioni real-time per Windows o un diverso sistema operativo (Windows 
CE, VXWorks, QNX) che garantisca il real-time.
-- 
Valter Minute
(the reply address of this message is invalid)
(l'indirizzo di reply di questo messaggio non è valido)

 CE, VXWorks, QNX) che garantisca il real-time.
No, come detto posso accettare un ritardo di tanto in tanto preferendo 
la semplicità del sistema.
Grazie!
Marco

 la semplicità del sistema.
buon lavoro!


 buon lavoro!
Grazie!
Io che sono abituato a programmare i microcontroller dove puoi tenere 
sotto controllo molto di più i tempi di esecuzione non è immediato 
scrivere con un sistema operativo!
Marco

 scrivere con un sistema operativo!
A questo punto mi viene da chiederti se un PC con XP (seppure embedded) 
non sia sprecato per quel tipo di lavoro.
Forse un sistema Windows CE (anche su un PC) potrebbe semplificarti la 
vita e ridurre i costi (perlomeno quelli della licenza del S.O.).


 vita e ridurre i costi (perlomeno quelli della licenza del S.O.).
Il problema è che devo acquisire per oltre 48 ore immagini da più 
telecamere firewire contemporaneamente ogni 250 ms. La mole di dati 
complessiva supera 1 TB.
In fase di analisi avevo giudicato più comodo basarmi su un'architettura 
PC104 per questioni di consumo e ingombro, con processore Atom per avere 
prestazioni decenti e con WinXPE poiché l'SDK delle telecamere è più 
completo e documentato per windows.
Ad ogni modo non so quanto costi la licenza di CE, ma quella di WinXPE è 
attorno al centinaio di euro (se non ricordo male). Tieni conto che il 
fornitore della scheda ci ha dato l'immagine, non abbiamo acquistato 
l'ambiente di sviluppo per WinXPE.
Marco