unit HamlibComponents;

interface

uses
  SysUtils, Types, Classes, QGraphics, QControls, QForms, QDialogs,
  hamlib_rigapi, hamlib_rotapi;


type
  TFrequencyEvent = procedure(Sender: TObject; vfo: vfo_t; Freq: freq_t) of object;
  TVfoEvent = procedure(Sender: TObject; vfo: vfo_t) of object;
  TModeEvent = procedure(Sender: TObject; vfo: vfo_t; mode: rmode_t) of object;

  TRigComponent = class(TComponent)
  private
    { Private declarations }
    FRig: PRig;
    FOnFrequency: TFrequencyEvent;
    FOnVfo : TVfoEvent;
    FOnMode : TModeEvent;
    function GetModel: integer;
    function GetModelName: string;
    function GetMfgName: string;
    function GetTrn: integer;
    procedure SetTrn(Value: integer);
  protected
    { Protected declarations }
  public
    { Public declarations }
    constructor Create(AOwner: TComponent); override;
    constructor CreateRig(AOwner: TComponent; AModel: integer);
    destructor Destroy; override;

    procedure OpenRig;
    procedure CloseRig;

    procedure SetTransceive(trn: integer);
    function GetFreq(vfo: vfo_t): freq_t;
    procedure SetFreq(vfo: vfo_t; freq: freq_t);

    function checkMagic: boolean;
  published
    { Published declarations }
    property Model: integer read GetModel;
    property ModelName: string read GetModelName;
    property MfgName: string read GetMfgName;

    property Transceive: integer read GetTrn write SetTrn default RIG_TRN_OFF;

    property OnFrequency: TFrequencyEvent read FOnFrequency write FOnFrequency;
    property OnVFO: TVfoEvent read FOnVfo write FOnVfo;
    property OnMode: TModeEvent read FOnMode write FOnMode;
  end;

type
  TRotatorComponent = class(TComponent)
  private
    { Private declarations }
    FRot: PRot;
    procedure SetMinAzim(const Value: float);
    procedure SetMaxAzim(const Value: float);
    procedure SetMinElev(const Value: float);
    procedure SetMaxElev(const Value: float);
    function GetMinAzim: float;
    function GetMaxAzim: float;
    function GetMinElev: float;
    function GetMaxElev: float;
    function GetModel: integer;
  protected
    { Protected declarations }
  public
    { Public declarations }
    constructor Create(AOwner : TComponent); override;
    constructor CreateRotator(AOwner : TComponent; AModel : Integer);
    destructor Destroy; override;

    procedure OpenRotator;
    procedure CloseRotator;

    procedure GetPosition(var Az: azimuth_t; var El: elevation_t);
    procedure SetPosition(var Az: azimuth_t; var El: elevation_t);
    procedure Stop;
    procedure Park;
    procedure Reset;

  published
    { Published declarations }
    property Model: integer read GetModel;
    property MinAzimuth: float read GetMinAzim write SetMinAzim;
    property MaxAzimuth: float read GetMaxAzim write SetMaxAzim;
    property MinElevation: float read GetMinElev write SetMinElev;
    property MaxElevation: float read GetMaxElev write SetMaxElev;
  end;

type
  ERigException = class(Exception);
  ERotatorException = class(Exception);

procedure Register;

implementation

procedure Register;
begin
  RegisterComponents('User', [TRigComponent, TRotatorComponent]);
end;

constructor TRotatorComponent.Create(AOwner: TComponent);
begin
    CreateRotator(AOwner, 1);
end;

constructor TRotatorComponent.CreateRotator(AOwner: TComponent; AModel: rot_model_t);
begin
    inherited Create(AOwner);

    {* Initialize the library for the specified model *}
    FRot := rot_init(AModel);
    if (FRot = nil)
    then raise ERotatorException.Create('Rig initialization error');

    with FRot^ do
        begin
        state.obj := Self; { Pointer back to TRotatorComponent }
        //callbacks.position_event := @position_callback; // TODO: have to implement this
        end;
end;

