📄 learndlg.cpp
字号:
/*
* This file is part of the WinLIRC package, which was derived from
* LIRC (Linux Infrared Remote Control) 0.5.4pre9.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published
* by the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* Copyright (C) 1998,99 Christoph Bartelmus <columbus@hit.handshake.de>
* Copyright (C) 1999 Jim Paris <jim@jtan.com>
*/
#include "stdafx.h"
#include "winlirc.h"
#include "learndlg.h"
#include <sys/types.h>
#include <string.h>
#include "dumpcfg.h"
#include "config.h"
#include "remote.h"
#ifndef min
#define min(a,b) (a>b ? b:a)
#endif
#ifndef max
#define max(a,b) (a>b ? a:b)
#endif
unsigned int LearnThread(void *dlg) {((Clearndlg *)dlg)->LearnThreadProc();return 0;}
unsigned int AnalyzeThread(void *dlg) {((Clearndlg *)dlg)->AnalyzeThreadProc();return 0;}
unsigned int RawThread(void *dlg) {((Clearndlg *)dlg)->RawThreadProc();return 0;}
/////////////////////////////////////////////////////////////////////////////
// Clearndlg dialog
Clearndlg::Clearndlg(CIRDriver *ndrv, const char *nfilename,
lm nlearn_mode, CWnd* pParent /*=NULL*/)
: CDialog(Clearndlg::IDD, pParent)
{
//{{AFX_DATA_INIT(Clearndlg)
// NOTE: the ClassWizard will add member initialization here
//}}AFX_DATA_INIT
drv=ndrv;
filename=nfilename;
learn_mode=nlearn_mode;
fout=NULL;
::learn_dialog=this;
}
Clearndlg::~Clearndlg()
{
KillThread(&LearnThreadHandle,&LearnThreadEvent);
if(fout!=NULL) { fclose(fout); fout=NULL; }
if(GotInput) { CloseHandle(GotInput); GotInput=NULL; }
}
void Clearndlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(Clearndlg)
// NOTE: the ClassWizard will add DDX and DDV calls here
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(Clearndlg, CDialog)
//{{AFX_MSG_MAP(Clearndlg)
ON_BN_CLICKED(IDC_BUTTON1, OnEnter)
ON_WM_CLOSE()
ON_BN_CLICKED(IDC_ENTER, OnEnter)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// Clearndlg message handlers
BOOL Clearndlg::OnInitDialog()
{
CDialog::OnInitDialog();
((CEdit *)GetDlgItem(IDC_OUT))->SetLimitText(0xFFFF);
char *mode=(learn_mode==lm_learn)?"w":"r";
if((fout=fopen(filename,mode))==NULL)
{
MessageBox("Could not open configuration file.");
EndDialog2(IDCANCEL);
}
if((GotInput=CreateEvent(NULL,FALSE,FALSE,NULL))==NULL)
{
MessageBox("Could not create event.");
EndDialog2(IDCANCEL);
}
/* THREAD_PRIORITY_IDLE combined with the REALTIME_PRIORITY_CLASS */
/* of this program still results in a really high priority. (16 out of 31) */
AFX_THREADPROC tp;
switch(learn_mode)
{
case lm_learn: tp=LearnThread; break;
case lm_analyze: tp=AnalyzeThread; break;
case lm_raw: tp=RawThread; break;
}
if((LearnThreadHandle=AfxBeginThread(tp,
(void *)this,THREAD_PRIORITY_IDLE))==NULL)
{
CloseHandle(GotInput); GotInput=NULL;
MessageBox("Could not initialize thread.");
EndDialog2(IDCANCEL);
}
return TRUE; // return TRUE unless you set the focus to a control
// EXCEPTION: OCX Property Pages should return FALSE
}
void Clearndlg::output(const char *s, bool replacelast)
{
CEdit *out=(CEdit *)GetDlgItem(IDC_OUT);
if (out==NULL) return;
if(s==NULL)
{
/* clear output */
out->SetSel(0,-1);
out->ReplaceSel("");
return;
}
/* limit it to 120 characters, then add \r\n (if not replacing current line) */
/* we don't add \r\n if replacing current line because that causes the box to */
/* scroll up and down real quick when the last line is deleted and removed. */
char t[256];
_snprintf(t,120,"%s",s);
t[120]=0;
if(replacelast && out->GetLineCount()>1)
{
out->SetSel(out->LineIndex(out->GetLineCount()-2),out->GetWindowTextLength()-2);
}
else
{
strcat(t,"\r\n");
out->SetSel(out->GetWindowTextLength(),out->GetWindowTextLength());
}
out->ReplaceSel(t);
if(out->GetLineCount()>500)
{
/* start clearing out lines to avoid hitting the 64k limit */
/* (122 * 500 = 61000) */
out->SetSel(0,out->LineIndex(100),TRUE);
out->ReplaceSel("");
}
out->SetSel(out->GetWindowTextLength(),out->GetWindowTextLength());
}
void Clearndlg::input(const char *prompt, char *s, int maxlen, bool allowempty)
{
CEdit *in=(CEdit *)GetDlgItem(IDC_IN);
CButton *ent=(CButton *)GetDlgItem(IDC_ENTER);
ent->EnableWindow(true);
in->SetSel(0,-1);
in->ReplaceSel("");
in->SetLimitText(maxlen);
this->GotoDlgCtrl(in);
int len;
HANDLE events[2]={GotInput,LearnThreadEvent};
do {
output(prompt);
ResetEvent(GotInput);
int res=WaitForMultipleObjects(2,events,FALSE,INFINITE);
if(res==(WAIT_OBJECT_0+1))
{
DEBUG("LearnThread terminating\n");
AfxEndThread(0);
return;
}
len=in->GetWindowTextLength();
} while((!allowempty && len==0));
s[len]=0;
ent->EnableWindow(false);
in->GetWindowText(s,maxlen);
in->SetSel(0,-1);
in->ReplaceSel("");
in->SetLimitText(maxlen);
}
void Clearndlg::OnClose()
{
DEBUG("Killing LearnThread\n");
KillThread(&LearnThreadHandle,&LearnThreadEvent);
DEBUG("Closing GotInput event\n");
if(GotInput) { CloseHandle(GotInput); GotInput=NULL; }
DEBUG("Closing fout\n");
if(fout!=NULL) fclose(fout); fout=NULL;
DEBUG("Calling CDialog::OnClose()\n");
CDialog::OnClose();
}
void Clearndlg::OnEnter()
{
SetEvent(GotInput);
}
bool Clearndlg::GetGap(unsigned long &gap,
unsigned long &count,
unsigned long &repeat_gap,
unsigned long *repeat)
{
unsigned long data, average, signalcount;
int mode;
signalcount=average=mode=0;
while(drv->readdata(250*1000,LearnThreadEvent)!=0)
; /* wait for signals to stop coming for at least 0.25 sec */
for(;;)
{
data=drv->readdata(30*1000*1000,LearnThreadEvent);
if(data==0) return false;
if(signalcount>MAX_SIGNALS) return false;
if(is_space(data) && mode==0)
{
if(average==0)
{
if(data>100000) continue;
average=data;
}
else
{
if(data>10*average ||
(signalcount>10 && data>5*average))
{
count=signalcount;
signalcount=0;
gap=data;
mode=1;
continue;
}
average = (average*signalcount + data)/(signalcount+1);
}
}
/* found gap, getting repeat code */
if(mode==1)
{
if(signalcount<3) repeat[signalcount]=data&(PULSE_BIT-1);
else
{
if(data < (gap - gap*remote.eps/100))
{
/* if value is less than current gap,
then it's probably not a repeat gap */
DEBUG("repeat not detected, data=%d gap=%d\n",data,gap);
repeat[0]=repeat[1]=repeat[2]=0;
}
else
{
/* otherwise, we'll assume it is */
DEBUG("repeat detected, repeat_gap=%d\n",data);
repeat_gap=data;
}
break;
}
}
signalcount++;
}
return true;
}
void Clearndlg::DoGetGap(void)
{
output("Step One: Determine signal gap, signal length, and repeat codes.");
output("----------------------------------------------------------------"
"----------------------------------------------------------------");
output("");
output("You will be asked to press an arbitrary button a number of times.");
output("Please hold it in for at least one second each time, and wait at");
output("least one second between keypresses.");
output("");
output("If you want to manually enter a signal gap and signal length, you");
output("may do so now (ie, \"31000 52\"). Otherwise, just hit ENTER.");
/* First, read it until we get two results in a row that are pretty close. */
int fault=0;
unsigned long last_gap=0;
unsigned long last_count=0;
unsigned long last_repeat_gap=0;
unsigned long last_repeat[3]={0,0,0};
unsigned long gap, count, repeat_gap, repeat[3];
int i;
bool manualdata=false;
char s[1024];
input("Gap and length?",s,1024,true);
if(strlen(s)!=0 && sscanf(s,"%ld %ld",&gap,&count)==2) manualdata=true;
if(manualdata)
{
DEBUG("manual data entered, gap=%ld count=%ld\n",gap,count);
code.length=count;
remote.gap=gap;
remote.repeat_gap=0;
remote.prepeat=0;
remote.srepeat=0;
remote.ptrail=0;
fprint_comment(fout,&remote);
fprint_remote_head(fout,&remote);
fprint_remote_signal_head(fout,&remote);
return;
}
output("Press a button.");
bool match=false;
while(!match)
{
if(GetGap(gap,count,repeat_gap,repeat)==false)
{
DEBUG("GetGap failed\n");
output("Error reading signal; please try again.");
continue;
}
if(last_count==0)
{
for(i=0;i<3;i++) last_repeat[i]=repeat[i];
last_count=count;
last_gap=gap;
last_repeat_gap=repeat_gap;
output("Please wait a second and press it again.");
continue;
}
match=true;
/* match repeats */
if(repeat[0]==0 && last_repeat[0]!=0)
{
DEBUG("repeat[0] was zero but last_repeat[0] was %d\n",last_repeat[0]);
match=false;
}
else if(last_repeat[0]==0 && repeat[0]!=0)
{
DEBUG("last_repeat[0] was zero but repeat[0] was %d\n",repeat[0]);
match=false;
}
else {
for(i=0;i<3;i++)
if(!expect(&remote,last_repeat[i],repeat[i]))
{
DEBUG("repeat[%d]=%d doesn't match last_repeat[%d]=%d\n",
i,repeat[i],i,last_repeat[i]);
match=false;
}
}
/* match counts */
if(count!=last_count)
{
DEBUG("Mismatched count: count=%d, last_count=%d\n",count,last_count);
match=false;
}
/* match gaps */
if(!expect(&remote,last_gap,gap))
{
DEBUG("gaps don't match: last_gap=%d, gap=%d\n",last_gap,gap);
match=false;
}
/* match repeat gaps */
if(!expect(&remote,last_repeat_gap,repeat_gap))
{
DEBUG("repeat gaps don't match: last_repeat_gap=%d, repeat_gap=%d\n",
last_repeat_gap,repeat_gap);
match=false;
}
if(!match)
{
for(i=0;i<3;i++) last_repeat[i]=repeat[i];
last_count=count;
last_gap=gap;
last_repeat_gap=repeat_gap;
fault++;
if(fault>5)
{
MessageBox("Too many faults. Possible reasons:\n"
"1) This remote can't be automatically learned (sorry)\n"
"2) The system is too slow or bogged down to accurately record\n"
" times (try closing all other programs)","Error");
EndDialog2(IDCANCEL);
DEBUG("LearnThread terminating\n");
AfxEndThread(0);
return;
}
DEBUG("Did not get consistent signal\n");
output("Did not get a consistent signal; please try again.");
}
}
/* Now, refine the information for gap and repeat */
unsigned long avg_gap;
unsigned long avg_repeat_gap;
unsigned long avg_count;
unsigned long avg_repeat[3];
avg_count=count;
avg_gap=(gap+last_gap)/2;
avg_repeat_gap=(repeat_gap+last_repeat_gap)/2;
for(i=0;i<3;i++) avg_repeat[i]=(repeat[i]+last_repeat[i])/2;
int j=0;
output("Baseline initialized.");
while(j<10)
{
sprintf(s,"Please wait a second and press a button again (%d left)",10-j);
output(s);
if(GetGap(gap,count,repeat_gap,repeat)==false)
{
DEBUG("GetGap error\n");
output("Error reading signal; please try again.");
continue;
}
match=true;
/* match repeats */
if(repeat[0]==0 && avg_repeat[0]!=0)
{
DEBUG("repeat[0] was zero but avg_repeat[0] was %d\n",avg_repeat[0]);
match=false;
}
else if(avg_repeat[0]==0 && repeat[0]!=0)
{
DEBUG("avg_repeat[0] was zero but repeat[0] was %d\n",repeat[0]);
match=false;
}
else if(avg_repeat[0]!=0) {
for(i=0;i<3;i++)
if(!expect(&remote,avg_repeat[i],repeat[i]))
{
DEBUG("repeat[%d]=%d doesn't match avg_repeat[%d]=%d\n",
i,repeat[i],i,avg_repeat[i]);
match=false;
}
}
/* match counts */
if(count!=avg_count)
{
DEBUG("counts didn't match\n");
match=false;
}
/* match gaps */
if(!expect(&remote,avg_gap,gap))
{
DEBUG("gap was too far from old gap\n");
match=false;
}
/* match repeat gaps */
if(!expect(&remote,last_repeat_gap,repeat_gap))
{
DEBUG("repeat gaps was too far from old repeat gap\n");
match=false;
}
if(!match)
{
fault++;
if(fault>10)
{
MessageBox("Too many faults. Possible reasons:\n"
"1) This remote can't be automatically learned (sorry)\n"
"2) The system is too slow or bogged down to accurately record\n"
" times (try closing all other programs)\n"
"3) The detection got off to a bad start (try again)","Error");
EndDialog2(IDCANCEL);
DEBUG("LearnThread terminating\n");
AfxEndThread(0);
return;
}
output("Did not get a consistent signal.");
continue;
}
else
{
avg_gap=((avg_gap*(j+2)) + gap)/(j+3);
avg_repeat_gap=((avg_repeat_gap*(j+2)) + repeat_gap)/(j+3);
for(i=0;i<3;i++) avg_repeat[i]=((avg_repeat[i]*(j+2)) + repeat[i])/(j+3);
j++;
}
}
/* Save it so far */
code.length=avg_count;
remote.gap=avg_gap;
remote.repeat_gap=avg_repeat_gap;
remote.prepeat=avg_repeat[0];
remote.srepeat=avg_repeat[1];
remote.ptrail=avg_repeat[2];
fprint_comment(fout,&remote);
fprint_remote_head(fout,&remote);
fprint_remote_signal_head(fout,&remote);
}
bool Clearndlg::GetRawButton(unsigned long *signals, int &count, bool waitgap)
{
count=0;
unsigned long data;
while(count<MAX_SIGNALS)
{
data=drv->readdata(waitgap?(30*1000*1000):(5*remote.gap),LearnThreadEvent);
if(data==0) return false;
if(waitgap)
{
if(!is_space(data) || data<remote.gap-remote.gap*remote.eps/100)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -