[ Pobierz całość w formacie PDF ]
.W ksi¹¿ce tej poruszamy temat komunikacji komputerowej poprzez interfejs RS232C.Programy pisane przez nas mog¹ komunikowaæ siê z ró¿nymi urz¹dzeniamizewnêtrznymi.Oprócz wysokiej sprawnoœci i niezawodnoœci musz¹ one posiadaæ niespotykan¹ gdzie indziej cechê, polegaj¹c¹ na mo¿liwoœci b³yskawicznegozdiagnozowania, czy w ogóle jest siê z kim ³¹czyæ, tzn.czy urz¹dzeniezewnêtrzne istnieje (jest w³¹czone).Mo¿e zdarzyæ siê i taka sytuacja, ¿emiernik najzwyczajniej w œwiecie mo¿e siê popsuæ w trakcie pomiaru lub z jakiœinnych wzglêdów odmówiæ dalszej wspó³pracy (uszkodzone ³¹cze lub liniatransmisyjna).Aplikacja steruj¹ca przyrz¹dem nie tylko nie powinna siê wówczaszawiesiæ, ale jeszcze powiadomiæ nas o zaistnia³ej sytuacji.Stosowana przeznas do tej pory konstrukcja:Read_Comm(hCommDev, &Number_Bytes_Read, sizeof(Buffer_I));if (Number_Bytes_Read > 0){// wyœwietl odebrane dane}jest ma³o praktyczna — je¿eli dane przestan¹ nap³ywaæ w wyniku uszkodzeniaprzyrz¹du, to na ekranie nie zobaczymy nic.Jedyn¹ jej zalet¹ jest fakt, ¿eprogram powinien dalej dzia³aæ.Powiedzmy, ¿e chcemy mieæ informacjê o tym, ¿eurz¹dzenie siê wy³¹czy³o.W tym celu skorzystamy z funkcji Win32 API,zwracaj¹cej typ ostatniego b³êdu:DWORD GetLastError(VOID);Win32 API umo¿liwia nam te¿ ustalanie w³asnego typu wartoœci danego b³êdu.Wystarczy u¿yæ:VOID SetLastError(DWORD fdwError);gdzie fdwError okreœla kod ostatniego b³êdu.Wygodny sposób wykorzystania tychfunkcji np.w ostatnio omawianej funkcji obs³ugi zdarzenia TimerOnTimer()móg³by wygl¹daæ nastêpuj¹co:DWORD dwError;.void __fastcall TForm1::TimerOnTimer(TObject *Sender){Write_Comm(hCommDev, strlen(Buffer_O));Sleep(100);Beep();FlushFileBuffers(hCommDev);Read_Comm(hCommDev, &Number_Bytes_Read, sizeof(Buffer_I));if (Number_Bytes_Read == 0){SetLastError(0xFFFFFFFF);dwError = GetLastError();RichEdit1->Text = (IntToStr(dwError));}elseRichEdit1->Text = Buffer_I;}Przetestowa³em nasz program z uwzglêdnieniem tej modyfikacji.W trakcie pomiaruod³¹czy³em miernik.Aplikacja wcale siê nie zawiesi³a, brzêczek (funkcjaBeep()) by³ dalej aktywny, natomiast w polu edycji pojawi³ siê nastêpuj¹cykomunikat:Rysunek 5.10.Dzia³anie aplikacji w momencie od³¹czenia przyrz¹du pomiarowegoJu¿ teraz wiemy, ¿e urz¹dzenie zosta³o po prostu wy³¹czone i nale¿y jakoœzareagowaæ na zaistnia³¹ sytuacjê.Odczyta³em tu jedynie liczbê reprezentuj¹c¹ostatnio wykryty b³¹d.Ktoœ móg³by post¹piæ bardziej wyszukanie, wyœwietlaj¹cnp.odpowiedni komunikat czy uruchamiaj¹c jakiœ wymyœlny sygna³ dŸwiêkowy.Wa¿ne jest jednak to, ¿e w prosty sposób mo¿emy zdiagnozowaæ nawet tak powa¿nyb³¹d w transmisji jak jej zatrzymanie.Wszystko wraca do normy po powtórnymw³¹czeniu miernika.Stosuj¹c GetLastError() nie tylko w obrêbie programów komunikacyjnych, mo¿emyspodziewaæ siê najczêœciej wartoœci 0xFFFFFFFF lub –1.Je¿eli zaœ b³¹d niewyst¹pi³, oczekuje siê ERROR_SUCCES, czyli 0.Nale¿y pamiêtaæ, ¿e funkcjaGetLastError() w g³Ã³wnej mierze bazuje na w¹tkach, dlatego pe³ne jejwykorzystanie mo¿e nast¹piæ tylko w ramach konkretnego w¹tku.Definiuj¹c b³¹djako 0xFFFFFFFF, post¹pi³em bardzo ostro¿nie.Kody b³êdów funkcji Win32 API s¹32-bitowe, przy czym bit numer 31 jest bitem bardziej znacz¹cym.Bit 29.jest zregu³y zarezerwowany dla aplikacji, w których chcemy zdefiniowaæ w³asnekomunikaty.Nale¿y go odpowiednio ustawiæ i wówczas nie napotkamy ¿adnegokonfliktu z kodami b³êdów innych funkcji.Niemniej nale¿y pamiêtaæ, ¿e bêdzieto prawd¹ wy³¹cznie wtedy, gdy korzystamy z funkcji Win32 API, które potrafi¹nam zwróciæ kod ostatniego b³êdu.Niekiedy wykorzystywanie funkcji b³êdów w sposób uproszczony mo¿e okazaæ siêzwodnicze, szczególnie w aplikacjach odczytuj¹cych wyniki pomiarów w postaciliczb.Powy¿szy przyk³ad jest tego ilustracj¹.Bardzo czêsto stykamy siê zsytuacj¹, w której zwracany kod b³êdu w postaci liczby mo¿e doœæ powa¿niewprowadziæ w b³¹d U¿ytkownika.W naszym przyk³adzie mierzona w stopniachCelsjusza temperatura mo¿e równie dobrze przyjmowaæ wartoœci ujemne, zatemprzedstawione rozwi¹zanie w tym konkretnym wypadku nie wydaje siê zbytfortunne.Bardziej przejrzysty i elegancki sposób skorzystania z us³ug paryfunkcji SetLastError() oraz GetLastError() w kontekœcie naszego programu móg³bywygl¹daæ tak, jak pokazano ni¿ej.Wykorzysta³em tu równie¿ funkcjêFormatMessage() umo¿liwiaj¹c¹ przedstawienie wybranego komunikatu Windows wbardzo wygodnej dla U¿ytkownika formie.LPVOID MsgBuf;.if (Number_Bytes_Read == 0){Timer1->Enabled = FALSE;SetLastError(ERROR_READ_FAULT);FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT), (LPTSTR) &MsgBuf, 0, NULL );MessageBox(NULL, (LPTSTR) MsgBuf, "B³¹d transmisji",MB_OK|MB_ICONINFORMATION);// zwolnienie buforaLocalFree(MsgBuf);}elseRichEdit1->Text = Buffer_I;W tym wypadku, je¿eli miernik z jakiœ przyczyn przestanie odpowiadaæ, naekranie ujrzymy pomocn¹ informacjê:Rysunek 5.11.Informacja pojawiaj¹ca siê w trakcie dzia³ania aplikacji wprzypadku utraty mo¿liwoœci czytania z urz¹dzeniaPrzedstawiony sposób umo¿liwia wzbogacenie pisanych programów jeszcze w szereginnych komunikatów sygnalizuj¹cych b³êdy Win32 API.Poni¿ej zamieszczam kilkanajbardziej u¿ytecznych:ERROR_BAD_UNIT — odnalezienie urz¹dzenia jest niemo¿liwe.ERROR_NOT_READY — urz¹dzenie nie jest gotowe.ERROR_BAD_COMMAND — urz¹dzenie nie rozpoznaje polecenia.ERROR_BAD_LENGTH — program wyda³ polecenie, ale jego d³ugoœæ jest niew³aœciwa.ERROR_WRITE_FAULT — system nie mo¿e zapisywaæ do okreœlonego urz¹dzenia.ERROR_READ_FAULT — system nie mo¿e czytaæ z okreœlonego urz¹dzenia.ERROR_GEN_FAILURE — urz¹dzenie pod³¹czone do komputera nie dzia³a
[ Pobierz całość w formacie PDF ]