summaryrefslogtreecommitdiff
path: root/irdecoderunit.pas
diff options
context:
space:
mode:
Diffstat (limited to 'irdecoderunit.pas')
-rw-r--r--irdecoderunit.pas365
1 files changed, 288 insertions, 77 deletions
diff --git a/irdecoderunit.pas b/irdecoderunit.pas
index 9114421..06b7c28 100644
--- a/irdecoderunit.pas
+++ b/irdecoderunit.pas
@@ -21,11 +21,14 @@ type
ersterEmpf,
letzterEmpf: boolean;
eingabePuffer: array of longword;
- eingabeLaenge: longword;
+ eingabeLaenge,
+ zustand: longword;
_watte: boolean;
procedure init;
procedure tastenDruckAnhaengen(lw: longword);
procedure befehlAusfuehren(cmd,params: string);
+ function findeZeichen(lw: longword): longword;
+ function findeBefehl(lw: longword): longword;
public
constructor create(inputName: string); overload;
constructor create(inputName, konfigName: string); overload;
@@ -38,14 +41,24 @@ type
end;
tBefehl = record
+ nummer,altZustand, // Index des gesendeten Zeichens in zeichenTabelle, sowie alter
+ neuZustand: longword; // und neuer Zustand
einzelKlick, // gedrückt gehaltene Taste = Befehl mehrmals?
kollapsTrenner: boolean; // Darf über diesen Befehl hinweg kollabiert werden?
cmd,params: string; // Befehl + Parameter
kollapsArt: tKollapsArt; // Wie kollabiert dieser Befehl?
end;
+procedure befehleKonfLesen(konfigName: string);
+procedure sortiereZeichenTabelle(von,bis: longword);
+procedure sortiereBefehlsTabelle(von,bis: longword);
+function befehlsVergleich(b1,b2: longword): integer; inline; overload;
+function befehlsVergleich(b1,b2Num,b2Zus: longword): integer; inline; overload;
+
implementation
+uses math;
+
var
zeichenTabelle: array of longword;
befehlsTabelle: array of tBefehl;
@@ -68,54 +81,12 @@ begin
end;
constructor tIRDecoder.create(inputName, konfigName: string; watte: boolean);
-var
- konfigDatei: tMyStringList;
- zeile,taste: string;
begin
inherited create;
if (length(zeichenTabelle)=0) or (length(befehlsTabelle)=0) then begin
- konfigDatei:=tMyStringList.create;
- konfigDatei.loadFromFile(konfigName);
- if not konfigDatei.unfoldMacros then
- raise exception.create('Fehler beim Entfalten der Makros in '''+konfigName+'''!');
- while konfigDatei.readln(zeile) do begin
- setlength(zeichenTabelle,length(zeichenTabelle)+1);
- setlength(befehlsTabelle,length(befehlsTabelle)+1);
- if copy(zeile,length(zeile),1)<>':' then
- raise exception.create('Die erste Zeile einer Befehlsdefinition muss mit einem : enden, '''+zeile+''' tut das nicht!');
- delete(zeile,length(zeile),1);
- taste:=trim(zeile);
- zeichenTabelle[length(zeichenTabelle)-1]:=strtoint(taste);
- if not konfigDatei.readln(zeile) then
- raise exception.create('Unerwartetes Dateiende in '''+konfigName+''' (Taste '+taste+')!');
- befehlsTabelle[length(befehlsTabelle)-1].einzelKlick:=not startetMit('!',zeile);
- if zeile<>'einzelKlick' then
- raise exception.create('Syntaxfehler: erste Option muss ''[!] einzelKlick'' sein (Taste '+taste+')!');
- if not konfigDatei.readln(zeile) then
- raise exception.create('Unerwartetes Dateiende in '''+konfigName+''' (Taste '+taste+')!');
- befehlsTabelle[length(befehlsTabelle)-1].kollapsTrenner:=not startetMit('!',zeile);
- if zeile<>'kollapsTrenner' then
- raise exception.create('Syntaxfehler: zweite Option muss ''[!] kollapsTrenner'' sein (Taste '+taste+')!');
- if not konfigDatei.readln(zeile) then
- raise exception.create('Unerwartetes Dateiende in '''+konfigName+''' (Taste '+taste+')!');
- if not startetMit('kollapsArt:',zeile) then
- raise exception.create('Syntaxfehler: dritte Option muss ''kollapsArt: ...'' sein, '''+zeile+''' ist das nicht (Taste '+taste+')!');
- if zeile='ignorieren' then
- befehlsTabelle[length(befehlsTabelle)-1].kollapsArt:=kaIgnorieren
- else if zeile='toggle' then
- befehlsTabelle[length(befehlsTabelle)-1].kollapsArt:=kaToggle
- else if zeile='addieren' then
- befehlsTabelle[length(befehlsTabelle)-1].kollapsArt:=kaAddieren
- else if zeile='nurEinMal' then
- befehlsTabelle[length(befehlsTabelle)-1].kollapsArt:=kaNurEinMal
- else
- raise exception.create('Unbekannte kollapsArt '''+zeile+''' (Taste '+taste+')!');
- if not konfigDatei.readln(zeile) then
- raise exception.create('Unerwartetes Dateiende in '''+konfigName+''' (Taste '+taste+')!');
- befehlsTabelle[length(befehlsTabelle)-1].cmd:=erstesArgument(zeile);
- befehlsTabelle[length(befehlsTabelle)-1].params:=zeile;
- end;
- konfigDatei.free;
+ setlength(zeichenTabelle,0);
+ setlength(befehlsTabelle,0);
+ befehleKonfLesen(konfigName);
end;
_watte:=watte;
@@ -137,6 +108,7 @@ begin
letztesZeichen[true]:=$ffffffff;
letzterEmpf:=false;
ersterEmpf:=false;
+ zustand:=0;
setlength(eingabePuffer,0);
eingabeLaenge:=0;
end;
@@ -144,7 +116,6 @@ end;
procedure tIRDecoder.tastenDruckAnhaengen(lw: longword);
var
empf: boolean;
- i: longword;
begin
empf:=odd(lw shr 1);
lw:=((lw shr 1) and not 1) or byte(odd(lw));
@@ -155,14 +126,7 @@ begin
if empf=ersterEmpf then begin
if eingabeLaenge>=length(eingabePuffer) then
setlength(eingabePuffer,eingabeLaenge+1024);
- eingabePuffer[eingabeLaenge]:=$ffffffff;
- for i:=0 to length(zeichenTabelle)-1 do
- if (lw and not $08)=zeichenTabelle[i] then begin
- eingabePuffer[eingabeLaenge]:=i;
- break;
- end;
- if eingabePuffer[eingabeLaenge]=$ffffffff then
- raise exception.create('Kann Tastencode '''+inttohex(lw,4)+''' nicht finden!');
+ eingabePuffer[eingabeLaenge]:=findeZeichen(lw and not $08);
inc(eingabeLaenge);
end;
@@ -187,6 +151,60 @@ begin
end;
end;
+function tIRDecoder.findeZeichen(lw: longword): longword;
+var
+ mi,ma: longword;
+begin
+ mi:=0;
+ ma:=length(zeichenTabelle)-1;
+ while mi<ma do begin
+ result:=(mi+ma) div 2;
+ if zeichenTabelle[result]<lw then begin
+ mi:=min(ma,result+1);
+ continue;
+ end;
+ if zeichenTabelle[result]>lw then begin
+ ma:=max(mi,result-1);
+ continue;
+ end;
+ mi:=result;
+ ma:=result;
+ break;
+ end;
+ if mi<>ma then
+ raise exception.create('Sanity-Check nicht bestanden: mi<>ma nach Bisektion!');
+ result:=mi;
+ if zeichenTabelle[result]<>lw then
+ raise exception.create('Kann Tastencode '''+inttohex(lw,4)+''' nicht finden!');
+end;
+
+function tIRDecoder.findeBefehl(lw: longword): longword;
+var
+ mi,ma: longword;
+begin
+ mi:=0;
+ ma:=length(befehlsTabelle)-1;
+ while mi<ma do begin
+ result:=(mi+ma+1) div 2;
+ if befehlsVergleich(result,lw,zustand)>0 then begin
+ ma:=max(mi,result-1);
+ continue;
+ end;
+ if befehlsVergleich(result,lw,zustand)<0 then begin
+ mi:=min(ma,result);
+ continue;
+ end;
+ mi:=result;
+ ma:=result;
+ break;
+ end;
+ if mi<>ma then
+ raise exception.create('Sanity-Check nicht bestanden: mi<>ma nach Bisektion!');
+ result:=mi;
+ if (befehlsTabelle[result].nummer<>lw) or (befehlsTabelle[result].altZustand>zustand) then
+ raise exception.create('Kann Befehl Nummer '''+inttohex(lw,4)+''' im Zustand '+inttostr(zustand)+' nicht finden!');
+end;
+
function tIRDecoder.zeileVerarbeitet: boolean;
var
s: string;
@@ -211,33 +229,39 @@ end;
function tIRDecoder.befehlVerarbeitet: boolean;
var
- i,cnt: longword;
+ i,cnt,bef,bef2: longword;
cmd,params,s,t: string;
begin
result:=eingabeLaenge>0;
if not result then exit;
- cmd:=befehlsTabelle[eingabePuffer[0]].cmd;
- params:=befehlsTabelle[eingabePuffer[0]].params;
+ bef:=findeBefehl(eingabePuffer[0]);
+
+ for i:=1 to eingabeLaenge-1 do
+ eingabePuffer[i-1]:=eingabePuffer[i];
+ dec(eingabeLaenge);
+
+ cmd:=befehlsTabelle[bef].cmd;
+ params:=befehlsTabelle[bef].params;
+ zustand:=befehlsTabelle[bef].neuZustand;
- if befehlsTabelle[eingabePuffer[0]].kollapsArt<>kaIgnorieren then begin
- cnt:=1;
+ if befehlsTabelle[bef].kollapsArt<>kaIgnorieren then begin
+ cnt:=0;
while cnt<eingabeLaenge do begin
- if (befehlsTabelle[eingabePuffer[0]].kollapsArt=befehlsTabelle[eingabePuffer[cnt]].kollapsArt) and
- (befehlsTabelle[eingabePuffer[0]].cmd=befehlsTabelle[eingabePuffer[cnt]].cmd) then begin
- case befehlsTabelle[eingabePuffer[0]].kollapsArt of
+ bef2:=findeBefehl(eingabePuffer[cnt]);
+ if (befehlsTabelle[bef].kollapsArt=befehlsTabelle[bef2].kollapsArt) and
+ (befehlsTabelle[bef].cmd=befehlsTabelle[bef2].cmd) then begin
+ for i:=1 to eingabeLaenge-1 do
+ eingabePuffer[i-1]:=eingabePuffer[i];
+ dec(eingabeLaenge,1);
+ case befehlsTabelle[bef].kollapsArt of
kaToggle: begin
- for i:=1 to cnt-1 do
- eingabePuffer[i-1]:=eingabePuffer[i];
- for i:=cnt+1 to eingabeLaenge-1 do
- eingabePuffer[i-2]:=eingabePuffer[i];
- dec(eingabeLaenge,2);
result:=befehlVerarbeitet;
exit;
end;
kaAddieren: begin
s:=params;
- t:=befehlsTabelle[eingabePuffer[cnt]].params;
+ t:=befehlsTabelle[bef2].params;
params:='';
while s<>'' do
params:=trim(params+' '+zusammenFassen(erstesArgument(s),erstesArgument(t)));
@@ -246,21 +270,16 @@ begin
else
raise exception.create('Weder Toggle, noch Addieren, noch NurEinMal, noch Ignorieren! Das ist komisch ...');
end{of case};
- for i:=cnt+1 to eingabeLaenge-1 do
- eingabePuffer[i-1]:=eingabePuffer[i];
- dec(eingabeLaenge);
continue;
end;
- if befehlsTabelle[eingabePuffer[cnt]].kollapsTrenner then
+ if befehlsTabelle[bef2].kollapsTrenner then
break;
inc(cnt);
end;
end;
- befehlAusfuehren(cmd,params);
- for i:=1 to eingabeLaenge-1 do
- eingabePuffer[i-1]:=eingabePuffer[i];
- dec(eingabeLaenge);
+ if cmd<>'nop' then
+ befehlAusfuehren(cmd,params);
end;
function tIRDecoder.gibAlleBefehle: string;
@@ -278,5 +297,197 @@ begin
end;
end;
+// allgemeine Funktionen *******************************************************
+
+procedure befehleKonfLesen(konfigName: string);
+var
+ konfigDatei: tMyStringList;
+ zeile,taste: string;
+ cStat: longword;
+begin
+ konfigDatei:=tMyStringList.create;
+ konfigDatei.loadFromFile(konfigName);
+ if not konfigDatei.unfoldMacros then
+ raise exception.create('Fehler beim Entfalten der Makros in '''+konfigName+'''!');
+ while konfigDatei.readln(zeile) do begin // Iteration über die Zeichen
+ setlength(zeichenTabelle,length(zeichenTabelle)+1);
+ if copy(zeile,length(zeile),1)<>':' then
+ raise exception.create('Die erste Zeile einer Befehlsdefinition muss mit einem : enden, '''+zeile+''' tut das nicht!');
+ delete(zeile,length(zeile),1);
+ taste:=trim(zeile);
+ zeichenTabelle[length(zeichenTabelle)-1]:=strtoint(taste);
+ cStat:=0;
+ repeat // Iteration über die Befehle pro Zeichen
+ if not konfigDatei.readln(zeile) then
+ raise exception.create('Unerwartetes Dateiende in '''+konfigName+''' (Taste '+taste+')!');
+ if zeile='Ende' then break;
+ if startetMit('Befehl:',zeile) then begin
+ setlength(befehlsTabelle,length(befehlsTabelle)+1);
+ befehlsTabelle[length(befehlsTabelle)-1].nummer:=length(zeichenTabelle)-1;
+ befehlsTabelle[length(befehlsTabelle)-1].altZustand:=cStat;
+ befehlsTabelle[length(befehlsTabelle)-1].neuZustand:=cStat;
+ inc(cStat);
+ befehlsTabelle[length(befehlsTabelle)-1].kollapsArt:=kaIgnorieren;
+ befehlsTabelle[length(befehlsTabelle)-1].einzelKlick:=true;
+ befehlsTabelle[length(befehlsTabelle)-1].kollapsTrenner:=false;
+ befehlsTabelle[length(befehlsTabelle)-1].cmd:=erstesArgument(zeile);
+ befehlsTabelle[length(befehlsTabelle)-1].params:=zeile;
+ continue;
+ end;
+ if startetMit('altZustand:',zeile) then begin
+ befehlsTabelle[length(befehlsTabelle)-1].altZustand:=strtoint(zeile);
+ continue;
+ end;
+ if startetMit('neuZustand:',zeile) then begin
+ befehlsTabelle[length(befehlsTabelle)-1].neuZustand:=strtoint(zeile);
+ continue;
+ end;
+ if startetMit('einzelKlick:',zeile) then begin
+ if zeile='ja' then befehlsTabelle[length(befehlsTabelle)-1].einzelKlick:=true
+ else if zeile='nein' then befehlsTabelle[length(befehlsTabelle)-1].einzelKlick:=false
+ else raise exception.create('''einzelKlick'' kann nur ''ja'' oder ''nein'' sein, nicht aber '''+zeile+'''!');
+ continue;
+ end;
+ if startetMit('kollapsTrenner:',zeile) then begin
+ if zeile='ja' then befehlsTabelle[length(befehlsTabelle)-1].kollapsTrenner:=true
+ else if zeile='nein' then befehlsTabelle[length(befehlsTabelle)-1].kollapsTrenner:=false
+ else raise exception.create('''kollapsTrenner'' kann nur ''ja'' oder ''nein'' sein, nicht aber '''+zeile+'''!');
+ continue;
+ end;
+ if startetMit('kollapsArt:',zeile) then begin
+ if zeile='ignorieren' then
+ befehlsTabelle[length(befehlsTabelle)-1].kollapsArt:=kaIgnorieren
+ else if zeile='toggle' then
+ befehlsTabelle[length(befehlsTabelle)-1].kollapsArt:=kaToggle
+ else if zeile='addieren' then
+ befehlsTabelle[length(befehlsTabelle)-1].kollapsArt:=kaAddieren
+ else if zeile='nurEinMal' then
+ befehlsTabelle[length(befehlsTabelle)-1].kollapsArt:=kaNurEinMal
+ else
+ raise exception.create('Unbekannte kollapsArt '''+zeile+''' (Taste '+taste+')!');
+ continue;
+ end;
+ raise exception.create('Verstehe Option '''+zeile+''' nicht in '''+konfigName+''' (Taste '+taste+')!');
+ until false;
+ end;
+ konfigDatei.free;
+ sortiereZeichenTabelle(0,length(zeichenTabelle)-1);
+ sortiereBefehlsTabelle(0,length(befehlsTabelle)-1);
+end;
+
+procedure sortiereZeichenTabelle(von,bis: longword);
+var
+ li,re,pv,i: longword;
+begin
+ if von>=bis then exit;
+ pv:=zeichenTabelle[von];
+ re:=pv;
+ for li:=von+1 to bis do begin
+ pv:=min(pv,zeichenTabelle[li]);
+ re:=max(re,zeichenTabelle[li]);
+ end;
+ pv:=(pv+re) div 2; // das Pivot-Element
+ li:=von;
+ re:=bis;
+ while li<=re do begin
+ while (li<bis) and (zeichenTabelle[li]<=pv) do
+ inc(li);
+ while (re>von) and (zeichenTabelle[re]>pv) do
+ dec(re);
+ if li>=re then break;
+ i:=zeichenTabelle[re];
+ zeichenTabelle[re]:=zeichenTabelle[li];
+ zeichenTabelle[li]:=i;
+ for i:=0 to length(befehlsTabelle)-1 do
+ if befehlsTabelle[i].nummer=li then
+ befehlsTabelle[i].nummer:=re
+ else if befehlsTabelle[i].nummer=re then
+ befehlsTabelle[i].nummer:=li;
+ inc(li);
+ dec(re);
+ end;
+ if li<>re+1 then
+ raise exception.create('Sanity-Check nicht bestanden: li<>re+1 kann beim Quicksort nicht sein!');
+ if re=bis then
+ raise exception.create('Rechter Rand hat sich nicht verbessert!');
+ if li=von then
+ raise exception.create('Linker Rand hat sich nicht verbessert!');
+ sortiereZeichenTabelle(von,re);
+ sortiereZeichenTabelle(li,bis);
+end;
+
+procedure sortiereBefehlsTabelle(von,bis: longword);
+var
+ mi,ma,li,re,pv,pvZ,i: longword;
+ tmp: tBefehl;
+begin
+ if von>=bis then exit;
+ mi:=von;
+ ma:=mi;
+ for i:=von+1 to bis do begin
+ if befehlsVergleich(mi,i)>0 then mi:=i;
+ if befehlsVergleich(ma,i)<0 then ma:=i;
+ end;
+ pv:=(befehlsTabelle[mi].nummer+befehlsTabelle[ma].nummer) div 2; // das
+ pvZ:=(befehlsTabelle[mi].altZustand+befehlsTabelle[ma].altZustand) div 2; // Pivot-Element
+
+ if befehlsVergleich(mi,pv,pvZ)<0 then begin
+ pv:=befehlsTabelle[mi].nummer;
+ pvZ:=befehlsTabelle[mi].altZustand;
+ end;
+
+ li:=von;
+ re:=bis;
+ while li<=re do begin
+ while (li<=bis) and
+ (befehlsVergleich(li,pv,pvZ)<=0) do
+ inc(li);
+ while (re>=von) and
+ (befehlsVergleich(re,pv,pvZ)>0) do
+ dec(re);
+ if li>=re then break;
+ move(befehlsTabelle[re],tmp,sizeOf(tBefehl));
+ move(befehlsTabelle[li],befehlsTabelle[re],sizeOf(tBefehl));
+ move(tmp,befehlsTabelle[li],sizeOf(tBefehl));
+ inc(li);
+ dec(re);
+ end;
+ fillchar(tmp,sizeof(tBefehl),#0);
+ if li<>re+1 then
+ raise exception.create('Sanity-Check nicht bestanden: li<>re+1 kann beim Quicksort nicht sein!');
+ if re=bis then
+ raise exception.create('Rechter Rand hat sich nicht verbessert!');
+ if li=von then
+ raise exception.create('Linker Rand hat sich nicht verbessert!');
+ sortiereBefehlsTabelle(von,re);
+ sortiereBefehlsTabelle(li,bis);
+end;
+
+function befehlsVergleich(b1,b2: longword): integer;
+begin
+ result:=befehlsVergleich(b1,befehlsTabelle[b2].nummer,befehlsTabelle[b2].altZustand);
+end;
+
+function befehlsVergleich(b1,b2Num,b2Zus: longword): integer;
+begin
+ if befehlsTabelle[b1].nummer<b2Num then begin
+ result:=-1;
+ exit;
+ end;
+ if befehlsTabelle[b1].nummer>b2Num then begin
+ result:=1;
+ exit;
+ end;
+ if befehlsTabelle[b1].altZustand<b2Zus then begin
+ result:=-1;
+ exit;
+ end;
+ if befehlsTabelle[b1].altZustand>b2Zus then begin
+ result:=1;
+ exit;
+ end;
+ result:=0;
+end;
+
end.