-- Copyright (c) 2021-2022 Nicholas Corgan -- SPDX-License-Identifier: BSL-1.0 --- -- Abstraction for an SDR transceiver device -- @module SoapySDR.Device local ffi = require("ffi") local lib = require("SoapySDR.Lib") local Utility = require("SoapySDR.Utility") -- -- Device-specific utility -- -- Note: lengthPtr is only needed for lists local function processDeviceOutput(ret, lengthPtr) -- See if an exception was caught in the last function call. local lastError = ffi.string(lib.SoapySDRDevice_lastError()) if #lastError > 0 then error(lastError) end return Utility.processOutput(ret, lengthPtr) end local function processDeviceSetting(settingRet, settingName, allSettingInfo) local settingStr = processDeviceOutput(settingRet) local nativeSetting = "" for i=1,#allSettingInfo do local settingInfo = allSettingInfo[i] if settingInfo["name"] == settingName then nativeSetting = Utility.stringToSoapySetting(settingStr, settingInfo["argType"]) break end end return nativeSetting end -- -- Device enumeration -- local function enumerateDevices(args) local devs = nil local lengthPtr = ffi.new("size_t[1]") -- No parameter means no args args = args or "" -- Abstract away different functions local argsType = tostring(type(args)) if argsType == "string" then devs = Utility.processRawKwargsList( lib.SoapySDRDevice_enumerateStrArgs(args, lengthPtr), lengthPtr) else devs = Utility.processRawKwargsList( lib.SoapySDRDevice_enumerate(Utility.toKwargs(args), lengthPtr), lengthPtr) end return devs end --- -- Abstraction for an SDR transceiver device. -- @type Device Device = {} Device_mt = { __index = Device, __tostring = function(self) return string.format("%s:%s", self:getDriverKey(), self:getHardwareKey()) end } --- Make a new device object given device construction args. -- -- @param[opt=""] args A table or markup string specifying construction args -- @usage -- local dev1 = SoapySDR.Device.new() -- local dev2 = SoapySDR.Device.new("driver=rtlsdr,serial=00000001") -- local dev3 = SoapySDR.Device.new({driver="audio",device_id=0}) function Device.new(args) -- No parameter means no args args = args or "" -- Abstract away different C constructor functions local dev = nil local argsType = tostring(type(args)) if argsType == "string" then dev = ffi.gc( lib.SoapySDRDevice_makeStrArgs(args), lib.SoapySDRDevice_unmake) else dev = ffi.gc( lib.SoapySDRDevice_make(Utility.toKwargs(args)), lib.SoapySDRDevice_unmake) end if dev == nil then error("Invalid device args") end return setmetatable({__deviceHandle = dev}, Device_mt) end -- -- Identification API -- --- -- A key that uniquely identifies the device driver. -- This key identifies the underlying implementation. -- Several variants of a product may share a driver. -- -- @treturn string Driver key function Device:getDriverKey() return processDeviceOutput(lib.SoapySDRDevice_getDriverKey(self.__deviceHandle)) end --- -- A key that uniquely identifies the hardware. -- This key should be meaningful to the user -- to optimize for the underlying hardware. -- -- @treturn string Hardware key function Device:getHardwareKey() return processDeviceOutput(lib.SoapySDRDevice_getHardwareKey(self.__deviceHandle)) end --- -- Query a dictionary of available device information. -- This dictionary can any number of values like -- vendor name, product name, revisions, serials... -- -- @treturn table A dictionary-like table with hardware info function Device:getHardwareInfo() return processDeviceOutput(lib.SoapySDRDevice_getHardwareInfo(self.__deviceHandle)) end -- -- Channels API -- --- -- Set the frontend mapping of available DSP units to RF frontends. -- This mapping controls channel mapping and channel availability. -- -- @tparam SoapySDR.Direction direction the channel direction (RX or TX) -- @tparam string mapping a vendor-specific mapping string function Device:setFrontendMapping(direction, mapping) return processDeviceOutput(lib.SoapySDRDevice_setFrontendMapping( self.__deviceHandle, direction, Utility.toString(mapping))) end --- -- Get the mapping configuration string. -- -- @tparam SoapySDR.Direction direction the channel direction (RX or TX) -- @treturn string The vendor-specific mapping string function Device:getFrontendMapping(direction) return processDeviceOutput(lib.SoapySDRDevice_getFrontendMapping( self.__deviceHandle, direction)) end --- -- Get a number of channels given the streaming direction -- -- @tparam SoapySDR.Direction direction the channel direction (RX or TX) function Device:getNumChannels(direction) return processDeviceOutput(lib.SoapySDRDevice_getNumChannels( self.__deviceHandle, direction)) end --- -- Query a dictionary of available channel information. -- This dictionary can any number of values like -- decoder type, version, available functions... -- -- @tparam SoapySDR.Direction direction the channel direction (RX or TX) -- @tparam uint channel an available channel on the device -- @treturn table A dictionary-like table with channel information function Device:getChannelInfo(direction, channel) return processDeviceOutput(lib.SoapySDRDevice_getChannelInfo( self.__deviceHandle, direction, channel)) end --- -- Find out if the specified channel is full or half duplex. -- -- @tparam SoapySDR.Direction direction the channel direction RX or TX -- @tparam uint channel an available channel on the device -- @treturn boolean True for full duplex, false for half duplex function Device:getFullDuplex(direction, channel) return processDeviceOutput(lib.SoapySDRDevice_getFullDuplex( self.__deviceHandle, direction, channel)) end -- -- Stream API -- --- -- Query a list of the available stream formats. -- -- @tparam SoapySDR.Direction direction the channel direction (RX or TX) -- @tparam uint channel an available channel on the device -- @treturn table A list of allowed @{SoapySDR.Format} strings. function Device:getStreamFormats(direction, channel) local lengthPtr = ffi.new("size_t[1]") return processDeviceOutput( lib.SoapySDRDevice_getStreamFormats( self.__deviceHandle, direction, channel, lengthPtr), lengthPtr) end --- -- Get the hardware's native stream format for this channel. -- This is the format used by the underlying transport layer. -- -- @tparam SoapySDR.Direction direction the channel direction (RX or TX) -- @tparam uint channel an available channel on the device -- @treturn string The device's native stream buffer @{SoapySDR.Format} string -- @treturn double The device's native fullscale conversion value -- -- @usage -- local format, fullScale = unpack(sdr:getNativeStreamFormat(SoapySDR.Direction.TX, 0)) function Device:getNativeStreamFormat(direction, channel) local fullScalePtr = ffi.new("double[1]") local format = processDeviceOutput( lib.SoapySDRDevice_getNativeStreamFormat( self.__deviceHandle, direction, channel, fullScalePtr), fullScalePtr) return {format, tonumber(fullScalePtr[0])} end --- -- Query the valid stream arguments for the given chain. -- -- @tparam SoapySDR.Direction direction the channel direction (RX or TX) -- @tparam uint channel an available channel on the device -- @treturn table A list of @{SoapySDR.ArgInfo} tables function Device:getStreamArgsInfo(direction, channel) local lengthPtr = ffi.new("size_t[1]") return processDeviceOutput( lib.SoapySDRDevice_getStreamArgsInfo( self.__deviceHandle, direction, channel, lengthPtr), lengthPtr) end --- -- Initialize a stream given a list of channels and stream arguments. -- The implementation may change switches or power-up components. -- All stream API calls should be usable with the new stream object -- after setupStream() is complete, regardless of the activity state. -- -- The API allows any number of simultaneous TX and RX streams, but many dual-channel -- devices are limited to one stream in each direction, using either one or both channels. -- This call will return an error if an unsupported combination is requested, -- or if a requested channel in this direction is already in use by another stream. -- -- When multiple channels are added to a stream, they are typically expected to have -- the same sample rate. -- -- @tparam SoapySDR.Direction direction the channel direction (RX or TX) -- @tparam string format A supported @{SoapySDR.Format} string -- @tparam table channels A list of device channels -- @param[opt=""] args Stream arguments (can be omitted or passed as string or table) -- @return An opaque stream handle to be passed into other functions -- @see Device:getStreamArgsInfo -- -- @usage -- local direction = SoapySDR.Direction.RX -- local format = SoapySDR.Format.CF32 -- local channels = {0,1} -- local args = "bufflen=8192,buffers=15" -- -- local stream = sdr:setupStream(direction, format, channels, args) function Device:setupStream(direction, format, channels, args) local ret = processDeviceOutput(lib.SoapySDRDevice_setupStream( self.__deviceHandle, direction, Utility.toString(format), Utility.luaArrayToFFIArray(channels, "size_t"), #channels, Utility.toKwargs(args))) return ret end --- -- Close an open stream created by setupStream. -- The implementation may change switches or power-down components. -- -- @param stream stream handle returned by @{Device:setupStream} function Device:closeStream(stream) return processDeviceOutput(lib.SoapySDRDevice_closeStream( self.__deviceHandle, stream)) end --- -- Get the stream's maximum transmission unit (MTU) in number of elements. -- The MTU specifies the maximum payload transfer in a stream operation. -- This value can be used as a stream buffer allocation size that can -- best optimize throughput given the underlying stream implementation. -- -- @param stream stream handle returned by @{Device:setupStream} -- @treturn uint The MTU in number of stream elements (always > 0) function Device:getStreamMTU(stream) return processDeviceOutput(lib.SoapySDRDevice_getStreamMTU( self.__deviceHandle, stream)) end --- -- Activate a stream. -- Call activate to prepare a stream before using read/write(). -- The implementations control switches or stimulate data flow. -- -- The timeNs is only valid when the flags have HAS_TIME. -- The numElems count can be used to request a finite burst size. -- The END_BURST flag can signal end on the finite burst. -- Not all implementations will support the full range of options. -- In this case, the implementation returns NOT_SUPPORTED. -- -- @param stream stream handle returned by @{Device:setupStream} -- @tparam[opt=0] SoapySDR.StreamFlags flags optional flag indicators about the stream. -- @tparam[opt=0] uint timeNs optional activation time in nanoseconds -- @tparam[opt=0] uint numElems optional element count for burst control -- @return 0 for success or @{SoapySDR.Error} on failure. function Device:activateStream(stream, flags, timeNs, numElems) -- To allow for optional parameters flags = flags or 0 timeNs = timeNs or 0 numElems = numElems or 0 return processDeviceOutput(lib.SoapySDRDevice_activateStream( self.__deviceHandle, stream, flags, timeNs, numElems)) end --- -- Deactivate a stream. -- Call deactivate when not using using read/write(). -- The implementation control switches or halt data flow. -- -- The timeNs is only valid when the flags have HAS_TIME. -- Not all implementations will support the full range of options. -- In this case, the implementation returns NOT_SUPPORTED. -- -- @param stream stream handle returned by @{Device:setupStream} -- @tparam[opt=0] SoapySDR.StreamFlags flags optional flag indicators about the stream. -- @tparam[opt=0] uint timeNs optional deactivation time in nanoseconds. -- @return 0 for success or @{SoapySDR.Error} on failure function Device:deactivateStream(stream, flags, timeNs) -- To allow for optional parameters flags = flags or 0 timeNs = timeNs or 0 return processDeviceOutput(lib.SoapySDRDevice_deactivateStream( self.__deviceHandle, stream, flags, timeNs)) end --- -- Read elements from a stream for reception. -- -- @param stream stream handle returned by @{Device:setupStream} -- @param buffs a LuaJIT FFI array of pointers to buffers of size numElems -- @tparam uint numElems the number of elements in each buffer -- @tparam[opt=100000] uint timeoutUs the timeout in microseconds -- @return The number of elements read or @{SoapySDR.Error} on failure -- @treturn SoapySDR.StreamFlags Metadata flags returned by the read operation -- @treturn uint The buffer's timestamp in nanoseconds -- -- @usage -- local cf32Buff0 = ffi.new("complex float[?]", numElems) -- local cf32Buff1 = ffi.new("complex float[?]", numElems) -- local cf32Buffs = ffi.new("complex float*[2]", {cf32Buff0, cf32Buff1}) -- -- local ret, flags, timeNs = unpack(sdr:readStream(stream, cf32Buffs, numElems, timeoutUs)) function Device:readStream(stream, buffs, numElems, timeoutUs) -- To allow for optional parameters timeoutUs = timeoutUs or 100000 local flagsPtr = ffi.new("int[1]") local timeNsPtr = ffi.new("long long[1]") local ret = processDeviceOutput(lib.SoapySDRDevice_readStream( self.__deviceHandle, stream, ffi.cast("void* const*", buffs), numElems, flagsPtr, timeNsPtr, timeoutUs)) return {ret, tonumber(flagsPtr[0]), tonumber(timeNsPtr[0])} end --- -- Write elements to a stream for transmission. -- -- @param stream stream handle returned by @{Device:setupStream} -- @param buffs a LuaJIT FFI array of pointers to buffers of size numElems -- @tparam uint numElems the number of elements in each buffer -- @tparam[opt=0] SoapySDR.StreamFlags flagsIn input flags for the write operation -- @tparam[opt=0] uint timeNs the buffer's timestamp in nanoseconds -- @tparam[opt=100000] uint timeoutUs the timeout in microseconds -- @return The number of elements written or @{SoapySDR.Error} on failure -- @treturn SoapySDR.StreamFlags Metadata flags returned by the write operation -- -- @usage -- local cf32Buff0 = ffi.new("complex float[?]", numElems) -- local cf32Buff1 = ffi.new("complex float[?]", numElems) -- local cf32Buffs = ffi.new("complex float*[2]", {cf32Buff0, cf32Buff1}) -- -- local ret, flagsOut = unpack(sdr:writeStream(stream, cf32Buffs, numElems, flagsIn, timeNs, timeoutUs)) function Device:writeStream(stream, buffs, numElems, flagsIn, timeNs, timeoutUs) -- To allow for optional parameters flagsIn = flagsIn or 0 timeNs = timeNs or 0 timeoutUs = timeoutUs or 100000 local flagsPtr = ffi.new("int[1]", {flagsIn}) local ret = processDeviceOutput(lib.SoapySDRDevice_writeStream( self.__deviceHandle, stream, ffi.cast("const void* const*", buffs), numElems, flagsPtr, timeNs, timeoutUs)) return {ret, tonumber(flagsPtr[0])} end --- -- Readback status information about a stream. -- This call is typically used on a transmit stream -- to report time errors, underflows, and burst completion. -- -- @param stream stream handle returned by @{Device:setupStream} -- @tparam[opt=100000] uint timeoutUs the timeout in microseconds -- @return The number of elements written or @{SoapySDR.Error} on failure -- @treturn SoapySDR.StreamFlags Metadata flags returned by the write operation -- @treturn uint The buffer's timestamp in nanoseconds function Device:readStreamStatus(stream, timeoutUs) -- To allow for optional parameters timeoutUs = timeoutUs or 100000 local chanMaskPtr = ffi.new("size_t[1]") local flagsPtr = ffi.new("int[1]") local timeNsPtr = ffi.new("long long[1]") local ret = processDeviceOutput(lib.SoapySDRDevice_readStreamStatus( self.__deviceHandle, stream, chanMaskPtr, flagsPtr, timeNsPtr, timeoutUs)) return {ret, tonumber(chanMaskPtr[0]), tonumber(flagsPtr[0]), tonumber(timeNsPtr[0])} end -- -- Antenna API -- --- -- Get a list of available antennas to select on a given chain. -- -- @tparam SoapySDR.Direction direction the channel direction (RX or TX) -- @tparam uint channel an available channel on the device -- @treturn table A list of available antenna names. function Device:listAntennas(direction, channel) local lengthPtr = ffi.new("size_t[1]") return processDeviceOutput( lib.SoapySDRDevice_listAntennas( self.__deviceHandle, direction, channel, lengthPtr), lengthPtr) end --- -- Set the selected antenna on a chain. -- -- @tparam SoapySDR.Direction direction the channel direction (RX or TX) -- @tparam uint channel an available channel on the device -- @tparam string name the name of an available antenna -- @see Device:listAntennas function Device:setAntenna(direction, channel, name) return processDeviceOutput(lib.SoapySDRDevice_setAntenna( self.__deviceHandle, direction, channel, Utility.toString(name))) end --- -- Get the selected antenna on a chain. -- -- @tparam SoapySDR.Direction direction the channel direction (RX or TX) -- @tparam uint channel an available channel on the device -- @return The name of an available antenna. -- @see Device:listAntennas function Device:getAntenna(direction, channel) return processDeviceOutput(lib.SoapySDRDevice_getAntenna( self.__deviceHandle, direction, channel)) end -- -- Frontend corrections API -- --- -- Does the device support automatic DC offset corrections? -- -- @tparam SoapySDR.Direction direction the channel direction (RX or TX) -- @tparam uint channel an available channel on the device -- @treturn boolean True if automatic corrections are supported function Device:hasDCOffsetMode(direction, channel) return processDeviceOutput(lib.SoapySDRDevice_hasDCOffsetMode( self.__deviceHandle, direction, channel)) end --- -- Set the automatic DC offset corrections mode. -- -- @tparam SoapySDR.Direction direction the channel direction (RX or TX) -- @tparam uint channel an available channel on the device -- @tparam boolean automatic true for automatic offset correction function Device:setDCOffsetMode(direction, channel, automatic) return processDeviceOutput(lib.SoapySDRDevice_setDCOffsetMode( self.__deviceHandle, direction, channel, automatic)) end --- -- Get the automatic DC offset corrections mode. -- -- @tparam SoapySDR.Direction direction the channel direction (RX or TX) -- @tparam uint channel an available channel on the device -- @treturn boolean True for automatic offset correction function Device:getDCOffsetMode(direction, channel) return processDeviceOutput(lib.SoapySDRDevice_getDCOffsetMode( self.__deviceHandle, direction, channel)) end --- -- Does the device support frontend DC offset correction? -- -- @tparam SoapySDR.Direction direction the channel direction (RX or TX) -- @tparam uint channel an available channel on the device -- @treturn boolean true if DC offset corrections are supported function Device:hasDCOffset(direction, channel) return processDeviceOutput(lib.SoapySDRDevice_hasDCOffset( self.__deviceHandle, direction, channel)) end --- -- Set the frontend DC offset correction. -- -- @tparam SoapySDR.Direction direction the channel direction (RX or TX) -- @tparam uint channel an available channel on the device -- @param offset new DC offset correction (can be either numeric or LuaJIT complex types) -- -- @usage -- sdr:setDCOffset(SoapySDR.Direction.RX, 0, 1) -- Becomes 1+0i -- sdr:setDCOffset(SoapySDR.Direction.RX, 0, ffi.new("complex float", 1, 0)) -- sdr:setDCOffset(SoapySDR.Direction.RX, 0, ffi.new("complex", 1, 0)) function Device:setDCOffset(direction, channel, offset) local complexOffset = Utility.toComplex(offset) return processDeviceOutput(lib.SoapySDRDevice_setDCOffset( self.__deviceHandle, direction, channel, complexOffset.re, complexOffset.im)) end --- -- Get the frontend DC offset correction. -- -- @tparam SoapySDR.Direction direction the channel direction (RX or TX) -- @tparam uint channel an available channel on the device -- @treturn complex The frontend DC offset correction function Device:getDCOffset(direction, channel) local iPtr = ffi.new("double[1]") local qPtr = ffi.new("double[1]") processDeviceOutput(lib.SoapySDRDevice_getDCOffset( self.__deviceHandle, direction, channel, iPtr, qPtr)) return ffi.new("complex", iPtr[0], qPtr[0]) end --- -- Does the device support automatic frontend IQ balance correction? -- -- @tparam SoapySDR.Direction direction the channel direction (RX or TX) -- @tparam uint channel an available channel on the device -- @treturn boolean True if IQ balance corrections are supported function Device:hasIQBalance(direction, channel) return processDeviceOutput(lib.SoapySDRDevice_hasIQBalance( self.__deviceHandle, direction, channel)) end --- -- Set the frontend IQ balance correction. -- -- @tparam SoapySDR.Direction direction the channel direction (RX or TX) -- @tparam uint channel an available channel on the device -- @param balance new IQ balance correction (can be either numeric or LuaJIT complex types) -- -- @usage -- sdr:setIQBalance(SoapySDR.Direction.RX, 0, 1) -- Becomes 1+0i -- sdr:setIQBalance(SoapySDR.Direction.RX, 0, ffi.new("complex float", 1, 0)) -- sdr:setIQBalance(SoapySDR.Direction.RX, 0, ffi.new("complex", 1, 0)) function Device:setIQBalance(direction, channel, balance) local complexBalance = Utility.toComplex(balance) return processDeviceOutput(lib.SoapySDRDevice_setIQBalance( self.__deviceHandle, direction, channel, complexBalance.re, complexBalance.im)) end --- -- Get the frontend IQ balance correction. -- -- @tparam SoapySDR.Direction direction the channel direction (RX or TX) -- @tparam uint channel an available channel on the device -- @treturn complex The frontend IQ balance correction function Device:getIQBalance(direction, channel) local iPtr = ffi.new("double[1]") local qPtr = ffi.new("double[1]") processDeviceOutput(lib.SoapySDRDevice_getIQBalance( self.__deviceHandle, direction, channel, iPtr, qPtr)) return ffi.new("complex", iPtr[0], qPtr[0]) end --- -- Does the device support automatic frontend IQ balance correction? -- -- @tparam SoapySDR.Direction direction the channel direction (RX or TX) -- @tparam uint channel an available channel on the device -- @treturn boolean True if IQ balance corrections are supported function Device:hasIQBalanceMode(direction, channel) return processDeviceOutput(lib.SoapySDRDevice_hasIQBalanceMode( self.__deviceHandle, direction, channel)) end --- -- Set the automatic frontend IQ balance correction mode. -- -- @tparam SoapySDR.Direction direction the channel direction (RX or TX) -- @tparam uint channel an available channel on the device -- @tparam boolean automatic true for automatic correction function Device:setIQBalanceMode(direction, channel, automatic) return processDeviceOutput(lib.SoapySDRDevice_setIQBalanceMode( self.__deviceHandle, direction, channel, automatic)) end --- -- Test the automatic front IQ balance correction mode. -- -- @tparam SoapySDR.Direction direction the channel direction (RX or TX) -- @tparam uint channel an available channel on the device -- @treturn boolean true for automatic correction function Device:getIQBalanceMode(direction, channel) return processDeviceOutput(lib.SoapySDRDevice_getIQBalanceMode( self.__deviceHandle, direction, channel)) end --- -- Does the device support frontend frequency correction? -- -- @tparam SoapySDR.Direction direction the channel direction (RX or TX) -- @tparam uint channel an available channel on the device -- @treturn boolean True if frequency corrections are supported function Device:hasFrequencyCorrection(direction, channel) return processDeviceOutput(lib.SoapySDRDevice_hasFrequencyCorrection( self.__deviceHandle, direction, channel)) end --- -- Set the frontend frequency correction value. -- -- @tparam SoapySDR.Direction direction the channel direction (RX or TX) -- @tparam uint channel an available channel on the device -- @tparam double value the correction in PPM function Device:setFrequencyCorrection(direction, channel, value) return processDeviceOutput(lib.SoapySDRDevice_setFrequencyCorrection( self.__deviceHandle, direction, channel, value)) end --- -- Get the frontend frequency correction value. -- -- @tparam SoapySDR.Direction direction the channel direction (RX or TX) -- @tparam uint channel an available channel on the device -- @treturn double The correction value in PPM function Device:getFrequencyCorrection(direction, channel) return processDeviceOutput(lib.SoapySDRDevice_getFrequencyCorrection( self.__deviceHandle, direction, channel)) end --- -- List available amplification elements. -- Elements should be in order RF to baseband. -- -- @tparam SoapySDR.Direction direction the channel direction (RX or TX) -- @tparam uint channel an available channel -- @return A list of gain string names function Device:listGains(direction, channel) local lengthPtr = ffi.new("size_t[1]") return processDeviceOutput( lib.SoapySDRDevice_listGains( self.__deviceHandle, direction, channel, lengthPtr), lengthPtr) end --- -- Does the device support automatic gain control? -- -- @tparam SoapySDR.Direction direction the channel direction (RX or TX) -- @tparam uint channel an available channel on the device -- @treturn boolean True for automatic gain control function Device:hasGainMode(direction, channel) return processDeviceOutput(lib.SoapySDRDevice_hasGainMode( self.__deviceHandle, direction, channel)) end --- -- Set the automatic gain mode on the chain. -- -- @tparam SoapySDR.Direction direction the channel direction (RX or TX) -- @tparam uint channel an available channel on the device -- @tparam boolean automatic True for automatic gain setting function Device:setGainMode(direction, channel, automatic) return processDeviceOutput(lib.SoapySDRDevice_setGainMode( self.__deviceHandle, direction, channel, automatic)) end --- -- Get the automatic gain mode on the chain. -- -- @tparam SoapySDR.Direction direction the channel direction (RX or TX) -- @tparam uint channel an available channel on the device -- @treturn boolean True for automatic gain setting function Device:getGainMode(direction, channel) return processDeviceOutput(lib.SoapySDRDevice_getGainMode( self.__deviceHandle, direction, channel)) end --- -- Set the overall amplification in a chain. -- The gain will be distributed automatically across available element. -- -- @tparam SoapySDR.Direction direction the channel direction (RX or TX) -- @tparam uint channel an available channel on the device -- @tparam double value The new amplification value in dB function Device:setGain(direction, channel, value) return processDeviceOutput(lib.SoapySDRDevice_setGain( self.__deviceHandle, direction, channel, value)) end --- -- Set the value of a amplification element in a chain. -- -- @tparam SoapySDR.Direction direction the channel direction (RX or TX) -- @tparam uint channel an available channel on the device -- @tparam string name the name of an amplification element -- @tparam double value the new amplification value in dB -- @see Device:listGains function Device:setGainElement(direction, channel, name, value) return processDeviceOutput(lib.SoapySDRDevice_setGainElement( self.__deviceHandle, direction, channel, Utility.toString(name), value)) end --- -- Get the overall value of the gain elements in a chain. -- -- @tparam SoapySDR.Direction direction the channel direction (RX or TX) -- @tparam uint channel an available channel on the device -- @treturn double The value of the gain in dB function Device:getGain(direction, channel) return processDeviceOutput(lib.SoapySDRDevice_getGain( self.__deviceHandle, direction, channel)) end --- -- Get the value of an individual amplification element in a chain. -- -- @tparam SoapySDR.Direction direction the channel direction (RX or TX) -- @tparam uint channel an available channel on the device -- @tparam string name the name of an amplification element -- @treturn double The value of the gain in dB -- @see Device:listGains function Device:getGainElement(direction, channel, name) return processDeviceOutput(lib.SoapySDRDevice_getGainElement( self.__deviceHandle, direction, channel, Utility.toString(name))) end --- -- Get the overall range of possible gain values. -- -- @tparam SoapySDR.Direction direction the channel direction (RX or TX) -- @tparam uint channel an available channel on the device -- @treturn SoapySDR.Range The range of possible values in dB function Device:getGainRange(direction, channel) return processDeviceOutput(lib.SoapySDRDevice_getGainRange( self.__deviceHandle, direction, channel)) end --- -- Get the range of possible gain values for a specific element. -- -- @tparam SoapySDR.Direction direction the channel direction (RX or TX) -- @tparam uint channel an available channel on the device -- @tparam string name the name of an amplification element -- @treturn SoapySDR.Range The range of possible values in dB -- @see Device:listGains function Device:getGainElementRange(direction, channel, name) return processDeviceOutput(lib.SoapySDRDevice_getGainElementRange( self.__deviceHandle, direction, channel, Utility.toString(name))) end --- -- Set the center frequency of the chain. --