{
  CmdStrArr: array[0..19] of String[3] = (
  'STR', // 255
  'IDN', // 254
  'TRG', // 249
  'VAL', // 0..255
  'FRQ', // 0
  'LVL', // 1
  'LVP', // 2
  'DBU', // 3
  'WAV', // 4
  'BST', // 5
  'PWR', // 6
  'INL', // 10..13
  'DCO', // 20
  'DSP', // 80
  'MCH', // 199 // Moduladresse
  'SCL', // 200..213
  'WEN', // 250
  'ERC', // 251 = ErrCount seit letztem Reset
  'SBD', // 252 = SerBaud UBRR-Register mit U2X=1
  'NOP');   //2 Parameter
}
{###########################################################################}

procedure ParseGetParam;
begin
  nachkomma:=0;
  case SubCh of
    0:
      nachkomma:=1;
      Param:=float(Frequenz)/10.0;
      |
    1:
      nachkomma:=1;
      Param:=Level;
      |
    2:
      nachkomma:=1;
      Param:=Level*2.8284;
      |
    3:
      nachkomma:=2;
      Param:=db;
      |
    4:
      param:=float(wave);
      |
    5:
      param:=float(BurstMode);
      |
    6:
      param:=float(OutputMode);
      |
    10:
      GetInLevel;
      |
    11:
      GetInLevel;
      Param:=Param*2.8284;
      |
    12:
      GetInLevel;
      nachkomma:=2;
      Param:= Level2dB(Param+0.1);     // 774.59667 mV
      |
    13:  // Test-Parameter, immer 1000
      Param:=1000;
      nachkomma:=1;
      |
    199:
      param:=float(SlaveCh);
      |
    251: // Fehlerzähler auslesen
      Param:=float(Errcount);
      |
    252: // Serielle Baudrate
      Param:=float(EESerBaudReg);
      |
    253: // SerTest, gibt Input-String komplett und unverändert wieder aus
      write(Serout, SerInpStr);
      SerCRLF;
      return;
      |
    254: //Wert
      WriteChPrefix;
      write(serout,Vers1Str);
      SerCRLF;
      return;
      |
    250,255: //Status
      serprompt(NoErr,Status);
      return;
      |
  else
    serprompt(ParamErr,status);
    return;
  endcase;
  WriteChPrefix;
  WriteParam;
end;

procedure ParseSetParam;
begin
  if Busyflag then
    serprompt(BusyErr,0);
    return;
  endif;
  case SubCh of
    0:
      Frequenz:=longint(Param)*10;
      AktuelleFrequenz:=LongInt(Frequenz);
      |
    1:
      Level:=Param;
      db:=Level2db(Level);
      |
    2:
      Level:=Param/2.8284;
      db:=Level2db(Level);
      |
    3:
      db:=param;
      Level:=dB2Level(db);
      |
    4:
      wave:=ParamByte;
      |
    5:
      BurstMode:=ParamByte;
      |
    6:
      OutputMode:=ParamByte;
      |
    80:
      ShowFrequency;
      |
    199:
      if EEunLocked then
        SlaveCh:=ParamByte;
      else
        serprompt(LockedErr,0);
        return;
      endif;
      |
    250: // EEPROM Write Enable
      |
    251: //Error-Count
      ErrCount:=ParamInt;
      |
    252: // Serielle Baudrate, erst beim nächsten Reset aktiv
      if EEunLocked then
        EESerBaudReg:=ParamByte;
      else
        serprompt(LockedErr,0);
        return;
      endif;
      |
   else
    serprompt(ParamErr,Status);
    return;
  endcase;
  EEunLocked:=false;
  if SubCh=250 then  // EEPROM Write Enable
    EEunLocked:=true;
  endif;
  SetLevelDDS;
  serprompt(NoErr,Status);
end;

// allgemeiner Parser-Teil

function Cmd2Index : tCmdWhich;
// Umsetzen eines Text-Befehls in Index-Eintrag der Befehlstabelle
var myCmdIndex: tCmdWhich;
begin
  ParamStr:= uppercase(ParamStr);
  for myCmdIndex := tError(0) to nop do
    if ParamStr = CmdStrArr[ord(myCmdIndex)] then
      return(myCmdIndex);
    endif;
  endfor;
  return(err);
end;

function ParseExtract:boolean;
//extrahiert ParamStr oder CmdStr aus SerInpStr,
//liefert true, wenn Parameter, sonst false, wenn Command
var myChar: char; myBool:boolean;
begin
  ParamStr:='';
  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 <='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 >= 'A' then
        append(mychar,ParamStr);
      else // Ziffer oder sonstirgendwas, abbrechen
        SerInpPtr:=i;
        return(mybool);
      endif;
    endfor;
  endif;
  return(mybool);
end;

procedure ParseSubCh;
//Überprüfen, ob Befehl oder Daten eingegangen und für uns, Parser-Vorbehandlung,
//wenn Busy => BusyErr
var
  GleichPos,
  CheckSpos, myCheckSum,CheckSumIn:byte;
  SubChOffset:byte;

  myChar:char;
  hasMainCh, hasCRC, isResult, isOmni, isRequest, isParam: Boolean;

begin
  if SerInpStr='' then
    serprompt(NoErr,0);
    return;
  endif;
  hasMainCh:=(pos(':',SerInpStr)>0); // Kanaltrenner-':'
  isRequest:=not (pos('=',SerInpStr)>0); // Abfrage
  myChar:=SerInpStr[1];
  isOmni:=(myChar='*');    // Omni-Flag
  isResult:=(myChar='#');  // Ergebnis-'#'
  if isResult then
    WriteSerInp;
    return;
  endif;
  SerInpPtr:=1;
  if hasMainCh then
    isParam:=ParseExtract;
    inc(SerInpPtr);
    if isOmni then // Omni-Befehl
      WriteSerInp; // weiterleiten
    else
      CurrentCh:=StrToInt(ParamStr);
    endif;
  endif;
  if (not isOmni) and (CurrentCh<>SlaveCh) then // nicht für uns
    WriteSerInp;
    return;
  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,0);
      return;
    endif;
  endif;
  SetSystimer(ActivityTimer, 25);
  RemoteFlag:=true; // statt LED!

//Parse einzelnen Befehl

  if ParseExtract then
    SubChOffset:=0; // direkter SubCh-Aufruf
  else
    CmdWhich:=Cmd2Index; // Klartext übersetzen
    if CmdWhich = err then
      serprompt(SyntaxErr,0);
      return;
    endif;
    SubChOffset:=Cmd2SubChArr[ord(CmdWhich)];
    isParam:=ParseExtract; // SubCh-Parameter holen
  endif;
  SubCh:=StrToInt(ParamStr)+SubChOffset; //auf neuen SubCh umrechnen

  if isRequest then
    ParseGetParam;
  else
    SerInpPtr:=pos('=',SerInpStr)+1; // Set-'='
    if (SerInpPtr>1) and ParseExtract then
      Param:=StrToFloat(ParamStr);
      ParamInt:=integer(Param);
      ParamByte:=byte(ParamInt);
    else
      serprompt(ParamErr,0);
      return;
    endif;
    ParseSetParam;
  endif;
end;

//  RemoteFlag:=true; // statt ActivityLED nicht vergessen bei Parser-Update

{###########################################################################}

