Kurz4 - Kapitola6

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

6.6 Členské funkce CIRcontrol

V minulé části jsme vytvořili třídu CIRcontrol pro ovládání infra portu. Členské funkce nové třídy jsou však zatím prázdné. Nyní je čas vdechnout těmto metodám život. Vložte tedy do těchto funkcí následující zdrojový kód. Pomocí ClassWizardu (pravé tlačítko myši na funkci v Class View a volba Go to Definition) se přenesete na patřičné místo a opravte:

Konstruktor:

CIRcontrol::CIRcontrol()
{
DCB dcb = {0};
COMMTIMEOUTS timeouts;
TCHAR chPort,str[80];
LARGE_INTEGER i;
HANDLE hFile;
DWORD dwNumFil;

// Nactu data - pokud jsou, jinak nuluju a hlasim to
if((hFile=CreateFile(REMCONFILENAME,GENERIC_READ,FILE_SHARE_READ,
NULL,OPEN_EXISTING,0,NULL))!=INVALID_HANDLE_VALUE) {
ReadFile(hFile,Impuls,sizeof(Impuls),&dwNumFil,NULL);
CloseHandle(hFile);
}
else {
for(int j=0;j<POCTLAC;j++) Impuls[j][0].pocet=0;
AfxMessageBox(_T("No data loaded!"),MB_OK);
}

// Zjisteni Performance Frequency
QueryPerformanceFrequency(&i);
m_llFrekv=i.QuadPart;

// A otevreni COM portu
m_bOpened = FALSE;

ASSERT(m_hIRPort == INVALID_HANDLE_VALUE);
/* Close connection to Desktop Computer */
EnumWindows(DisconnectActiveSync, 0);
/* Get number of RAW IR port*/
chPort=GetIRPort();
/* Get a handle to the IR port */
wsprintf(str,_T("COM%d:"), chPort);
m_hIRPort = CreateFile(str, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
if (m_hIRPort == INVALID_HANDLE_VALUE) {
// Generate error
AfxMessageBox(_T("Invalid port handle"), MB_ICONERROR | MB_OK);
return;
}
/* Nastaveni velikosti bufferu */
SetupComm(m_hIRPort, 1024,1024);
/* Set port in IR mode */
EscapeCommFunction(m_hIRPort, SETIR);

/* Get device-control block */
if (GetCommState(m_hIRPort, &dcb) == FALSE) {
// Generate error
AfxMessageBox(_T("Error retrieving DCB"), MB_ICONERROR | MB_OK);
return;
}
dcb.BaudRate = CBR_115200;
dcb.fBinary = TRUE; // binary mode, no EOF check
dcb.fParity = FALSE; // no parity checking
dcb.fOutxCtsFlow = FALSE; // no CTS output flow control
dcb.fOutxDsrFlow = FALSE; // no DSR output flow control
dcb.fDtrControl = DTR_CONTROL_DISABLE; // no DTR flow control type
dcb.fDsrSensitivity = FALSE; // ignore DSR sensitivity
dcb.fTXContinueOnXoff = TRUE; // XOFF continues Tx
dcb.fOutX = FALSE; // no XON/XOFF out flow control
dcb.fInX = FALSE; // no XON/XOFF in flow control
dcb.fErrorChar = FALSE; // disable error replacement
dcb.fNull = FALSE; // don't dump null bytes
dcb.fRtsControl = RTS_CONTROL_DISABLE; // disable RTS control
dcb.fAbortOnError = FALSE; // no abort reads/writes on error
//dcb.fDummy2 = reserved; do not use.
dcb.wReserved = 0; // not currently used
dcb.XonLim = 0; // transmit XON threshold
dcb.XoffLim = 0; // transmit XOFF threshold
dcb.ByteSize = 7; // number of bits/byte, 4-8
dcb.Parity = NOPARITY; // 0-4=no,odd,even,mark,space;
dcb.StopBits = ONESTOPBIT; //TWOSTOPBITS; // 0,1,2 = 1, 1.5, 2
dcb.XonChar = 0; // Tx and Rx XON character
dcb.XoffChar = 0; // Tx and Rx XOFF character
dcb.ErrorChar = 0; // error replacement character
dcb.EofChar = 0; // end of input character
dcb.EvtChar = 0; // received event character
//dcb.wReserved1 = reserved; do not use.
if (SetCommState(m_hIRPort, &dcb) == FALSE) {
// Generate error
AfxMessageBox(_T("Error setting DCB"), MB_ICONERROR | MB_OK);
return;
}
/* setup the timeout values for the port (see help for a full description) */
timeouts.ReadIntervalTimeout = MAXDWORD; /* No Timeout */
timeouts.ReadTotalTimeoutMultiplier = 0; /* */
timeouts.ReadTotalTimeoutConstant = 0; /* */
timeouts.WriteTotalTimeoutMultiplier = 0;
timeouts.WriteTotalTimeoutConstant = 0;
if (SetCommTimeouts(m_hIRPort, &timeouts) == FALSE) {
// Generate error
AfxMessageBox(_T("Error setting port time outs"), MB_ICONERROR | MB_OK);
return;
}
m_bOpened = TRUE;
}

Destruktor:

CIRcontrol::~CIRcontrol()
{
if (m_hIRPort != INVALID_HANDLE_VALUE) {
// Restore COM state
EscapeCommFunction(m_hIRPort, CLRIR);
if (CloseHandle(m_hIRPort) == FALSE) {
// Generate error
AfxMessageBox(_T("Error closing COM handle"), MB_ICONERROR | MB_OK);
}
m_hIRPort = INVALID_HANDLE_VALUE;
}
m_bOpened = FALSE;
}

Funkce pro učení:

int CIRcontrol::Learn(int nButt)
{
LARGE_INTEGER lli;
LONGLONG llTime,llStart,llLastCh,llMaxTime,llMaxByte;
UINT nPocZn;
DWORD dwKolik;
int dwThrPr,i,j;
BYTE buf[10];

// Je-li nejaka chyba vstupnich dat vracim chybovy kod 8888
if((!m_bOpened) || (nButt<0) || (nButt>=POCTLAC)) return 8888;
// Nastavime hodnoty casu pro 1 sec (max. cas) a pro mezeru
llMaxTime=m_llFrekv;llMaxByte=m_llFrekv/(LONGLONG)4000;
// Nastavime prioritu procesu
dwThrPr=GetThreadPriority(GetCurrentThread());
SetThreadPriority(GetCurrentThread(),THREAD_PRIORITY_TIME_CRITICAL);

// Ulozime si zacatecni cas
QueryPerformanceCounter(&lli);
llStart=lli.QuadPart;

// Nejprve vymazu pocet prijatych znaku u vsech impulsu
for(i=0;i<MAXIMP;i++) Impuls[nButt][i].pocet=0;
// Pockam na zahajeni vysilani maximalne 1 sekundu
do {
ReadFile(m_hIRPort,buf,1,&dwKolik,NULL);
QueryPerformanceCounter(&lli);
llTime=lli.QuadPart - llStart;
if(dwKolik) break;
} while(llTime<m_llFrekv);
// Pokud do 1 sekundy neprisel znak, tak koncim
if(!dwKolik) {SetThreadPriority(GetCurrentThread(),dwThrPr);return 0;}
// Znak prisel, zahajim prijem kodu
llLastCh=llStart=lli.QuadPart;
for(i=0;i<MAXIMP;i++) {
// Jiz 1 znak prisel, proto pocitadlo nastavim na 1
nPocZn=1;
do {
ReadFile(m_hIRPort,buf,1,&dwKolik,NULL);
QueryPerformanceCounter(&lli);
llTime=(lli.QuadPart - llLastCh);
if(dwKolik) {nPocZn++; llLastCh=lli.QuadPart;};
} while(llTime<llMaxByte);
// Impuls skoncil, zapisu pocet '0x5b' a posledni znak
Impuls[nButt][i].pocet=nPocZn;
Impuls[nButt][i].lastch=buf[0];
// Pockam, neobjevi-li se dalsi impuls (max. do 1 sekundy)
do {
ReadFile(m_hIRPort,buf,1,&dwKolik,NULL);
QueryPerformanceCounter(&lli);
llTime=lli.QuadPart - llLastCh;
if(dwKolik) break;
} while(llTime<llMaxTime);
// Znak se objevil - je dalsi impuls
if(llTime<m_llFrekv) {
Impuls[nButt][i].kdy=(lli.QuadPart-llStart);
llLastCh=lli.QuadPart;
}
// Impuls nedosel - koncim s prijmem
else {
Impuls[nButt][i].kdy=0;break;
}
}

// Vratim puvodni prioritu
SetThreadPriority(GetCurrentThread(),dwThrPr);
// Pro jistotu - kontrola poctu znaku, aby nedoslo k chybe pri vysilani
for(j=0;j<MAXIMP;j++) if(Impuls[nButt][j].pocet>512) Impuls[nButt][j].pocet=512;
// Vracim pocet ziskanych impulsu
return i+1;
}

Funkce pro vyslání povelu:

void CIRcontrol::Send(int nButt)
{
LARGE_INTEGER lli;
LONGLONG llTime,llStart;
DWORD dwKolik;
UINT i,j;
int dwThrPr;
BYTE buf[512];

// Je-li nejaka chyba vstupnich dat koncim
if((!m_bOpened) || (nButt<0) || (nButt>=POCTLAC)) return;
// Nastavime prioritu procesu
dwThrPr=CeGetThreadPriority(GetCurrentThread());
CeSetThreadPriority(GetCurrentThread(),0);

// Ulozime si zacatecni cas
QueryPerformanceCounter(&lli);
llStart=lli.QuadPart;

// Zde kod vysilame
for(i=0;i<MAXIMP;i++) {
if(!Impuls[nButt][i].pocet) break;
// Naplnime buffer odpovidajicim poctem znaku ...
for(j=0;j<(Impuls[nButt][i].pocet-1);j++) {
buf[j]=0x5b;
}
// ... doplnim posledni znak ...
buf[j]=Impuls[nButt][i].lastch;
// ... odesleme data ...
WriteFile(m_hIRPort,buf,Impuls[nButt][i].pocet,&dwKolik,NULL);
// ... a cekame na dalsi impuls
do {
QueryPerformanceCounter(&lli);
llTime=lli.QuadPart - llStart;
} while(llTime<=Impuls[nButt][i].kdy);
}

// ... a vratime zpet puvodni prioritu
CeSetThreadPriority(GetCurrentThread(),dwThrPr);
}

Uložení dat:

void CIRcontrol::Save()
{
HANDLE hFile;
DWORD dwNumFil;

if((hFile=CreateFile(REMCONFILENAME,GENERIC_WRITE,0,
NULL,CREATE_ALWAYS,0,NULL))!=INVALID_HANDLE_VALUE) {
WriteFile(hFile,Impuls,sizeof(Impuls),&dwNumFil,NULL);
CloseHandle(hFile);
}
}

... a do stejného souboru také 3 pomocné funkce, které budeme potřebovat:

char GetIRPort()
/*********************************************************************
description: Gets the IR port number from the registry
parameters: <none>
result: COM port number
Negative number indicates error (position in source code);
use GetLastError to retrieve (system) error code
n = COMn
-1 = RegOpenKey IrDA unsuccessful
-2 = RegCloseKey IrDA unsuccessful
-3 = RegOpenKey IrDA\Linkage unsuccessful
-4 = RegQueryValueEx Bind unsuccessful
-5 = RegQueryValueEx Bind unsuccessful
-6 = RegOpenKey [Bind]\Parms unsuccessful
-7 = RegQueryValueEx Port unsuccessful
-8 = final RegCloseKey unsuccessful
*********************************************************************/
{
HKEY hkResult;
LONG lResult;
BYTE lpbyData[sizeof(DWORD)];
DWORD dwData;
TCHAR szSubKey[128];

/* Try read from HKEY_LOCAL_MACHINE\Comm\IrDA value Port */
lResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("Comm\\IrDA"), 0, 0, &hkResult);
if (lResult != ERROR_SUCCESS) {
// Generate error
SetLastError(lResult);
return -1;
}
lResult = RegQueryValueEx(hkResult, _T("Port"), NULL, NULL, lpbyData, &dwData);
if (lResult != ERROR_SUCCESS) {
// Try to find Linkage
lResult = RegCloseKey(hkResult);
if (lResult != ERROR_SUCCESS) {
// Generate error
SetLastError(lResult);
return -2;
}
/* Try read from HKEY_LOCAL_MACHINE\Comm\IrDA\Linkage value Bind */
lResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("Comm\\IrDA\\Linkage"), 0, 0, &hkResult);
if (lResult != ERROR_SUCCESS) {
// Generate error
SetLastError(lResult);
return -3;
}
// Read Bind size
lResult = RegQueryValueEx(hkResult, _T("Bind"), NULL, NULL, NULL, &dwData);
if (lResult != ERROR_SUCCESS) {
// Generate error
SetLastError(lResult);
return -4;
}
LPTSTR lpszData = new TCHAR[dwData/sizeof(TCHAR)];
lResult = RegQueryValueEx(hkResult, _T("Bind"), NULL, NULL, (LPBYTE)lpszData, &dwData);
if (lResult != ERROR_SUCCESS) {
delete[] lpszData;
// Generate error
SetLastError(lResult);
return -5;
}
/* Try read from HKEY_LOCAL_MACHINE\Comm\[Bind]\Parms value Port */
wsprintf(szSubKey,_T("Comm\\%s\\Parms"), lpszData);
lResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, szSubKey, 0, 0, &hkResult);
if (lResult != ERROR_SUCCESS) {
delete[] lpszData;
// Generate error
SetLastError(lResult);
return -6;
}
delete[] lpszData;
dwData = sizeof(DWORD);
lResult = RegQueryValueEx(hkResult, _T("Port"), NULL, NULL, lpbyData, &dwData);
if (lResult != ERROR_SUCCESS) {
// Generate error
SetLastError(lResult);
return -7;
}
}
lResult = RegCloseKey(hkResult);
if (lResult != ERROR_SUCCESS) {
// Generate error
SetLastError(lResult);
return -8;
}
return (char) *((DWORD*) lpbyData); // Convert byte pointer (which points to a DWORD) to a char
}

