{
    This file is part of SkantiControl

    Skanti TRP8000 series control program (CU8000 control unit)
    This program was developed for a CU8000 control unit marked
    TRP 8255 S R GB1. May work or not with other units. The CU
    firmware version can be either 80R or 92.

    Copyright (C) 2012-2025 G. Perotti, I1EPJ, i1epj@aricasale.it

    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 3 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, see <http://www.gnu.org/licenses/.

                                    * * *

    Hamlib rigctld-maybe-compatible TRP8255 control net server.
    The strictly-networking part is in skanti.pas using lNET.

    Rigctld commands are only partially coded, a little more than needed to work
    with WSJTX NONE, RIG and FAKE IT split modes. The implementation uses
    only some of the Skanti TRP8000 series remote command capabilities.
    ==========================================================================
                                   WANTED
    ==========================================================================
             Someone with better knowledge of how rigctld works
                to help complete/correct the implementation.
    ==========================================================================
}

{$include defines.inc}

unit UParse;

{$mode ObjFPC}

interface

uses
  Classes, SysUtils, UState, StrUtils, lNet;

procedure ParseNetMsg(RXLine: string; MySocket: TLSocket);

// Messages declared here for i18n
resourcestring
  REMCMDNOTREC='Remote command not recognized: %s';
  REMCMDNOTIMP='Remote command not implemented: %s';
  REMCMDNOTAVA='Remote command not available: %s';
  EXTPROTNOTSUPP='Extended response protocol is not supported';
  SENTHAMLIBCMDS='Sent: %s to port %d';
  RECVHAMLIBCMDS='Recv: %s %s %s from port %d';

implementation

uses Skanti;

type

  // The hamlib rigtcld commands
  TCmdCodes =
    (SET_FREQ, GET_FREQ, SET_MODE, GET_MODE, SET_VFO, GET_VFO,
     SET_RIT, GET_RIT, SET_XIT, GET_XIT, SET_PTT, GET_PTT,
     SET_SPLIT_VFO, GET_SPLIT_VFO, SET_SPLIT_FREQ, GET_SPLIT_FREQ,
     SET_SPLIT_MODE, GET_SPLIT_MODE, SET_ANT, GET_ANT, SEND_MORSE,
     GET_DCD, SET_RPTR_SHIFT, GET_RPTR_SHIFT, SET_RPTR_OFFS,GET_RPTR_OFFS,
     SET_CTCSS_TONE, GET_CTCSS_TONE, SET_DCS_CODE, GET_DCS_CODE,
     SET_CTCSS_SQL, GET_CTCSS_SQL, SET_DCS_SQL, GET_DCS_SQL, SET_TS,
     GET_TS, SET_FUNC, GET_FUNC, SET_LEVEL, GET_LEVEL, SET_PARM, GET_PARM,
     SET_BANK, SET_MEM, GET_MEM, VFO_OP, SCAN, SET_CHANNEL, GET_CHANNEL,
     SET_TRN, GET_TRN, RESET, SET_POWERSTAT, GET_POWERSTAT, SEND_DTMF,
     RECV_DTMF, GET_INFO, GET_RIG_INFO, GET_VFO_INFO, DUMP_STATE,DUMP_CAPS,
     POWER2MW, MW2POWER, SET_CLOCK, GET_CLOCK, CHK_VFO, SET_VFO_OPT, QUIT,
     SET_LOCK_MODE,GET_LOCK_MODE,LASTCMD);

  // The hamlib rigtcld VFOs
  TVFONames =
    (NONE, VFOA, VFOB, VFOC, currVFO, VFO, MEM, Main, Sub, TX, RX);

  // The hamlib rigtcld levels
  TLevels = (PREAMP,ATT,LVOX,AF,LRF,LSQL,LIF,LAPF,LNR,PBT_IN,PBT_OUT,CWPITCH,RFPOWER,
     RFPOWER_METER,RFPOWER_METER_WATTS,MICGAIN,KEYSPD,NOTCHF,LCOMP,AGC,BKINDL,BAL,
     METER,VOXGAIN,ANTIVOX,SLOPE_LOW,SLOPE_HIGH,RAWSTR,SWR,ALC,STRENGTH,
     LASTLEVEL);

  // The hamlib rigtcld functions
  TFunctions =
    (FAGC,NB,COMP,FVOX,TONE,TSQL,SBKIN,FBKIN,ANF,NR,AIP,APF,MON,MN,FRF,ARO,LOCK,
     MUTE,VSC,REV,FSQL,ABM,BC,MBC,RIT,AFC,SATMODE,SCOPE,RESUME,TBURST,TUNER,XIT,
     LASTFUNCTION);

  // Hamlib error codes
  // Taken from hamlib 4.7~git sources (rig.h)
