unit irdecoderunit; {$mode objfpc}{$H+} interface uses Classes, SysUtils, lesethreadunit, lowlevelunit, process, myStringListUnit; type tKollapsArt = ( kaIgnorieren, // kann nicht kollabieren kaToggle, // 2x Befehl = 0x Befehl kaAddieren, // Parameter sind zu addieren kaNurEinMal); // 2x Befehl = 1x Befehl tIRDecoder = class private ttySLeser: tLeseProzess; letztesZeichen: array[boolean] of longword; letzterEmpf: boolean; eingabePuffer: array of longword; eingabeLaenge, letzterBefehl: longword; _watte: boolean; procedure init; procedure tastenDruckAnhaengen(lw: longword); procedure befehlAusfuehren(lw: longword); public constructor create(inputName: string); overload; constructor create(inputName, konfigName: string); overload; constructor create(inputName: string; watte: boolean); overload; constructor create(inputName, konfigName: string; watte: boolean); overload; destructor destroy; override; function zeileVerarbeitet: boolean; function befehlVerarbeitet: boolean; function gibAlleBefehle: string; end; tBefehl = record 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; implementation var zeichenTabelle: array of longword; befehlsTabelle: array of tBefehl; // tIRDecoder ****************************************************************** constructor tIRDecoder.create(inputName: string); begin create(inputName,false); end; constructor tIRDecoder.create(inputName: string; watte: boolean); begin create(inputName,'/dev/null',watte); end; constructor tIRDecoder.create(inputName, konfigName: string); begin create(inputName,konfigName,false); 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; end; _watte:=watte; ttySLeser:=tLeseProzess.create(inputName,1); fillchar(eingabePuffer,sizeof(eingabePuffer),#0); init; end; destructor tIRDecoder.destroy; begin ttySLeser.free; inherited destroy; end; procedure tIRDecoder.init; begin letztesZeichen[false]:=$ffffffff; letztesZeichen[true]:=$ffffffff; letzterEmpf:=false; letzterBefehl:=$ffffffff; setlength(eingabePuffer,0); eingabeLaenge:=0; end; procedure tIRDecoder.tastenDruckAnhaengen(lw: longword); var empf: boolean; begin empf:=odd(lw shr 1); lw:=((lw shr 1) and not 1) or byte(odd(lw)); if (lw<>letztesZeichen[letzterEmpf]) or (empf=letzterEmpf) or empf then begin if eingabeLaenge>=length(eingabePuffer) then setlength(eingabePuffer,eingabeLaenge+1024); eingabePuffer[eingabeLaenge]:=lw; inc(eingabeLaenge); end; letztesZeichen[empf]:=lw; letzterEmpf:=empf; end; procedure tIRDecoder.befehlAusfuehren(lw: longword); var neu: boolean; bw: longword; output: string; p: tProcess; begin neu:=lw<>letzterBefehl; letzterBefehl:=lw; lw:=lw and not $08; for bw:=0 to length(befehlsTabelle)-1 do if zeichenTabelle[bw]=lw then begin if neu or not befehlsTabelle[bw].einzelKlick then begin if _watte then writeln(befehlsTabelle[bw].cmd+' '+befehlsTabelle[bw].params) else begin p:=tProcess.create(nil); p.executable:=befehlsTabelle[bw].cmd; output:=befehlsTabelle[bw].params; while output<>'' do p.parameters.add(erstesArgument(output)); p.options:=p.options + [poWaitOnExit]; p.execute; p.free; end; end; exit; end; writeln('roh: '+hexDump(@lw,sizeof(lw))); end; function tIRDecoder.zeileVerarbeitet: boolean; var s: string; inByte: longword; begin result:=ttySLeser.gibZeile(s); if not result then exit; if s='Ha!' then begin // Startzeichen writeln('Empfänger hat sich gemeldet!'); init; exit; end; if (length(s)=3) and base64Decode(s,inByte) then begin tastenDruckAnhaengen(inByte); exit; end; writeln('Warnung: Kenne Kommando '''+s+''' nicht - komisch formatiert!'); end; function tIRDecoder.befehlVerarbeitet: boolean; var i: longword; begin result:=eingabeLaenge>0; if not result then exit; befehlAusfuehren(eingabePuffer[0]); for i:=1 to eingabeLaenge-1 do eingabePuffer[i-1]:=eingabePuffer[i]; dec(eingabeLaenge); end; function tIRDecoder.gibAlleBefehle: string; var bw,lw: longword; b1,b2: boolean; begin result:=''; for bw:=0 to length(zeichenTabelle)-1 do begin lw:=zeichenTabelle[bw]; lw:=((lw and not 1) shl 1) or byte(odd(lw)); for b1:=false to true do for b2:=false to true do result:=result+base64Encode(lw or (byte(b1) shl 1) or (byte(b2) shl 4),3)+#10; end; end; end.