[ Pobierz całość w formacie PDF ]
.Kodnaszej funkcji Write_Comm() zapisującej dane do portu będzie mógł przyjąć następującąuproszczoną postać:int __fastcall Write_Comm(HANDLE hCommDev, LPCVOID lpBuffer,DWORD nNumberOfBytesToWrite){DWORD NumberOfBytesWritten;if (WriteFile(hCommDev, lpBuffer, nNumberOfBytesToWrite,&NumberOfBytesWritten, NULL) > 0){WaitCommEvent(hCommDev, &fdwEvtMask, NULL);100 return TRUE;}elsereturn FALSE;}Zwróćmy jeszcze uwagę, że nagłówek tej funkcji mógłby być równie dobrze zapisany tradycyjnie:int __fastcall Write_Comm(HANDLE hCommDev, const void *Buffer,DWORD nNumberOfBytesToWrite)lub nawet jako:int __fastcall Write_Comm(., void *Buffer,.)// LPVOID lpBufferDeklarując wskaznik bufora reprezentującego pewien obszar pamięci operacyjnej przy wysyłaniudanych, wcale nie musimy wskazywać na jakiś stały obszar tej pamięci, chociaż API właśnie tosugeruje.Pamiętajmy, że operujemy na C-łańcuchach.Jeżeli w buforze wyjściowym znajdzie sięNUL bajt (nazywany niekiedy zerowym ogranicznikiem) kończący łańcuch, nadawanie zostanieprzerwane.Nieco inaczej będzie to wyglądało w przypadku danych odbieranych, co zostanieomówione za chwilę.PRZYPOMNIJMYDane typu LPVOID (void *), będąc wskazaniami adresowymi, nie wskazują na obiekty.Lokalizują jedynie pewne obszary pamięci operacyjnej.Pokazany sposób zapisu funkcji wysyłającej komunikaty do łącza szeregowego nie jest oczywiściejedynym z możliwych.Można ją zapisać w sposób maksymalnie uproszczony, jedynie z dwomaparametrami formalnymi, które tak naprawdę są dla nas najistotniejsze.Będą nimi: identyfikatorportu oraz liczba bajtów do wysłania:char Buffer_O[cbOutQueue]; // bufor danych wyjściowych.int __fastcall Write_Comm(HANDLE hCommDev,DWORD nNumberOfBytesToWrite){.if (WriteFile(hCommDev, &Buffer_O[0],nNumberOfBytesToWrite, &NumberOfBytesWritten, NULL) > 0){.return TRUE;}else101 return FALSE;}Jeżeli zdecydujemy się na taki zapis, wówczas jednym z parametrów wywoływanej funkcji APIWriteFile() musi być jawnie użyty bufor danych wyjściowych Buffer_O.Standardowoargumenty funkcji w C++ przekazujemy przez wartość.W ten sposób powodujemy utworzeniekopii argumentu w wywoływanej funkcji, zapobiegając tym samym możliwości zmodyfikowaniajego początkowej wartości.W przypadku naszej funkcji Write_Comm() będzie tonNumberOfBytesToWrite, czyli liczba bajtów do wysłania będąca jednocześnie parametremfunkcji Win32 API WriteFile().Jeżeli z kolei funkcja ma zmodyfikować wartości zmiennychbędących jej argumentami, parametry powinny być jawnie zadeklarowane jako wskazniki.Jest jeszcze wiele rzeczy, których nie uwzględniliśmy.Naprawdę niezawodna aplikacjapowinna mieć parę dodatkowych zabezpieczeń.Wszystkie je omówimy po kolei w następnychpodrozdziałach.Obecnie ważne jest dla nas to, że użyliśmy wszystkich omówionych do tej poryfunkcji Win32 API, poznaliśmy w jakiej kolejności należy je wywoływać.Po skompletowaniucałego programu przekonasz się, że mimo swojej prostoty będzie on funkcjonalny.Teraz, kiedypoznaliśmy, w jaki sposób można coś powiedzieć do urządzenia, czas najwyższy, abyśmynauczyli się słuchać i rozumieć jego odpowiedzi.Segment odbierający komunikatyDRUGIE PRAWO SODDA:Wcześniej czy pózniej i tak musi nastąpić najgorszy z możliwych splotów okoliczności.Uzupełnienie:Każdy system musi być zaprojektowany w taki sposób, aby stawić czoła najgorszemu zmożliwych splotów okoliczności.Każdy, kto kiedykolwiek interesował się komunikacją komputerową wie, żewystępowanie błędów w tym procesie jest czymś nieuniknionym i poniekąd naturalnym.Ustaleniesposobu reagowania na wystąpienie błędu w czasie transmisji szeregowej jest zawsze bardzoistotnym elementem aplikacji.Przypominamy sobie z poprzednich rozdziałów, że istnieje pewiensposób zabezpieczenia danych przed zafałszowaniem w czasie ich przekazu.Sposobem tym jestkontrola bitu parzystości.Jest on jednak mało efektywny.Korzystając z zasobów struktury DCB,można w pewnym stopniu zabezpieczyć się przed odbieraniem przekłamanych danych.Wystarczyw części konfiguracyjnej aplikacji odwołać się do jednego ze znaczników DCB, a mianowicie dofAbortOnError (patrz tabela 5.5.), pisząc:dcb.fAbortOnError = TRUE;102co spowoduje wstrzymanie wykonywania wszelkich operacji wysyłania i odbierania danych przywykryciu jakiegokolwiek błędu w komunikacji z portem szeregowym.Reinicjalizacja odbioru inadawania poprzez port komunikacyjny identyfikowany przez hCommDev nastąpi po wywołaniufunkcji:BOOL ClearCommError(HANDLE hCommDev,LPDWORD lpErrors,LPCOMSTAT lpStat);gdzie:lpErrors jest wskaznikiem do 32-bitowej danej typu DWORD, reprezentującej jeden z typówbłędów:CE_BREAK wykryto przerwanie połączenia.CE_DNS urządzenie przyłączone do łącza równoległego nie zostało określone (Win 9x).CE_FRAME wystąpił błąd protokołu ramki danych.CE_IOE podczas komunikacji nastąpił jakiś błąd wejścia-wyjścia ( Input-Output).CE_MODE żądanie nadawania nie jest podtrzymywane lub identyfikator portu(urządzenia) ma błędną specyfikację.CE_OOP urządzenie przyłączone do łącza równoległego sygnalizuje brak papieru, co jesttypowe dla drukarek, faksów, niektórych faksmodemów (Win 9x).CE_OVERRUN nastąpiło całkowite wypełnienie wejściowego bufora danych.Następnyznak będzie zignorowany.CE_PTO został przekroczony czas oczekiwania na połączenie z portem równoległym, tzw.przeterminowanie czasu połączenia (Win 9x).CE_RXOVER bufor wejściowy został przepełniony.Albo nie ma w nim już fizyczniemiejsca, albo został odebrany jakiś znak następujący po znaku końcapliku EOF.CE_RXPARITY wykryto błąd niezgodności kontroli parzystości.CE_TXFULL próba transmisji znaku przy całkowitym wypełnieniu bufora wyjściowego.Zbiór wartości, na które wskazuje lpErrors, można z powodzeniem traktować jako maski bitowez możliwością wykonywania na nich odpowiednich działań.Zawarta tam pełna informacja możebyć aktualnie zapisana na 16 bitach
[ Pobierz całość w formacie PDF ]