destructor TRotatorComponent.Destroy;
begin
    rot_cleanup(FRot);
    FRot := nil;
    inherited Destroy;
end;

procedure TRotatorComponent.OpenRotator;
var
    retval: integer;
begin
    retval := rot_open(FRot);
    if (retval <> RIG_OK)
    then raise ERotatorException.Create('rot_open: ' + StrPas(rigerror(retval)));
end;

procedure TRotatorComponent.CloseRotator;
var
    retval: integer;
begin
    retval := rot_close(FRot);
    if (retval <> RIG_OK)
    then raise ERotatorException.Create('rot_close: ' + StrPas(rigerror(retval)));
end;

procedure TRotatorComponent.GetPosition;
var
    retval: integer;
begin
    retval := rot_get_position(FRot, az, el);
    if (retval <> RIG_OK)
    then raise ERotatorException.Create('rot_get_position: ' + StrPas(rigerror(retval)));
end;

procedure TRotatorComponent.SetPosition;
var
    retval: integer;
begin
    retval := rot_set_position(FRot, az, el);
    if (retval <> RIG_OK)
    then raise ERotatorException.Create('rot_set_position: ' + StrPas(rigerror(retval)));
end;

procedure TRotatorComponent.Stop;
var
    retval: integer;
begin
    retval := rot_stop(FRot);
    if (retval <> RIG_OK)
    then raise ERotatorException.Create('rot_stop: ' + StrPas(rigerror(retval)));
end;

procedure TRotatorComponent.Park;
var
    retval: integer;
begin
    retval := rot_park(FRot);
    if (retval <> RIG_OK)
    then raise ERotatorException.Create('rot_park: ' + StrPas(rigerror(retval)));
end;

procedure TRotatorComponent.Reset;
var
    retval: integer;
begin
    retval := rot_reset(FRot, 0);
    if (retval <> RIG_OK)
    then raise ERotatorException.Create('rot_reset: ' + StrPas(rigerror(retval)));
end;

function TRotatorComponent.GetModel: integer;
begin
    with FRot^ do
        result := Caps^.rot_model;
end;

function TRotatorComponent.GetMinAzim: float;
begin
    with FRot^ do
        result := State.min_az;
end;

function TRotatorComponent.GetMaxAzim: float;
begin
    with FRot^ do
        result := State.max_az;
end;

function TRotatorComponent.GetMinElev: float;
begin
    with FRot^ do
        result := State.min_el;
end;

function TRotatorComponent.GetMaxElev: float;
begin
    with FRot^ do
        result := State.max_el;
end;

procedure TRotatorComponent.SetMinAzim(const Value: float);
begin
    with FRot^ do
        State.min_az := Value;
end;

procedure TRotatorComponent.SetMaxAzim(const Value: float);
begin
    with FRot^ do
        State.max_az := Value;
end;

procedure TRotatorComponent.SetMinElev(const Value: float);
begin
    with FRot^ do
        State.min_el := Value;
end;

procedure TRotatorComponent.SetMaxElev(const Value: float);
begin
    with FRot^ do
        State.max_el := Value;
end;

(*
 *
 *
 *
 *
 *
 *
 *
 *
 * TRigComponent
 *
 *)

function freq_callback(rig: PRig; vfo: vfo_t; freq: freq_t): integer; cdecl;
var
    component: TRigComponent;
begin
    rig_debug(RIG_DEBUG_TRACE, 'Inside the callback: freq_callback...'+chr($a));
    component := rig^.state.obj;
    with component do
        begin
        if Assigned(FOnFrequency)
        then FOnFrequency(component, vfo, freq);
        end;
    result := 1;
end;

{* These callback still have to be implemented 
 *
function mode_callback(rig: PRig; vfo: vfo_t; mode: rmode; width: pbwidth_t): integer; cdecl;
function vfo_callback(rig: PRig; vfo: vfo_t; freq_t: freq_t): integer; cdecl;
function ptt_callback(rig: PRig; mode: ptt_t): integer; cdecl;
function dcd_callback(rig: PRig; mode: dcd_t): integer; cdecl;
 *
 *}