void GetConnectionName(TCHAR* lpszName)
/*********************************************************************
description: Reads the (ActiveSync) connection name from the registry
parameters: *lpszName - (out) pointer to CString receiving connection name
result: <none>
comment:
Under HKEY_CURRENT_USER\ControlPanel\Comm are a few values related to
auto-connecting the Windows CE device to the desktop:
AutoCnct - is a true/false value, where true means the device will
attempt to automatically connect to the desktop.
Cnct - represents the current rasbook connection name to use for
the connection. See HKEY_CURRENT_USER\Comm\RasBook for the list of
available connection types.
*********************************************************************/
{
HKEY hkResult;
unsigned char *lpchConnection;
DWORD dwData;

/* Try read from HKEY_CURRENT_USER\ControlPanel\Comm value Cnct */
if (RegOpenKeyEx(HKEY_CURRENT_USER, _T("ControlPanel\\Comm"), 0, 0, &hkResult)
!= ERROR_SUCCESS) {
return;
}
if (RegQueryValueEx(hkResult, _T("Cnct"), NULL, NULL, NULL, &dwData) != ERROR_SUCCESS) {
RegCloseKey(hkResult);
return;
}
lpchConnection = new unsigned char[dwData];
if (RegQueryValueEx(hkResult, _T("Cnct"), NULL, NULL, lpchConnection, &dwData) == ERROR_SUCCESS) {
wcscpy(lpszName,(TCHAR*)lpchConnection);
}
RegCloseKey(hkResult);
delete[] lpchConnection;
}

