Repository: NTIA/tekrsa-api-wrap (language: python)

Issue:
Add helper method to get device temperature
The underlying RSA API makes it possible to query the device temperature, but in a very round-about way which requires overwriting frequency reference user settings.

This update adds a new helper method `DEVICE_GetTemperature()` which queries the RSA device temperature while preserving the frequency reference user setting (by reading it and re-applying it after getting the temperature).

To do this, previously missing API functions were added:

- `CONFIG_DecodeFreqRefUserSettingString()`
- `CONFIG_GetFreqRefUserSetting()`
- `CONFIG_SetFreqRefUserSetting()`

Additionally, minor updates to the README are included.


Discussion / hints:

Fix patch:
diff --git a/README.md b/README.md
index b99de1b..ae23778 100644
--- a/README.md
+++ b/README.md
@@ -28,7 +28,7 @@ These shared object files are required, and this API wrapper by default expects
 Next, download the most recent [release](https://github.com/NTIA/tekrsa-api-ntia/releases) of this package, and install it using `pip`:
 
 ```bash
-pip install tekrsa-api-wrap-1.2.0.tar.gz
+pip install tekrsa_api_wrap-1.2.0.tar.gz
 ```
 
 ## Usage
@@ -90,9 +90,12 @@ Known issues exist in the underlying Tektronix RSA API for Linux, and therefore
 
 A testing file is included in the `tests` directory of this repository. The test uses `unittest` to test supported API functions. Running a test requires an RSA device to be connected. The same test is used for any supported RSA device, with some tests being enabled, disabled, or modified as needed depending on the device's specific supported API functions. For example, tests of the preamp configuration are not run when testing with an RSA which does not have a preamp.
 
-From the top-level directory of this repository, run the test, with segmentation fault handling, by running:
+From the top-level directory of this repository, run the test by running:
 
-`python3 -q -X faulthandler tests/rsa_api_test.py <path-to-shared-objects>`
+  ```bash
+  export SO_DIR=/path/to/drivers
+  python -X faulthandler -m unittest
+  ```
 
 Replacing `<path-to-shared-objects>` with the path to a directory containing both `libRSA_API.so` and `libcyusb_shared.so`.
 
diff --git a/rsa_api/__init__.py b/rsa_api/__init__.py
new file mode 100644
index 0000000..1b65072
--- /dev/null
+++ b/rsa_api/__init__.py
@@ -0,0 +1,1 @@
+from .rsa_api import *
\ No newline at end of file
diff --git a/src/rsa_api/rsa_api_wrap.py b/rsa_api/rsa_api.py
similarity index 98%
rename from src/rsa_api/rsa_api_wrap.py
rename to rsa_api/rsa_api.py
index d15c8f3..4c48213 100644
--- a/src/rsa_api/rsa_api_wrap.py
+++ b/rsa_api/rsa_api.py
@@ -6,7 +6,7 @@
 from enum import Enum
 from os.path import abspath, join
 from time import sleep
-from typing import Union, Any, Tuple, Dict
+from typing import Union, Any, Tuple
 
 import numpy as np
 
@@ -33,7 +33,7 @@
 _SPECTRUM_TRACES = ('Trace1', 'Trace2', 'Trace3')
 _SPECTRUM_VERTICAL_UNITS = ('dBm', 'Watt', 'Volt', 'Amp', 'dBmV')
 _SPECTRUM_WINDOWS = ('Kaiser', 'Mil6dB', 'BlackmanHarris', 'Rectangular', 'FlatTop', 'Hann')
-_TRIGGER_MODE = ('freeRun', 'triggered')
+_TRIGGER_MODE = ('freerun', 'triggered')
 _TRIGGER_SOURCE = ('External', 'IFPowerLevel')
 _TRIGGER_TRANSITION = ('LH', 'HL', 'Either')
 
@@ -1817,7 +1817,7 @@ def TRIG_GetTriggerMode(self) -> str:
         Returns
         -------
         string
-            Either "freeRun" or "Triggered".
+            Either "freeRun" or "triggered".
         """
         global _TRIGGER_MODE
         mode = c_int()
@@ -1859,11 +1859,10 @@ def TRIG_GetTriggerTransition(self) -> str:
 
         Returns
         -------
-        string
-            Name of the trigger transition mode. Valid results:
-                LH : Trigger on low-to-high input level change.
-                HL : Trigger on high-to-low input level change.
-                Either : Trigger on either LH or HL transitions.
+        Name of the trigger transition mode. Valid results:
+            LH : Trigger on low-to-high input level change.
+            HL : Trigger on high-to-low input level change.
+            Either : Trigger on either LH or HL transitions.
         """
         global _TRIGGER_TRANSITION
         transition = c_int()
@@ -1875,7 +1874,7 @@ def TRIG_SetIFPowerTriggerLevel(self, level: Union[float, int]) -> None:
         Set the IF power detection level.
 
         Parameters
-         ----------
+        ----------
         level : float or int
             The detection power level setting for the IF power trigger
             source.
@@ -1890,10 +1889,9 @@ def TRIG_SetTriggerMode(self, mode: str) -> None:
 
         Parameters
         ----------
-        mode : string
-            The trigger mode. Valid settings:
-                freeRun : to continually gather data
-                Triggered : do not acquire new data unless triggered
+        mode : The trigger mode, case insensitive. Valid settings:
+            freeRun : to continually gather data
+            Triggered : do not acquire new data unless triggered
 
         Raises
         ------
@@ -1902,8 +1900,8 @@ def TRIG_SetTriggerMode(self, mode: str) -> None:
         """
         global _TRIGGER_MODE
         mode = RSA.check_string(mode)
-        if mode in _TRIGGER_MODE:
-            mode_value = _TRIGGER_MODE.index(mode)
+        if mode.lower() in _TRIGGER_MODE:
+            mode_value = _TRIGGER_MODE.index(mode.lower())
             self.err_check(self.rsa.TRIG_SetTriggerMode(c_int(mode_value)))
         else:
             raise RSAError("Invalid trigger mode input string.")
@@ -2263,7 +2261,7 @@ def IQSTREAM_StatusParser(iq_stream_info: _IQStreamFileInfo, exit: bool=True):
                 return status_str
 
     def SPECTRUM_Acquire(self, trace: str = 'Trace1', trace_points: int = 801,
-                         timeout_msec: int = 10) -> Tuple[np.ndarray, int]:
+                         timeout_msec: int = 50) -> Tuple[np.ndarray, int]:
         """
         Acquire spectrum trace.
 
@@ -2287,8 +2285,10 @@ def SPECTRUM_Acquire(self, trace: str = 'Trace1', trace_points: int = 801,
         """
         self.DEVICE_Run()
         self.SPECTRUM_AcquireTrace()
-        while not self.SPECTRUM_WaitForTraceReady(timeout_msec):
-            pass
+        ready = False
+        while not ready:
+            ready = self.SPECTRUM_WaitForTraceReady(timeout_msec)
+            sleep(int(timeout_msec * 1e-3))
         return self.SPECTRUM_GetTrace(trace, trace_points)
 
     def IQBLK_Configure(self, cf: Union[float, int] = 1e9, ref_level: Union[float, int] = 0,
@@ -2312,7 +2312,7 @@ def IQBLK_Configure(self, cf: Union[float, int] = 1e9, ref_level: Union[float, i
         self.IQBLK_SetIQBandwidth(iq_bw)
         self.IQBLK_SetIQRecordLength(record_length)
 
-    def IQBLK_Acquire(self, rec_len: int = 1024, timeout_ms: int = 10) -> Tuple[np.ndarray, np.ndarray]:
+    def IQBLK_Acquire(self, rec_len: int = 1024, timeout_ms: int = 50) -> Tuple[np.ndarray, np.ndarray]:
         """
         Acquire IQBLK data using IQBLK_GetIQDataDeinterleaved.
 
@@ -2332,8 +2332,10 @@ def IQBLK_Acquire(self, rec_len: int = 1024, timeout_ms: int = 10) -> Tuple[np.n
         """
         self.DEVICE_Run()
         self.IQBLK_AcquireIQData()
-        while not self.IQBLK_WaitForIQDataReady(timeout_ms):
-            pass
+        ready = False
+        while not ready:
+            ready = self.IQBLK_WaitForIQDataReady(timeout_ms)
+            sleep(int(timeout_ms * 1e-3))
         return self.IQBLK_GetIQDataDeinterleaved(req_length=rec_len)
 
 
diff --git a/setup.cfg b/setup.cfg
index d661509..e93d531 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -1,5 +1,5 @@
 [metadata]
-name = tekrsa-api-wrap
+name = tekrsa_api_wrap
 version = 1.2.0
 author = The Institute for Telecommunication Sciences
 description = NTIA Python wrapper for Tektronix RSA API for Linux
@@ -18,11 +18,11 @@ classifiers =
 
 [options]
 package_dir =
-    = src
+    = rsa_api
 packages = find:
 python_requires = >=3.7
 install_requires =
     numpy>=1.21
 
 [options.packages.find]
-where = src
+where = rsa_api
diff --git a/src/rsa_api/__init__.py b/src/rsa_api/__init__.py
deleted file mode 100644
index 406612f..0000000
--- a/src/rsa_api/__init__.py
+++ /dev/null
@@ -1,1 +0,0 @@
-from .rsa_api_wrap import *
\ No newline at end of file


Test patch:
diff --git a/tests/__init__.py b/tests/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/tests/rsa_api_test.py b/tests/rsa_api_test.py
deleted file mode 100644
index 25d2be2..0000000
--- a/tests/rsa_api_test.py
+++ /dev/null
@@ -1,483 +0,0 @@
-import unittest
-from os.path import isdir
-from os import mkdir
-import rsa_api
-from time import sleep
-import numpy as np
-import sys
-
-"""
-This is a test for the entire API Wrapper.
-It requires a compatible RSA device to be connected.
-"""
-
-class rsa_api_test(unittest.TestCase):
-    """Test for rsa_api_wrap.py"""
-
-    """ALIGN Command Testing"""
-
-    def test_ALIGN_GetAlignmentNeeded(self):
-        self.assertIsInstance(rsa.ALIGN_GetAlignmentNeeded(), bool)
-
-    def test_ALIGN_GetWarmupStatus(self):
-        self.assertIsInstance(rsa.ALIGN_GetWarmupStatus(), bool)
-
-    def test_ALIGN_RunAlignment(self):
-        self.assertIsNone(rsa.ALIGN_RunAlignment())
-
-    """CONFIG Command Testing"""
-
-    def test_CONFIG_CenterFreq(self):
-        cf = 2.4453e9
-        self.assertIsNone(rsa.CONFIG_SetCenterFreq(cf))
-        self.assertEqual(rsa.CONFIG_GetCenterFreq(), cf)
-
-        self.assertRaises(TypeError, rsa.CONFIG_SetCenterFreq, 'abc')
-        self.assertRaises(TypeError, rsa.CONFIG_SetCenterFreq, False)
-        self.assertRaises(ValueError, rsa.CONFIG_SetCenterFreq, 400e9)
-        self.assertRaises(ValueError, rsa.CONFIG_SetCenterFreq, -40e6)
-
-    """
-    # The following test requires an external reference to be in use.
-    def test_CONFIG_ExternalRef(self):
-        self.assertIsNone(CONFIG_SetExternalRefEnable(exRefEn=True))
-        self.assertTrue(CONFIG_GetExternalRefEnable())
-        extRefFreq = 10e6
-        self.assertEqual(CONFIG_GetExternalRefFrequency(), extRefFreq)
-        CONFIG_SetExternalRefEnable(exRefEn=False)
-        self.assertRaises(rsa_api.RSAError, CONFIG_GetExternalRefFrequency)
-    """
-
-    def test_CONFIG_FrequencyReferenceSource(self):
-        self.assertRaises(rsa_api.RSAError, rsa.CONFIG_SetFrequencyReferenceSource, 'GNSS')
-        self.assertRaises(rsa_api.RSAError, rsa.CONFIG_SetFrequencyReferenceSource, 'abc')
-        self.assertRaises(TypeError, rsa.CONFIG_SetFrequencyReferenceSource, 0)
-        self.assertIsNone(rsa.CONFIG_SetFrequencyReferenceSource('INTERNAL'))
-        self.assertIsInstance(rsa.CONFIG_GetFrequencyReferenceSource(), str)
-
-    def test_CONFIG_Preset(self):
-        self.assertIsNone(rsa.CONFIG_Preset())
-        self.assertEqual(rsa.CONFIG_GetCenterFreq(), 1.5e9)
-        self.assertEqual(rsa.CONFIG_GetReferenceLevel(), 0)
-        self.assertEqual(rsa.IQBLK_GetIQBandwidth(), 40e6)
-        self.assertEqual(rsa.IQBLK_GetIQRecordLength(), 1024)
-
-    def test_CONFIG_ReferenceLevel(self):
-        refLevel = 17
-        self.assertIsNone(rsa.CONFIG_SetReferenceLevel(refLevel))
-        self.assertEqual(rsa.CONFIG_GetReferenceLevel(), refLevel)
-        self.assertRaises(TypeError, rsa.CONFIG_SetReferenceLevel, 'abc')
-        self.assertRaises(ValueError, rsa.CONFIG_SetReferenceLevel, 31)
-        self.assertRaises(ValueError, rsa.CONFIG_SetReferenceLevel, -131)
-
-    def test_CONFIG_GetMaxCenterFreq(self):
-        global device
-        maxCf = 0
-        if device in ['RSA306B', 'RSA306']:
-            # Unsure if RSA306 (non-B variant) has same max freq.
-            maxCf = 6.2e9
-        elif device in ['RSA503A', 'RSA603A']:
-            maxCf = 3.0e9
-        elif device in ['RSA507A', 'RSA607A']:
-            maxCf = 7.5e9
-        elif device == 'RSA513A':
-            maxCf = 13.6e9
-        elif device == 'RSA518A':
-            maxCf = 18.0e9
-        self.assertEqual(rsa.CONFIG_GetMaxCenterFreq(), maxCf)
-
-    def test_CONFIG_GetMinCenterFreq(self):
-        minCf = 9e3
-        self.assertEqual(rsa.CONFIG_GetMinCenterFreq(), minCf)
-
-    def test_CONFIG_Attenuation(self):
-        # Only run test for RSA 500A/600A devices
-        global device
-        if device not in ['RSA306B', 'RSA306']:
-            self.assertIsNone(rsa.CONFIG_SetAutoAttenuationEnable(True))
-            self.assertTrue(rsa.CONFIG_GetAutoAttenuationEnable())
-            self.assertIsNone(rsa.CONFIG_SetAutoAttenuationEnable(False))
-            self.assertFalse(rsa.CONFIG_GetAutoAttenuationEnable())
-            atten_setting = -25
-            self.assertIsNone(rsa.CONFIG_SetRFAttenuator(atten_setting))
-            self.assertEqual(rsa.CONFIG_GetRFAttenuator(), atten_setting)
-
-    def test_CONFIG_Preamp(self):
-        # Only run test for RSA 500A/600A devices.
-        global device
-        if device not in ['RSA306B', 'RSA306']:
-            self.assertIsNone(rsa.CONFIG_SetRFPreampEnable(False))
-            rsa.DEVICE_Stop()
-            rsa.CONFIG_SetAutoAttenuationEnable(True)
-            rsa.DEVICE_Run()
-            self.assertFalse(rsa.CONFIG_GetRFPreampEnable())
-            self.assertIsNone(rsa.CONFIG_SetRFPreampEnable(True))
-            rsa.DEVICE_Stop()
-            rsa.DEVICE_Run()
-            self.assertTrue(rsa.CONFIG_GetRFPreampEnable())
-
-    """DEVICE Command Testing"""
-
-    def test_DEVICE_Connect(self):
-        # Stop and disconnect device first
-        rsa.DEVICE_Stop()
-        self.assertIsNone(rsa.DEVICE_Disconnect())
-        self.assertRaises(TypeError, rsa.DEVICE_Connect, 'abc')
-        self.assertRaises(ValueError, rsa.DEVICE_Connect, neg)
-        self.assertIsNone(rsa.DEVICE_Connect(0))
-
-    def test_DEVICE_PrepareForRun(self):
-        self.assertIsNone(rsa.DEVICE_PrepareForRun())
-
-    def test_DEVICE_Run(self):
-        self.assertIsNone(rsa.DEVICE_Run())
-        self.assertTrue(rsa.DEVICE_GetEnable())
-
-    def test_DEVICE_Stop(self):
-        self.assertIsNone(rsa.DEVICE_Stop())
-        self.assertFalse(rsa.DEVICE_GetEnable())
-
-    def test_DEVICE_GetEventStatus_no_signal(self):
-        eventType = ['OVERRANGE', 'TRIGGER', '1PPS']
-        for e in eventType:
-            event, timestamp = rsa.DEVICE_GetEventStatus(e)
-            self.assertFalse(event)
-            self.assertEqual(timestamp, 0)
-        self.assertRaises(TypeError, rsa.DEVICE_GetEventStatus, 0)
-        self.assertRaises(rsa_api.RSAError, rsa.DEVICE_GetEventStatus, 'abc')
-
-    def test_DEVICE_GetEventStatus_trig_event(self):
-        rsa.DEVICE_Run()
-        rsa.TRIG_ForceTrigger()
-        sleep(0.05)
-        trig, trigTs = rsa.DEVICE_GetEventStatus('TRIGGER')
-        self.assertTrue(trig)
-        self.assertGreater(trigTs, 0)
-
-    """
-    # The following test would require an actual overrange event.
-    def test_DEVICE_GetEventStatus_overrange(self):
-        pass
-    """
-
-    def test_DEVICE_GetOverTemperatureStatus(self):
-        self.assertIsInstance(rsa.DEVICE_GetOverTemperatureStatus(), bool)
-        self.assertEqual(rsa.DEVICE_GetOverTemperatureStatus(), False)
-
-    def test_DEVICE_GetNomenclature(self):
-        self.assertIsInstance(rsa.DEVICE_GetNomenclature(), str)
-
-    def test_DEVICE_GetSerialNumber(self):
-        sn = rsa.DEVICE_GetSerialNumber()
-        self.assertIsInstance(sn, str)
-        self.assertEqual(len(sn), 7)
-
-    def test_DEVICE_GetAPIVersion(self):
-        # This uses the Linux API version number
-        self.assertEqual(rsa.DEVICE_GetAPIVersion(), '1.0.0014')
-
-    def test_DEVICE_GetFWVersion(self):
-        self.assertIsInstance(rsa.DEVICE_GetFWVersion(), str)
-
-    def test_DEVICE_GetFPGAVersion(self):
-        self.assertIsInstance(rsa.DEVICE_GetFPGAVersion(), str)
-
-    def test_DEVICE_GetHWVersion(self):
-        self.assertIsInstance(rsa.DEVICE_GetHWVersion(), str)
-
-    def test_DEVICE_GetInfo(self):
-        info = rsa.DEVICE_GetInfo()
-        self.assertIsInstance(info, dict)
-        self.assertEqual(len(info), 6)
-        self.assertEqual(len(info['serialNum']), 7)
-        self.assertEqual(info['apiVersion'], '1.0.0014')
-        self.assertIsInstance(info['fwVersion'], str)
-        self.assertIsInstance(info['fpgaVersion'], str)
-        self.assertIsInstance(info['hwVersion'], str)
-
-    """IQBLK Command Testing"""
-
-    def test_IQBLK_MinMaxIQBandwidth(self):
-        maxBw = rsa.IQBLK_GetMaxIQBandwidth()
-        minBw = rsa.IQBLK_GetMinIQBandwidth()
-        rsa.IQBLK_SetIQBandwidth(maxBw)  # To get maxRl properly
-        maxRl = rsa.IQBLK_GetMaxIQRecordLength()
-        self.assertEqual(maxBw, 40e6)
-        self.assertEqual(minBw, 100)
-        self.assertEqual(maxRl, 126000000)
-
-    def test_IQBLK_IQBandwidth(self):
-        iqBw = 20e6
-        self.assertIsNone(rsa.IQBLK_SetIQBandwidth(iqBw))
-        self.assertEqual(iqBw, rsa.IQBLK_GetIQBandwidth())
-        self.assertRaises(ValueError, rsa.IQBLK_SetIQBandwidth, neg)
-        self.assertRaises(ValueError, rsa.IQBLK_SetIQBandwidth, 100e6)
-        self.assertRaises(TypeError, rsa.IQBLK_SetIQBandwidth, 'abc')
-
-    def test_IQBLK_IQRecordLength(self):
-        iqRl = 8192
-        self.assertIsNone(rsa.IQBLK_SetIQRecordLength(iqRl))
-        self.assertEqual(iqRl, rsa.IQBLK_GetIQRecordLength())
-        self.assertRaises(ValueError, rsa.IQBLK_SetIQRecordLength, neg)
-        self.assertRaises(ValueError, rsa.IQBLK_SetIQRecordLength, 200e6)
-        self.assertRaises(TypeError, rsa.IQBLK_SetIQRecordLength, 'abc')
-
-    def test_IQBLK_GetSampleRate(self):
-        self.assertIsInstance(rsa.IQBLK_GetIQSampleRate(), float)
-
-    def test_IQBLK_GetIQData(self):
-        rl = 1000
-        rsa.IQBLK_Configure()  # Configure to defaults
-        i, q = rsa.IQBLK_Acquire(rl, 10)
-        self.assertEqual(len(i), rl)
-        self.assertEqual(len(q), rl)
-
-        self.assertRaises(ValueError, rsa.IQBLK_Acquire, rec_len=neg)
-        self.assertRaises(ValueError, rsa.IQBLK_Acquire, rec_len=200000000)
-        self.assertRaises(TypeError, rsa.IQBLK_Acquire, rec_len='abc')
-
-    """IQSTREAM Command Testing"""
-
-    def test_IQSTREAM_MinMaxIQBandwidth(self):
-        minBandwidthHz = rsa.IQSTREAM_GetMinAcqBandwidth()
-        maxBandwidthHz = rsa.IQSTREAM_GetMaxAcqBandwidth()
-        self.assertEqual(minBandwidthHz, 9765.625)
-        self.assertEqual(maxBandwidthHz, 40e6)
-
-    def test_IQSTREAM_AcqBandwidth(self):
-        bwHz_req = [40e6, 20e6, 10e6, 5e6, 2.5e6, 1.25e6, 625e3, 312.5e3,
-                    156.25e3, 78125, 39062.5, 19531.25, 9765.625]
-        srSps_req = [56e6, 28e6, 14e6, 7e6, 3.5e6, 1.75e6, 875e3,
-                     437.5e3, 218.75e3, 109.375e3, 54687.5, 27343.75,
-                     13671.875]
-        baseSize = [65536, 65536, 65536, 65536, 65536, 32768, 16384, 8192,
-                    4096, 2048, 1024, 512, 256, 128]
-        for b, s, r in zip(bwHz_req, srSps_req, baseSize):
-            self.assertIsNone(rsa.IQSTREAM_SetAcqBandwidth(b))
-            bwHz_act, srSps = rsa.IQSTREAM_GetAcqParameters()
-            self.assertEqual(bwHz_act, b)
-            self.assertEqual(srSps, s)
-            self.assertIsNone(rsa.IQSTREAM_SetIQDataBufferSize(r))
-            self.assertEqual(rsa.IQSTREAM_GetIQDataBufferSize(), r)
-
-        self.assertRaises(TypeError, rsa.IQSTREAM_SetAcqBandwidth, 'abc')
-        self.assertRaises(TypeError, rsa.IQSTREAM_SetAcqBandwidth, [num])
-        self.assertRaises(ValueError, rsa.IQSTREAM_SetAcqBandwidth, 41e6)
-
-    def test_IQSTREAM_SetOutputConfiguration(self):
-        dest = ['CLIENT', 'FILE_TIQ', 'FILE_SIQ', 'FILE_SIQ_SPLIT']
-        dtype = ['SINGLE', 'INT32', 'INT16', 'SINGLE_SCALE_INT32']
-
-        for d in dest:
-            for t in dtype:
-                if d == 'FILE_TIQ' and 'SINGLE' in t:
-                    self.assertRaises(rsa_api.RSAError,
-                                      rsa.IQSTREAM_SetOutputConfiguration, d, t)
-                else:
-                    self.assertIsNone(rsa.IQSTREAM_SetOutputConfiguration(d, t))
-
-        self.assertRaises(TypeError, rsa.IQSTREAM_SetOutputConfiguration,
-                          num, dtype[0])
-        self.assertRaises(TypeError, rsa.IQSTREAM_SetOutputConfiguration,
-                          dest[0], num)
-        self.assertRaises(rsa_api.RSAError, rsa.IQSTREAM_SetOutputConfiguration, 'a', 'SINGLE')
-        self.assertRaises(rsa_api.RSAError, rsa.IQSTREAM_SetOutputConfiguration, 'CLIENT', 'a')
-
-    def test_IQSTREAM_SetDiskFilenameBase(self):
-        path = '/tmp/rsa_api_unittest'
-        if not isdir(path):
-            mkdir(path)
-        filename = 'iqstream_test'
-        filenameBase = path + filename
-        self.assertIsNone(rsa.IQSTREAM_SetDiskFilenameBase(filenameBase))
-
-        self.assertRaises(TypeError, rsa.IQSTREAM_SetDiskFilenameBase, num)
-        self.assertRaises(TypeError, rsa.IQSTREAM_SetDiskFilenameBase, b'abc')
-        self.assertRaises(TypeError, rsa.IQSTREAM_SetDiskFilenameBase, [num])
-
-    def test_IQSTREAM_SetDiskFilenameSuffix(self):
-        suffixCtl = [0, -1, -2]
-        for s in suffixCtl:
-            self.assertIsNone(rsa.IQSTREAM_SetDiskFilenameSuffix(s))
-
-        self.assertRaises(TypeError, rsa.IQSTREAM_SetDiskFilenameSuffix, 'abc')
-        self.assertRaises(ValueError, rsa.IQSTREAM_SetDiskFilenameSuffix, neg)
-
-    def test_IQSTREAM_SetDiskFileLength(self):
-        length = 100
-        self.assertIsNone(rsa.IQSTREAM_SetDiskFileLength(length))
-        self.assertRaises(TypeError, rsa.IQSTREAM_SetDiskFileLength, 'abc')
-        self.assertRaises(ValueError, rsa.IQSTREAM_SetDiskFileLength, neg)
-
-    def test_IQSTREAM_Operation(self):
-        rsa.IQSTREAM_SetAcqBandwidth(5e6)
-        rsa.IQSTREAM_SetOutputConfiguration('CLIENT', 'INT16')
-        rsa.IQSTREAM_GetAcqParameters()
-        rsa.DEVICE_Run()
-
-        self.assertIsNone(rsa.IQSTREAM_Start())
-        self.assertTrue(rsa.IQSTREAM_GetEnable())
-
-        self.assertIsNone(rsa.IQSTREAM_Stop())
-        self.assertFalse(rsa.IQSTREAM_GetEnable())
-
-        rsa.DEVICE_Stop()
-
-    def test_IQSTREAM_ClearAcqStatus(self):
-        self.assertIsNone(rsa.IQSTREAM_ClearAcqStatus())
-
-    """TRIG Command Testing"""
-
-    def test_TRIG_TriggerMode(self):
-        mode = ["freeRun", "triggered"]
-        for m in mode:
-            self.assertIsNone(rsa.TRIG_SetTriggerMode(m))
-            self.assertEqual(rsa.TRIG_GetTriggerMode(), m)
-
-    def test_TRIG_TriggerSource(self):
-        source = ["External", "IFPowerLevel"]
-        for s in source:
-            self.assertIsNone(rsa.TRIG_SetTriggerSource(s))
-            self.assertEqual(rsa.TRIG_GetTriggerSource(), s)
-
-    def test_TRIG_TriggerTransition(self):
-        trans = ["LH", "HL", "Either"]
-        for t in trans:
-            self.assertIsNone(rsa.TRIG_SetTriggerTransition(t))
-            self.assertEqual(rsa.TRIG_GetTriggerTransition(), t)
-        self.assertRaises(TypeError, rsa.TRIG_SetTriggerTransition, 0)
-
-    def test_TRIG_IFPowerTriggerLevel(self):
-        trigLevel = -10
-        self.assertIsNone(rsa.TRIG_SetIFPowerTriggerLevel(trigLevel))
-        self.assertEqual(rsa.TRIG_GetIFPowerTriggerLevel(), trigLevel)
-        self.assertRaises(TypeError, rsa.TRIG_SetIFPowerTriggerLevel, 'trigger')
-        self.assertRaises(ValueError, rsa.TRIG_SetIFPowerTriggerLevel, 31)
-        self.assertRaises(ValueError, rsa.TRIG_SetIFPowerTriggerLevel, -131)
-
-    def test_TRIG_TriggerPositionPercent(self):
-        self.assertRaises(ValueError, rsa.TRIG_SetTriggerPositionPercent, 0.5)
-        self.assertRaises(ValueError, rsa.TRIG_SetTriggerPositionPercent, 100)
-        self.assertRaises(TypeError, rsa.TRIG_SetTriggerPositionPercent, 'abc')
-
-        pos = 20
-        self.assertIsNone(rsa.TRIG_SetTriggerPositionPercent(pos))
-        self.assertEqual(rsa.TRIG_GetTriggerPositionPercent(), pos)
-
-    def test_TRIG_ForceTrigger(self):
-        self.assertIsNone(rsa.TRIG_ForceTrigger())
-
-    """SPECTRUM Command Testing"""
-
-    def test_SPECTRUM_Enable(self):
-        enable = [False, True]
-        for e in enable:
-            self.assertIsNone(rsa.SPECTRUM_SetEnable(e))
-            self.assertEqual(rsa.SPECTRUM_GetEnable(), e)
-
-    def test_SPECTRUM_Settings(self):
-        self.assertIsNone(rsa.SPECTRUM_SetDefault())
-
-        span = 20e6
-        rbw = 100e3
-        enableVBW = True
-        vbw = 50e3
-        traceLength = 1601
-        window = 'Hann'
-        verticalUnit = 'dBm'
-        self.assertIsNone(rsa.SPECTRUM_SetSettings(span, rbw, enableVBW, vbw,
-                                                   traceLength, window,
-                                                   verticalUnit))
-        settings = rsa.SPECTRUM_GetSettings()
-        self.assertIsInstance(settings, dict)
-        self.assertEqual(len(settings), 13)
-        self.assertEqual(settings['span'], span)
-        self.assertEqual(settings['rbw'], rbw)
-        self.assertEqual(settings['enableVBW'], enableVBW)
-        self.assertEqual(settings['vbw'], vbw)
-        self.assertEqual(settings['window'], window)
-        self.assertEqual(settings['traceLength'], traceLength)
-        self.assertEqual(settings['verticalUnit'], verticalUnit)
-
-        self.assertRaises(TypeError, rsa.SPECTRUM_SetSettings, 'span', 'rbw',
-                          'enableVBW', 'vbw', 'traceLength',
-                          1, 0)
-
-    def test_SPECTRUM_TraceType(self):
-        trace = 'Trace2'
-        enable = True
-        detector = 'AverageVRMS'
-        self.assertIsNone(rsa.SPECTRUM_SetTraceType(trace, enable, detector))
-        o_enable, o_detector = rsa.SPECTRUM_GetTraceType(trace)
-        self.assertEqual(enable, o_enable)
-        self.assertEqual(detector, o_detector)
-
-        self.assertRaises(rsa_api.RSAError, rsa.SPECTRUM_SetTraceType, trace='abc')
-        self.assertRaises(TypeError, rsa.SPECTRUM_SetTraceType, trace=40e5)
-        self.assertRaises(rsa_api.RSAError, rsa.SPECTRUM_SetTraceType,
-                          detector='abc')
-        self.assertRaises(TypeError, rsa.SPECTRUM_SetTraceType, detector=40e5)
-
-    def test_SPECTRUM_GetLimits(self):
-        global device
-        if device in ['RSA306B', 'RSA306']:
-            maxSpan = 6.2e9
-        elif device in ['RSA503A', 'RSA603A']:
-            maxSpan = 3.0e9
-        elif device in ['RSA507A', 'RSA607A']:
-            maxSpan = 7.5e9
-        elif device == 'RSA513A':
-            maxSpan = 13.6e9
-        elif device == 'RSA518A':
-            maxSpan = 18.0e9
-
-        limits = rsa.SPECTRUM_GetLimits()
-        self.assertIsInstance(limits, dict)
-        self.assertEqual(len(limits), 8)
-        self.assertEqual(limits['maxSpan'], maxSpan)
-        self.assertEqual(limits['minSpan'], 1e3)
-        self.assertEqual(limits['maxRBW'], 10e6)
-        self.assertEqual(limits['minRBW'], 10)
-        self.assertEqual(limits['maxVBW'], 10e6)
-        self.assertEqual(limits['minVBW'], 1)
-        self.assertEqual(limits['maxTraceLength'], 64001)
-        self.assertEqual(limits['minTraceLength'], 801)
-
-    def test_SPECTRUM_Acquire(self):
-        rsa.SPECTRUM_SetEnable(True)
-        span = 20e6
-        rbw = 100e3
-        enableVBW = True
-        vbw = 50e3
-        traceLength = 1601
-        window = 'Hann'
-        verticalUnit = 'dBm'
-        rsa.SPECTRUM_SetSettings(span, rbw, enableVBW, vbw, traceLength, window,
-                                 verticalUnit)
-        spectrum, outTracePoints = rsa.SPECTRUM_Acquire(trace='Trace1',
-                                                        trace_points=traceLength)
-        self.assertEqual(len(spectrum), traceLength)
-        self.assertIsInstance(spectrum, np.ndarray)
-        self.assertRaises(TypeError, rsa.SPECTRUM_Acquire, trace=1)
-
-        traceInfo = rsa.SPECTRUM_GetTraceInfo()
-        self.assertIsInstance(traceInfo, dict)
-        self.assertEqual(len(traceInfo), 2)
-
-
-if __name__ == '__main__':
-    """There must be a connected RSA device in order to test."""
-    TEST_SO_DIR = sys.argv[1]
-    del sys.argv[1:]
-    rsa = rsa_api.RSA(so_dir=TEST_SO_DIR)
-    rsa.DEVICE_Connect(0)
-    device = rsa.DEVICE_GetNomenclature()
-
-    # Some values used in testing
-    num = 400
-    neg = -400
-    unittest.main()
-
-    # Test cleanup
-    rsa.DEVICE_Stop()
-    rsa.DEVICE_Disconnect()
diff --git a/tests/test_rsa_api.py b/tests/test_rsa_api.py
new file mode 100644
index 0000000..0e3b9aa
--- /dev/null
+++ b/tests/test_rsa_api.py
@@ -0,0 +1,487 @@
+import unittest
+import numpy as np
+from os.path import isdir
+from os import mkdir, environ
+from time import sleep
+
+import rsa_api
+
+"""
+This is a test for the entire API Wrapper.
+It requires a compatible RSA device to be connected.
+"""
+
+class rsa_api_test(unittest.TestCase):
+    """Test for rsa_api_wrap.py"""
+
+    @classmethod
+    def setUpClass(cls):
+        cls.rsa = rsa_api.RSA(so_dir=environ["SO_DIR"])
+        cls.rsa.DEVICE_Connect(0)
+        cls.device = cls.rsa.DEVICE_GetNomenclature()
+        cls.num = 400
+        cls.neg = -400
+
+    @classmethod
+    def tearDownClass(cls):
+        cls.rsa.DEVICE_Disconnect()
+        
+    """ALIGN Command Testing"""
+
+    def test_ALIGN_GetAlignmentNeeded(self):
+        self.assertIsInstance(self.rsa.ALIGN_GetAlignmentNeeded(), bool)
+
+    def test_ALIGN_GetWarmupStatus(self):
+        self.assertIsInstance(self.rsa.ALIGN_GetWarmupStatus(), bool)
+
+    def test_ALIGN_RunAlignment(self):
+        self.assertIsNone(self.rsa.ALIGN_RunAlignment())
+
+    """CONFIG Command Testing"""
+
+    def test_CONFIG_CenterFreq(self):
+        cf = 2.4453e9
+        self.assertIsNone(self.rsa.CONFIG_SetCenterFreq(cf))
+        self.assertEqual(self.rsa.CONFIG_GetCenterFreq(), cf)
+
+        self.assertRaises(TypeError, self.rsa.CONFIG_SetCenterFreq, 'abc')
+        self.assertRaises(TypeError, self.rsa.CONFIG_SetCenterFreq, False)
+        self.assertRaises(ValueError, self.rsa.CONFIG_SetCenterFreq, 400e9)
+        self.assertRaises(ValueError, self.rsa.CONFIG_SetCenterFreq, -40e6)
+
+    """
+    # The following test requires an external reference to be in use.
+    def test_CONFIG_ExternalRef(self):
+        self.assertIsNone(CONFIG_SetExternalRefEnable(exRefEn=True))
+        self.assertTrue(CONFIG_GetExternalRefEnable())
+        extRefFreq = 10e6
+        self.assertEqual(CONFIG_GetExternalRefFrequency(), extRefFreq)
+        CONFIG_SetExternalRefEnable(exRefEn=False)
+        self.assertRaises(rsa_api.RSAError, CONFIG_GetExternalRefFrequency)
+    """
+
+    def test_CONFIG_FrequencyReferenceSource(self):
+        if self.device in ['RSA306B', 'RSA306']:
+            self.assertRaises(rsa_api.RSAError, self.rsa.CONFIG_SetFrequencyReferenceSource, 'GNSS')
+        self.assertRaises(rsa_api.RSAError, self.rsa.CONFIG_SetFrequencyReferenceSource, 'abc')
+        self.assertRaises(TypeError, self.rsa.CONFIG_SetFrequencyReferenceSource, 0)
+        self.assertIsNone(self.rsa.CONFIG_SetFrequencyReferenceSource('INTERNAL'))
+        self.assertIsInstance(self.rsa.CONFIG_GetFrequencyReferenceSource(), str)
+
+    def test_CONFIG_FreqRefUserSetting(self):
+        self.assertIsInstance(self.rsa.CONFIG_GetFreqRefUserSetting(), str)
+        self.assertRaises(TypeError, self.rsa.CONFIG_SetFreqRefUserSetting, 0)
+        self.assertRaises(rsa_api.RSAError, self.rsa.CONFIG_SetFreqRefUserSetting, 'Invalid User Setting')
+        self.assertRaises(rsa_api.RSAError, self.rsa.CONFIG_SetFreqRefUserSetting, 'incorrect length input')
+        self.assertIsNone(self.rsa.CONFIG_SetFreqRefUserSetting(None))
+        self.assertIsInstance(self.rsa.CONFIG_DecodeFreqRefUserSettingString(self.rsa.CONFIG_GetFreqRefUserSetting()), dict)
+
+    def test_CONFIG_Preset(self):
+        self.assertIsNone(self.rsa.CONFIG_Preset())
+        self.assertEqual(self.rsa.CONFIG_GetCenterFreq(), 1.5e9)
+        self.assertEqual(self.rsa.CONFIG_GetReferenceLevel(), 0)
+        self.assertEqual(self.rsa.IQBLK_GetIQBandwidth(), 40e6)
+        self.assertEqual(self.rsa.IQBLK_GetIQRecordLength(), 1024)
+
+    def test_CONFIG_ReferenceLevel(self):
+        refLevel = 17
+        self.assertIsNone(self.rsa.CONFIG_SetReferenceLevel(refLevel))
+        self.assertEqual(self.rsa.CONFIG_GetReferenceLevel(), refLevel)
+        self.assertRaises(TypeError, self.rsa.CONFIG_SetReferenceLevel, 'abc')
+        self.assertRaises(ValueError, self.rsa.CONFIG_SetReferenceLevel, 31)
+        self.assertRaises(ValueError, self.rsa.CONFIG_SetReferenceLevel, -131)
+
+    def test_CONFIG_GetMaxCenterFreq(self):
+        maxCf = 0
+        if self.device in ['RSA306B', 'RSA306']:
+            # Unsure if RSA306 (non-B variant) has same max freq.
+            maxCf = 6.2e9
+        elif self.device in ['RSA503A', 'RSA603A']:
+            maxCf = 3.0e9
+        elif self.device in ['RSA507A', 'RSA607A']:
+            maxCf = 7.5e9
+        elif self.device == 'RSA513A':
+            maxCf = 13.6e9
+        elif self.device == 'RSA518A':
+            maxCf = 18.0e9
+        self.assertEqual(self.rsa.CONFIG_GetMaxCenterFreq(), maxCf)
+
+    def test_CONFIG_GetMinCenterFreq(self):
+        minCf = 9e3
+        self.assertEqual(self.rsa.CONFIG_GetMinCenterFreq(), minCf)
+
+    def test_CONFIG_Attenuation(self):
+        # Only run test for RSA 500A/600A devices
+        if self.device not in ['RSA306B', 'RSA306']:
+            self.assertIsNone(self.rsa.CONFIG_SetAutoAttenuationEnable(True))
+            self.assertTrue(self.rsa.CONFIG_GetAutoAttenuationEnable())
+            self.assertIsNone(self.rsa.CONFIG_SetAutoAttenuationEnable(False))
+            self.assertFalse(self.rsa.CONFIG_GetAutoAttenuationEnable())
+            atten_setting = -25
+            self.assertIsNone(self.rsa.CONFIG_SetRFAttenuator(atten_setting))
+            self.assertEqual(self.rsa.CONFIG_GetRFAttenuator(), atten_setting)
+
+    def test_CONFIG_Preamp(self):
+        # Only run test for RSA 500A/600A devices.
+        if self.device not in ['RSA306B', 'RSA306']:
+            self.assertIsNone(self.rsa.CONFIG_SetRFPreampEnable(False))
+            self.rsa.DEVICE_Stop()
+            self.rsa.CONFIG_SetAutoAttenuationEnable(True)
+            self.rsa.DEVICE_Run()
+            self.assertFalse(self.rsa.CONFIG_GetRFPreampEnable())
+            self.assertIsNone(self.rsa.CONFIG_SetRFPreampEnable(True))
+            self.rsa.DEVICE_Stop()
+            self.rsa.DEVICE_Run()
+            self.assertTrue(self.rsa.CONFIG_GetRFPreampEnable())
+
+    """DEVICE Command Testing"""
+
+    def test_DEVICE_Connect(self):
+        # Stop and disconnect device first
+        self.rsa.DEVICE_Stop()
+        self.assertIsNone(self.rsa.DEVICE_Disconnect())
+        self.assertRaises(TypeError, self.rsa.DEVICE_Connect, 'abc')
+        self.assertRaises(ValueError, self.rsa.DEVICE_Connect, self.neg)
+        self.assertIsNone(self.rsa.DEVICE_Connect(0))
+
+    def test_DEVICE_PrepareForRun(self):
+        self.assertIsNone(self.rsa.DEVICE_PrepareForRun())
+
+    def test_DEVICE_Run(self):
+        self.assertIsNone(self.rsa.DEVICE_Run())
+        self.assertTrue(self.rsa.DEVICE_GetEnable())
+
+    def test_DEVICE_Stop(self):
+        self.assertIsNone(self.rsa.DEVICE_Stop())
+        self.assertFalse(self.rsa.DEVICE_GetEnable())
+
+    def test_DEVICE_GetEventStatus_no_signal(self):
+        eventType = ['OVERRANGE', 'TRIGGER', '1PPS']
+        for e in eventType:
+            event, timestamp = self.rsa.DEVICE_GetEventStatus(e)
+            self.assertFalse(event)
+            self.assertEqual(timestamp, 0)
+        self.assertRaises(TypeError, self.rsa.DEVICE_GetEventStatus, 0)
+        self.assertRaises(rsa_api.RSAError, self.rsa.DEVICE_GetEventStatus, 'abc')
+
+    def test_DEVICE_GetEventStatus_trig_event(self):
+        self.rsa.DEVICE_Stop()
+        # Setup trigger mode
+        self.rsa.TRIG_SetTriggerMode('triggered')
+        self.rsa.TRIG_SetTriggerSource('IFPowerLevel')
+        self.rsa.TRIG_SetTriggerTransition('Either')
+        self.rsa.TRIG_SetIFPowerTriggerLevel(0)
+        self.rsa.DEVICE_Run()
+        self.rsa.TRIG_ForceTrigger()
+        sleep(0.5)
+        trig, trigTs = self.rsa.DEVICE_GetEventStatus('TRIGGER')
+        self.assertTrue(trig)
+        self.assertGreater(trigTs, 0)
+
+    """
+    # The following test would require an actual overrange event.
+    def test_DEVICE_GetEventStatus_overrange(self):
+        pass
+    """
+
+    def test_DEVICE_GetOverTemperatureStatus(self):
+        self.assertIsInstance(self.rsa.DEVICE_GetOverTemperatureStatus(), bool)
+        self.assertEqual(self.rsa.DEVICE_GetOverTemperatureStatus(), False)
+
+    def test_DEVICE_GetNomenclature(self):
+        self.assertIsInstance(self.rsa.DEVICE_GetNomenclature(), str)
+
+    def test_DEVICE_GetSerialNumber(self):
+        sn = self.rsa.DEVICE_GetSerialNumber()
+        self.assertIsInstance(sn, str)
+        self.assertEqual(len(sn), 7)
+
+    def test_DEVICE_GetAPIVersion(self):
+        # This uses the Linux API version number
+        self.assertEqual(self.rsa.DEVICE_GetAPIVersion(), '1.0.0014')
+
+    def test_DEVICE_GetFWVersion(self):
+        self.assertIsInstance(self.rsa.DEVICE_GetFWVersion(), str)
+
+    def test_DEVICE_GetFPGAVersion(self):
+        self.assertIsInstance(self.rsa.DEVICE_GetFPGAVersion(), str)
+
+    def test_DEVICE_GetHWVersion(self):
+        self.assertIsInstance(self.rsa.DEVICE_GetHWVersion(), str)
+
+    def test_DEVICE_GetInfo(self):
+        info = self.rsa.DEVICE_GetInfo()
+        self.assertIsInstance(info, dict)
+        self.assertEqual(len(info), 6)
+        self.assertEqual(len(info['serialNum']), 7)
+        self.assertEqual(info['apiVersion'], '1.0.0014')
+        self.assertIsInstance(info['fwVersion'], str)
+        self.assertIsInstance(info['fpgaVersion'], str)
+        self.assertIsInstance(info['hwVersion'], str)
+
+    """IQBLK Command Testing"""
+
+    def test_IQBLK_MinMaxIQBandwidth(self):
+        maxBw = self.rsa.IQBLK_GetMaxIQBandwidth()
+        minBw = self.rsa.IQBLK_GetMinIQBandwidth()
+        self.rsa.IQBLK_SetIQBandwidth(maxBw)  # To get maxRl properly
+        maxRl = self.rsa.IQBLK_GetMaxIQRecordLength()
+        self.assertEqual(maxBw, 40e6)
+        self.assertEqual(minBw, 100)
+        self.assertEqual(maxRl, 126000000)
+
+    def test_IQBLK_IQBandwidth(self):
+        iqBw = 20e6
+        self.assertIsNone(self.rsa.IQBLK_SetIQBandwidth(iqBw))
+        self.assertEqual(iqBw, self.rsa.IQBLK_GetIQBandwidth())
+        self.assertRaises(ValueError, self.rsa.IQBLK_SetIQBandwidth, self.neg)
+        self.assertRaises(ValueError, self.rsa.IQBLK_SetIQBandwidth, 100e6)
+        self.assertRaises(TypeError, self.rsa.IQBLK_SetIQBandwidth, 'abc')
+
+    def test_IQBLK_IQRecordLength(self):
+        iqRl = 8192
+        self.assertIsNone(self.rsa.IQBLK_SetIQRecordLength(iqRl))
+        self.assertEqual(iqRl, self.rsa.IQBLK_GetIQRecordLength())
+        self.assertRaises(ValueError, self.rsa.IQBLK_SetIQRecordLength, self.neg)
+        self.assertRaises(ValueError, self.rsa.IQBLK_SetIQRecordLength, 200e6)
+        self.assertRaises(TypeError, self.rsa.IQBLK_SetIQRecordLength, 'abc')
+
+    def test_IQBLK_GetSampleRate(self):
+        self.assertIsInstance(self.rsa.IQBLK_GetIQSampleRate(), float)
+
+    def test_IQBLK_GetIQData(self):
+        self.rsa.IQBLK_Configure()  # Configure to defaults
+        i, q = self.rsa.IQBLK_Acquire()
+        self.assertEqual(len(i), 1024)
+        self.assertEqual(len(q), 1024)
+
+        self.assertRaises(ValueError, self.rsa.IQBLK_Acquire, rec_len=self.neg)
+        self.assertRaises(ValueError, self.rsa.IQBLK_Acquire, rec_len=200000000)
+        self.assertRaises(TypeError, self.rsa.IQBLK_Acquire, rec_len='abc')
+
+    """IQSTREAM Command Testing"""
+
+    def test_IQSTREAM_MinMaxIQBandwidth(self):
+        minBandwidthHz = self.rsa.IQSTREAM_GetMinAcqBandwidth()
+        maxBandwidthHz = self.rsa.IQSTREAM_GetMaxAcqBandwidth()
+        self.assertEqual(minBandwidthHz, 9765.625)
+        self.assertEqual(maxBandwidthHz, 40e6)
+
+    def test_IQSTREAM_AcqBandwidth(self):
+        bwHz_req = [40e6, 20e6, 10e6, 5e6, 2.5e6, 1.25e6, 625e3, 312.5e3,
+                    156.25e3, 78125, 39062.5, 19531.25, 9765.625]
+        srSps_req = [56e6, 28e6, 14e6, 7e6, 3.5e6, 1.75e6, 875e3,
+                     437.5e3, 218.75e3, 109.375e3, 54687.5, 27343.75,
+                     13671.875]
+        baseSize = [65536, 65536, 65536, 65536, 65536, 32768, 16384, 8192,
+                    4096, 2048, 1024, 512, 256, 128]
+        for b, s, r in zip(bwHz_req, srSps_req, baseSize):
+            self.assertIsNone(self.rsa.IQSTREAM_SetAcqBandwidth(b))
+            bwHz_act, srSps = self.rsa.IQSTREAM_GetAcqParameters()
+            self.assertEqual(bwHz_act, b)
+            self.assertEqual(srSps, s)
+            self.assertIsNone(self.rsa.IQSTREAM_SetIQDataBufferSize(r))
+            self.assertEqual(self.rsa.IQSTREAM_GetIQDataBufferSize(), r)
+
+        self.assertRaises(TypeError, self.rsa.IQSTREAM_SetAcqBandwidth, 'abc')
+        self.assertRaises(TypeError, self.rsa.IQSTREAM_SetAcqBandwidth, [self.num])
+        self.assertRaises(ValueError, self.rsa.IQSTREAM_SetAcqBandwidth, 41e6)
+
+    def test_IQSTREAM_SetOutputConfiguration(self):
+        dest = ['CLIENT', 'FILE_TIQ', 'FILE_SIQ', 'FILE_SIQ_SPLIT']
+        dtype = ['SINGLE', 'INT32', 'INT16', 'SINGLE_SCALE_INT32']
+
+        for d in dest:
+            for t in dtype:
+                if d == 'FILE_TIQ' and 'SINGLE' in t:
+                    self.assertRaises(rsa_api.RSAError,
+                                      self.rsa.IQSTREAM_SetOutputConfiguration, d, t)
+                else:
+                    self.assertIsNone(self.rsa.IQSTREAM_SetOutputConfiguration(d, t))
+
+        self.assertRaises(TypeError, self.rsa.IQSTREAM_SetOutputConfiguration,
+                          self.num, dtype[0])
+        self.assertRaises(TypeError, self.rsa.IQSTREAM_SetOutputConfiguration,
+                          dest[0], self.num)
+        self.assertRaises(rsa_api.RSAError, self.rsa.IQSTREAM_SetOutputConfiguration, 'a', 'SINGLE')
+        self.assertRaises(rsa_api.RSAError, self.rsa.IQSTREAM_SetOutputConfiguration, 'CLIENT', 'a')
+
+    def test_IQSTREAM_SetDiskFilenameBase(self):
+        path = '/tmp/rsa_api_unittest'
+        if not isdir(path):
+            mkdir(path)
+        filename = 'iqstream_test'
+        filenameBase = path + filename
+        self.assertIsNone(self.rsa.IQSTREAM_SetDiskFilenameBase(filenameBase))
+
+        self.assertRaises(TypeError, self.rsa.IQSTREAM_SetDiskFilenameBase, self.num)
+        self.assertRaises(TypeError, self.rsa.IQSTREAM_SetDiskFilenameBase, b'abc')
+        self.assertRaises(TypeError, self.rsa.IQSTREAM_SetDiskFilenameBase, [self.num])
+
+    def test_IQSTREAM_SetDiskFilenameSuffix(self):
+        suffixCtl = [0, -1, -2]
+        for s in suffixCtl:
+            self.assertIsNone(self.rsa.IQSTREAM_SetDiskFilenameSuffix(s))
+
+        self.assertRaises(TypeError, self.rsa.IQSTREAM_SetDiskFilenameSuffix, 'abc')
+        self.assertRaises(ValueError, self.rsa.IQSTREAM_SetDiskFilenameSuffix, self.neg)
+
+    def test_IQSTREAM_SetDiskFileLength(self):
+        length = 100
+        self.assertIsNone(self.rsa.IQSTREAM_SetDiskFileLength(length))
+        self.assertRaises(TypeError, self.rsa.IQSTREAM_SetDiskFileLength, 'abc')
+        self.assertRaises(ValueError, self.rsa.IQSTREAM_SetDiskFileLength, self.neg)
+
+    def test_IQSTREAM_Operation(self):
+        self.rsa.IQSTREAM_SetAcqBandwidth(5e6)
+        self.rsa.IQSTREAM_SetOutputConfiguration('CLIENT', 'INT16')
+        self.rsa.IQSTREAM_GetAcqParameters()
+        self.rsa.DEVICE_Run()
+
+        self.assertIsNone(self.rsa.IQSTREAM_Start())
+        self.assertTrue(self.rsa.IQSTREAM_GetEnable())
+
+        self.assertIsNone(self.rsa.IQSTREAM_Stop())
+        self.assertFalse(self.rsa.IQSTREAM_GetEnable())
+
+        self.rsa.DEVICE_Stop()
+
+    def test_IQSTREAM_ClearAcqStatus(self):
+        self.assertIsNone(self.rsa.IQSTREAM_ClearAcqStatus())
+
+    """TRIG Command Testing"""
+
+    def test_TRIG_TriggerMode(self):
+        mode = ["freerun", "triggered"]
+        for m in mode:
+            self.assertIsNone(self.rsa.TRIG_SetTriggerMode(m))
+            self.assertEqual(self.rsa.TRIG_GetTriggerMode(), m)
+
+    def test_TRIG_TriggerSource(self):
+        source = ["External", "IFPowerLevel"]
+        for s in source:
+            self.assertIsNone(self.rsa.TRIG_SetTriggerSource(s))
+            self.assertEqual(self.rsa.TRIG_GetTriggerSource(), s)
+
+    def test_TRIG_TriggerTransition(self):
+        trans = ["LH", "HL", "Either"]
+        for t in trans:
+            self.assertIsNone(self.rsa.TRIG_SetTriggerTransition(t))
+            self.assertEqual(self.rsa.TRIG_GetTriggerTransition(), t)
+        self.assertRaises(TypeError, self.rsa.TRIG_SetTriggerTransition, 0)
+
+    def test_TRIG_IFPowerTriggerLevel(self):
+        trigLevel = -10
+        self.assertIsNone(self.rsa.TRIG_SetIFPowerTriggerLevel(trigLevel))
+        self.assertEqual(self.rsa.TRIG_GetIFPowerTriggerLevel(), trigLevel)
+        self.assertRaises(TypeError, self.rsa.TRIG_SetIFPowerTriggerLevel, 'trigger')
+        self.assertRaises(ValueError, self.rsa.TRIG_SetIFPowerTriggerLevel, 31)
+        self.assertRaises(ValueError, self.rsa.TRIG_SetIFPowerTriggerLevel, -131)
+
+    def test_TRIG_TriggerPositionPercent(self):
+        self.assertRaises(ValueError, self.rsa.TRIG_SetTriggerPositionPercent, 0.5)
+        self.assertRaises(ValueError, self.rsa.TRIG_SetTriggerPositionPercent, 100)
+        self.assertRaises(TypeError, self.rsa.TRIG_SetTriggerPositionPercent, 'abc')
+
+        pos = 20
+        self.assertIsNone(self.rsa.TRIG_SetTriggerPositionPercent(pos))
+        self.assertEqual(self.rsa.TRIG_GetTriggerPositionPercent(), pos)
+
+    def test_TRIG_ForceTrigger(self):
+        self.assertIsNone(self.rsa.TRIG_ForceTrigger())
+
+    """SPECTRUM Command Testing"""
+
+    def test_SPECTRUM_Enable(self):
+        enable = [False, True]
+        for e in enable:
+            self.assertIsNone(self.rsa.SPECTRUM_SetEnable(e))
+            self.assertEqual(self.rsa.SPECTRUM_GetEnable(), e)
+
+    def test_SPECTRUM_Settings(self):
+        self.assertIsNone(self.rsa.SPECTRUM_SetDefault())
+
+        span = 20e6
+        rbw = 100e3
+        enableVBW = True
+        vbw = 50e3
+        traceLength = 1601
+        window = 'Hann'
+        verticalUnit = 'dBm'
+        self.assertIsNone(self.rsa.SPECTRUM_SetSettings(span, rbw, enableVBW, vbw,
+                                                   traceLength, window,
+                                                   verticalUnit))
+        settings = self.rsa.SPECTRUM_GetSettings()
+        self.assertIsInstance(settings, dict)
+        self.assertEqual(len(settings), 13)
+        self.assertEqual(settings['span'], span)
+        self.assertEqual(settings['rbw'], rbw)
+        self.assertEqual(settings['enableVBW'], enableVBW)
+        self.assertEqual(settings['vbw'], vbw)
+        self.assertEqual(settings['window'], window)
+        self.assertEqual(settings['traceLength'], traceLength)
+        self.assertEqual(settings['verticalUnit'], verticalUnit)
+
+        self.assertRaises(TypeError, self.rsa.SPECTRUM_SetSettings, 'span', 'rbw',
+                          'enableVBW', 'vbw', 'traceLength',
+                          1, 0)
+
+    def test_SPECTRUM_TraceType(self):
+        trace = 'Trace2'
+        enable = True
+        detector = 'AverageVRMS'
+        self.assertIsNone(self.rsa.SPECTRUM_SetTraceType(trace, enable, detector))
+        o_enable, o_detector = self.rsa.SPECTRUM_GetTraceType(trace)
+        self.assertEqual(enable, o_enable)
+        self.assertEqual(detector, o_detector)
+
+        self.assertRaises(rsa_api.RSAError, self.rsa.SPECTRUM_SetTraceType, trace='abc')
+        self.assertRaises(TypeError, self.rsa.SPECTRUM_SetTraceType, trace=40e5)
+        self.assertRaises(rsa_api.RSAError, self.rsa.SPECTRUM_SetTraceType,
+                          detector='abc')
+        self.assertRaises(TypeError, self.rsa.SPECTRUM_SetTraceType, detector=40e5)
+
+    def test_SPECTRUM_GetLimits(self):
+        if self.device in ['RSA306B', 'RSA306']:
+            maxSpan = 6.2e9
+        elif self.device in ['RSA503A', 'RSA603A']:
+            maxSpan = 3.0e9
+        elif self.device in ['RSA507A', 'RSA607A']:
+            maxSpan = 7.5e9
+        elif self.device == 'RSA513A':
+            maxSpan = 13.6e9
+        elif self.device == 'RSA518A':
+            maxSpan = 18.0e9
+
+        limits = self.rsa.SPECTRUM_GetLimits()
+        self.assertIsInstance(limits, dict)
+        self.assertEqual(len(limits), 8)
+        self.assertEqual(limits['maxSpan'], maxSpan)
+        self.assertEqual(limits['minSpan'], 1e3)
+        self.assertEqual(limits['maxRBW'], 10e6)
+        self.assertEqual(limits['minRBW'], 10)
+        self.assertEqual(limits['maxVBW'], 10e6)
+        self.assertEqual(limits['minVBW'], 1)
+        self.assertEqual(limits['maxTraceLength'], 64001)
+        self.assertEqual(limits['minTraceLength'], 801)
+
+    def test_SPECTRUM_Acquire(self):
+        self.rsa.SPECTRUM_SetEnable(True)
+        span = 20e6
+        rbw = 100e3
+        enableVBW = True
+        vbw = 50e3
+        traceLength = 1601
+        window = 'Hann'
+        verticalUnit = 'dBm'
+        self.rsa.SPECTRUM_SetSettings(span, rbw, enableVBW, vbw, traceLength, window,
+                                 verticalUnit)
+        spectrum, outTracePoints = self.rsa.SPECTRUM_Acquire(trace='Trace1',
+                                                        trace_points=traceLength)
+        self.assertEqual(len(spectrum), traceLength)
+        self.assertIsInstance(spectrum, np.ndarray)
+        self.assertRaises(TypeError, self.rsa.SPECTRUM_Acquire, trace=1)
+
+        traceInfo = self.rsa.SPECTRUM_GetTraceInfo()
+        self.assertIsInstance(traceInfo, dict)
+        self.assertEqual(len(traceInfo), 2)