Kurz3 - Kapitola6

17. června 2007 v 15:50 | http://www.sweb.cz/kurz_evt/ |  Programování pro WinCE

5.6 Členské funkce pro práci se sériovým portem

Tento díl naváže na minulý. Měli bychom si doplnit chybějící členské funkce třídy CPort. Nejrozsáhlejší z nich je Otevreni:
/////////////////////////////////////////
/// CPort
void CPort::Otevreni(int nCOM)
{
// Promenna pro nastaveni Timeoutu
COMMTIMEOUTS ctNewTimOut;
// Promenne pro prohledani klice, nejde-li o Infra Port
HKEY hKey;
DWORD dwType,dwSize,dwData;

// Zkus otevrit tento port
m_nTypPortu=0;
if(hCOM!=INVALID_HANDLE_VALUE) CloseHandle(hCOM);
if(nCOM>0 && nCOM<7)
hCOM = CreateFile(szCOM[nCOM],GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0);
else hCOM = INVALID_HANDLE_VALUE;
bAvCOM= !(hCOM == INVALID_HANDLE_VALUE);
if(bAvCOM) {
m_nTypPortu=2;
// Nastavim pozadovane parametry portu
if(!SetPort()) m_nTypPortu=1;
ctNewTimOut.ReadIntervalTimeout = MAXDWORD;
ctNewTimOut.ReadTotalTimeoutConstant = 10;
ctNewTimOut.ReadTotalTimeoutMultiplier = MAXDWORD;
ctNewTimOut.WriteTotalTimeoutConstant = 0;
ctNewTimOut.WriteTotalTimeoutMultiplier = 0;
if(!SetCommTimeouts(hCOM,&ctNewTimOut)) {
MessageBox(NULL,_T("Not able to set Timeouts"),_T("Warning!"),MB_OK);
m_nTypPortu=1;
}
// Nastavim COM buffer
SetupComm(hCOM,1000,100);
// Pomoci cteni hodnot z klice v registrech se pokusim zjistit,
// nejedna-li se o standardni IrCOMM...
// Otevru si IrDA/IrCOMM klic
if (RegOpenKeyEx (HKEY_LOCAL_MACHINE,_T("Drivers\\BuiltIn\\IrCOMM"), 0,
0, &hKey) == ERROR_SUCCESS) {
// Zjistim jeho cislo
dwSize = sizeof (dwData);
if (RegQueryValueEx (hKey, _T("Index"), 0, &dwType,
(PBYTE)&dwData, &dwSize) == ERROR_SUCCESS)
// Zjistim, zda jde o testovany port
if (dwData == (unsigned)nCOM) m_nTypPortu=3;
RegCloseKey (hKey);
}
}
}
Vstupním parametrem funkce je číslo otevíraného portu. Na úvod předpokládám, že požadovaný port není dostupný m_nTypPortu si nastavím na "žádný". Je-li nějaký port otevřený, nejprve jej uzavřu. Pak se pokusím pomocí CreateFile požadovaný port otevřít. Podle toho, co se vrátí, se nastavuje (ne nezbytná) pomocná logická proměnná bAvCOM.
Jestliže se port podařilo otevřít, označím jej jako běžný sériový port. Pokud se nepodaří nastavit jeho parametry (jsou uloženy v členských proměnných), změním typ portu na neurčitý. Takto se projevuje např. IrDa port ve Windows 2000, který nemá nainstalovaný ovládač IrCOMM.
Následuje pokus o nastavení Timeout parametrů portu. Při selhání je port opět označen jako "záhada". Funkce SetupComm nastavuje velikost vyrovnávací paměti portu. Posledním krokem je detekce, nepracujeme-li náhodou s infračerveným portem. Díky ovládači IrCOMM se takový port chová zcela shodně s běžným sériovým rozhraním. Nejjednodušší způsob, jak informaci o infračerveném portu zjistit, je podívat se do registru Windows CE. Zkusíme tedy otevřít příslušný klíč a porovnat, není-li číslo portu, kde je nainstalován IrCOMM, shodné s námi otevřeným portem.
BOOL CPort::SetPort()
{
DCB dcb;
// Vynuluju a pripravim si strukturu DCB
memset(&dcb,'\0',sizeof(dcb));
dcb.DCBlength = sizeof(dcb);
// Pripravim parametry portu
dcb.BaudRate=dwBaud[m_nBaud];
dcb.ByteSize=8-m_nData;
dcb.Parity=byParity[m_nParity];
dcb.StopBits=byStop[m_nStop];
dcb.ErrorChar=(char)0xFF;
dcb.fParity=m_nParity?1:0;
dcb.fErrorChar=m_nParity?1:0;
// A nyni to nastavim
if (!SetCommState(hCOM,&dcb)) {
MessageBox(NULL,_T("Not able to set COM parameters"),_T("Warning!"),MB_OK);
return FALSE;
}
return TRUE;
}
Funkce SetPort nastavuje parametry portu (např. po změně na prvním listu našeho programu). Je v ní volána funkce SetCommState. Před tím je ovšem potřeba nastavit požadované parametry ve struktuře dcb podle hodnot uložených v členských proměnných.
void CPort::SetBit(DWORD dwBit)
{
// Jenom nastavim prislusny bit portu
if(bAvCOM) EscapeCommFunction(hCOM,dwBit);
}
DWORD CPort::GetBits()
{
DWORD dwBity;
// Prectu stav signalu na portu
if(bAvCOM)
if(GetCommModemStatus(hCOM,&dwBity)) return dwBity;
return 0;
}
Tyto dvě funkce pracují s modemovými bity portu. Je-li port dostupný, zavolají příslušnou API funkci.
Podobně jednoduché jsou pak funkce pro příjem nebo vyslání sériových dat:
int CPort::JeZnak()
{
DWORD nPocet;
// Pokusim se precist "hodne znaku z portu",
// diky Timeoutu mi vrati pouze tolik, kolik jich prislo
ReadFile(hCOM,bPortBuf,950,&nPocet,NULL);
return nPocet;
}
TCHAR CPort::Znak(int i)
{
// Beru prislusny znak prijaty do bufferu portu
if(i<1000)
return bPortBuf[i];
else return 0;
}
void CPort::Posli(TCHAR chZnak)
{
BYTE chBuf[2];
DWORD nPocet;
// Poslu znak na vystup portu
chBuf[0]= chZnak % 256;
WriteFile(hCOM,chBuf,1,&nPocet,NULL);
}
Přeložíte-li program, nezjistíte v něm žádnou změnu. Objekt mujPort je ale v tuto chvíli připraven k použití.
Zde uvedené funkce jsem záměrně podrobně nekomentoval. Měly by být relativně jasné a pochopitelné. Jejich hlavní část leží na použití odpovídajících API funkcí a datových struktur určených pro sériovou komunikaci. Doporučuji prostudovat Help k použitým funkcím.
Poznámka: Windows CE neumožňují asynchronní přístup k datům sériového portu. Používáme tedy synchronní přístup (viz nápověda :-).

Co bychom si měli z této lekce zapamatovat?

  • Se sériovým portem se pracuje podobně jako se souborem.
  • Ovládání sériového portu nám umožňuje sada API funkcí.
 

Buď první, kdo ohodnotí tento článek.

Nový komentář

Přihlásit se
  Ještě nemáte vlastní web? Můžete si jej zdarma založit na Blog.cz.