BOOL CALLBACK DisconnectActiveSync(HWND hwnd, LPARAM lParam)
/*********************************************************************
description: Closes the connection to the desktop (ActiveSync), when opened
parameters: <none>
result: <none>
Comments: Callback function, called by EnumWindows for each top-level
windows on the screen. If the windows title bar contains
the (ActiveSync) connection name, that application is closed!
*********************************************************************/
{
TCHAR szWindowName[80], szConnName[80];
LPTSTR lpchWindowName;

lpchWindowName = new TCHAR[50];
GetWindowText(hwnd, lpchWindowName, 50);
wcscpy(szWindowName, lpchWindowName);
delete[] lpchWindowName;
GetConnectionName(szConnName);
if (wcscmp(szConnName,_T("`USB Socket Default")) != 0) {
// Only disconnect on non usb connection
if (wcsstr(szWindowName,szConnName) != NULL) {
if (SendMessage(hwnd, WM_CLOSE, 0, 0) == 0)
Sleep(200); // Give app some time to disconnect (empirical value)
return FALSE;
}
}
return TRUE;
}
Výše uvedené pomocné funkce a část konstruktoru jsem převzal z těchto stránek. Stačilo pouze několik pokusů při hledání v Internetu a objevil jsem, že někdo se přepnutím sériového infra portu do "Raw" režimu již zabýval a své dílo uveřejnil. Vyzkoušel jsem to a hle - fungovalo to. Mírně jsem kód podle potřeby upravil. Části, které jsou převzaté, poznáte podle komentářů v angličtině.
Pokusíte-li se o cvičný překlad (program nebude dělat nic nového), zjistíte, že chybí jméno souboru, kam se ukládají data. Můžete si zvolit např.:
// Jmeno souboru, do ktereho ukladame data
TCHAR REMCONFILENAME[]=_T("RmtCntrl.rcd");
Windows CE neznají pojem "pracovní adresář", takže tento soubor se uloží do kořenového adresáře. Vy si však můžete zvolit vhodnější umístění.
Protože tento díl je už poměrně rozsáhlý, necháme si popis a vysvětlení zdrojového kódu na příště.

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

  • Hledáním v Internetu si můžeme ušetřit hodně práce.
 

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

Komentáře

1 Bibi Bibi | Web | 17. června 2007 v 15:47 | Reagovat

Ahojik na mem blogu je velice jednoducha bleskovka kde vyhrava i ten ktery odpovi třeba jako 60!!!!!!!Tak pojd!!!!!

Nový komentář

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