THamlibErrors = (
    RIG_OK,          //  0 No error, operation completed successfully
    RIG_EINVAL,      //  1 invalid parameter
    RIG_ECONF,       //  2 invalid configuration (serial,..)
    RIG_ENOMEM,      //  3 memory shortage
    RIG_ENIMPL,      //  4 function not implemented, but will be
    RIG_ETIMEOUT,    //  5 communication timed out
    RIG_EIO,         //  6 IO error, including open failed
    RIG_EINTERNAL,   //  7 Internal Hamlib error, huh!
    RIG_EPROTO,      //  8 Protocol error
    RIG_ERJCTED,     //  9 Command rejected by the rig
    RIG_ETRUNC,      // 10 Command performed, but arg truncated
    RIG_ENAVAIL,     // 11 Function not available
    RIG_ENTARGET,    // 12 VFO not targetable
    RIG_BUSERROR,    // 13 Error talking on the bus
    RIG_BUSBUSY,     // 14 Collision on the bus
    RIG_EARG,        // 15 NULL RIG handle or any invalid pointer parameter in
    RIG_EVFO,        // 16 Invalid VFO
    RIG_EDOM,        // 17 Argument out of domain of func
    RIG_EDEPRECATED, // 18 Function deprecated
    RIG_ESECURITY,   // 19 Security error
    RIG_EPOWER,      // 20 Rig not powered on
    RIG_ELIMIT,      // 21 Limit exceeded
    RIG_EACCESS,     // 22 Access denied -- e.g. port already in use
    RIG_EEND,        // Last item, not needed, but...
    NOTREQUIRED = 99 // 99 For get commands (no RPRT X required)
  );

  // The command parser structure
  THamLibCmd = record
    LongName: string;
    ShortName: string;
    CmdCode: TCmdCodes;
  end;

  // The level parser structure
  THamlibLevel = record
    LevelName: string;
    LevelCode: TLevels;
  end;

  // The function parser structure
  THamlibFunction = record
    FunctionName: string;
    FunctionCode: TFunctions;
  end;

  // The commands array
  THamlibCmds = array[1..ord(LASTCMD)] of THamLibCmd;

  // The levels array
  THamlibLevels = array[1..ord(LASTLEVEL)] of THamlibLevel;

  // The functions array
  THamlibFunctions = array[1..ord(LASTFUNCTION)] of THamlibFunction;


  // Various constant values
  const
    RPRT: string = 'RPRT ';
    RPRT_OK: string = 'RPRT 0';
    VFOMode: integer = 0;
    RFLEVSTEPS: integer = 60;

  HamLibCmds: THamlibCmds = (
    (LongName: 'set_freq'; ShortName:'F'; CmdCode: SET_FREQ),
    (LongName: 'get_freq'; ShortName:'f'; CmdCode: GET_FREQ),
    (LongName: 'set_lock_mode'; ShortName:''; CmdCode: SET_LOCK_MODE),
    (LongName: 'get_lock_mode'; ShortName:''; CmdCode: GET_LOCK_MODE),
    (LongName: 'set_mode'; ShortName:'M'; CmdCode: SET_MODE),
    (LongName: 'get_mode'; ShortName:'m'; CmdCode: GET_MODE),
    (LongName: 'set_vfo'; ShortName:'V'; CmdCode: SET_VFO),
    (LongName: 'get_vfo'; ShortName:'v'; CmdCode: GET_VFO),
    (LongName: 'set_rit'; ShortName:'J'; CmdCode: SET_RIT),
    (LongName: 'get_rit'; ShortName:'j'; CmdCode: GET_RIT),
    (LongName: 'set_xit'; ShortName:'Z'; CmdCode: SET_XIT),
    (LongName: 'het_xit'; ShortName:'z'; CmdCode: GET_XIT),
    (LongName: 'set_ptt'; ShortName:'T'; CmdCode: SET_PTT),
    (LongName: 'get_ptt'; ShortName:'t'; CmdCode: GET_PTT),
    (LongName: 'set_split_vfo'; ShortName:'S'; CmdCode: SET_SPLIT_VFO),
    (LongName: 'get_split_vfo'; ShortName:'s'; CmdCode: GET_SPLIT_VFO),
    (LongName: 'set_split_freq'; ShortName:'I'; CmdCode: SET_SPLIT_FREQ),
    (LongName: 'get_split_freq'; ShortName:'i'; CmdCode: GET_SPLIT_FREQ),
    (LongName: 'set_split_mode'; ShortName:'X'; CmdCode: SET_SPLIT_MODE),
    (LongName: 'get_split_mode'; ShortName:'x'; CmdCode: GET_SPLIT_MODE),
    (LongName: 'set_ant'; ShortName:'Y'; CmdCode: SET_ANT),
    (LongName: 'get_ant'; ShortName:'y'; CmdCode: GET_ANT),
    (LongName: 'send_morse'; ShortName:'b'; CmdCode: SEND_MORSE),
    (LongName: 'get_dcd'; ShortName:#$8B; CmdCode: GET_DCD),
    (LongName: 'set_rptr_shift'; ShortName:'R'; CmdCode: SET_RPTR_SHIFT),
    (LongName: 'get_rptr_shift'; ShortName:'r'; CmdCode: GET_RPTR_SHIFT),
    (LongName: 'set_rptr_offs'; ShortName:'O'; CmdCode: SET_RPTR_OFFS),
    (LongName: 'get_rptr_offs'; ShortName:'o'; CmdCode: GET_RPTR_OFFS),
    (LongName: 'set_ctcss_tone'; ShortName:'C'; CmdCode: SET_CTCSS_TONE),
    (LongName: 'get_ctcss_tone'; ShortName:'c'; CmdCode: GET_CTCSS_TONE),
    (LongName: 'set_dcs_code'; ShortName:'D'; CmdCode: SET_DCS_CODE),
    (LongName: 'get_dcs_code'; ShortName:'d'; CmdCode: GET_DCS_CODE),
    (LongName: 'set_ctcss_sql'; ShortName:#$90; CmdCode: SET_CTCSS_SQL),
    (LongName: 'get_ctcss_sql'; ShortName:#$91; CmdCode: GET_CTCSS_SQL),
    (LongName: 'set_dcs_sql'; ShortName:#$92; CmdCode: SET_DCS_SQL),
    (LongName: 'get_dcs_sql'; ShortName:#$93; CmdCode: GET_DCS_SQL),
    (LongName: 'set_ts'; ShortName:'N'; CmdCode: SET_TS),
    (LongName: 'get_ts'; ShortName:'n'; CmdCode: GET_TS),
    (LongName: 'set_func'; ShortName:'U'; CmdCode: SET_FUNC),
    (LongName: 'get_func'; ShortName:'u'; CmdCode: GET_FUNC),
    (LongName: 'set_level'; ShortName:'L'; CmdCode: SET_LEVEL),
    (LongName: 'get_level'; ShortName:'l'; CmdCode: GET_LEVEL),
    (LongName: 'set_parm'; ShortName:'P'; CmdCode: SET_PARM),
    (LongName: 'get_parm'; ShortName:'p'; CmdCode: GET_PARM),
    (LongName: 'set_bank'; ShortName:'B'; CmdCode: SET_BANK),
    (LongName: 'set_mem'; ShortName:'E'; CmdCode: SET_MEM),
    (LongName: 'get_mem'; ShortName:'e'; CmdCode: GET_MEM),
    (LongName: 'vfo_op'; ShortName:'G'; CmdCode: VFO_OP),
    (LongName: 'scan'; ShortName:'g'; CmdCode: SCAN),
    (LongName: 'set_channel'; ShortName:'H'; CmdCode: SET_CHANNEL),
    (LongName: 'get_channel'; ShortName:'h'; CmdCode: GET_CHANNEL),
    (LongName: 'set_trn'; ShortName:'A'; CmdCode: SET_TRN),
    (LongName: 'get_trn'; ShortName:'a'; CmdCode: GET_TRN),
    (LongName: 'reset'; ShortName:'*'; CmdCode: RESET),
    (LongName: 'set_powerstat'; ShortName:#$87; CmdCode: SET_POWERSTAT),
    (LongName: 'get_powerstat'; ShortName:#$88; CmdCode: GET_POWERSTAT),
    (LongName: 'send_dtmf'; ShortName:#$89; CmdCode: SEND_DTMF),
    (LongName: 'recv_dtmf'; ShortName:#$8A; CmdCode: RECV_DTMF),
    (LongName: 'get_info'; ShortName:'_'; CmdCode: GET_INFO),
    (LongName: 'get_rig_info'; ShortName:#$F5; CmdCode: GET_RIG_INFO),
    (LongName: 'get_vfo_info'; ShortName:#$F3; CmdCode: GET_VFO_INFO),
    (LongName: 'dump_state'; ShortName:#0; CmdCode: DUMP_STATE),
    (LongName: 'dump_caps'; ShortName:'1'; CmdCode: DUMP_CAPS),
    (LongName: 'power2mW'; ShortName:'2'; CmdCode: POWER2MW),
    (LongName: 'mW2power'; ShortName:'4'; CmdCode: MW2POWER),
    (LongName: 'set_clock'; ShortName:''; CmdCode: SET_CLOCK),
    (LongName: 'get_clock'; ShortName:''; CmdCode: GET_CLOCK),
    (LongName: 'chk_vfo'; ShortName:''; CmdCode: CHK_VFO),
    (LongName: 'set_vfo_opt'; ShortName:''; CmdCode: SET_VFO_OPT),
    (LongName: 'quit'; ShortName: 'q';  CmdCode:  QUIT)
  );

  HamlibLevels: THamlibLevels = (
    (LevelName: 'PREAMP'; LevelCode: PREAMP),
    (LevelName: 'ATT'; LevelCode: ATT),
    (LevelName: 'VOX'; LevelCode: LVOX),
    (LevelName: 'AF'; LevelCode: AF),
    (LevelName: 'RF'; LevelCode: LRF),
    (LevelName: 'SQL'; LevelCode: LSQL),
    (LevelName: 'IF'; LevelCode: LIF),
    (LevelName: 'APF'; LevelCode: LAPF),
    (LevelName: 'NR'; LevelCode: LNR),
    (LevelName: 'PBT_IN'; LevelCode: PBT_IN),
    (LevelName: 'PBT_OUT'; LevelCode: PBT_OUT),
    (LevelName: 'CWPITCH'; LevelCode: CWPITCH),
    (LevelName: 'RFPOWER'; LevelCode: RFPOWER),
    (LevelName: 'RFPOWER_METER'; LevelCode: RFPOWER_METER),
    (LevelName: 'RFPOWER_METER_WATTS'; LevelCode: RFPOWER_METER_WATTS),
    (LevelName: 'MICGAIN'; LevelCode: MICGAIN),
    (LevelName: 'KEYSPD'; LevelCode: KEYSPD),
    (LevelName: 'NOTCHF'; LevelCode: NOTCHF),
    (LevelName: 'COMP'; LevelCode: NOTCHF),
    (LevelName: 'AGC'; LevelCode: AGC),
    (LevelName: 'BKINDL'; LevelCode: BKINDL),
    (LevelName: 'BAL'; LevelCode: BAL),
    (LevelName: 'METER'; LevelCode: METER),
    (LevelName: 'VOXGAIN'; LevelCode: VOXGAIN),
    (LevelName: 'ANTIVOX'; LevelCode: ANTIVOX),
    (LevelName: 'SLOPE_LOW'; LevelCode: SLOPE_LOW),
    (LevelName: 'SLOPE_HIGH'; LevelCode: SLOPE_HIGH),
    (LevelName: 'RAWSTR'; LevelCode: RAWSTR),
    (LevelName: 'SWR'; LevelCode: SWR),
    (LevelName: 'ALC'; LevelCode: ALC),
    (LevelName: 'STRENGTH'; LevelCode: STRENGTH)
  );

  HamlibFunctions: THamlibFunctions = (
   (FunctionName: 'FAGC'; FunctionCode: FAGC),
   (FunctionName: 'NB'; FunctionCode: NB),
   (FunctionName: 'COMP'; FunctionCode: COMP),
   (FunctionName: 'VOX'; FunctionCode: FVOX),
   (FunctionName: 'TONE'; FunctionCode: TONE),
   (FunctionName: 'TSQL'; FunctionCode: TSQL),
   (FunctionName: 'SBKIN'; FunctionCode: SBKIN),
   (FunctionName: 'FBKIN'; FunctionCode: FBKIN),
   (FunctionName: 'ANF'; FunctionCode: ANF),
   (FunctionName: 'NR'; FunctionCode: NR),
   (FunctionName: 'AIP'; FunctionCode: AIP),
   (FunctionName: 'APF'; FunctionCode: APF),
   (FunctionName: 'MON'; FunctionCode: MON),
   (FunctionName: 'MN'; FunctionCode: MN),
   (FunctionName: 'RF'; FunctionCode: FRF),
   (FunctionName: 'ARO'; FunctionCode: ARO),
   (FunctionName: 'LOCK'; FunctionCode: LOCK),
   (FunctionName: 'MUTE'; FunctionCode: MUTE),
   (FunctionName: 'VSC'; FunctionCode: VSC),
   (FunctionName: 'REV'; FunctionCode: REV),
   (FunctionName: 'SQL'; FunctionCode: FSQL),
   (FunctionName: 'ABM'; FunctionCode: ABM),
   (FunctionName: 'BC'; FunctionCode: BC),
   (FunctionName: 'MBC'; FunctionCode: MBC),
   (FunctionName: 'RIT'; FunctionCode: RIT),
   (FunctionName: 'AFC'; FunctionCode: AFC),
   (FunctionName: 'SATMODE'; FunctionCode: SATMODE),
   (FunctionName: 'SCOPE'; FunctionCode: SCOPE),
   (FunctionName: 'RESUME'; FunctionCode: RESUME),
   (FunctionName: 'TBURST'; FunctionCode: TBURST),
   (FunctionName: 'TUNER'; FunctionCode: TUNER),
   (FunctionName: 'XIT'; FunctionCode: XIT)
  );

// Global variables
var
  SplitVFOActive: boolean;
  curVFO: TVFONames = VFOA;
  tmpVFO: TVFONames = NONE;
  p,i: integer;
  dbS9: integer;
  ipwr: integer;
  pwr01: real;
  HamlibResult: THamlibErrors;
  Lock_Mode: integer = 0;

// Auxiliary procedures & functions

// Send a string via TCP socket
procedure SendNetMsg(Msg:string; MySocket: TLSocket);

var s: string;

begin
  Msg := Msg+stLF;
  MySocket.SendMessage(Msg);
  // If "Show hamlib commands" option checked, show sent reply
  if TRP.MSHOWHAMLIB.Checked then begin
    s := Format(SENTHAMLIBCMDS,[TRP.ShowControlChars(Msg), MySocket.LocalPort]);
    TRP.MsgToShow := s;
  end;
end;

// Parse and execute hamlib commands
procedure ParseNetMsg(RXLine: string; MySocket: TLSocket);

var LineNum, ParamNum, NewFreq,iRFLev: integer;
    sCmd, sParam1, sParam2, sTmp: string;
    {$IFDEF THIRDPARAMETER}
    // not required so far
    sParam3: string;
    {$ENDIF}
    Cmd: TCmdCodes = LASTCMD;
    Level: TLevels = LASTLEVEL;
    Functn: TFunctions = LASTFUNCTION;
    Success: Boolean = FALSE;
    TXFrequencyModified: boolean = FALSE;

begin
  {$IFDEF DEBUG_PARSE}
  MsgToShow := LineEnding+'------- ParseNetMsg entered';
  MsgToShow := 'Line received: '+TRP.ShowControlChars(RXLine);
  {$ENDIF}

  if RXLine='' then exit;

  Cmd := LASTCMD;
  HamlibResult := NOTREQUIRED;

  // Remove traling/ending white spaces and control chars
  RXLine := Trim(RXLine);

  // Separate command and parameters, if any, and remove remaining spaces
  // and control chars. Accept both LF and SPACE as parameters delimiter.
  sCmd := Trim(ExtractDelimited(1,RXLine,[' ',#$0a]));
  sParam1 := Trim(ExtractDelimited(2,RXLine,[' ',#$0a]));
  sParam2 := Trim(ExtractDelimited(3,RXLine,[' ',#$0a]));
  {$IFDEF NOTDEF}
  // not required so far
  sParam3 := Trim(ExtractDelimited(4,RXLine,[' ',#$0a]));
  {$ENDIF}
  {$IFDEF DEBUG_PARSE}
  MsgToShow := 'Cmd: '+sCmd;
  MsgToShow := 'Param1: '+sParam1;
  MsgToShow := 'Param2: '+sParam2;
  {$IFDEF NOTDEF}
  MsgToShow := 'Param3: '+sParam3;
  {$ENDIF}
  {$ENDIF}

  // Ignore empty commands
  if sCmd = '' then exit;

  // Check for extended response protocol (NOT SUPPORTED)
  if sCmd[1] in ['+',';','|',','] then begin
    TRP.MsgToShow := EXTPROTNOTSUPP;
    SendNetMsg(RPRT+IntToStr(-Ord(RIG_ENIMPL)),MySocket);
    exit;
  end;

  // Parse hamlib long commands
  if sCmd[1]='\' then begin
    // It is a long command
    Delete(sCmd,1,1);
    for ParamNum := 1 to Ord(LASTCMD) do begin
      if sCmd=HamLibCmds[ParamNum].LongName then begin
        Cmd := HamLibCmds[ParamNum].CmdCode;
        break;
      end;
    end;
  end else begin
    // parse hamlib short commands
    for ParamNum := 1 to ord(LASTCMD) do begin
      if sCmd=HamLibCmds[ParamNum].ShortName then begin
         Cmd := HamLibCmds[ParamNum].CmdCode;
         break;
      end;
    end;
  end;

  // If "Show hamlib commands" option checked, show received command
  if TRP.MSHOWHAMLIB.Checked then begin
    sTmp := Format(RECVHAMLIBCMDS, [HamLibCmds[ParamNum].LongName, sParam1, sParam2,
                MySocket.LocalPort]);
    TRP.MsgToShow := sTmp;
  end;

  // Now we have a non-empty command in Cmd with parameters in sParam1, sParam2
  // and possibly sParam3

  // Execute command
  // FIXME: At present only VFOMode 0 is handled.
  // Any program out there *wants* VFOMODE 1?
  case Cmd of
    SET_FREQ: begin
      // If other commands running, return BUSBUSY. Done that way since break
      // is not allowed in case statement
      if not In_Command then begin
        // Frequency can have decimal figures (not used here) so remove them if present
        // The separator should be '.', but handle also ',', just in case
        sParam1 := ExtractDelimited(1,sParam1,['.',',']);
        if VFOMode=0 then begin
          // The only handled so far
          if TryStrToInt(sParam1, NewFreq) then begin
            NewFreq := (NewFreq div 100)*100; // Stay on 100Hz steps

            // Check if frequency is in allowable range
            // if outside, set it to lowest/highest allowed value
            // The TX limits are the most stringent, so use them
            if NewFreq < MINTXF then NewFreq := MINTXF;
            if NewFreq > MAXTXF then NewFreq := MAXTXF;

            Success := FALSE;

            // To speed operations and limit TUNE requests set frequency only
            // if the new frequency is really new
            if (RTXState.Freq_RX <> NewFreq) or
               (RTXstate.Freq_TX <> NewFreq) then begin
               In_Command := TRUE;
              case curVFO of
                VFOA,RX: begin
                  // If split VFO modify only RX frequency, else both
                  if SplitVFOActive then begin
                    RTXState.Freq_Rx := NewFreq;
                    Success := TRP.SetRXFreq;
                    TXFrequencyModified := FALSE;
                  end else begin
                    RTXState.Freq_Rx := NewFreq;
                    RTXState.Freq_Tx := NewFreq;
                    Success := TRP.SetRXTXFreq;
                    TXFrequencyModified := Success;
                  end;
                end;
                VFOB,TX: begin
                  // Modify only TX frequency
                  RTXState.Freq_Tx := NewFreq;
                  Success := TRP.SetTXFreq;
                  TXFrequencyModified := Success;
                end;
                otherwise
                  ; // do nothing (TBD?)
              end;
              if not In_Command then
                TRP.SendCommand(stEOT,''); // Release priority
              In_Command := FALSE;
              if Success then begin
                if TuneAtFreqChange and TXFrequencyModified then TuneRequired := TRUE;
                HamlibResult := RIG_OK;
                RemFreqChange := TRUE;
              end else HamlibResult := RIG_BUSBUSY
            end else HamlibResult := RIG_OK;
          end else HamLibResult := RIG_EINVAL;
        end else HamLibResult := RIG_ENIMPL;
      end else HamLibResult := RIG_BUSBUSY;
    end;
    GET_FREQ: begin
      // TBD correctly for VFOmode 1 if required
      if VFOMode=0 then begin
        case curVFO of
          VFOA,RX: SendNetMsg(IntToStr(RTXState.Freq_rx),MySocket);
          VFOB,TX: SendNetMsg(IntToStr(RTXState.Freq_tx),MySocket);
          otherwise SendNetMsg(IntToStr(RTXState.Freq_rx),MySocket);
        end;
      end;
    end;
    SET_MODE: begin
      // Check if no other command is running
      if not In_Command then begin
        HamlibResult := RIG_BUSBUSY;
        // To be completed if needed and possible for all modes supported by TRP8000
        if sParam1='USB' then TRP.BUSBClick(nil)
        else if sParam1='LSB' then TRP.BLSBClick(nil)
        else if sParam1='RTTY' then TRP.BTELEXClick(nil)
        else if sParam1='CW' then TRP.BCWClick(nil)
        else if sParam1='AM' then TRP.BAMClick(nil);

        // For CW and AM modes only bandwidth is selectable
        if (RTXState.Mode_RX = M_CW) or (RTXState.Mode_RX = M_AM) then begin
          if sParam2 = '6000' then TRP.BWIDEClick(nil)
          else if sParam2 = '2700' then TRP.BINTERClick(nil)
          else if sParam2 = '1000' then TRP.BNARclick(nil)
          else if sParam2 = '250' then TRP.BVNARClick(nil)
        end;
        HamlibResult := RIG_OK;
        TRP.SendCommand(stEOT,''); // Release priority
      end else HamLibResult := RIG_BUSBUSY;
    end;
    GET_MODE: begin
      sTmp := '';
      case RTXState.Mode_RX of
        M_USB: begin
          sTmp:='USB';
          RTXState.Filter := FILTER_INTERMEDIATE;
        end;
        M_LSB: begin
          sTmp:='LSB';
          RTXState.Filter := FILTER_INTERMEDIATE;
        end;
        M_TLX: begin
          sTmp:='RTTY';
          RTXState.Filter := FILTER_VERYNARROW;
        end;
        M_CW: sTmp:='CW';
        M_AM: sTmp:='AM';
        // FIXME: what to return for these modes?!
        M_R3E:sTmp:='AM';
        M_MCW:sTmp:='AM';
        M_500K:sTmp:='AM';
        M_2182K:sTmp:='AM';
      end;
      // rigctld returns <mode><LF><bandwidth>, so the same is done here.
      sTmp := sTmp+stLF;

      // Values are for my own TRP8255
      case RTXState.Filter of
        FILTER_Default: sTmp := sTmp+'2700';
        FILTER_WIDE: sTmp := sTmp+'6000';
        FILTER_INTERMEDIATE: sTmp := sTmp+'2700';
        FILTER_NARROW: sTmp := sTmp+'1000';
        FILTER_VERYNARROW: sTmp := sTmp+'250';
      end;
      SendNetMsg(sTmp,MySocket);
    end;
    SET_VFO: begin
      tmpVFO := curVFO;
      curVFO := NONE;
      if sParam1='VFOA' then curVFO := VFOA;
      if sParam1='VFOB' then curVFO := VFOB;
      if sParam1='VFOC' then curVFO := VFOC;
      if sParam1='currVFO' then curVFO := tmpVFO;
      if sParam1='VFO' then curVFO := VFO;
      if sParam1='MEM' then curVFO := MEM;
      if sParam1='Main' then curVFO := MAIN;
      if sParam1='Sub' then curVFO := SUB;
      if sParam1='TX' then curVFO := TX;
      if sParam1='RX' then curVFO := RX;

      if curVFO=NONE then
        HamlibResult := RIG_EVFO
      else
        HamlibResult := RIG_OK;
    end;
    GET_VFO: begin
      sTmp := '';
      case curVFO of
        VFOA: sTmp := 'VFOA';
        VFOB: sTmp := 'VFOB';
        VFOC: sTmp := 'VFOC';
        VFO: sTmp := 'VFO';
        MEM: sTmp := 'MEM';
        MAIN: sTmp := 'Main';
        SUB: sTmp := 'VFOA';
        TX: sTmp := 'VFOA';
        RX: sTmp := 'VFOA';
      end;
      SendNetMsg(sTmp,MySocket);
    end;
    SET_RIT: begin
      // Not available
      MsgToShow := Format(REMCMDNOTAVA,[sCmd]);
      HamlibResult := RIG_ENAVAIL;
    end;
    GET_RIT: begin
      // Not available
      MsgToShow := Format(REMCMDNOTAVA,[sCmd]);
      HamlibResult := RIG_ENAVAIL;
    end;
    SET_XIT: begin
      // Not available
      MsgToShow := Format(REMCMDNOTAVA,[sCmd]);
      HamlibResult := RIG_ENAVAIL;
    end;
    GET_XIT: begin
      // Not available
      MsgToShow := Format(REMCMDNOTAVA,[sCmd]);
      HamlibResult := RIG_ENAVAIL;
    end;
    SET_PTT: begin
      // Check for other command running
      if not In_Command then begin
        In_Command := TRUE;
        if sParam1<>'0' then begin
          RTXState.PTT_State := TRUE;
          TRP.TX.Enabled := TRUE;
          if TRP.SendCommand(TX_Cmd,'') then
            HamlibResult := RIG_OK
          else
            HamlibResult := RIG_BUSBUSY;
        end else begin
          RTXState.PTT_State := FALSE;
          TRP.TX.Enabled := FALSE;
          if TRP.SendCommand(RX_Cmd,'') then
            HamlibResult := RIG_OK
          else
            HamlibResult := RIG_BUSERROR;
        end;
        In_Command := FALSE;
      end else HamLibResult := RIG_BUSBUSY;
    end;
    GET_PTT: begin
      if RTXState.PTT_State then
        SendNetMsg('1',MySocket)
      else
        SendNetMsg('0',MySocket);
    end;
    SET_SPLIT_VFO: begin
      // Check for other command running
      if not In_Command then begin
        In_Command := TRUE;
        // TRP8000 VFO is split only...
        if sParam1='1' then begin
          SplitVFOActive := TRUE;
          Success := TRUE;
        end else if sParam1='0' then begin
          // ...so if asked to disable it (which is impossible),
          // note that and set TXf=RXf
          SplitVFOActive := FALSE;
          RTXState.Freq_tx := RTXState.Freq_rx;
          In_Command := TRUE;
          Success := TRP.SendCommand(EQTXRX,'');
          TRP.SendCommand(stEOT,''); // Release priority
          In_Command := FALSE;
          RemFreqChange := TRUE;
        end;
        if Success then
          HamlibResult := RIG_OK
        else
          HamlibResult := RIG_BUSERROR;
        In_Command := FALSE;
      end else HamLibResult:= RIG_BUSBUSY;
    end;
    GET_SPLIT_VFO: begin
      sTmp := '';
      case curVFO of
        VFOA: sTmp := 'VFOA';
        VFOB: sTmp := 'VFOB';
        VFOC: sTmp := 'VFOC';
        VFO: sTmp := 'VFO';
        MEM: sTmp := 'MEM';
        MAIN: sTmp := 'Main';
        SUB: sTmp := 'SUB';
        TX: sTmp := 'TX';
        RX: sTmp := 'RX';
      end;
      if SplitVFOActive then
        SendNetMsg('1'+stLF+sTmp,MySocket)
      else
        SendNetMsg('0'+stLF+sTmp,MySocket);
    end;
    SET_SPLIT_FREQ: begin
      // Check for other command running
      if not In_Command then begin
        In_Command := TRUE;
        // Frequency can have decimal figures (not used here) so remove them if present
        // The separator should be '.', but handle also ',', just in case
        sParam1 := ExtractDelimited(1,sParam1,['.',',']);
        NewFreq := StrToInt(sParam1);

        // Check if frequency is in allowable range
        // if outside, set it to lowest/highest allowed value
        if NewFreq < MINTXF then NewFreq := MINTXF;
        if NewFreq > MAXTXF then NewFreq := MAXTXF;
        RTXState.Freq_Tx := NewFreq;

        // For CW and AM modes only bandwidth is selectable
        if (RTXState.Mode_RX = M_CW) or (RTXState.Mode_RX = M_AM) then begin
          if sParam2 = '6000' then TRP.BWIDEClick(nil);
          if sParam2 = '2700' then TRP.BINTERClick(nil);
          if sParam2 = '1000' then TRP.BNARclick(nil);
          if sParam2 = '250' then TRP.BVNARClick(nil);
        end;
        Success := TRP.SetTXFreq;
        TXFrequencyModified := Success;
        if Success then begin
          if TuneAtFreqChange and TXFrequencyModified then TuneRequired := TRUE;
          HamlibResult := RIG_OK;
          RemFreqChange := TRUE;
          HamlibResult := RIG_OK;
          TRP.SendCommand(stEOT,''); // Release priority
        end;
        In_Command := FALSE;
      end else HamLibResult := RIG_BUSBUSY;
    end;
    SET_SPLIT_MODE: begin
      // Check if no other command is running
      if not In_Command then begin
         // if no lock mode ad no other command running, proceed.
        // TRP8000 supports split modes, but this code does not.
        // To be completed if needed with all split modes supported by TRP8000
        if sParam1='USB' then TRP.BUSBClick(nil)
        else if sParam1 = 'LSB' then TRP.BLSBClick(nil)
        else if sParam1 = 'RTTY' then TRP.BTELEXClick(nil)
        else if sParam1 = 'CW' then TRP.BCWClick(nil)
        else if sParam1 = 'AM' then TRP.BAMClick(nil)
        else Success := FALSE;

        // For CW and AM modes only bandwidth is selectable
        if (RTXState.Mode_RX = M_CW) or (RTXState.Mode_RX = M_AM) then begin
          if sParam2 = '6000' then TRP.BWIDEClick(nil);
          if sParam2 = '2700' then TRP.BINTERClick(nil);
          if sParam2 = '1000' then TRP.BNARclick(nil);
          if sParam2 = '250' then TRP.BVNARClick(nil);
        end;
        TRP.SendCommand(stEOT,''); // Release priority
        HamlibResult := RIG_OK;
      end else HamLibResult := RIG_BUSBUSY;
    end;
    GET_SPLIT_MODE: begin
      // Ditto
      // TBD
      // To be completed if needed with all modes supported by TRP8000
      Success:=TRUE;
      sTmp := '';
      case RTXState.Mode_TX of
        M_USB: sTmp := sTmp+'USB';
        M_LSB: sTmp := sTmp+'LSB';
        M_CW: sTmp := sTmp+'CW';
        M_AM: sTmp := sTmp+'AM';
        M_TLX: sTmp := sTmp+'RTTY';
        // FIXME: what to return for these modes?!
        M_R3E: sTmp := 'AM';
        M_MCW: sTmp := 'AM';
        M_500K: sTmp := 'AM';
        M_2182K: sTmp := 'AM';
      end;

      // rigctld returns <mode><LF><bandwidth>, so the same is done here.
      sTmp := sTmp+stLF;

      // Values are for my own TRP8255
      case RTXState.Filter of
        FILTER_Default: sTmp := sTmp+'2700';
        FILTER_WIDE: sTmp := sTmp+'6000';
        FILTER_INTERMEDIATE: sTmp := sTmp+'2700';
        FILTER_NARROW: sTmp := sTmp+'1000';
        FILTER_VERYNARROW: sTmp := sTmp+'250';
      end;
      SendNetMsg(sTmp,MySocket);
    end;
    SET_ANT: begin
      // Not available
      MsgToShow := Format(REMCMDNOTAVA,[sCmd]);
      HamlibResult := RIG_ENAVAIL;
    end;
    GET_ANT: begin
      // Not available
      MsgToShow := Format(REMCMDNOTAVA,[sCmd]);
      HamlibResult := RIG_ENAVAIL;
    end;
    SEND_MORSE: begin
      // Not available
      MsgToShow := Format(REMCMDNOTAVA,[sCmd]);
      HamlibResult := RIG_ENAVAIL;
    end;
    GET_DCD: begin
      // Not available
      MsgToShow := Format(REMCMDNOTAVA,[sCmd]);
      HamlibResult := RIG_ENAVAIL;
    end;
    SET_RPTR_SHIFT: begin
      // Not available
      MsgToShow := Format(REMCMDNOTAVA,[sCmd]);
      HamlibResult := RIG_ENAVAIL;
    end;
    GET_RPTR_SHIFT: begin
      // Not available
      MsgToShow := Format(REMCMDNOTAVA,[sCmd]);
      HamlibResult := RIG_ENAVAIL;
    end;
    SET_RPTR_OFFS: begin
      // Not available
      MsgToShow := Format(REMCMDNOTAVA,[sCmd]);
      HamlibResult := RIG_ENAVAIL;
    end;
    GET_RPTR_OFFS: begin
      // Not available
      MsgToShow := Format(REMCMDNOTAVA,[sCmd]);
      HamlibResult := RIG_ENAVAIL;
    end;
    SET_CTCSS_TONE: begin
      // Not available
      MsgToShow := Format(REMCMDNOTAVA,[sCmd]);
      HamlibResult := RIG_ENAVAIL;
    end;
    GET_CTCSS_TONE: begin
      // Not available
      MsgToShow := Format(REMCMDNOTAVA,[sCmd]);
      HamlibResult := RIG_ENAVAIL;
    end;
    SET_DCS_CODE: begin
      // Not available
      MsgToShow := Format(REMCMDNOTAVA,[sCmd]);
      HamlibResult := RIG_ENAVAIL;
    end;
    GET_DCS_CODE: begin
      // Not available
      MsgToShow := Format(REMCMDNOTAVA,[sCmd]);
      HamlibResult := RIG_ENAVAIL;
    end;
    SET_CTCSS_SQL: begin
      // Not available
      MsgToShow := Format(REMCMDNOTAVA,[sCmd]);
      HamlibResult := RIG_ENAVAIL;
    end;
    GET_CTCSS_SQL: begin
      // Not available
      MsgToShow := Format(REMCMDNOTAVA,[sCmd]);
      HamlibResult := RIG_ENAVAIL;
    end;
    SET_DCS_SQL: begin
      // Not available
      MsgToShow := Format(REMCMDNOTAVA,[sCmd]);
      HamlibResult := RIG_ENAVAIL;
    end;
    GET_DCS_SQL: begin
      // Not available
      MsgToShow := Format(REMCMDNOTAVA,[sCmd]);
      HamlibResult := RIG_ENAVAIL;
    end;
    SET_TS: begin
      // TRP8000 supports 10Hz, 100Hz and 1kHz tune steps plus a programmable one.
      // TBD if some program *needs* it
      MsgToShow := Format(REMCMDNOTIMP,[sCmd]);
      HamlibResult := RIG_ENIMPL;
    end;
    GET_TS: begin
      // TBD in a complete way if some program *needs* it
      SendNetMsg(IntToStr(RTXState.Freq_step), MySocket);
    end;
    SET_FUNC: begin
      // Check for other command running
      if not In_Command then begin
        In_Command := TRUE;
        // To be completed with all applicable functions
        for ParamNum := 1 to ord(LASTFUNCTION) do begin
          if sParam1=HamlibFunctions[ParamNum].FunctionName then begin
            Functn := HamlibFunctions[ParamNum].FunctionCode;
            break;
          end;
        end;

        // Handle requested function
        case Functn of
          MUTE: begin
            In_Command := TRUE;
            if sParam2<>'0' then begin
              Success := TRP.SendCommand(Speaker_Off,'');
              if Success then RTXState.Speaker_Enabled := FALSE;
            end else begin
              Success := TRP.SendCommand(Speaker_On,'');
              if Success then RTXState.Speaker_Enabled := TRUE;
            end;
           In_Command := FALSE;
           if Success then
             HamlibResult := RIG_OK
           else
             HamlibResult := RIG_BUSERROR;
          end;
          FSQL: begin
            In_Command := TRUE;
            if sParam2<>'0' then begin
              Success := TRP.SendCommand(Squelch_On,'');
              if Success then RTXState.Squelch_Enabled := TRUE;
            end else begin
              Success := TRP.SendCommand(Squelch_Off,'');
              if Success then RTXState.Squelch_Enabled := FALSE;
            end;
            if Success then
              HamlibResult := RIG_OK
            else
              HamlibResult := RIG_BUSERROR;
            In_Command := FALSE;
          end;
        end;
        PanelUpdateRequired := TRUE;
        In_Command := FALSE;
      end else HamLibResult := RIG_BUSBUSY;
    end;
    GET_FUNC: begin
      // To be completed with all applicable functions
      for ParamNum := 1 to ord(LASTFUNCTION) do begin
        if sParam1=HamlibFunctions[ParamNum].FunctionName then begin
          Functn := HamlibFunctions[ParamNum].FunctionCode;
          break;
        end;
      end;

      case Functn of
        MUTE: begin
          if RTXState.Speaker_Enabled then
            SendNetMsg('0',MySocket)
          else
            SendNetMsg('1',MySocket);
        end;
        FSQL: begin
          if RTXState.Squelch_Enabled then
            SendNetMsg('1',MySocket)
          else
            SendNetMsg('0',MySocket)
        end;
      end;
    end;
    SET_LEVEL: begin
      // To be completed with all applicable levels
     for ParamNum := 1 to ord(LASTLEVEL) do begin
       if sParam1=HamlibLevels[ParamNum].LevelName then begin
         Level := HamlibLevels[ParamNum].LevelCode;
         break;
       end;
     end ;

     // Handle requested level
     case Level of
       AGC: begin
         Success := TRUE;
         case StrToInt(sParam2) of
           0: begin
             Success := Success and TRP.SendCommand(AGC_Off,'');
             if Success then RTXState.AGC := AVC_OFF;
           end;
           1,2: begin
             Success := Success and TRP.SendCommand(AGC_Fast,'');
             if Success then begin
               RTXState.AGC := AVC_FAST;
               Last_AGC := AVC_FAST;
             end;
           end;
           3: begin
             Success := Success and TRP.SendCommand(AGC_Slow,'');
             if Success then begin
               RTXState.AGC := AVC_SLOW;
               Last_AGC := AVC_SLOW;
             end;
           end;
           otherwise
             Success := Success and TRP.SendCommand(AGC_On,'');
         end;
         if Success then begin
           if RTXState.AGC = AVC_OFF then RTXState.AGC := Last_AGC;
           HamlibResult := RIG_OK;
         end else
           HamlibResult := RIG_BUSERROR;
         In_Command := FALSE;
       end;
       ATT: begin
         if sParam2<>'0' then begin
           if TRP.SendCommand(Attenuator_On,'') then begin
             RTXState.RFAtt_Enabled := TRUE;
             Success := TRUE;
           end else
             Success := FALSE;
         end else begin
           if TRP.SendCommand(Attenuator_Off,'') then begin
             RTXState.RFAtt_Enabled := FALSE;
             HamlibResult := RIG_OK;
             Success := TRUE;
           end else
             Success := FALSE;
         end;
       end;
       PREAMP: begin
         if sParam2<>'0' then begin
           if TRP.SendCommand(Preamp_On,'') then begin
             RTXState.RFamp_Enabled := TRUE;
             Success := TRUE;
           end else
             Success := FALSE;
         end else begin
           if TRP.SendCommand(Preamp_Off,'') then begin
             RTXState.RFAtt_Enabled := FALSE;
             Success := TRUE;
           end else
             Success := FALSE;
         end;
       end;
       RFPOWER: begin
         pwr01 := StrToFloat(sParam2);
         ipwr := trunc(250.0*pwr01);
         In_Command := TRUE;
         case ipwr of
           0..10: begin
             Success := TRP.SendCommand(TX_LowPwr,'');
             if Success then RTXstate.TX_power := LOW_POWER;
           end;
           11..60: begin
             Success := TRP.SendCommand(TX_MediumPwr,'');
             if Success then RTXstate.TX_power := MEDIUM_POWER;
           end;
            61..250: begin
             Success := TRP.SendCommand(TX_HighPwr,'');
             if Success then RTXstate.TX_power := FULL_POWER;
           end;
           otherwise Success := FALSE;
         end;
         In_Command := FALSE;
         if Success then
           HamlibResult := RIG_OK
         else
           HamlibResult := RIG_BUSERROR;
       end;
       AF: begin
         RTXState.Volume := 99 - Round(99.0*StrToFloat(sParam2));
         In_Command := TRUE;
         TRP.SendCommand(AF_GAINSET, IntToStr(RTXState.Volume)+stCR);
         In_Command := FALSE;
         HamLibResult := RIG_OK;
       end;
       LRF: begin
         // There is no command to directly set sensitivity, so when requested
         // to do that, first set to minimum sensitivity, then go to required level.
         // Works, but it is *very* slow. Better to not use it.
         if not In_Command then begin
           In_Command := TRUE;
           if TRP.SendCommand(Agc_Off,'') then begin // RF Gain control requires AGC OFF
             RTXState.AGC := AVC_OFF;
             iRFLev := trunc(RFLEVSTEPS*StrToFloat(sParam2));
             // Set to minimum sensitivity
             for i := 0 to RFLEVSTEPS do
               TRP.SendCommand(Sensitivity_Dn,'');
             // Go to required level
             for i := 0 to iRFLev do
               TRP.SendCommand(Sensitivity_Up,'');
             RTXState.Sensitivity := iRFLev;
             In_Command := FALSE;
             HamLibResult := RIG_OK;
           end else HamLibResult := RIG_BUSERROR;
         end else HamLibResult := RIG_BUSBUSY;
       end;
       LASTLEVEL: HamlibResult := RIG_EINVAL;
     end;
     PanelUpdateRequired := TRUE;
     In_Command := FALSE;
    end;
    GET_LEVEL: begin
      // To be completed with all applicable levels
      for ParamNum := 1 to ord(LASTLEVEL) do begin
        if sParam1=HamlibLevels[ParamNum].LevelName then begin
          Level := HamlibLevels[ParamNum].LevelCode;
          break;
        end;
      end;

      // Handle requested level
      case Level of
        AGC: begin
          case RTXstate.AGC of
            AVC_OFF: SendNetMsg('0',MySocket);
            AVC_FAST: SendNetMsg('2',MySocket);
            AVC_SLOW: SendNetMsg('3',MySocket);
          end;
        end;
        ATT: begin
          if RTXState.RFAtt_Enabled then
            SendNetMsg('20',MySocket)
          else
            SendNetMsg('0',MySocket);
        end;
        PREAMP: begin
          if RTXstate.RFamp_Enabled then
            SendNetMsg('10',MySocket)
          else
            SendNetMsg('0',MySocket);
        end;
        STRENGTH: begin
          dBS9 := 10*(s-15);  // 15 leds=S9=0dBS9, 20 leds=s9+50=50dBS9
          SendNetMsg(IntToStr(dBS9),MySocket);
        end;
        RFPOWER: begin
          case RTXstate.TX_power of
            FULL_POWER: SendNetMsg('1.0',MySocket);
            MEDIUM_POWER: SendNetMsg('0.24',MySocket);
            LOW_POWER: SendNetMsg('0.1',MySocket);
          end;
        end;
        AF: begin
          sTmp := FormatFloat('#.##',1-RTXState.Volume/99.0);
          SendNetMsg(sTmp, MySocket);
        end;
        LRF: begin
          SendNetMsg(FloatToStr(real(RTXState.Sensitivity)/real(RFLEVSTEPS)),MySocket);
        end;
        LASTLEVEL: HamlibResult := RIG_EINVAL;
      end;
    end;
    SET_PARM: begin
      // TBD if some program *needs* it
      MsgToShow := Format(REMCMDNOTIMP,[sCmd]);
      HamlibResult := RIG_ENIMPL;
    end;
    GET_PARM: begin
      // TBD if some program *needs* it
      MsgToShow := Format(REMCMDNOTIMP,[sCmd]);
      HamlibResult := RIG_ENIMPL;
    end;
    SET_BANK: begin
      // Not available
      MsgToShow := Format(REMCMDNOTAVA,[sCmd]);
      HamlibResult := RIG_ENAVAIL;
    end;
    SET_MEM: begin
      // TBD if some program *needs* it
      MsgToShow := Format(REMCMDNOTIMP,[sCmd]);
      HamlibResult := RIG_ENAVAIL;
    end;
    GET_MEM: begin
      // TBD if some program *needs* it
      MsgToShow := Format(REMCMDNOTIMP,[sCmd]);
      HamlibResult := RIG_ENIMPL;
    end;
    VFO_OP: begin
      // TBD for ops supported, if any, and if *needed* by some program
      MsgToShow := Format(REMCMDNOTIMP,[sCmd]);
      HamlibResult := RIG_ENIMPL;
    end;
    SCAN: begin
      // TBD if some program *needs* it
      MsgToShow := Format(REMCMDNOTIMP,[sCmd]);
      HamlibResult := RIG_ENIMPL;
    end;
    SET_CHANNEL: begin
      // TBD if some program *needs* it
      MsgToShow := Format(REMCMDNOTIMP,[sCmd]);
      HamlibResult := RIG_ENIMPL;
    end;
    GET_CHANNEL: begin
      // TBD if some program *needs* it
      MsgToShow := Format(REMCMDNOTIMP,[sCmd]);
      HamlibResult := RIG_ENIMPL;
    end;
    SET_TRN: begin
      // Not available (?)
      MsgToShow := Format(REMCMDNOTAVA,[sCmd]);
      HamlibResult := RIG_ENAVAIL;
    end;
    GET_TRN: begin
      // Not available (?)
      MsgToShow := Format(REMCMDNOTAVA,[sCmd]);
      HamlibResult := RIG_ENAVAIL;
    end;
    RESET: begin
      // TBD if some program *needs* it
      MsgToShow := Format(REMCMDNOTIMP,[sCmd]);
      HamlibResult := RIG_ENIMPL;
    end;
    SET_POWERSTAT: begin
      // Not available
      MsgToShow := Format(REMCMDNOTAVA,[sCmd]);
      HamlibResult := RIG_ENAVAIL;
    end;
    GET_POWERSTAT: begin
      // wsjtx 2.7.0-rc6 use this command. Reply always 1 (=power on)
      SendNetMsg('1',MySocket);
    end;
    SEND_DTMF: begin
      // Not available
      MsgToShow := Format(REMCMDNOTAVA,[sCmd]);
      HamlibResult := RIG_ENAVAIL;
    end;
    RECV_DTMF: begin
      // Not available
      MsgToShow := Format(REMCMDNOTAVA,[sCmd]);
      HamlibResult := RIG_ENAVAIL;
    end;
    GET_INFO: begin
      // TBD if some program *needs* it
      MsgToShow := Format(REMCMDNOTIMP,[sCmd]);
      HamlibResult := RIG_ENIMPL;
    end;
    GET_RIG_INFO: begin
      // TBD if some program *needs* it
      MsgToShow := Format(REMCMDNOTIMP,[sCmd]);
      HamlibResult := RIG_ENIMPL;
    end;
    GET_VFO_INFO: begin
      // TBD if some program *needs* it
      MsgToShow := Format(REMCMDNOTIMP,[sCmd]);
      HamlibResult := RIG_ENIMPL;
    end;
    DUMP_STATE: begin
      // TBD in the correct way - See UState.pas
{$IFDEF SENDDONE}
      LineNum := -1;
      repeat
        LineNum := Linenum + 1;
        SendNetMsg(TRP8255_State[LineNum],MySocket);
      until TRP8255_State[LineNum]='done';
{$ELSE}
LineNum := 0;
repeat
  SendNetMsg(TRP8255_State[LineNum],MySocket);
  LineNum := Linenum + 1;
until TRP8255_State[LineNum]='done';
{$ENDIF}
    end;
    DUMP_CAPS: begin
      // TBD if required by some program (none found yet)
      MsgToShow := Format(REMCMDNOTIMP,[sCmd]);
      HamlibResult := RIG_ENIMPL;
    end;
    POWER2MW: begin
      // To be completed
      ipwr := Trunc(250.0*StrToFloat(sParam1));
      case ipwr of
        0..10: SendNetMsg('10000',MySocket);
        11..60: SendNetMsg('60000',MySocket);
        otherwise SendNetMsg('250000',MySocket);
      end;
    end;
    MW2POWER: begin
      // To be completed
      pwr01:= real(StrToInt(sParam1)) / 250000.0 ;
      SendNetMsg(Format('%1.1f',[pwr01]),MySocket);
    end;
    SET_CLOCK: begin
      // Check for other command running
      if not In_Command then begin
        In_Command := TRUE;
        // TRP8000 has a RTC (only time available)
        // so only HH:MM in the parameter is used. See rigctld man page.
        p := pos(':', sparam1);
        if p > 0 then begin
          sTmp := Copy(sParam1,p-2,2)+Copy(sParam1,p+1,2);
          if TRP.SendCommand(Set_Time, sTmp+stCR) then
            HamlibResult := RIG_OK
          else
            HamlibResult := RIG_BUSBUSY;
          In_Command := FALSE;
        end else
          HamlibResult := RIG_EINVAL;
        In_Command := FALSE;
      end else HamLibResult := RIG_BUSBUSY;
    end;
    GET_CLOCK: begin
      // TRP8000 has a RTC but it is not readable from remote
      MsgToShow := Format(REMCMDNOTAVA,[sCmd]);
      HamlibResult := RIG_ENAVAIL;
    end;
    CHK_VFO: begin
      // Required by WSJTX and other programs
      // Only Mode 0 at present is handled
      SendNetMsg(IntToStr(VFOMode),MySocket);
    end;
    SET_VFO_OPT: begin
      // TDB if any and if it is *needed* by some program
      MsgToShow := Format(REMCMDNOTIMP,[sCmd]);
      HamlibResult := RIG_ENIMPL;
    end;
    QUIT: begin
      SendNetMsg(RPRT_OK,MySocket);
      MySocket.Disconnect(FALSE);
      PanelUpdateRequired := TRUE;
    end;
    SET_LOCK_MODE: begin
      if sParam1[1] in ['0'..'9'] then begin
        Lock_Mode := StrToInt(sParam1[1]);
        HamlibResult := RIG_OK;
      end else HamLibResult := RIG_EINVAL;
    end;
    GET_LOCK_MODE: begin
      SendNetMsg(IntToStr(Lock_Mode), MySocket);
      {$IFDEF SENDRPRT0}
      HamlibResult := RIG_OK;     // Required. Don't know why.
      {$ENDIF}
    end;
    otherwise begin
      // command not recognized
      MsgToShow := Format(REMCMDNOTREC,[sCmd]);
      HamlibResult := RIG_EINVAL;
    end;
  end;
  if HamlibResult <> NOTREQUIRED then
    SendNetMsg(RPRT+IntToStr(-Ord(HamlibResult)),MySocket);
end;

end.

