{###########################################################################}

// Clock einzelnes Digit ausgeben
procedure ClockSerout(digit:byte);
begin
  ParamStr:= ByteToStr(digit);
  if digit<10 then
    mySerOut('0');
  endif;
  write(mySerOut, ParamStr);
end;

// gerätespezifischer Parser-Teil
procedure ParseGetParam;
var IntInOutFlag:boolean;
    myBranch:boolean;
    myByte:byte;
    myIndex:Byte;

begin
  if Labelseek and (not (SubCh in [1000..1099])) then
    return; // nichts machen, wenn Label gesucht wird
  endif;
  IntInOutFlag:= (SubCh>=2000);
  if IntInOutFlag then  // Out-Befehl
    SubCh:=SubCh-2000;
  endif;
  myIndex:=byte(SubCh mod 10);  // angespr. Register 0..9 errechnen aus SubCh-Rest
  case SubCh of
    0..63:
      FPGAreg:=byte(SubCh);
      SendFPGAreg;
      if (SubCh < 4) then
        FPGAsendLong:=ParamLongArray[SubCh];  // bei SPI-Lesen gesendeter Param retten
      endif;
      SendFPGA32;
      ParamLong:=FPGAreceiveLong;
      if IntInOutFlag then  // Out-Befehl
        AccA:=float(ParamLong);
      else
        WriteParamLongSer;
      endif;
      |
    64..71:
      FPGAreg:=byte(SubCh);
      SendFPGAreg;
      SendFPGA8;
      Parambyte:=FPGAreceivebyte;
      if IntInOutFlag then  // Out-Befehl
        AccA:=float(Parambyte);
      else
        WriteParamByteSer;
      endif;
      |
    73:
      SendFPGA8;
      Parambyte:=FPGAreceiveByte;
      WriteParamByteSer;
      |
    74:
      SendFPGA16;
      ParamInt:=integer(FPGAreceiveWord);
      WriteParamIntSer;
      |
    75:
      SendFPGA32;
      ParamLong:=FPGAreceiveLong;
      WriteParamLongSer;
      |
    80:
      ParamByte:=ord(Modify);
      WriteParamByteSer;
      |
    88:
      if hexmode then
        ParamByte:=1;
      else
        ParamByte:=0;
      endif;
      WriteParamByteSer;
      |
    89:
      ParamByte:=byte(IncRast);
      WriteParamByteSer;
      |
    90..96: // OPT
      GetRTC;
      ParamInt:=integer(RTCarray[myIndex]);
      WriteParamIntSer;
      |
    97: // Sync RTC, Stringausgabe
{$IFNDEF EXTDCF}
      GetExtRTC;
      SetRTC;
{$ENDIF}
      GetRTC;
      WriteChPrefix;
      ParamByte:=0;
{$IFDEF EXTDCF}
      ParamByte:=DCFfield;
{$ENDIF}
      ParamStr:= ByteToStr(ParamByte);
      write(mySerOut, ParamStr);
      mySerOut(' ');
      mySerOut('[');
      ClockSerout(Hour);
      mySerOut(':');
      ClockSerout(Minute);
      mySerOut(':');
      ClockSerout(Second);
      mySerOut(' ');
      ClockSerout(Day);
      mySerOut('.');
      ClockSerout(Month);
      mySerOut('.');
      ClockSerout(Year);
      mySerOut(']');
      SerCRLF;
      |
    128..131: // AutoInc-Register
      FPGAreg:=byte(SubCh);
      SendFPGAreg;
      SendFPGA32;
      ParamLong:=FPGAreceiveLong;
      WriteParamLongSer;
      |
    280:  // Auto-Increment-Registernummer im SPI
      ParamByte:=AutoIncReg;
      WriteParamByteSer;
      |
    281:  // Auto-Increment-Select, Ausgabe vor Dateitransfer
      ParamByte:=AutoIncSel;
      WriteParamByteSer;
      |
    282:  //  Auto-Increment-Registerbreite im SPI, Anzahl Bytes (1, 2 oder 4)
      ParamByte:=AutoIncWidth;
      WriteParamByteSer;
      |
    285:  //  Auto-Increment-Blockstart zum Speichern auf SD
      ParamLong:=AutoIncBlockStart;
      WriteParamLongSer;
      |
    286:  //  Auto-Increment-Blockende zum Speichern auf SD
      ParamLong:=AutoIncBlockEnd;
      WriteParamLongSer;
      |

    150..169: // OPT
      ParamInt:=OptionArray[myIndex];
      WriteParamIntSer;
      |
    170..173:
      ParamLong:=InitParamLongArray[SubCh-160];
      WriteParamLongSer;
      |
    180:
      WriteChPrefix;
      mySerOut('0');
      mySerOut(' ');
      mySerOut('[');
      write(mySerOut, EEinitFileName);
      mySerOut(']');
      SerCRLF;
      |
    181:
      WriteChPrefix;
      mySerOut('0');
      mySerOut(' ');
      mySerOut('[');
      write(mySerOut, EEDatFileName);
      mySerOut(']');
      SerCRLF;
      |
    270: // letzter PUT/GET-Kanal
      ParamInt:=integer(TransferCh);
      WriteParamIntSer;
      |
    271: // letzter PUT/GET-Subkanal
      ParamInt:=TransferSubCh;
      WriteParamIntSer;
      |
    290: // Nächsten Stunden-Tick abwarten
      tickHours:=false;
      repeat
        mdelay(100);
      until tickHours or ButtonPressed;
      |
    291: // Nächsten Minuten-Tick abwarten
      tickMinutes:=false;
      repeat
        mdelay(100);
      until tickMinutes or ButtonPressed;
      |
    292: // Nächsten Sekunden-Tick abwarten
      tickSeconds:=false;
      repeat
        mdelay(10);
      until tickSeconds or ButtonPressed;
      |
    299: // letzter Pausenwert
      ParamInt:=integer(Pause);
      WriteParamIntSer;
      |
    300..309: // REG, ACA, ACB
      Param:=RegisterArray[myIndex];
      WriteParamSer;
      |
    320..329: // DEC
      Param:=RegisterArray[myIndex]-1;
      RegisterArray[myIndex]:=Param;
      CompareParam:=Param;
      |
    330..339: // INC
      Param:=RegisterArray[myIndex]+1;
      RegisterArray[myIndex]:=Param;
      CompareParam:=Param;
      |
    340..349: // CMP
      CompareParam:=RegisterArray[myIndex];
      |
    400..409: // GET, Wert anfordern und warten
      WriteTransferChPrefix;
      mySerOut('?');
      SerCRLF;
      GetWaitFlag:=true;
      DestinationRegister:=byte(myIndex);
      |
    500..509: // PUT
      Param:=RegisterArray[myIndex];
      WriteTransferParamSer;
      |
    350..359: // XCH ohne Parameter, deshalb hier!
      Param:=RegisterArray[myIndex];
      RegisterArray[myIndex]:=AccA;
      AccA:=Param;
      |
    600..609: // MUL ohne Parameter, deshalb hier!
      Param:=AccA;
      AccA:=Param*RegisterArray[myIndex];
      |
    610..619: // DIV ohne Parameter, deshalb hier!
      Param:=AccA;
      AccA:=Param/RegisterArray[myIndex];
      |
    620..629: // ADD ohne Parameter, deshalb hier!
      Param:=AccA;
      AccA:=Param+RegisterArray[myIndex];
      |
    630..639: // SUB ohne Parameter, deshalb hier!
      Param:=AccA;
      AccA:=Param-RegisterArray[myIndex];
      |
    640..649: // SQR ohne Parameter, deshalb hier!
      Param:=RegisterArray[myIndex];
      RegisterArray[myIndex]:=sqrt(Param); // square root
      |
    650..659: // SQU ohne Parameter, deshalb hier!
      Param:=RegisterArray[myIndex];
      RegisterArray[myIndex]:=sqr(Param); // square root
      |
    660..669: // NEG ohne Parameter, deshalb hier!
      Param:=RegisterArray[myIndex];
      RegisterArray[myIndex]:=negate(Param); // square root
      |
    1000..1099: // LBL X, Label setzen, auch "if LabelSeek" oben beachten!
      if INITfileIsOpen then
        myByte:=byte(SubCh mod 100) and 31;
        if (CurrentGotoLabel=myByte) then // Label gefunden
          LabelSeek:=false;
        endif;
        LabelArray[myByte]:=word(F16_FilePos(InitFile)); // aktuelle Position
        LabelValidArray[myByte]:=true;             // gültiges Label
      endif;
      |
    1100..1699: // Goto/Branch für Script-Verarbeitung, SubCh = Label-Nummer
      if INITfileIsOpen then
        CurrentGotoLabel:=byte(SubCh mod 100) and 31;
        myBranch:=false;
        case SubCh of
        1100..1199:  // BRA, GTO
          myBranch:=true;
          |
        1200..1299:  // BRG
          if CompareParam > 0 then
            myBranch:=true;
          endif;
          |
        1300..1399:  // BGE
          if CompareParam >= 0 then
            myBranch:=true;
          endif;
          |
        1400..1499:  // BEQ
          if CompareParam = 0 then
            myBranch:=true;
          endif;
          |
        1500..1599:  // BLE
          if CompareParam <= 0 then
            myBranch:=true;
          endif;
          |
        1600..1699:  // BLE
          if CompareParam < 0 then
            myBranch:=true;
          endif;
          |
        endcase;
        if not LabelValidArray[CurrentGotoLabel] then // noch leer, also vorwärts
          LabelSeek:=myBranch; // aber nur, wenn Sprung
        else
          if myBranch then
            F16_FileSeek(InitFile,longword(LabelArray[CurrentGotoLabel])); // Label aufsuchen
          endif;
        endif;
      endif;
      |
    240:
      WriteDirEntry;
      |
    241:
      ClearDirectory;
      GetDirectory;
      FileNumTemp:=FileNum;
      if FileAnzahl>0 then
        for FileNum:= 0 to FileAnzahl-1 do
          WriteDirEntry;
        endfor;
      else
        FileNum:= 0;
        WriteDirEntry;
      endif;
      FileNum:=FileNumTemp;
      |
    242:
      ParamByte:=FileAnzahl;
      WriteParamByteSer;
      |
    243: // DatFileName
      WriteChPrefix;
      write(mySerOut,'0 ['+DatFileName+']');
      SerCRLF;
      |
    251: // Fehlerzähler auslesen
      ParamInt:=Errcount;
      WriteParamIntSer;
      |
    252: // Serielle Baudrate
      ParamByte:=EESerBaudReg;
      WriteParamByteSer;
      |
    253: // SerTest, gibt Input-String komplett und unverändert wieder aus
      write(mySerOut, SerInpStr);
      SerCRLF;
      |
    254: // Version
      WriteChPrefix;
      write(mySerOut,Vers1Str);
      SerCRLF;
      |
    250,255: // Status
      serprompt(NoErr);
      |
    890:
      XModemRx;
      WriteParamLongSer;
      |
    990:
      ParamByte:=CoreRxSubCh;
      WriteParamByteSer;
      |
    991:
      ParamByte:=CoreTxSubCh;
      WriteParamByteSer;
      |
    992:
      if MainChInternFlag then
        ParamByte:=1; // an OptoBus
      else
        ParamByte:=0;  // an FPGA
      endif;
      WriteParamByteSer;
      |
  else
    serprompt(ParamErr);
  endcase;
end;


procedure ParseSetParam;
var myByte:byte;
    myIndex:Byte;
    myBranch:boolean;

begin
  if Labelseek then
    return; // nichts machen, wenn Label gesucht wird
  endif;
  ChangedFlag:=true;
  if SubCh>=2000 then  // RIO-Befehl
    Param:=RegisterArray[Parambyte];
    SubCh:=SubCh-2000;
    ParamLong:=LongInt(Param);
    ParamInt:=integer(ParamLong);
    ParamByte:=byte(ParamInt);
  endif;
  myIndex:=byte(SubCh mod 10);  // angespr. Register 0..9 errechnen aus SubCh-Rest
  case SubCh of
    0..63:
      if (SubCh < 4) then
        ParamLongArray[SubCh]:=ParamLong;
      endif;
      FPGAreg:=byte(SubCh);
      SendFPGAreg;
      FPGAsendLong:=ParamLong;
      SendFPGA32;
      |
    64..71: // Einzelbyte-Register, per Default COM LabTerm
      FPGAreg:=byte(SubCh);
      SendFPGAreg;
      FPGAsendbyte:=Parambyte;
      SendFPGA8;
      |
    79:
      F_Aux:=(Parambyte>0); //
      |
    80: // LCD Anzeige-Wert
      Modify:=tModify(ParamByte);
      |
    88: //Hex-Mode
      hexmode:= (ParamByte<>0);
      if EEunLocked then
        InitHexMode:=Hexmode;
      endif;
      |
    89: // Inkrementalgeber Impulse pro Rastung
      if EEunLocked then
        IncRast:=ParamInt;
        InitIncRast:=IncRast;
      else
        serprompt(LockedErr);
        return;
      endif;
      |
    90..96: // CLK-Funktionen
      GetRTC;
      RTCarray[myIndex]:=ParamByte;
      SetRTC;
{$IFDEF EXTRTC}
      SetExtRTC;
{$ENDIF}
      |
    128..131:  // Default-Auto-Increment-Register
      FPGAreg:=byte(SubCh);
      SendFPGAreg;
      FPGAsendLong:=ParamLong;
      SendFPGA32;
      |
    150..169:
      if EEunLocked then
        OptionArray[myIndex]:=ParamInt;
        mdelay(3);
        InitVars;
        Param:=0;
        DispReg:=Param;
        ParamToStr;
        // ParamStr2LED;
      else
        serprompt(LockedErr);
        return;
      endif;
      |
    170..173:
      if EEunLocked then
        InitParamLongArray[SubCh-160]:=ParamLong;
        ParamLongArray[SubCh-160]:=ParamLong;
      endif;
      |
    180:
      if EEunLocked then
        if ParamAlpha then
          EEInitFileName:=uppercase(ParamStr);
        else
          serprompt(ParamErr);
          return;
        endif;
      endif;
      |
    181:
      if EEunLocked then
        if ParamAlpha then
          EEdatFileName:=uppercase(ParamStr);
        else
          serprompt(ParamErr);
          return;
        endif;
      endif;
      |
    270: // GET-Kanal
      TransferCh:=ParamByte;
      |
    271: // GET-Subkanal
      TransferSubCh:=ParamInt;
      |
    299: //Pause für Script-Verarbeitung, Wert in ms
      Pause:=word(ParamInt);
      if Pause>0 then
        mdelay(Pause);
      endif;
      |
    300..309: // REG, LDA, LDB
      RegisterArray[myIndex]:=Param;
      if subCh=309 then  // DispReg, gleich auf Anzeige bringen
        ParamToStr;
        // ParamStr2LED;
      endif;
      |
    310..319: // MOV
      Param:=RegisterArray[ParamByte];
      RegisterArray[myIndex]:=Param;
      if subCh=319 then  // DispReg, gleich auf Anzeige bringen
        ParamToStr;
        // ParamStr2LED;
      endif;
      |
    350..359: // XCH mit Parameter, zwei beliebige Register tauschen
      if ParamByte in [0..9] then
        Param:=RegisterArray[ParamByte];
        RegisterArray[ParamByte]:= RegisterArray[myIndex];
        RegisterArray[myIndex]:=Param;
      endif;
      |
    500: // PUT
      Param:=RegisterArray[ParamByte];
      WriteTransferParamSer;
      |

    784: // Parameter-Stellen
      digits:=ParamByte;
      |
    785: // Parameter-Nachkommas
      nachkomma:=ParamByte;
      |
    800..880:  // Teletype File auf OptoBus oder SPI-Register
      myBranch:=(SubCh<880); // auf SPI-Register wenn true
      myIndex:=byte(SubCh-800);
      if ParamAlpha then
        DataFileType(uppercase(ParamStr),myBranch,myIndex);
      else
        FileNum:=ParamByte;
        DataFileType(DirectoryArray[FileNum],myBranch,myIndex);
      endif;
      if FaultFlags<>0 then
        serprompt(FileErr);
        return;
      endif;
      |
    881:  // Text Save (append) to File von OptoBus oder SPI-Register-IRQ
      if ParamAlpha then
        DataFileReceive(uppercase(ParamStr));
      else
        FileNum:=ParamByte;
        DataFileReceive(DirectoryArray[FileNum]);
      endif;
      if FaultFlags<>0 then
        serprompt(FileErr);
        return;
      endif;
      |
    900..979: // String an SPI-Register
      if ParamAlpha then
        myByte:=CoreTxSubCh;
        CoreTxSubCh:=byte(SubCh-900);
        MainChInternFlag:=true;  // String an FPGA SPI-Register
        write(fpgaSerOut,ParamStr);
        SerCRLF;
        CoreTxSubCh:=myByte;
      else
        serprompt(ParamErr);
        return;
      endif;
      |
    980: // String senden
      if ParamAlpha then
        write(serout,ParamStr);
        serOut(#$0D);
        serOut(#$0A);
      else
        serprompt(ParamErr);
        return;
      endif;
      |
    990:
      CoreRxSubCh:=ParamByte;
      |
    991:
      CoreTxSubCh:=ParamByte;
      |
    992:
      if ParamByte=0 then
        MainChInternFlag:=false; // an OptoBus
      else
        MainChInternFlag:=true;  // an FPGA
      endif;
      |
    220..229: // RWR FileWrite Registerwert in DataFile
      DataWrite(ParamByte,true);
      |
    230..239: // VWR FileWrite Parameter in DataFile
      DataWrite(myIndex,false);
      |
    240:  // CFG=
      if ParamAlpha then
        FileLoad(uppercase(ParamStr));
      else
        FileNum:=ParamByte;
        FileLoad(DirectoryArray[FileNum]);
      endif;
      if FaultFlags<>0 then
        serprompt(FileErr);
        return;
      endif;
      |
    243:  // DatFileName, FNA=
      if ParamAlpha then
        DatFileName:=uppercase(ParamStr);
      else
        FileNum:=ParamByte;
        DatFileName:=DirectoryArray[FileNum];
      endif;
      if FaultFlags<>0 then
        serprompt(FileErr);
        return;
      endif;
      |
    244:  // Delete, FDL=
      if ParamAlpha then
        SerInpStr:=uppercase(ParamStr);
      else
        FileNum:=ParamByte;
        SerInpStr:=DirectoryArray[FileNum];
      endif;
      if CardOK then
        if not F16_FileDelete ('\', SerInpStr) then
          ReadErr:=true;
          WriteErr:=true;
          serprompt(FileErr);
          return;
        endif;
      else
        serprompt(FileErr);
        return;
      endif;
      |
    249:  // FileExists
      if ParamAlpha then
        SerInpStr:=uppercase(ParamStr);
      else
        FileNum:=ParamByte;
        SerInpStr:=DirectoryArray[FileNum];
      endif;
      if CardOK and F16_FileExist ('\', SerInpStr, faFilesOnly) then
        FaultFlags:=0;
        serprompt(noErr);
        return;
      else
        ReadErr:=true;
        serprompt(FileErr);
        return;
      endif;
      |
    251: //Error-Count
      ErrCount:=ParamInt;
      |
    252: // Serielle Baudrate, erst beim nächsten Reset aktiv
      if EEunLocked then
        EESerBaudReg:=ParamByte;
      else
        serprompt(LockedErr);
        return;
      endif;
      |
    253: // SerTest, gibt Input-String komplett und unverändert wieder aus
      write(mySerOut, SerInpStr);
      SerCRLF;
      return;
      |
    250: // EEPROM Write Enable
      |
    280: //AutoIncrement-Register für DAT-Files
      AutoIncReg:= ParamByte;
      |
    281: //AutoIncrement-Select (AUX-Select auf SubCh <AutoIncReg> für DAT-Files
      AutoIncSel:= ParamByte;
      |
    282:  //  Auto-Increment-Registerbreite im SPI, Anzahl Bytes (1, 2 oder 4)
      AutoIncWidth:=ParamByte;
      |
    283:  // BLD   AutoInc Block Load
      if ParamAlpha then
        DATLoad(uppercase(ParamStr));
      else
        FileNum:=ParamByte;
        DATLoad(DirectoryArray[FileNum]);
      endif;
      if FaultFlags<>0 then
        serprompt(FileErr);
        return;
      endif;
      |
    284:  // BSV   AutoInc Block Save
      if ParamAlpha then
        DATsave(uppercase(ParamStr));
      else
        FileNum:=ParamByte;
        DATsave(DirectoryArray[FileNum]);
      endif;
      if FaultFlags<>0 then
        serprompt(FileErr);
        return;
      endif;
      |
    285:  //  Auto-Increment-Blockstart zum Speichern auf SD
      AutoIncBlockStart:=ParamLong;
      |
    286:  //  Auto-Increment-Blockende zum Speichern auf SD
      AutoIncBlockEnd:=ParamLong;
      |
   else
    serprompt(ParamErr);
    return;
  endcase;
  EEunLocked:=false;
  if SubCh=250 then  // EEPROM Write Enable
    EEunLocked:=true;
  endif;
  if CheckLimits then
    serprompt(ParamErr);
  else
    if verbose then
      serprompt(NoErr);
    else
      serinpCoreACK;           // angenommen, kann weitergehen
    endif;
  endif;
end;

{###########################################################################}
// Neuer Alpha-Parser, nimmt in ParamStr auch Strings nach "=" entgegen

{$IFDEF PARSERESULT}        // Results entgegennehmen
procedure ParseTransferParam;
begin
  if SubCh=TransferSubCh then
    if DestinationRegister in [0..9] then
      RegisterArray[destinationRegister]:=Param;
      if DestinationRegister=9 then  // gleich auf Anzeige bringen
        ParamToStr;
        // ParamStr2LED;
      endif;
    endif;
    GetWaitFlag:=false; // angefordertes Ergebnis eingetroffen
    SerInpStr:='';
  endif;
end;
{$ENDIF}

// allgemeiner Parser-Teil

function Cmd2Index : byte;
// Umsetzen eines Text-Befehls in Index-Eintrag der Befehlstabelle
var myCmdIndex: byte;
begin
  ParamStr:= uppercase(ParamStr);
  for myCmdIndex := 0 to CmdAnzahl do
    if ParamStr = CmdStrArr[ord(myCmdIndex)] then
      return(myCmdIndex);
    endif;
  endfor;
  return(cmderr);
end;

function ParseExtract(nachGleich:boolean):boolean;
//extrahiert ParamStr oder CmdStr aus SerInpStr,
//liefert true, wenn Parameter, sonst false, wenn Command
//akzeptiert auch alphanumerische Parameter als String nach "="
var myChar: char; myBool:boolean;
begin
  ParamStr:='';
  ParamAlpha:=false;
  myBool:=false;
  while SerInpStr[SerInpPtr] =' ' do // Leerzeichen überspringen
    inc(serInpPtr);
  endwhile;
  if SerInpStr[SerInpPtr] in ['*'..'9'] then // Zahlen oder Wildcard, es wird ein Parameter
    myBool:=true;
    for i:=SerInpPtr to length(SerInpStr) do
      mychar:=SerInpStr[i];
      if myChar in ['*'..'9'] then
        append(mychar,ParamStr);
      else // Buchstabe oder sonstirgendwas, abbrechen
        SerInpPtr:=i;
        return(mybool);
      endif;
    endfor;
  else
    for i:=SerInpPtr to length(SerInpStr) do
      mychar:=SerInpStr[i];
      if mychar='"' then
        ParamAlpha:=true;
      else
        if (mychar>='A') or ParamAlpha then
          if (myChar in ['!','?','$']) then
            SerInpPtr:=i;
            return(mybool);
          else
            append(mychar,ParamStr);
          endif;
          if nachGleich then
            ParamAlpha:=true;
          endif;
        else // Ziffer oder sonstirgendwas, abbrechen
          SerInpPtr:=i;
          return(mybool);
        endif;
      endif;
    endfor;
  endif;
  return(mybool);
end;

procedure ParamStr2Param;
var DecPointPos:byte;
begin
  Param:=StrToFloat(ParamStr);
// 32-Bit-Werte passen nicht in ein Float, deshalb getrennt wandeln
  DecPointPos:= pos('.',ParamStr);
// vor Dezimalpunkt abschneiden
  if DecPointPos>0 then
    SetLength (ParamStr,DecPointPos-1);
  endif;
  ParamLong:=StrToInt(ParamStr);
  ParamInt:=integer(ParamLong);
  ParamByte:=byte(ParamInt);
end;


procedure ParseSubCh;
//Überprüfen, ob Befehl oder Daten eingegangen und für uns, Parser-Vorbehandlung,
//Achtung: Erweitert um ParseResult für Anzeige-Auswertung, KEIN REFERENZ-PARSER!

var
  GleichPos,
  CheckSpos, myCheckSum,CheckSumIn:byte;
  SubChOffset:integer;

  myChar:char;
  hasMainCh, hasCRC, isResult, isOmni, isRequest: Boolean;

begin
  if SerInpStr='' then
    serprompt(NoErr);
    return;
  endif;
  hasMainCh:=(pos(':',SerInpStr)>0); // Kanaltrenner-':'
  gleichPos:=pos('=',SerInpStr); // Set-'='
  isRequest:=(GleichPos=0); // Abfrage
  myChar:=SerInpStr[1];
  isOmni:=(myChar='*');    // Omni-Flag
  isResult:=(myChar='#');  // Ergebnis-'#'
  SerInpPtr:=1;
  if isResult then
    SerInpPtr:=2;
  endif;
  if hasMainCh then
    ParseExtract(false);
    inc(SerInpPtr);
    if isOmni then // Omni-Befehl
      WriteSerInp; // weiterleiten
    else
      CurrentCh:=StrToInt(ParamStr);
    endif;
  endif;
  if CurrentCh=9 then // interne Anfrage vom FPGA-Core
    isOmni:=true;  // weitere Verarbeitung erzwingen
  endif;
  if isResult and (CurrentCh=TransferCh) then
    if not INITfileIsOpen then
      WriteSerInp;
    endif;
    ParseResult:=true;
  else
    if (not isOmni) and (CurrentCh<>MainCh) and hasMainCh then // nicht für uns
      WriteSerInp;
      return;
    endif;
  endif;

// Befehl/Parameter ist für uns, ab hier eigentliche Behandlung
// Wenn vorhanden, XOR-Prüfsumme checken, Präfix-"$" zählt nicht mit!
  verbose:=(pos('!',SerInpStr)>0) OR (pos('?',SerInpStr)>0); // Ausführliche Antwort erwünscht
  CheckSpos:=pos('$',SerInpStr);
  hasCRC:=CheckSpos>0; // CheckSumIn-'$'

  if hasCRC then
    ParamStr:=copy(SerInpStr,CheckSpos+1, 2);
    CheckSumIn:=HexToInt(ParamStr); // erhaltene XOR-Checksumme
    myCheckSum:=0;
    for i:= 1 to CheckSpos-1 do
      myChar:=SerInpStr[i];
      myCheckSum:=myCheckSum xor ord(myChar);
    endfor;
    if myCheckSum <> CheckSumIn then
      serprompt(CheckSumErr);
      return;
    endif;
  endif;
//  SerInpStr:=trim(SerInpStr);

//Parse einzelnen Befehl
  if ParseExtract(false) then
    SubChOffset:=0; // direkter SubCh-Aufruf
  else
    CmdWhich:=Cmd2Index; // Klartext übersetzen
    if CmdWhich = cmderr then
      serprompt(SyntaxErr);
      return;
    endif;
    SubChOffset:=Cmd2SubChArr[ord(CmdWhich)];
    ParseExtract(false); // SubCh-Parameter holen
  endif;
  SubCh:=StrToInt(ParamStr)+SubChOffset; //auf neuen SubCh umrechnen
{$IFDEF PARSERESULT}        // Results entgegennehmen
  if ParseResult then
    if not isRequest then
      SerInpPtr:=gleichPos+1; // Set-'='
      ParseExtract(true);
      ParamStr2Param;
      ParseTransferParam;
    endif;
  else
{$ENDIF}
    if isRequest then
      ParseGetParam;
    else
      SerInpPtr:=gleichPos+1; // Set-'='
      if ParseExtract(true) then
        ParamStr2Param;
      else
        Param:=0;             // evt. auch Alpha-Parameter
        ParamLong:=0;
        ParamInt:=0;
        ParamByte:=0;
      endif;
      ParseSetParam;
    endif;
{$IFDEF PARSERESULT}        // Results entgegennehmen
  endif;
  ParseResult:=false;
{$ENDIF}
end;