constructor TRigComponent.CreateRig(AOwner: TComponent; AModel: integer);
begin
    inherited Create(AOwner);

    {* Initialize the library for the specified model *}
    FRig := rig_init(AModel);
    if (FRig = nil)
    then raise ERigException.Create('Rig initialization error');

    with FRig^ do
        begin
        state.obj := Self; { Pointer back to TRigComponent }
        callbacks.freq_event := @freq_callback;
        end;
end;

constructor TRigComponent.Create(AOwner: TComponent);
begin
    CreateRig(AOwner, 1);   { Use Dummy by default }
end;


destructor TRigComponent.Destroy;
begin
    rig_cleanup(FRig);
    FRig := nil;
    inherited Destroy;
end;

{*
 * Because FRig is initialized with constructor and cleared with the
 * destructor, all methods will assume that FRig != NIL during the life
 * of the object.
 *}

procedure TRigComponent.OpenRig;
var
    retval: integer;
begin
    retval := rig_open(FRig);
    if (retval <> RIG_OK)
    then raise ERigException.Create('rig_open: ' + StrPas(rigerror(retval)));
end;

procedure TRigComponent.CloseRig;
var
    retval: integer;
begin
    retval := rig_close(FRig);
    if (retval <> RIG_OK)
    then raise ERigException.Create('rig_close: ' + StrPas(rigerror(retval)));
end;

function TRigComponent.GetModel: integer;
begin
    result := FRig^.caps^.rig_model;
end;

function TRigComponent.GetModelName: string;
begin
    result := StrPas(FRig^.caps^.model_name);
end;

function TRigComponent.GetMfgName: string;
begin
    result := StrPas(FRig^.caps^.mfg_name);
end;

function TRigComponent.GetTrn: integer;
var
    retval : integer;
    trn : integer;
begin
    retval := rig_get_trn(FRig, trn);
    if (retval <> RIG_OK)
    then raise ERigException.Create('rig_get_trn: ' + StrPas(rigerror(retval)));
    result := trn;
end;

procedure TRigComponent.SetTrn(Value: integer);
var
    retval: integer;
begin
    retval := rig_set_trn(FRig, Value);
    if (retval <> RIG_OK) and (retval <> -RIG_ENAVAIL)
    then raise ERigException.Create('rig_set_trn: ' + StrPas(rigerror(retval)));
end;

function TRigComponent.GetFreq(vfo: vfo_t): freq_t;
var
    freq: freq_t;
    retval: integer;
begin
    freq := 0;

    retval := rig_get_freq(FRig, vfo, freq);
    if (retval <> RIG_OK)
    then raise ERigException.Create('rig_get_freq: ' + StrPas(rigerror(retval)));

    result := freq;
end;

procedure TRigComponent.SetFreq(vfo: vfo_t; freq: freq_t);
var
    retval: integer;
begin
    vfo:=1;
    writeln('vfo=',vfo,' freq=',freq);
    retval := rig_set_freq(FRig, vfo, freq);
    if (retval <> RIG_OK)
    then
    begin
       writeln('Return=',retval);
       raise ERigException.Create('rig_set_freq: ' + StrPas(rigerror(retval)));
       end;
end;

procedure TRigComponent.SetTransceive(trn: integer);
var
    retval: integer;
begin
    retval := rig_set_trn(FRig, trn);
    if (retval <> RIG_OK)
    then raise ERigException.Create('rig_set_trn: ' + StrPas(rigerror(retval)));

    { Note: This will cause a SIGIO interruption.  The application will handle
            the SIGIO.  Please disable SIGIO handling in the debugger, else the
            debugger will interrupt the program.
      Menu: Tools|Debugger Options|Signals
    }
end;

function TRigComponent.checkMagic: boolean;
begin
{$IFDEF HAVE_MAGIC_NUMBERS}
    result := rigapi_check_magic(FRig) = 0;
{$ELSE}
    result := true;
{$ENDIF}
end;


end.
