// // Rig.cs // // Author: // Jae Stutzman // // Copyright (c) 2016 Jae Stutzman // // This library is free software; you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as // published by the Free Software Foundation; either version 2.1 of the // License, or (at your option) any later version. // // This library 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 // Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License along with this library; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA using System; using System.Collections.Generic; using System.Collections.Concurrent; using System.Threading; using System.Runtime.InteropServices; using HamLibSharp.Utils; using HamLibSharp.x86; using HamLibSharp.x64; namespace HamLibSharp { internal interface INativeRig { IntPtr Caps { get; } IRigStateNative State { get; } IntPtr Callbacks { get; } }; public partial class Rig : IDisposable { const int CommErrors = 10; // milliseconds const int UpdateRate = 250; const string ConfTokenDevice = "rig_pathname"; const string ConfTokenSerialSpeed = "serial_speed"; const string ConfTokenDatabits = "data_bits"; const string ConfTokenStopbits = "stop_bits"; const string ConfTokenSerialParity = "serial_parity"; const string ConfTokenSerialHandshake = "serial_handshake"; const string ConfTokenDataBits = "data_bits"; IntPtr theRig; INativeRig nativeRig; RigCaps rigCaps; public RigCaps Caps { get { return rigCaps; } } bool disposed; int errorCount; BlockingCollection taskQueue; System.Timers.Timer timer; Thread thread; int updateRate; volatile bool commErrorClose = false; public event EventHandler CommErrorClose; /// /// Gets the unique model identifier /// /// The model id. public int Model { get { return rigCaps.RigModel; } } /// /// Gets the name of the manufacturer. /// /// The name of the manufacturer. public string MfgName { get { return rigCaps.MfgName; } } /// /// Gets the name of the model. /// /// The name of the model. public string ModelName { get { return rigCaps.ModelName; } } /// /// Gets the version of the backend. /// /// The version. public string Version { get { return rigCaps.Version; } } /// /// Gets the max serial baud rate. /// /// The serial rate. public int SerialRateMax { get { return rigCaps.SerialRateMax; } } /// /// Gets the min serial baud rate. /// /// The serial rate. public int SerialRateMin { get { return rigCaps.SerialRateMin; } } /// /// Gets the current serial baud rate. /// /// The serial rate. public int SerialRate { get { if (rigOpen) { return int.Parse (GetConf (ConfTokenSerialSpeed)); } else { return 0; } } } /// /// Gets the rig path (i.e. serial port). /// /// The rig path. public string RigPath { get { if (rigOpen) { return GetConf (ConfTokenDevice); } else { return string.Empty; } } } double freq; /// /// Gets the current frequency of the rig. /// Last updated by call to UpdateFrequency(). /// /// The frequency in Hz. public double Freq { get { if (updateRate > 0) { lock (this) { return freq; } } else { return GetFrequency (); } } private set { lock (this) { freq = value; } } } long width; RigMode mode; public RigMode Mode { get { if (updateRate > 0) { lock (this) { return mode; } } else { return GetMode (ref width); } } private set { lock (this) { mode = value; } } } public string ModeText { get { return TextNameAttribute.GetTextName (Mode); } } volatile PttMode ptt; /// /// Gets the Push-To-Talk status. /// Last updated by call to UpdatePtt(). /// /// The PTT status. public PttMode Ptt { get { if (updateRate > 0) { lock (this) { return ptt; } } else { return GetPtt (); } } private set { lock (this) { ptt = value; } } } volatile string lastStatus; /// /// Gets the last status. /// /// The last status. public string LastStatus { get { lock (this) { return lastStatus; } } private set { lock (this) { lastStatus = value; } } } volatile bool rigOpen; /// /// Gets a value indicating whether this rig open. /// /// true if rig open; otherwise, false. public bool RigOpen { get { lock (this) { return rigOpen; } } private set { lock (this) { rigOpen = value; } } } public RigMode ModeList { get { return nativeRig.State.Mode_list; } } public int VfoList { get { return nativeRig.State.Vfo_list; } } /// /// Initializes a new instance of the class. /// This constructor attempts to find the correct backend based on input name. /// /// Rig model name. public Rig (string rigModel, int updateRate = UpdateRate) { this.updateRate = updateRate < UpdateRate ? UpdateRate : updateRate; if (!HamLib.Initialized) { HamLib.Initialize (); } // Look up model from name RigCaps rig; if (!HamLib.Rigs.TryGetValue (rigModel, out rig)) { throw new RigException ("Rig model not found"); } // init the underlying rig and library InitRig (rig.RigModel); } /// /// Initializes a new instance of the class. /// This constructor initializing the rig backend based on input model id. /// /// Rig model id. public Rig (int rigModel, int updateRate = UpdateRate) { this.updateRate = updateRate < UpdateRate ? UpdateRate : updateRate; if (!HamLib.Initialized) { HamLib.Initialize (); } InitRig (rigModel); } private void InitRig (int rigModel) { theRig = rig_init (rigModel); if (theRig == IntPtr.Zero) throw new RigException ("Rig initialization error"); nativeRig = MarshalNativeRig (theRig); var caps = HamLib.MarshalRigCaps (nativeRig.Caps); rigCaps = new RigCaps (caps, this); // test... //Console.WriteLine("TEST>>>>>>"); //Console.WriteLine (nativeRig.State.Itu_region); //Console.WriteLine ("HamLibPortNative: {0}", Marshal.SizeOf ()); // end test.... } internal static INativeRig MarshalNativeRig (IntPtr rig_ptr) { INativeRig rig = null; switch (HamLib.hamLibVersion) { case HamLibVersion.Current: case HamLibVersion.V301: // if the platform is 64-bit, but not windows if (!HamLib.isWindows && HamLib.bitsize64) { rig = Marshal.PtrToStructure (rig_ptr); } else { rig = Marshal.PtrToStructure (rig_ptr); } break; case HamLibVersion.V2: // if the platform is 64-bit, but not windows if (!HamLib.isWindows && HamLib.bitsize64) { rig = Marshal.PtrToStructure (rig_ptr); } else { rig = Marshal.PtrToStructure (rig_ptr); } break; default: throw new RigException ("Unknown or Incompatible HamLib library found"); } return rig; } private static int OnFrequency (IntPtr theRig, int vfo, double freq, IntPtr rig_ptr) { // Console.WriteLine (freq); return 1; } private void Dispose (bool disposing) { if (!this.disposed) { if (disposing) { // Dispose here any managed resources } if (theRig != IntPtr.Zero) { Stop (); Close (); var ret = rig_cleanup (theRig); if (ret != RigError.OK) { throw new RigException (ErrorString (ret)); } theRig = IntPtr.Zero; rigCaps = null; nativeRig = null; } } disposed = true; } /// /// Releases all resource used by the object. /// /// Call when you are finished using the . The /// method leaves the in an unusable state. After calling /// , you must release all references to the so the garbage /// collector can reclaim the memory that the was occupying. public void Dispose () { Dispose (true); GC.SuppressFinalize (this); } ~Rig () { Dispose (false); } /// /// Opens communication to a radio. If it is a serial connected rig, /// searches for the correct baud rate. /// /// Device path (i.e. serial port). public void Open (string devicePath) { if (rigCaps.PortType == RigPort.Serial) { // find the baud... var foundBaud = false; foreach (int baud in Enum.GetValues(typeof(RigSerialBaudRate))) { if (baud >= SerialRateMin && baud <= SerialRateMax) { try { SetConf (ConfTokenSerialSpeed, baud); OpenInternal (devicePath); // throws exception if IO error GetPtt (); foundBaud = true; break; } catch (RigException) { Close (); } } } if (!foundBaud) { throw new RigException ("Unable to communicate with rig"); } } else { OpenInternal (devicePath); } } /// /// Opens communication to a radio. /// /// Device path (i.e. serial port). /// baud rate of serial port. public void Open (string device, RigSerialBaudRate baud, RigSerialHandshake handshake, int databits, int stopbits) { if (rigCaps.PortType == RigPort.Serial) { SetConf (ConfTokenSerialSpeed, (int)baud); SetConf (ConfTokenSerialHandshake, TextNameAttribute.GetTextName(handshake)); SetConf (ConfTokenDatabits, databits); SetConf (ConfTokenStopbits, stopbits); OpenInternal (device); } else { throw new RigException (string.Format ("Device is not serial, but {0}", rigCaps.PortType)); } } /// /// Open communication to a radio /// public void Open () { OpenInternal (null); } private void OpenInternal (string device) { if (device != null && device != string.Empty) { SetConf (ConfTokenDevice, device); } var ret = rig_open (theRig); if (ret != RigError.OK) { throw new RigException (ErrorString (ret)); } rigOpen = true; // untested since I don't have a rig that supports this ret = rig_set_freq_callback (theRig, OnFrequency, IntPtr.Zero); if (ret != RigError.OK) { LastStatus = ErrorString (ret); throw new RigException (ErrorString (ret)); } } /// /// Closes communication to a radio that was previously open with Open(). /// public void Close () { if (rigOpen) { var ret = rig_close (theRig); if (ret != RigError.OK) { LastStatus = ErrorString (ret); throw new RigException (ErrorString (ret)); } Freq = 0; rigOpen = false; } } /// /// Start will create a timer and a thread to manage the invocation /// of calls to the rig. This is useful when an application cannot /// block on rig calls. If Start is not called, each call is /// called syncronously. /// The timer will begin calling UpdateFrequency() and UpdatePtt() /// to update the state properties on a periodic basis. /// public void Start () { commErrorClose = false; errorCount = 0; taskQueue = new BlockingCollection (); lock (this) { try { Freq = GetFrequency (RigVfo.Current); } catch (RigException ex) { LastStatus = ex.Message; Freq = 0; } } if (updateRate > 0) { timer = new System.Timers.Timer (updateRate); timer.AutoReset = false; timer.Elapsed += Timer_Elapsed; timer.Enabled = true; timer.Start (); } thread = new Thread (TaskThread); thread.Start (); } void Timer_Elapsed (object sender, System.Timers.ElapsedEventArgs e) { //logger.Debug ("Timer elapsed, Id: {0}", System.Threading.Thread.CurrentThread.ManagedThreadId); if (commErrorClose) { Stop (); Close (); if (CommErrorClose != null) { CommErrorClose (this, new EventArgs ()); } } else { UpdateFrequency (RigVfo.Current); UpdateMode (RigVfo.Current); UpdatePtt (RigVfo.Current); timer.Enabled = true; } } /// /// Stop the thread and timer that was started by the /// call to Start(). /// public void Stop () { if (timer != null) { timer.Dispose (); timer = null; } if (taskQueue != null) { // this will cause thread to exit by throwing InvalidOperationException taskQueue.CompleteAdding (); // wait for taskQueue thread to exit thread.Join (); thread = null; } } private void TaskThread () { var running = true; while (running) { try { taskQueue.Take ().Invoke (); errorCount = 0; LastStatus = string.Empty; } catch (InvalidOperationException) { running = false; taskQueue = null; } catch (RigException e) { LastStatus = e.Message; errorCount++; } if (errorCount > CommErrors) { commErrorClose = true; } } } /// /// Sets a radio configuration parameter. /// /// Parameter Token. /// Value to set. public void SetConf (int token, string val) { var ret = rig_set_conf (theRig, token, val); if (ret != RigError.OK) { throw new RigException (ErrorString (ret)); } } /// /// Sets a radio configuration parameter. /// /// Parameter Token. /// Value to set. public void SetConf (int token, int val) { var ret = rig_set_conf (theRig, token, val.ToString ()); if (ret != RigError.OK) { throw new RigException (ErrorString (ret)); } } /// /// Sets a radio configuration parameter. /// /// Name of parameter. /// Value to set. public void SetConf (string name, string val) { var ret = rig_set_conf (theRig, TokenLookup (name), val); if (ret != RigError.OK) { throw new RigException (ErrorString (ret)); } } /// /// Sets a radio configuration parameter. /// /// Name of parameter. /// Value to set. public void SetConf (string name, int val) { var ret = rig_set_conf (theRig, TokenLookup (name), val.ToString ()); if (ret != RigError.OK) { throw new RigException (ErrorString (ret)); } } /// /// Retrieves the value of a configuration parameter associated with token. /// /// The configuration parameter. /// Parameter Token. public string GetConf (int token) { string val; var ret = rig_get_conf (theRig, token, out val); if (ret != RigError.OK) { throw new RigException (ErrorString (ret)); } return val; } /// /// Retrieves the value of a configuration parameter associated with token. /// /// The configuration parameter. /// Name of parameter. public string GetConf (string name) { string val; var ret = rig_get_conf (theRig, TokenLookup (name), out val); if (ret != RigError.OK) { throw new RigException (ErrorString (ret)); } return val; } /// /// Simple lookup returning token id assicated with name. /// /// The token ID /// The name of the configuration parameter. public int TokenLookup (string name) { return rig_token_lookup (theRig, name); } /// /// Sets the frequency of the target VFO /// /// Frequency in Hz. /// The target VFO. public void SetFrequency (double freq, int vfo = RigVfo.Current) { if (thread != null) { taskQueue.Add (() => setfreq (vfo, freq)); } else { setfreq (vfo, freq); } } private void setfreq (int vfo, double freq) { var ret = rig_set_freq (theRig, vfo, freq); if (ret != RigError.OK) { throw new RigException (ErrorString (ret)); } } /// /// Retrieves the updated frequency from the targeted VFO. /// Will use Task Queue if Start() has been called. /// /// The target VFO. public void UpdateFrequency (int vfo = RigVfo.Current) { if (thread != null) { taskQueue.Add (() => Freq = GetFrequency (vfo)); } else { Freq = GetFrequency (vfo); } } /// /// Retrieves the updated frequency from the targeted VFO. /// Blocks until data received. /// /// The frequency in Hz. /// The target VFO. public double GetFrequency (int vfo = RigVfo.Current) { double freq; var ret = rig_get_freq (theRig, vfo, out freq); if (ret != RigError.OK) { throw new RigException (ErrorString (ret)); } return freq; } /// /// Sets the mode and associated passband of the target VFO. /// The passband width must be supported by the backend of the rig. /// /// The mode to set to. /// The passband width to set to. /// The target VFO. public void SetMode (RigMode mode, long width, int vfo = RigVfo.Current) { if (thread != null) { taskQueue.Add (() => setmode (mode, width, vfo)); } else { setmode (mode, width, vfo); } } private void setmode (RigMode mode, long width, int vfo = RigVfo.Current) { var ret = rig_set_mode (theRig, vfo, mode, width); if (ret != RigError.OK) { throw new RigException (ErrorString (ret)); } } /// /// Retrieves the updated mode and passband of the target VFO. /// Will use Task Queue if Start() has been called. /// /// The target VFO. public void UpdateMode (int vfo = RigVfo.Current) { if (thread != null) { taskQueue.Add (() => Mode = GetMode(ref width, vfo)); } else { Mode = GetMode(ref width, vfo); } } /// /// Retrieves the mode and passband of the target VFO. If the backend is /// unable to determine the width, the width will be set to RIG_PASSBAND_NORMAL /// as a default. The value stored at mode location equals RIG_MODE_NONE when /// the current mode of the VFO is not defined (e.g. blank memory). /// /// The current mode. /// The target VFO. /// Retrieves the current passband width. public RigMode GetMode (ref long width, int vfo = RigVfo.Current) { RigMode mode; var ret = rig_get_mode (theRig, vfo, out mode, out width); if (ret != RigError.OK) { throw new RigException (ErrorString (ret)); } return mode; } /// /// Sets the current VFO. The VFO can be RIG_VFO_A, RIG_VFO_B, RIG_VFO_C /// for VFOA, VFOB, VFOC respectively or RIG_VFO_MEM for Memory mode. /// Supported VFOs depends on rig capabilities. /// /// The target VFO. public void SetVFO (int vfo = RigVfo.Current) { var ret = rig_set_vfo (theRig, vfo); if (ret != RigError.OK) { throw new RigException (ErrorString (ret)); } } /// /// Retrieves the current VFO. The VFO can be RIG_VFO_A, RIG_VFO_B, /// RIG_VFO_C for VFOA, VFOB, VFOC respectively or RIG_VFO_MEM for /// Memory mode. Supported VFOs depends on rig capabilities. /// /// The current VFO. public int GetVFO () { int vfo; var ret = rig_get_vfo (theRig, out vfo); if (ret != RigError.OK) { throw new RigException (ErrorString (ret)); } return vfo; } /// /// Sets "Push-To-Talk" on/off. /// /// The PTT status to set to. /// The target VFO. public void SetPtt (PttMode ptt, int vfo = RigVfo.Current) { if (thread != null) { taskQueue.Add (() => SetPttInternal (ptt, vfo)); } else { SetPttInternal (ptt, vfo); } } private void SetPttInternal (PttMode ptt, int vfo) { var ret = rig_set_ptt (theRig, vfo, ptt); if (ret != RigError.OK) { throw new RigException (ErrorString (ret)); } } /// /// Updates the Ptt property /// /// The target VFO. public void UpdatePtt (int vfo = RigVfo.Current) { if (thread != null) { taskQueue.Add (() => Ptt = GetPtt (vfo)); } else { Ptt = GetPtt (vfo); } } /// /// Returns PttMode /// /// The ptt. /// The target VFO. public PttMode GetPtt (int vfo = RigVfo.Current) { PttMode ptt; var ret = rig_get_ptt (theRig, vfo, out ptt); if (ret != RigError.OK) { throw new RigException (ErrorString (ret)); } return ptt; } /// /// Retrieves the status of DCD (is squelch open?). /// /// The status of the DCD. /// The target VFO. public DcdState GetDCD (int vfo = RigVfo.Current) { DcdState dcd; var ret = rig_get_dcd (theRig, vfo, out dcd); if (ret != RigError.OK) { throw new RigException (ErrorString (ret)); } return dcd; } /// /// Sets the level of a setting. The level value val can be a float or an integer. /// /// The level setting. /// The value to set the level setting to. /// The target VFO. public void SetLevel (RigLevel level, int val, int vfo = RigVfo.Current) { var ret = rig_set_level (theRig, vfo, (uint)level, val); if (ret != RigError.OK) { throw new RigException (ErrorString (ret)); } } /// /// Sets the level of a setting. The level value val can be a float or an integer. /// /// The level setting. /// The value to set the level setting to. /// The target VFO. public void SetLevel (RigLevel level, float val, int vfo = RigVfo.Current) { var ret = rig_set_level (theRig, vfo, (uint)level, val); if (ret != RigError.OK) { throw new RigException (ErrorString (ret)); } } private bool LevelIsFloat (RigLevel level) { return level == (level & (RigLevel.Volume | RigLevel.RF | RigLevel.Squelch | RigLevel.AudioPeakFilter | RigLevel.NoiseReduction | RigLevel.TwinPbtIn | RigLevel.TwinPbtOut | RigLevel.RFPower | RigLevel.MicGain | RigLevel.Compressor | RigLevel.Balance | RigLevel.Swr | RigLevel.Alc | RigLevel.VoxGain | RigLevel.AntiVox)); } /// /// Retrieves the value of a level. The level value val can be a float or an integer. /// /// The level setting. /// Get the value of the level setting. /// The target VFO. public void GetLevel (RigLevel level, out int val, int vfo = RigVfo.Current) { if (LevelIsFloat (level)) throw new RigException (ErrorString (-(int)RigError.InvalidParameter)); var ret = rig_get_level (theRig, vfo, (uint)level, out val); if (ret != RigError.OK) { throw new RigException (ErrorString (ret)); } } /// /// Retrieves the value of a level. The level value val can be a float or an integer. /// /// The level setting. /// Get the value of the level setting. /// The target VFO. public void GetLevel (RigLevel level, out float val, int vfo = RigVfo.Current) { if (!LevelIsFloat (level)) throw new RigException (ErrorString (-(int)RigError.InvalidParameter)); var ret = rig_get_level (theRig, vfo, (uint)level, out val); if (ret != RigError.OK) { throw new RigException (ErrorString (ret)); } } private bool ParmIsFloat (RigParm parm) { return parm == (parm & (RigParm.Backlight | RigParm.BatteryLevel)); } /// /// Sets a parameter. The parameter value val can be a float or an integer. /// /// The parameter. /// The value to set the parameter. public void SetParm (RigParm parm, int val) { var ret = rig_set_parm (theRig, (uint)parm, val); if (ret != RigError.OK) { throw new RigException (ErrorString (ret)); } } /// /// Sets a parameter. The parameter value val can be a float or an integer. /// /// The parameter. /// The value to set the parameter. public void SetParm (RigParm parm, float val) { var ret = rig_set_parm (theRig, (uint)parm, val); if (ret != RigError.OK) { throw new RigException (ErrorString (ret)); } } /// /// Retrieves the value of a parm. The parameter value val can be a float or an integer. /// /// The parameter. /// The retrieved value. public void GetParm (RigParm parm, out int val) { if (ParmIsFloat (parm)) throw new RigException (ErrorString (-(int)RigError.InvalidParameter)); var ret = rig_get_parm (theRig, (uint)parm, out val); if (ret != RigError.OK) { throw new RigException (ErrorString (ret)); } } /// /// Retrieves the value of a parm. The parameter value val can be a float or an integer. /// /// The parameter. /// The retrieved value. public void GetParm (RigParm parm, out float val) { if (!ParmIsFloat (parm)) throw new RigException (ErrorString (-(int)RigError.InvalidParameter)); var ret = rig_get_parm (theRig, (uint)parm, out val); if (ret != RigError.OK) { throw new RigException (ErrorString (ret)); } } /// /// Sets the split(TX) frequency. /// /// Tx frequency. /// The target VFO. public void SetSplitFreq (double tx_freq, int vfo = RigVfo.Current) { var ret = rig_set_split_freq (theRig, vfo, tx_freq); if (ret != RigError.OK) { throw new RigException (ErrorString (ret)); } } /// /// Retrieves the current split(TX) frequency. /// /// The split freq. /// The target VFO. public double GetSplitFreq (int vfo = RigVfo.Current) { double tx_freq; var ret = rig_get_split_freq (theRig, vfo, out tx_freq); if (ret != RigError.OK) { throw new RigException (ErrorString (ret)); } return tx_freq; } /// /// Sets the split(TX) mode. /// /// The transmit split mode to set to. /// The transmit split width to set to. /// The target VFO. public void SetSplitMode (RigMode mode, int width, int vfo = RigVfo.Current) { var ret = rig_set_split_mode (theRig, vfo, mode, width); if (ret != RigError.OK) { throw new RigException (ErrorString (ret)); } } /// /// Retrieves the current split(TX) mode and passband. If the backend is /// unable to determine the width, the tx_width will be set to RIG_PASSBAND_NORMAL /// as a default. The value stored at tx_mode location equals RIG_MODE_NONE when /// the current mode of the VFO is not defined (e.g. blank memory). /// /// Retrieve the current split mode. /// Retrieve the current split width. /// The target VFO. public RigMode GetSplitMode (out int width, int vfo = RigVfo.Current) { RigMode mode; var ret = rig_get_split_mode (theRig, vfo, out mode, out width); if (ret != RigError.OK) { throw new RigException (ErrorString (ret)); } return mode; } /// /// Sets the current split mode. /// /// The split mode to set to. /// The target Tx VFO. /// The target Rx VFO. public void SetSplitVFO (RigSplit split, int tx_vfo, int rx_vfo = RigVfo.Current) { var ret = rig_set_split_vfo (theRig, rx_vfo, split, tx_vfo); if (ret != RigError.OK) { throw new RigException (ErrorString (ret)); } } /// /// Retrieves the current split mode. /// /// The split mode. /// Retrieves the transmit VFO. /// Rx vfo. public RigSplit GetSplitVFO (out int tx_vfo, int rx_vfo = RigVfo.Current) { RigSplit split; var ret = rig_get_split_vfo (theRig, rx_vfo, out split, out tx_vfo); if (ret != RigError.OK) { throw new RigException (ErrorString (ret)); } return split; } /// /// Checks if a rig is capable of *getting* a level setting. Since the level /// is an OR'ed bitwise argument, more than one level can be checked at the same time. /// /// true if this instance has get level the specified level; otherwise, false. /// Level. public bool HasGetLevel (uint level) { return rig_has_get_level (theRig, level) == level; } /// /// Checks if a rig can *set* a level setting. Since the level /// is an OR'ed bitwise argument, more than one level can be check at the same time. /// /// true if this instance has set level the /// specified level; otherwise, false. /// Level. public bool HasSetLevel (uint level) { return rig_has_set_level (theRig, level) == level; } /// /// Checks if a rig is capable of *getting* a parm setting. Since the /// parm is an OR'ed bitwise argument, more than one parameter can /// be checked at the same time. /// /// true if this instance has get parm the /// specified parm; otherwise, false. /// Parm. public bool HasGetParm (uint parm) { return rig_has_get_parm (theRig, parm) == parm; } /// /// Checks if a rig can *set* a parameter setting. Since the parm /// is an OR'ed bitwise argument, more than one parameter can be /// check at the same time. /// /// true if this instance has set parm the /// specified parm; otherwise, false. /// Parm. public bool HasSetParm (uint parm) { return rig_has_set_parm (theRig, parm) == parm; } /// /// Retrieves some general information from the radio. This can /// include firmware revision, exact model name, or just nothing. /// /// The info. public string GetInfo () { return RigGetInfo (theRig); } /// /// Returns the normal (default) passband for the given mode. /// /// The passband in Hz if the operation has been sucessful, or a 0 /// if an error occured /// The mode to get the passband. public int PassbandNormal (RigMode mode) { return rig_passband_normal (theRig, mode); } /// /// Returns the narrow (closest) passband for the given mode. /// EXAMPLE: SetMode(RIG_MODE_LSB, PassbandNarrow(RIG_MODE_LSB)); /// /// The passband in Hz if the operation has been sucessful, or a 0 /// if an error occured /// The mode to get the passband. public int PassbandNarrow (RigMode mode) { return rig_passband_narrow (theRig, mode); } /// /// Returns the wide (default) passband for the given mode. /// EXAMPLE: SetMode(RIG_MODE_AM, PassbandWide(RIG_MODE_AM)); /// /// The passband in Hz if the operation has been sucessful, or a 0 /// if an error occured /// The mode to get the passband. public int PassbandWide (RigMode mode) { return rig_passband_wide (theRig, mode); } /// /// Sets the current repeater shift. /// /// The repeater shift to set to. /// The target VFO. public void SetRepeaterShift (RepeaterShift rptr_shift, int vfo = RigVfo.Current) { if (thread != null) { taskQueue.Add (() => SetRepeaterShiftInternal (rptr_shift, vfo)); } else { SetRepeaterShiftInternal (rptr_shift, vfo); } } private void SetRepeaterShiftInternal (RepeaterShift rptr_shift, int vfo = RigVfo.Current) { var ret = rig_set_rptr_shift (theRig, vfo, rptr_shift); if (ret != RigError.OK) { throw new RigException (ErrorString (ret)); } } /// /// Retrieves the current repeater shift. /// /// The repeater shift. /// The target VFO. public RepeaterShift GetRepeaterShift (int vfo = RigVfo.Current) { RepeaterShift rptr_shift; var ret = rig_get_rptr_shift (theRig, vfo, out rptr_shift); if (ret != RigError.OK) { throw new RigException (ErrorString (ret)); } return rptr_shift; } /// /// Sets the current repeater offset. /// /// Repeater offset. /// The target VFO. public void SetRepeaterOffset (int rptr_offs, int vfo = RigVfo.Current) { var ret = rig_set_rptr_offs (theRig, vfo, rptr_offs); if (ret != RigError.OK) { throw new RigException (ErrorString (ret)); } } /// /// Retrieves the current repeater offset. /// /// The repeater offset. /// The target VFO. public int GetRepeaterOffset (int vfo = RigVfo.Current) { int rptr_offs; var ret = rig_get_rptr_offs (theRig, vfo, out rptr_offs); if (ret != RigError.OK) { throw new RigException (ErrorString (ret)); } return rptr_offs; } /// /// Sets the Tuning Step. /// /// Tuning step to set to. /// The target VFO. public void SetTuningStep (int ts, int vfo = RigVfo.Current) { var ret = rig_set_ts (theRig, vfo, ts); if (ret != RigError.OK) { throw new RigException (ErrorString (ret)); } } /// /// Retrieves the current tuning step. /// /// The tuning step. /// The target VFO. public int GetTuningStep (int vfo = RigVfo.Current) { int ts; var ret = rig_get_ts (theRig, vfo, out ts); if (ret != RigError.OK) { throw new RigException (ErrorString (ret)); } return ts; } /// /// Sets the current Continuous Tone Controlled Squelch /// System (CTCSS) sub-audible tone frequency. /// /// Tone to set to. /// The target VFO. public void SetCTCSS (uint tone, int vfo = RigVfo.Current) { var ret = rig_set_ctcss_tone (theRig, vfo, tone); if (ret != RigError.OK) { throw new RigException (ErrorString (ret)); } } /// /// Retrieves the current Continuous Tone Controlled Squelch /// System (CTCSS) sub-audible tone frequency. /// /// The current tone. /// The target VFO. public uint GetCTCSS (int vfo = RigVfo.Current) { uint tone; var ret = rig_get_ctcss_tone (theRig, vfo, out tone); if (ret != RigError.OK) { throw new RigException (ErrorString (ret)); } return tone; } /// /// Sets the current encoding Digitally-Coded Squelch code. /// /// The code to set to. /// The target VFO. public void SetDCS (uint code, int vfo = RigVfo.Current) { var ret = rig_set_dcs_code (theRig, vfo, code); if (ret != RigError.OK) { throw new RigException (ErrorString (ret)); } } /// /// Retrieves the current encoding Digitally-Coded Squelch code. /// /// The current code. /// The target VFO. public uint GetDCS (int vfo = RigVfo.Current) { uint code; var ret = rig_get_dcs_code (theRig, vfo, out code); if (ret != RigError.OK) { throw new RigException (ErrorString (ret)); } return code; } /// /// Sets the current Continuous Tone Controlled Squelch /// System (CTCSS) sub-audible *squelch* tone. /// Note: tone is NOT in Hz, but in tenth of Hz! This way, /// if you want to set subaudible squelch tone of 88.5 Hz for /// example, then pass 885 to this function. /// NB: the tone squelch has to be explicitly enabled or disabled /// through a call to SetFunc() with arg RIG_FUNC_TSQL, /// unless it is unavailable and the tone arg has to be set to 0. /// /// The PL tone to set the squelch to. /// The target VFO. public void SetCTCSSsql (uint tone, int vfo = RigVfo.Current) { var ret = rig_set_ctcss_sql (theRig, vfo, tone); if (ret != RigError.OK) { throw new RigException (ErrorString (ret)); } } /// /// Retrieves the current Continuous Tone Controlled Squelch /// System (CTCSS) sub-audible *squelch* tone. /// Note: tone is NOT in Hz, but in tenth of Hz! This way, /// the function returns a subaudible tone of 885 for example, /// then the real tone is 88.5 Hz. Also a value of 0 for tone /// means that the Tone Squelch is disabled. /// /// The PL squelch tone. /// The target VFO. public uint GetCTCSSsql (int vfo = RigVfo.Current) { uint tone; var ret = rig_get_ctcss_sql (theRig, vfo, out tone); if (ret != RigError.OK) { throw new RigException (ErrorString (ret)); } return tone; } /// /// Sets the current Digitally-Coded *Squelch* code. /// /// The squelch code to set to. /// The target VFO. public void SetDCSsql (uint code, int vfo = RigVfo.Current) { var ret = rig_set_dcs_sql (theRig, vfo, code); if (ret != RigError.OK) { throw new RigException (ErrorString (ret)); } } /// /// Retrieves the current Digitally-Coded *Squelch* code. /// /// The the squelch code. /// The target VFO. public uint GetDCSsql (int vfo = RigVfo.Current) { uint code; var ret = rig_get_dcs_sql (theRig, vfo, out code); if (ret != RigError.OK) { throw new RigException (ErrorString (ret)); } return code; } /// /// Activate/de-activate a function of the radio. /// The status argument is true for "activate", false for "de-activate" /// /// The functions to activate/de-activate. /// true or false /// The target VFO. public void SetFunc (uint func, bool status, int vfo = RigVfo.Current) { var ret = rig_set_func (theRig, vfo, func, status ? 1 : 0); if (ret != RigError.OK) { throw new RigException (ErrorString (ret)); } } /// /// Retrieves the status (on/off) of a function of the radio. /// /// true if function is "on", false if function is "off" /// The functions to get the status. /// The target VFO. public bool GetFunc (uint func, int vfo = RigVfo.Current) { int status; var ret = rig_get_func (theRig, vfo, func, out status); if (ret != RigError.OK) { throw new RigException (ErrorString (ret)); } return status != 0; } /// /// Performs Memory/VFO operation. /// /// VfoOperation to perform. /// The target VFO. public void VfoOP (RigVfoOperation op, int vfo = RigVfo.Current) { var ret = rig_vfo_op (theRig, vfo, op); if (ret != RigError.OK) { throw new RigException (ErrorString (ret)); } } /// /// Checks if a rig is capable of executing a VFO operation. /// Since the op is an OR'ed bitmap argument, more than one /// op can be checked at the same time. /// /// true if the rig supports the specified op; otherwise, false. /// VfoOperation to check. public bool HasVfoOP (RigVfoOperation op) { return rig_has_vfo_op (theRig, op) == op; } /// /// Performs scanning operation. /// /// The scanning operation to perform. /// Optional channel argument used for the scan. /// The target VFO. public void Scan (RigScanOperation scan, int ch, int vfo = RigVfo.Current) { var ret = rig_scan (theRig, vfo, scan, ch); if (ret != RigError.OK) { throw new RigException (ErrorString (ret)); } } /// /// Checks if a rig is capable of performing a scan operation. /// Since the scan parameter is an OR'ed bitmap argument, /// more than one op can be checked at the same time. /// /// true if the rig supports the specified op; otherwise, false. /// Scan. public bool HasScan (RigScanOperation scan) { return rig_has_scan (theRig, scan) == scan; } /// /// Sets the current RIT offset. A value of 0 for rit disables RIT. /// /// The RIT offset to adjust to. /// The target VFO. public void SetRit (int rit, int vfo = RigVfo.Current) { var ret = rig_set_rit (theRig, vfo, rit); if (ret != RigError.OK) { throw new RigException (ErrorString (ret)); } } /// /// Retrieves the current RIT offset. /// /// The current RIT offset. /// The target VFO. public int GetRit (int vfo = RigVfo.Current) { int rit; var ret = rig_get_rit (theRig, vfo, out rit); if (ret != RigError.OK) { throw new RigException (ErrorString (ret)); } return rit; } /// /// Sets the current XIT offset. A value of 0 for xit disables XIT. /// /// The XIT offset to adjust to. /// The target VFO. public void SetXit (int xit, int vfo = RigVfo.Current) { var ret = rig_set_xit (theRig, vfo, xit); if (ret != RigError.OK) { throw new RigException (ErrorString (ret)); } } /// /// Retrieves the current XIT offset. /// /// The current XIT offset. /// The target VFO. public int GetXit (int vfo = RigVfo.Current) { int xit; var ret = rig_get_xit (theRig, vfo, out xit); if (ret != RigError.OK) { throw new RigException (ErrorString (ret)); } return xit; } /// /// Select the antenna connector. /// Example: SetAntenna(RIG_ANT_1); // apply to both TX&RX /// SetAntenna(RIG_ANT_2, RIG_VFO_RX); /// /// The anntena to select. /// The target VFO. public void SetAntenna (int ant, int vfo = RigVfo.Current) { var ret = rig_set_ant (theRig, vfo, ant); if (ret != RigError.OK) { throw new RigException (ErrorString (ret)); } } /// /// Retrieves the current antenna. /// /// The current antenna selected. /// The target VFO. public int GetAntenna (int vfo = RigVfo.Current) { int ant; var ret = rig_get_ant (theRig, vfo, out ant); if (ret != RigError.OK) { throw new RigException (ErrorString (ret)); } return ant; } /// /// Sends DTMF digits. See DTMF change speed, etc. /// /// String of digits to send. /// The target VFO. public void SendDtmf (string digits, int vfo = RigVfo.Current) { var ret = rig_send_dtmf (theRig, vfo, digits); if (ret != RigError.OK) { throw new RigException (ErrorString (ret)); } } /// /// Receives DTMF digits (not blocking). See DTMF change speed, etc. /// /// The string of digits received. /// The target VFO. public string RecvDtmf (int vfo = RigVfo.Current) { string digits; var ret = rig_recv_dtmf (theRig, vfo, out digits); if (ret != RigError.OK) { throw new RigException (ErrorString (ret)); } return digits; } /// /// Sends morse message. See keyer change speed, etc. /// /// Message to send. /// The target VFO. public void SendMorse (string msg, int vfo = RigVfo.Current) { var ret = rig_send_morse (theRig, vfo, msg); if (ret != RigError.OK) { throw new RigException (ErrorString (ret)); } } /// /// Returns the best frequency resolution of the rig, for a given mode. /// /// The frequency resolution in Hertz if the operation has been sucessful. /// The mode to get the frequency resolution for. public int GetResolution (RigMode mode) { int res; res = rig_get_resolution (theRig, mode); if (res < 0) throw new RigException (ErrorString (res)); return res; } /// /// Resets the radio. See RIG_RESET_NONE, RIG_RESET_SOFT and /// RIG_RESET_MCALL defines for the reset. /// /// The reset operation to perform. void Reset (RigReset reset) { if (thread != null) { taskQueue.Add (() => rig_reset (theRig, reset)); } else { var ret = rig_reset (theRig, reset); if (ret != RigError.OK) { throw new RigException (ErrorString (ret)); } } } /// /// Checks if a rig supports a set of functions. /// Since the func is an OR'ed bitwise argument, more than one function /// can be checked at the same time. /// /// true if this rig as the ability of radio functions ; otherwise, false. /// The Functions. public bool HasGetFunc (uint func) { return rig_has_get_func (theRig, func) == func; } /// /// Checks if a rig supports a set of functions. /// Since the func is an OR'ed bitwise argument, more than one /// function can be checked at the same time. /// /// true if this instance has set func the specified func; otherwise, false. /// Func. public bool HasSetFunc (uint func) { return rig_has_set_func (theRig, func) == func; } /// /// Converts a power value expressed in a range on a [0.0 .. 1.0] relative /// scale to the real transmit power in milli Watts the radio would emit. /// The freq and mode where the conversion should take place must be also /// provided since the relative power is peculiar to a specific freq and /// mode range of the radio. /// /// The converted power in mW. /// The relative power. /// The frequency where the conversion should take place. /// The mode where the conversion should take place. public uint Power2Milliwatt (float power, double freq, RigMode mode) { uint mwpower; var ret = rig_power2mW (theRig, out mwpower, power, freq, mode); if (ret != RigError.OK) { throw new RigException (ErrorString (ret)); } return mwpower; } /// /// Converts a power value expressed in the real transmit power in milli Watts /// the radio would emit to a range on a [0.0 .. 1.0] relative scale. The freq /// and mode where the conversion should take place must be also provided since /// the relative power is peculiar to a specific freq and mode range of the radio. /// /// The converted relative power. /// The power in mW. /// The frequency where the conversion should take place. /// The mode where the conversion should take place. public float Milliwatt2power (uint mwpower, double freq, RigMode mode) { float power; var ret = rig_mW2power (theRig, out power, mwpower, freq, mode); if (ret != RigError.OK) { throw new RigException (ErrorString (ret)); } return power; } /// /// Enable/disable the transceive handling of a rig and kick off async mode. /// /// The transceive status to set to. public void SetTransceive (int trn) { var ret = rig_set_trn (theRig, trn); if (ret != RigError.OK) { throw new RigException (ErrorString (ret)); } } /// /// Retrieves the current status of the transceive mode, i.e. if radio /// sends new status automatically when some changes happened on the radio. /// /// The current transceive mode public int GetTransceive () { int trn; var ret = rig_get_trn (theRig, out trn); if (ret != RigError.OK) { throw new RigException (ErrorString (ret)); } return trn; } /// /// Sets the current memory bank number. It is not mandatory /// for the radio to be in memory mode. Actually it depends on rigs. /// /// The memory bank. /// The target VFO. public void SetBank (int bank, int vfo = RigVfo.Current) { var ret = rig_set_bank (theRig, vfo, bank); if (ret != RigError.OK) { throw new RigException (ErrorString (ret)); } } /// /// Sets the current memory channel number. It is not mandatory for /// the radio to be in memory mode. Actually it depends on rigs. /// /// The memory channel number. /// The target VFO. public void SetMem (int ch, int vfo = RigVfo.Current) { var ret = rig_set_mem (theRig, vfo, ch); if (ret != RigError.OK) { throw new RigException (ErrorString (ret)); } } /// /// Retrieves the current memory channel number. It is not mandatory /// for the radio to be in memory mode. Actually it depends on rigs. /// /// The current memory channel number /// The target VFO. public int GetMem (int vfo = RigVfo.Current) { int ch; var ret = rig_get_mem (theRig, vfo, out ch); if (ret != RigError.OK) { throw new RigException (ErrorString (ret)); } return ch; } // TODO: channel struct is not yet defined in wrapper // void SetChannel (const channel_t *chan) // { // CHECK_RIG( rig_set_channel(theRig, chan) ); // } // // void GetChannel (channel_t *chan) // { // CHECK_RIG( rig_get_channel(theRig, chan) ); // } /// /// turns on/off the radio. See RIG_POWER_ON, RIG_POWER_OFF /// and RIG_POWER_STANDBY defines for the status. /// /// The status to set to. public void SetPowerState (PowerState status) { var ret = rig_set_powerstat (theRig, status); if (ret != RigError.OK) { throw new RigException (ErrorString (ret)); } } /// /// Retrieve the status of the radio. See RIG_POWER_ON, /// RIG_POWER_OFF and RIG_POWER_STANDBY defines for the status. /// /// The power state. public PowerState GetPowerState () { PowerState status; var ret = rig_get_powerstat (theRig, out status); if (ret != RigError.OK) { throw new RigException (ErrorString (ret)); } return status; } // RadioMode RngRxModes (freq_t freq) // { // unsigned modes = RIG_MODE_NONE; // freq_range_t *rng; // int i; // // for (i=0; istate.rx_range_list[i]; // if (RIG_IS_FRNG_END(*rng)) { // return (RadioMode)modes; // } // if (freq >= rng->start && freq <= rng->end) // modes |= (unsigned)rng->modes; // } // // return (RadioMode)modes; // } // // RadioMode RngTxModes (freq_t freq) // { // unsigned modes = RIG_MODE_NONE; // freq_range_t *rng; // int i; // // for (i=0; istate.tx_range_list[i]; // if (RIG_IS_FRNG_END(*rng)) { // return (RadioMode)modes; // } // if (freq >= rng->start && freq <= rng->end) // modes |= (unsigned)rng->modes; // } // // return (RadioMode)modes; // } // static public int Hz (int f) { return f; } static public int kHz (int f) { return f * 1000; } static public int MHz (int f) { return f * 1000000; } static public int GHz (int f) { return f * 1000000000; } public static string FrequencyToString (double frequencyHz) { double f; string hz; if (frequencyHz >= GHz (1)) { hz = "GHz"; f = (double)frequencyHz / GHz (1); } else if (frequencyHz >= MHz (1)) { hz = "MHz"; f = (double)frequencyHz / MHz (1); } else if (frequencyHz >= kHz (1)) { hz = "kHz"; f = (double)frequencyHz / kHz (1); } else { hz = "Hz"; f = (double)frequencyHz; } return string.Format ("{0} {1}", f, hz); } internal IConfigurationParameter[] GetExtParm (IntPtr ptr) { List cparams = new List (); Rig.rig_ext_parm_foreach (theRig, (rig, confPtr, rig_ptr) => { var conf = confparam_marshal (confPtr); cparams.Add (conf); return 1; }, IntPtr.Zero); return cparams.ToArray (); } internal IConfigurationParameter[] GetExtLevels (IntPtr ptr) { List cparams = new List (); Rig.rig_ext_level_foreach (theRig, (rig, confPtr, rig_ptr) => { var conf = confparam_marshal (confPtr); cparams.Add (conf); return 1; }, IntPtr.Zero); return cparams.ToArray (); } } }