Kurz3 - Kapitola10

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

5.10 Dialog sériového přenosu dat

Zbývá dokončit poslední dialog našeho prográmku. Se znalostmi, které máte, byste to asi dokázali již sami. Tento díl se proto bude skládat hlavně ze zdrojového kódu, vysvětlující poznámky jsou omezeny na minimum.
V hlavičkovém souboru se změní třída CTreti např. takto:
////// Trida tretiho dialogu - Prenos dat
////////////////////////////////////////////////////
class CTreti: public CPropertyPage
{
UINT m_nTimer; // Odkaz na nastartovany casovac
int m_nRezim; // Rezim odeslani dat na vystup
int m_nVypis; // Zpusob vypisu prijatych dat
TCHAR cTestZn;
CString sInp,sOut; // Retezce pro vstup a vystup dat
public:
CTreti():CPropertyPage(IDD_TRETI) {m_nRezim=m_nVypis=cTestZn=0;};
protected:
virtual void DoDataExchange(CDataExchange*);
// Inicializace, aktivace a deaktivace dialogoveho listu
afx_msg BOOL OnInitDialog();
afx_msg BOOL OnSetActive();
afx_msg BOOL OnKillActive();
// Funkce obsluhy casovace - kazdych 100 msec
afx_msg void OnTimer(UINT);
// Skupina funkci pro jednotlive prvky dialogoveho listu
afx_msg void ZmenaVstupu();
afx_msg void Posli();
afx_msg void Test();
afx_msg void Manual();
afx_msg void Autom();
afx_msg void Ascii();
afx_msg void Hexa();
afx_msg void Octal();
afx_msg void Decimal();
DECLARE_MESSAGE_MAP()
};
Všimněte si, že pro uložení řetězců znaků jsou použity jako proměnné objekty třídy CString. Tato třída poskytuje prostředky pro snadnou práci s řetězci. Protože použití textových řetězců je poměrně časté, zařadili návrháři do kolekce MFC svoji představu snadného zpracování textu. Podobně jsou přichystány další třídy pro práci s typickými datovými objekty.
V souboru TestCOM.cpp doplníme mapu zpráv a inicializaci dialogu:
/////////////////////////////////////////
/// CTreti

#define MAXZNA 20 // Maximalni pocet znaku v Edit okne

BEGIN_MESSAGE_MAP (CTreti,CPropertyPage)
ON_WM_TIMER()
ON_BN_CLICKED(IDC_SEND,Posli)
ON_BN_CLICKED(IDC_AUTOM,Autom)
ON_BN_CLICKED(IDC_MANUAL,Manual)
ON_BN_CLICKED(IDC_TEST,Test)
ON_BN_CLICKED(IDC_ASCII,Ascii)
ON_BN_CLICKED(IDC_HEXA,Hexa)
ON_BN_CLICKED(IDC_OCTAL,Octal)
ON_BN_CLICKED(IDC_DECIMAL,Decimal)
ON_EN_CHANGE(IDC_OUT,ZmenaVstupu)
END_MESSAGE_MAP()

BOOL CTreti::OnInitDialog()
{
CButton *pBut;
CEdit *pEdit;

CDialog::OnInitDialog();
// Zatrhnu default pozici prepinacu a max. pocet pismen ve vyst. okne
pBut=(CButton *)GetDlgItem(IDC_AUTOM); pBut->SetCheck(BST_CHECKED);
pBut=(CButton *)GetDlgItem(IDC_ASCII); pBut->SetCheck(BST_CHECKED);
pEdit=(CEdit*)GetDlgItem(IDC_OUT); pEdit->SetLimitText(MAXZNA);
return 0;
}
Při aktivaci dialogu nastartuje časovač a okna pro vyslání dat jsou povolena nebo zakázána podle typu otevřeného portu. V OnKillActive pouze vypneme časovač:
BOOL CTreti::OnSetActive()
{
CWnd *pWnd;

// Nastavim casovac pro kontrolu vstupu
CPropertyPage::OnSetActive();
if(!(m_nTimer=SetTimer(1,100,NULL))) {
MessageBox(_T("Timer error!"));
return FALSE;
}
// Povolim odesilaci Edit okno a tlacitko Send
pWnd=GetDlgItem(IDC_SEND); pWnd->EnableWindow((mujCOM.TypPortu()>1)&&(m_nRezim==1));
pWnd=GetDlgItem(IDC_OUT); pWnd->EnableWindow(mujCOM.TypPortu()>1);
return TRUE;
}

