Credo che chiunque stia sviluppando sul compact framework conosca www.opennetcf.org, una pregevole iniziativa di alcuni programmatori, molti dei quali MVP, per estendere le funzionalità del Compact Framework.
Una delle librerie più apprezzate è quella per la comunicazione via seriale, anche perchè i device bluetooth (gps, lettori di codice a barre, etc.) sono mappati sui pocket pc su una seriale virtuale così come se fossero collegati ad un cavo (ma ovviamente non lo sono).
Il problema banale che ho riscontrato è che la libreria seriale interrompe la comunicazine qualora il pocket venga spento (o si spenga da solo per risparmiare le batterie). Nel momento in cui il pocket viene riacceso l'handle della seriale non sembra essere più valido, la comunicazione sullo stack bluetooth non è più valido, tipicamente il device bluetooth si scollega, e qualsiasi tentativo di spedire/ricevere dei byte fallisce.
Visto che il progetto è open source ho quindi ricompilato la libreria attivando una sorta di log su file per vedere cosa accade alla WaitCommEvent alla riaccensione del pocket. La WaitCommEvent è una API Win32 che mima la WaitForSingleObject sospendendo il thread in attesa di un evento dalla porta seriale. Bene, alla riaccensione la WaitCommEvent si risveglia lanciando un 'urlo' e recuperando l'ultimo errore Win32 si scopre che si è verificato un ERROR_GEN_FAILURE (vedi winerror.h delle librerie del C++).
Visto che il problema deriva dal fatto che ormai quell'handle della porta seriale non è più valido, la soluzione è semplice: riaprire la comunicazione seriale dopo un adeguato tempo di Sleep che permetta al Pocket di riprendersi per bene dopo la dormitina ;-).
La patch è quindi molto semplice e subito dopo la WaitCommEvent, avendo recuperato l'errore tramite Marshal.GetLastWin32Error, ho aggiunto:
if(e == 31) // ERROR_GEN_FAILURE
{
System.Threading.Thread.Sleep(3500);
hPort = m_CommAPI.CreateFile(portName);
if(hPort == (IntPtr)CommAPI.INVALID_HANDLE_VALUE)
{
int MyErr = Marshal.GetLastWin32Error();
if(MyErr == (int)APIErrors.ERROR_ACCESS_DENIED)
return;
string error = String.Format("CreateFile Failed: {0}", e);
throw new CommPortException(error);
}
Il risultato è che dopo la riaccensione, il pocket pc mostra nuovamente la scelta del device bluetooth a cui collegarsi. Questa è la classica schermata che appare sempre dopo l'apertura della seriale virtuale dello stack bluetooth ed è indispensabile perchè dopo un paio di minuti che non vengono usati, i device bluetooth entrano in una modalità di sleep per risparmiare le batterie.
Attualmente non ho ancora sottoposto la patch perchè sto valutando il tempo di sleep più adeguato a seconda dei pocket. Non escludo di dover alzare ancora un po' il valore di tre secondi e mezzo.