BOOL CTreti::OnKillActive()
{
KillTimer(m_nTimer);
return CPropertyPage::OnKillActive();
}
Data jsou vyslána automaticky po změně v okně IDC_OUT nebo manuálně po stisknutí tlačítka Send:
// Data muzu poslat automaticky...
void CTreti::ZmenaVstupu()
{
if(m_nRezim==0) {
UpdateData();
mujCOM.Posli(sOut[0]);
sOut="";
UpdateData(FALSE);
}
}

// ... nebo manualne
void CTreti::Posli()
{
int i,pocet;

UpdateData();
pocet=sOut.GetLength();
for(i=0;i<pocet;i++) mujCOM.Posli(sOut[i]);
sOut="";
UpdateData(FALSE);
}
Přepínačem se nastavuje proměnná m_nRezim s údajem o režimu odesílání dat a také se povolí/zakáže použití tlačítka Send:
// Volba zpusobu odeslani dat (a take povolim tlacitko Send)
void CTreti::Autom()
{
CWnd *pWnd;

pWnd=GetDlgItem(IDC_SEND); pWnd->EnableWindow(FALSE);
m_nRezim=0;
}

void CTreti::Manual()
{
CWnd *pWnd;

pWnd=GetDlgItem(IDC_SEND); pWnd->EnableWindow(mujCOM.TypPortu()>1);
m_nRezim=1;
}

void CTreti::Test()
{
CWnd *pWnd;

pWnd=GetDlgItem(IDC_SEND); pWnd->EnableWindow(FALSE);
m_nRezim=2;
}
Většinu práce udělá obsluha zprávy od časovače. Nejenom že posílá data v automatickém režimu - každých 100 msec znak o 1 vyšší, ale především se stará o příjem dat. Každých 100 msec zkontroluje, zda něco nepřišlo. Pokud ano, pak přijaté znaky vypíše podle zvoleného formátu dat. V ASCII výpisu je prvních 32 znaků nahrazováno pomlčkou.
// Obsluha prijmu znaku na vstupu
void CTreti::OnTimer(UINT nTim)
{
int i,pocet,kolik=1;
BYTE znak;
CString sData;

if(mujCOM.TypPortu()>1) {
// Je-li test rezim posilam automaticky kazdych 100 msec znak
if(m_nRezim==2)mujCOM.Posli(cTestZn++);
UpdateData();
// Zjistim kolik znaku je na vstupu
pocet=mujCOM.JeZnak();
// Jsou-li nejake, zaradim je do vstupniho retezce
for(i=0;i>pocet;i++) {
znak=(BYTE) mujCOM.Znak(i);
// Typ vypisu volim podle nastavene hodnoty m_nVypis
switch (m_nVypis) {
case 0: sInp+=(znak>31?znak:_T('-')); break;
case 1: sData.Format(_T(" %X"), znak); sInp+=sData; break;
case 2: sData.Format(_T(" %o"), znak); sInp+=sData; break;
case 3: sData.Format(_T(" %d"), znak); sInp+=sData; break;
}
// Je-li retezec delsi, zrusim stare znaky...
kolik=sInp.GetLength()-MAXZNA;
if(sInp.GetLength()>MAXZNA) sInp.Delete(0,kolik);
}
// ... a vypisu jej
UpdateData(FALSE);
}
}
Funkce DoDataExchange nám přináší pouze 1 novinku - použití funkce DDX_Text, která svazuje textové pole s řetězcovou proměnnou.
void CTreti::DoDataExchange(CDataExchange* pDX)
{
DDX_Text(pDX, IDC_INP, sInp);
DDX_Text(pDX, IDC_OUT, sOut);
}
Na závěr jsem si nechal netradičně pojatou obsluhu přepínače. Vhodnější by asi bylo použít funkci DDX_Radio. Proč jsem to řešil takto, si můžete přečíst v komentáři.
// Ve Win95 prepinac zlobil, pouzil jsem "manualni" obsluhu
// Vhodnejsi by byla DDX funkce
void CTreti::Ascii()
{
m_nVypis=0;
}
void CTreti::Hexa()
{
m_nVypis=1;
}
void CTreti::Octal()
{
m_nVypis=2;
}
void CTreti::Decimal()
{
m_nVypis=3;
}
Když se teď zpětně dívám na celou třídu CTreti, říkám si, že by to šlo lépe "učesat". I jinde v kódu tohoto dialogu je vidět, že program vznikl rychle jako jednoúčelová utilita. Protože se ale nezabýváme výukou jazyka C++, snad mi prominete. Příště se určitě polepším :-)).

obr. 60 Odesílání znaků po sériové lince
V tomto okamžiku je program v podstatě hotov. Zbývají ještě nějaké drobnosti a můžeme končit...

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

  • DDX funkcí svazujeme s proměnnou jen ty prvky, kde je to třeba.
  • Pro práci s textem můžeme použít třídu CString.
 

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.