From 3c767fe32af2baa8327930389dccd81c9bc13134 Mon Sep 17 00:00:00 2001 From: Brandon Smith Date: Thu, 10 Sep 2020 16:20:14 -0400 Subject: [PATCH] Updaing for 9-10-20 --- cyberradiodriver/CyberRadioDriver.doxyfile | 2 +- cyberradiodriver/CyberRadioDriver/__init__.py | 107 +- cyberradiodriver/CyberRadioDriver/command.py | 4 +- .../CyberRadioDriver/components.py | 19 +- .../CyberRadioDriver/configKeys.py | 12 +- cyberradiodriver/CyberRadioDriver/log.py | 4 +- cyberradiodriver/CyberRadioDriver/radio.py | 1063 ++++++++++++----- .../CyberRadioDriver/radios/__init__.py | 4 +- .../CyberRadioDriver/radios/ndr301.py | 7 +- .../CyberRadioDriver/radios/ndr301ptt.py | 22 +- .../CyberRadioDriver/radios/ndr304.py | 4 +- .../CyberRadioDriver/radios/ndr308.py | 226 ++-- .../CyberRadioDriver/radios/ndr354.py | 6 +- .../CyberRadioDriver/radios/ndr357.py | 5 +- .../CyberRadioDriver/radios/ndr358.py | 437 ++++++- .../CyberRadioDriver/radios/ndr364.py | 8 +- .../CyberRadioDriver/radios/ndr378.py | 279 +++++ .../CyberRadioDriver/radios/ndr511.py | 266 +++++ .../CyberRadioDriver/radios/ndr551.py | 116 +- .../CyberRadioDriver/radios/ndr562.py | 23 +- .../CyberRadioDriver/radios/ndr601.py | 4 +- .../CyberRadioDriver/radios/ndr651.py | 4 +- .../CyberRadioDriver/transport.py | 82 +- cyberradiodriver/cyberradiodriver.spec | 3 + gr-CyberRadio/debian/postinst | 7 + gr-CyberRadio/gr-cyberradio.spec | 2 +- .../CyberRadio_generic_ddc_control_block.xml | 5 +- ...CyberRadio_generic_tuner_control_block.xml | 9 + .../lib/snapshot_vector_source_impl.cc | 62 +- .../python/generic_ddc_control_block.py | 56 +- .../python/generic_radio_control_block.py | 6 +- .../python/generic_tuner_control_block.py | 15 +- gr-CyberRadio/swig/CyberRadio_swig.i | 3 - gr-CyberRadio/version.txt | 2 +- libcyberradio/.autotools | 1 + libcyberradio/.cproject | 45 +- libcyberradio/.settings/language.settings.xml | 7 +- libcyberradio/examples/CMakeLists.txt | 6 +- libcyberradio/libcyberradio.spec | 2 +- libcyberradio/libcyberradio/CMakeLists.txt | 6 +- libcyberradio/version.txt | 2 +- makerpm | 352 ++++++ 42 files changed, 2707 insertions(+), 588 deletions(-) create mode 100644 cyberradiodriver/CyberRadioDriver/radios/ndr378.py create mode 100755 cyberradiodriver/CyberRadioDriver/radios/ndr511.py create mode 100755 makerpm diff --git a/cyberradiodriver/CyberRadioDriver.doxyfile b/cyberradiodriver/CyberRadioDriver.doxyfile index 9921c10..a052252 100755 --- a/cyberradiodriver/CyberRadioDriver.doxyfile +++ b/cyberradiodriver/CyberRadioDriver.doxyfile @@ -32,7 +32,7 @@ PROJECT_NAME = CyberRadioDriver # This could be handy for archiving the generated documentation or # if some version control system is used. -PROJECT_NUMBER = 20.02.14 +PROJECT_NUMBER = 20.09.04a # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer diff --git a/cyberradiodriver/CyberRadioDriver/__init__.py b/cyberradiodriver/CyberRadioDriver/__init__.py index bfadc10..e11f9f6 100755 --- a/cyberradiodriver/CyberRadioDriver/__init__.py +++ b/cyberradiodriver/CyberRadioDriver/__init__.py @@ -23,8 +23,8 @@ # \author NH # \author DA # \author MN -# \copyright Copyright (c) 2017 CyberRadio Solutions, Inc. All -# rights reserved. +# \copyright Copyright (c) 2017-2020 CyberRadio Solutions, Inc. +# All rights reserved. # ############################################################### @@ -56,7 +56,7 @@ # # # -# +# # # # @@ -108,7 +108,7 @@ description = "CyberRadio Solutions NDR Driver" ## # \brief Driver version number (string). -version = "20.02.14e" +version = "20.09.04a" # # This section of code inspects the "radio" module for radio handler # # objects (objects derived from _radio, thus implementing the IRadio interface) @@ -252,13 +252,19 @@ def getRadioClass(nameString): # \brief Factory method for obtaining a radio handler object from the name # of the radio. # -# The name string used to identify the radio can be any string returned -# by getSupportedRadios(), but the check is not case-sensitive. The name -# string can also be "auto", in which case the method will attempt to -# auto-detect the type of radio connected to the system. Since radios can -# operate over both TCP and TTY (serial) links, the user needs to supply -# keyword arguments to indicate which devices to scan ("host" to scan over TCP, -# and/or "dev" to scan over TTY -- see below). +# The name string used to identify the radio can be: +# * Any string returned by getSupportedRadios() (but the check is not case- +# sensitive). +# * "auto", in which case the method will attempt to auto-detect the type of +# radio connected to the system. Since radios can operate over both +# Ethernet and TTY (serial) links, the user needs to supply keyword +# arguments to indicate which devices to scan ("host" to scan over +# Ethernet and/or "dev" to scan over TTY -- see below). +# * "server" or "crdd", in which case the method attempts to connect to the +# radio via the CyberRadio Driver Daemon (crdd). Supply the "host" and/or +# "port" arguments if CRDD is not running at the default location (local +# host, port 65432). Also, supply the "clientId" argument if you want +# crdd to log transactions for this client specially. # # This method uses keyword arguments to configure the returned radio handler # object. It consumes the following keyword arguments: @@ -278,6 +284,8 @@ def getRadioClass(nameString): # on this device if requested, and automatically connect to it. #
  • "baudrate": For TTY-connected radios, this is the baud rate for the serial # connection. If not provided, this defaults to the standard (921600). +#
  • "clientId": For connections through crdd, this provides an identifier +# that crdd can use to identify this client for logging purposes. # # If the "host" and "dev" keyword arguments are both provided, then the auto- # detection algorithm will try a TCP connection first before falling back to a @@ -354,10 +362,17 @@ def getRadioObject(nameString, *args, **kwargs): radioType = radioType.replace("ts", "_ts") radioType = radioType.replace("-", "_") radioType = radioType.replace("__", "_") + # NDR804-PTT weirdness: the model name has a space in it -- DA + if radioType == "ndr804 ptt": + radioType = "ndr804-ptt" + # NDR301-PTT weirdness: sometimes the model name does not have the dash + # in it -- DA + if radioType == "ndr301ptt": + radioType = "ndr301-ptt" # NDR358 weirdness: the NDR358 Recorder mode variant can self-identify # as "NDR358-5", per NH -- DA if radioType == "ndr358_5": - radioType = "ndr358_recorder" + radioType = "ndr358_recorder" # For NDR358 models, read the radio function to identify we should use # a handler for a specific variant. Note that we don't have handlers # for all potential variants yet. -- DA @@ -375,6 +390,7 @@ def getRadioObject(nameString, *args, **kwargs): if radioType != "": break if radioType != "": + kwargs["clientId"] = None obj = getRadioClass(radioType)(*args, **kwargs) if connMode in ["tcp", "udp", "https"]: obj.connect(connMode, kwargs.get("host"), kwargs.get("port", None)) @@ -383,22 +399,23 @@ def getRadioObject(nameString, *args, **kwargs): return obj else: raise RuntimeError("Radio not found") - elif nameString == "server": + elif nameString == "server" or nameString == "crdd": connMode = "tcp" host = kwargs.get("host", "localhost") - port = kwargs.get("port", 31415) + port = kwargs.get("port", 65432) radioType = "" # Use a temporary radio identifier class to determine what kind of radio the # server is managing tmpHandler = None - # -- Try the non-JSON radio identifier first, since the handshake is just a + # -- Try the non-JSON radio identifier first, since the handshake is just a # line feed. If that doesn't work, then try the JSON identifier. for radioIdentifierCls in [radio._radio_identifier, radio._radio_identifier_json]: - tmpHandler = radioIdentifierCls(verbose=False, - logFile=None, + tmpHandler = radioIdentifierCls(verbose=False, + logFile=None, timeout=kwargs.get("timeout", None)) tmpHandler.connect(connMode, host, port) - if tmpHandler.isConnected() or any(["Radio is not connected" in q for q in tmpHandler.connectError]): + #if tmpHandler.isConnected() or any(["Radio is not connected" in q for q in tmpHandler.connectError]): + if tmpHandler.isConnected(): break # If the radio identifier connected, then identify the radio managed by the server # and establish a radio-specific handler. @@ -410,13 +427,39 @@ def getRadioObject(nameString, *args, **kwargs): radioType = radioType.replace("ts", "_ts") radioType = radioType.replace("-", "_") radioType = radioType.replace("__", "_") + # NDR804-PTT weirdness: the model name has a space in it -- DA + if radioType == "ndr804 ptt": + radioType = "ndr804-ptt" + # NDR301-PTT weirdness: sometimes the model name does not have the dash + # in it -- DA + if radioType == "ndr301ptt": + radioType = "ndr301-ptt" + # NDR358 weirdness: the NDR358 Recorder mode variant can self-identify + # as "NDR358-5", per NH -- DA + if radioType == "ndr358_5": + radioType = "ndr358_recorder" + # For NDR358 models, read the radio function to identify we should use + # a handler for a specific variant. Note that we don't have handlers + # for all potential variants yet. -- DA + if radioType == "ndr358": + radioFn = tmpHandler.getConfigurationByKeys(configKeys.RADIO_FUNCTION) + # radioFn == 0 ==> Receiver mode + # radioFn == 1 ==> Fast Scan mode + if radioFn == 2: + radioType = "ndr358_coherent" + # radioFn == 3 ==> Resampler mode + elif radioFn == 4: + radioType = "ndr358_recorder" + # radioFn == 5 ==> ALT_RX1 mode tmpHandler.disconnect() if radioType != "": obj = getRadioClass(radioType)(*args, **kwargs) - # Make sure that the connection mode used for the server is in + # Make sure that the connection mode used for the server is in # the allowed connection mode list for the radio handler if not obj.isConnectionModeSupported(connMode): obj.connectionModes.append(connMode) + # Set crdd flag + obj.isCrddConnection = True # Connect to the new handler obj.connect(connMode, host, port) return obj @@ -426,6 +469,7 @@ def getRadioObject(nameString, *args, **kwargs): else: raise RuntimeError("Radio not found") else: + kwargs["clientId"] = None obj = getRadioClass(nameString)(*args, **kwargs) if kwargs.get("host", None) and any(obj.isConnectionModeSupported(i) for i in ("https","tcp","udp")): hostname = kwargs["host"] @@ -1069,9 +1113,13 @@ def getPps(self): # # \param checkTime Whether to verify that the time was set properly. # \param useGpsTime Whether to use the GPS time rather than the system time. + # \param newPpsTime A specific UTC date/time to set the radio's clock to + # (string). This method supports several formats for the time string, + # including YYYY-MM-DD HH:MM:SS and ISO 8601. Set this to None if you + # want to use the current system/GPS time. # \return True if successful, False if the radio does not support # PPS edge detection and time setting or if the command was unsuccessful. - def setTimeNextPps(self,checkTime=False,useGpsTime=False): + def setTimeNextPps(self,checkTime=False,useGpsTime=False,newPpsTime=None): raise NotImplementedError ## @@ -1222,6 +1270,14 @@ def setGpioOutput(self, value): def setGpioOutputByIndex(self, index, value, duration, loop, go): raise NotImplementedError + ## + # \brief Gets the current bandwith of the given tuner. + # \param tuner Tuner index number + # \returns The tuner bandwidth, in Hz + # \throws ValueError if the tuner does not exist on the radio + def getTunerBandwidth(self, tuner): + raise NotImplementedError + ## # \brief Gets the name of the radio. # @@ -1308,7 +1364,16 @@ def getTunerAttenuationRes(cls): @classmethod def getTunerIfFilterList(cls): raise NotImplementedError - + + ## + # \brief Gets whether or not the radio supports setting tuner + # bandwidth + # + # \return True if the bandwidth is settable, False otherwise + @classmethod + def isTunerBandwidthSettable(cls): + raise NotImplementedError + ## # \brief Gets the number of wideband DDCs on the radio. # diff --git a/cyberradiodriver/CyberRadioDriver/command.py b/cyberradiodriver/CyberRadioDriver/command.py index 7325c99..8eaf852 100755 --- a/cyberradiodriver/CyberRadioDriver/command.py +++ b/cyberradiodriver/CyberRadioDriver/command.py @@ -13,8 +13,8 @@ # \author NH # \author DA # \author MN -# \copyright Copyright (c) 2017 CyberRadio Solutions, Inc. -# All rights reserved. +# \copyright Copyright (c) 2017-2020 CyberRadio Solutions, Inc. +# All rights reserved. # ############################################################### diff --git a/cyberradiodriver/CyberRadioDriver/components.py b/cyberradiodriver/CyberRadioDriver/components.py index 148943c..54fdce5 100755 --- a/cyberradiodriver/CyberRadioDriver/components.py +++ b/cyberradiodriver/CyberRadioDriver/components.py @@ -15,8 +15,8 @@ # \author NH # \author DA # \author MN -# \copyright Copyright (c) 2017 CyberRadio Solutions, Inc. -# All rights reserved. +# \copyright Copyright (c) 2017-2020 CyberRadio Solutions, Inc. +# All rights reserved. # ############################################################### @@ -119,10 +119,13 @@ def __init__(self, *args, **kwargs): # CyberRadioDriver.transport.radio_transport). # \param callback A method that the component uses to send data over the # connected transport. - def addTransport(self,transport,callback,): + # \param queryConfig Whether or not to query the configuration + # through hardware commands + def addTransport(self,transport,callback,queryConfig=True): self.transport = transport self.callback = callback - self.queryConfiguration() + if queryConfig: + self.queryConfiguration() ## # Deletes the communication transport from this component. @@ -1066,10 +1069,12 @@ def __init__(self,*args,**kwargs): # CyberRadioDriver.transport.radio_transport). # \param callback A method that the component uses to send data over the # connected transport. - def addTransport(self,transport,callback,): + # \param queryConfig Whether or not to query the configuration + # through hardware commands + def addTransport(self,transport,callback,queryConfig=True): for i in self.toneGenDict: - self.toneGenDict[i].addTransport(transport, callback) - _base.addTransport(self, transport, callback) + self.toneGenDict[i].addTransport(transport, callback, queryConfig) + _base.addTransport(self, transport, callback, queryConfig) # OVERRIDE ## diff --git a/cyberradiodriver/CyberRadioDriver/configKeys.py b/cyberradiodriver/CyberRadioDriver/configKeys.py index b497b77..23e58fb 100755 --- a/cyberradiodriver/CyberRadioDriver/configKeys.py +++ b/cyberradiodriver/CyberRadioDriver/configKeys.py @@ -8,8 +8,8 @@ # \author NH # \author DA # \author MN -# \copyright Copyright (c) 2017 CyberRadio Solutions, Inc. -# All rights reserved. +# \copyright Copyright (c) 2017-2020 CyberRadio Solutions, Inc. +# All rights reserved. # ############################################################### @@ -51,6 +51,8 @@ REFERENCE_MODE = "referenceMode" ## Noise State NOISE_STATE = "noiseState" +## Noise generator selection +NOISE_GENERATOR = "noiseGenerator" ## Reference bypass mode. BYPASS_MODE = "bypassMode" ## Frequency normalization mode. @@ -157,6 +159,8 @@ TUNER_IF = "if" ## LO sync indicator TUNER_LO_SYNC = "loSync" +## Tuner Band for NDR511 +TUNER_BAND = "band" #------ Transmitter Configuration Keys --------------------------------# TX_INDEX = "txIndex" @@ -602,6 +606,10 @@ ## Low RF LO STATUS_LOW_RF_LOCK = "lowrflo" +#-- Cntrl Keys ------------------------------------------------------# +## ifOut +CNTRL_IF_OUT = "ifout" + #-- Reset Type Keys --------------------------------------------------# ## Reset type. diff --git a/cyberradiodriver/CyberRadioDriver/log.py b/cyberradiodriver/CyberRadioDriver/log.py index 0103f7c..e4d8939 100755 --- a/cyberradiodriver/CyberRadioDriver/log.py +++ b/cyberradiodriver/CyberRadioDriver/log.py @@ -7,8 +7,8 @@ # \author NH # \author DA # \author MN -# \copyright Copyright (c) 2017 CyberRadio Solutions, Inc. -# All rights reserved. +# \copyright Copyright (c) 2017-2020 CyberRadio Solutions, Inc. +# All rights reserved. # ############################################################### diff --git a/cyberradiodriver/CyberRadioDriver/radio.py b/cyberradiodriver/CyberRadioDriver/radio.py index 683e2b4..d3779cc 100755 --- a/cyberradiodriver/CyberRadioDriver/radio.py +++ b/cyberradiodriver/CyberRadioDriver/radio.py @@ -13,8 +13,8 @@ # \author NH # \author DA # \author MN -# \copyright Copyright (c) 2017 G3 Technologies, Inc. All rights -# reserved. +# \copyright Copyright (c) 2017-2020 CyberRadio Solutions, Inc. +# All rights reserved. # ############################################################### @@ -26,7 +26,9 @@ import transport # Imports from external modules # Python standard library imports +import ast import copy +import datetime import json import math import sys @@ -300,6 +302,8 @@ class _radio(log._logger, configKeys.Configurable): fpgaStateCmd = None ## \brief Radio function (mode) selection command funCmd = None + ## \brief Radio Cntrl command + cntrlCmd = None # Mode settings ## \brief Supported reference modes refModes = {} @@ -315,19 +319,22 @@ class _radio(log._logger, configKeys.Configurable): defaultPort = 8617 ## \brief Default timeout for communications over the radio transport defaultTimeout = transport.radio_transport.defaultTimeout + ## \brief Does this radio support setting the tuner bandwidth? + tunerBandwithSettable = False + ## \brief Tuner bandwidth (Hz) for radios that do not support setting it + tunerBandwidthConstant = 40e6 ## # \brief The list of valid configuration keywords supported by this # object. Override in derived classes as needed. - validConfigurationKeywords = [configKeys.CONFIG_MODE, \ - configKeys.REFERENCE_MODE, \ - configKeys.BYPASS_MODE, \ - configKeys.CALIB_FREQUENCY, \ - configKeys.FNR_MODE, \ - configKeys.GPS_ENABLE, \ - configKeys.REF_TUNING_VOLT, \ - configKeys.GIGE_FLOW_CONTROL, \ - configKeys.RADIO_FUNCTION, \ + validConfigurationKeywords = [configKeys.CONFIG_MODE, + configKeys.REFERENCE_MODE, + configKeys.BYPASS_MODE, + configKeys.CALIB_FREQUENCY, + configKeys.FNR_MODE, + configKeys.GPS_ENABLE, + configKeys.REF_TUNING_VOLT, + configKeys.GIGE_FLOW_CONTROL, ] ## \brief Default "set time" value setTimeDefault = False @@ -346,6 +353,7 @@ def __init__(self, *args, **kwargs): self.setTime = kwargs.get("setTime",self.setTimeDefault) self.logCtrl = kwargs.get("logCtrl",None) self.transportTimeout = kwargs.get("timeout", None) + self.clientId = kwargs.get("clientId", None) if self.transportTimeout is None: self.transportTimeout = self.defaultTimeout self.name = "%s%s"%(self._name,"-%s"%kwargs.get("name") if kwargs.has_key("name") else "",) @@ -413,6 +421,12 @@ def __init__(self, *args, **kwargs): self.dipTable = {} self.versionInfo = {} # State variables + # -- is the radio connected through crdd? + self.isCrddConnection = False + # -- crdd command prefix, which tells crdd that this isn't a pass-through + # radio command. Set this to four vertical bars, because no NDR-class + # radio uses them. + self.crddCommandPrefix = "||||" # Set the time on the radio self.setTime = False self.connectError = "" @@ -437,6 +451,15 @@ def isConnected(self,): # # \copydetails CyberRadioDriver::IRadio::getVersionInfo() def getVersionInfo(self): + # If this is a crdd connection, try to get the version info from + # crdd's radio handler rather than through direct radio commands + if self.isCrddConnection: + # Get the radio's version information from crdd + rsp = self._crddSendCommand(cmd="GETVERINFO") + if rsp is not None: + # Set the version info by running the first response string (the + # version info dict) through ast.literal_eval(). + self.versionInfo = ast.literal_eval(rsp[0]) # Query hardware for details if we don't have them already if not all([self.versionInfo.has_key(key) for key in \ [configKeys.VERINFO_MODEL, configKeys.VERINFO_SN]]): @@ -522,9 +545,14 @@ def connect(self,mode,host_or_dev,port_or_baudrate=None,setTime=False,initDdc=Fa json=self.json, timeout=self.transportTimeout) if self.transport.connect(mode, self.host_or_dev, self.port_or_baudrate): - self._queryConfiguration() + if self.isCrddConnection: + self._crddInitialize() + # Query the configuration if we didn't already have it + if self.configuration == {}: + self._queryConfiguration() for obj in self.componentList: - obj.addTransport(self.transport,self.sendCommand,) + obj.addTransport(self.transport, self.sendCommand, + not self.isCrddConnection) self.getVersionInfo() if reset: self.sendReset() @@ -559,6 +587,7 @@ def disconnect(self): #traceback.print_exc() for obj in self.componentList: obj.delTransport() + self.configuration = {} ## # \brief Sends a command to the radio. @@ -569,8 +598,12 @@ def sendCommand(self,cmdString,timeout=None): # transport object, or if it's disconnected if self.transport is None or not self.transport.isConnected(): return None + # Check if this is an outgoing crdd command. These commands don't + # use JSON framing, so we want to avoid trying to run it through + # the JSON layer (which won't work). + isCrddCommand = cmdString.startswith(self.crddCommandPrefix) try: - if self.json: + if not isCrddCommand and self.json: if isinstance(cmdString, str): jsonCmd = json.loads(cmdString) elif isinstance(cmdString, dict): @@ -578,7 +611,7 @@ def sendCommand(self,cmdString,timeout=None): jsonCmd["msg"] = command.jsonConfig.newMessageId() x = self.transport.sendCommandAndReceive(json.dumps(jsonCmd),timeout) else: - x = self.transport.sendCommandAndReceive(cmdString,timeout) + x = self.transport.sendCommandAndReceive(cmdString, timeout, useJson=False) if not self.transport.connected: self.transport.disconnect() return None @@ -595,142 +628,145 @@ def sendCommand(self,cmdString,timeout=None): # # \copydetails CyberRadioDriver::IRadio::setConfiguration() def setConfiguration(self, configDict={}): - with self._setConfigLock: - self.cmdErrorInfo = [] - # Normalize the incoming configuration dictionary before trying to process it. - configDict2 = self._normalizeConfigDict(configDict) - success = configKeys.Configurable.setConfiguration(self, **configDict2) - # Tuner configuration - tunerConfDict = configDict2.get(configKeys.CONFIG_TUNER,{}) - for index in self.tunerIndexList: - if tunerConfDict.has_key(index): - confDict = tunerConfDict[index] - confDict[configKeys.TUNER_INDEX] = index - success &= self.setTunerConfigurationNew(**confDict) - # DDC configuration - for ddcType in [configKeys.CONFIG_WBDDC, configKeys.CONFIG_NBDDC]: - isWideband = (ddcType == configKeys.CONFIG_WBDDC) - ddcConfDict = configDict2.get(configKeys.CONFIG_DDC,{}).get(ddcType,{}) - ddcIndexRange = self.wbddcIndexList if isWideband else self.nbddcIndexList - for index in ddcIndexRange: - if ddcConfDict.has_key(index): - confDict = ddcConfDict[index] - confDict[configKeys.DDC_INDEX] = index - success &= self.setDdcConfigurationNew(wideband=isWideband, **confDict) - # IP configuration - success &= self.setIpConfigurationNew(configDict2.get(configKeys.CONFIG_IP, {})) - # Transmitter configuration - txConfDict = configDict2.get(configKeys.CONFIG_TX,{}) - for index in self.getTransmitterIndexRange(): - if txConfDict.has_key(index): - confDict = txConfDict[index] - confDict[configKeys.TX_INDEX] = index - success &= self.setTxConfigurationNew(**confDict) - for ducType in [configKeys.CONFIG_WBDUC, configKeys.CONFIG_NBDUC]: - isWideband = (ducType == configKeys.CONFIG_WBDUC) - ducConfDict = configDict2.get(configKeys.CONFIG_DUC,{}).get(ducType,{}) - ducIndexRange = self.wbducIndexList if isWideband else self.nbducIndexList - for index in ducIndexRange: - if ducConfDict.has_key(index): - confDict = ducConfDict[index] - confDict[configKeys.DUC_INDEX] = index - success &= self.setDucConfigurationNew(wideband=isWideband, **confDict) - # DDC group configuration - for ddcType in [configKeys.CONFIG_WBDDC_GROUP, configKeys.CONFIG_NBDDC_GROUP]: - # Flag for forcing the driver to query DDCs for status information - forceDdcQuery = False - isWideband = (ddcType == configKeys.CONFIG_WBDDC_GROUP) - ddcGroupConfDict = configDict2.get(configKeys.CONFIG_DDC_GROUP,{}).get(ddcType,{}) - ddcGroupIndexRange = self.wbddcGroupIndexList if isWideband else self.nbddcGroupIndexList - for index in ddcGroupIndexRange: - if ddcGroupConfDict.has_key(index): - confDict = ddcGroupConfDict[index] - confDict[configKeys.INDEX] = index - success &= self.setDdcGroupConfigurationNew(wideband=isWideband, **confDict) - # Force DDC query if DDC grouping configuration gets changed - forceDdcQuery = True - # This section forces hardware queries to update the corresponding DDC - # and DDC group configurations. - if forceDdcQuery: - ddcDict = self.wbddcDict if isWideband else self.nbddcDict - for i in self._getIndexList(None, ddcDict): - ddcDict[i]._queryConfiguration() - ddcGroupDict = self.wbddcGroupDict if isWideband else self.nbddcGroupDict - for i in self._getIndexList(None, ddcGroupDict): - ddcGroupDict[i]._queryConfiguration() - # Combined DDC group configuration - for ddcType in [configKeys.CONFIG_COMBINED_DDC_GROUP]: - #self.logIfVerbose("[ndr551][setConfiguration()] Configure combined DDCs") - # Flag for forcing the driver to query DDCs for status information - forceDdcQuery = False - ddcGroupConfDict = configDict2.get(configKeys.CONFIG_DDC_GROUP,{}).get(ddcType,{}) - ddcGroupIndexRange = self.cddcGroupIndexList - for index in ddcGroupIndexRange: - if ddcGroupConfDict.has_key(index): - confDict = ddcGroupConfDict[index] - confDict[configKeys.INDEX] = index - #self.logIfVerbose("[ndr551][setConfiguration()] Combined DDC", index) - #self.logIfVerbose("[ndr551][setConfiguration()] %s" % confDict) - success &= self.setCombinedDdcGroupConfigurationNew(**confDict) - # Force DDC query if DDC grouping configuration gets changed - forceDdcQuery = True - # This section forces hardware queries to update the corresponding DDC - # and DDC group configurations. - if forceDdcQuery: - for isWideband in [True, False]: + if self.isCrddConnection: + return self._crddSetConfiguration(configDict) + else: + with self._setConfigLock: + self.cmdErrorInfo = [] + # Normalize the incoming configuration dictionary before trying to process it. + configDict2 = self._normalizeConfigDict(configDict) + success = configKeys.Configurable.setConfiguration(self, **configDict2) + # Tuner configuration + tunerConfDict = configDict2.get(configKeys.CONFIG_TUNER,{}) + for index in self.tunerIndexList: + if tunerConfDict.has_key(index): + confDict = tunerConfDict[index] + confDict[configKeys.TUNER_INDEX] = index + success &= self.setTunerConfigurationNew(**confDict) + # DDC configuration + for ddcType in [configKeys.CONFIG_WBDDC, configKeys.CONFIG_NBDDC]: + isWideband = (ddcType == configKeys.CONFIG_WBDDC) + ddcConfDict = configDict2.get(configKeys.CONFIG_DDC,{}).get(ddcType,{}) + ddcIndexRange = self.wbddcIndexList if isWideband else self.nbddcIndexList + for index in ddcIndexRange: + if ddcConfDict.has_key(index): + confDict = ddcConfDict[index] + confDict[configKeys.DDC_INDEX] = index + success &= self.setDdcConfigurationNew(wideband=isWideband, **confDict) + # IP configuration + success &= self.setIpConfigurationNew(configDict2.get(configKeys.CONFIG_IP, {})) + # Transmitter configuration + txConfDict = configDict2.get(configKeys.CONFIG_TX,{}) + for index in self.getTransmitterIndexRange(): + if txConfDict.has_key(index): + confDict = txConfDict[index] + confDict[configKeys.TX_INDEX] = index + success &= self.setTxConfigurationNew(**confDict) + for ducType in [configKeys.CONFIG_WBDUC, configKeys.CONFIG_NBDUC]: + isWideband = (ducType == configKeys.CONFIG_WBDUC) + ducConfDict = configDict2.get(configKeys.CONFIG_DUC,{}).get(ducType,{}) + ducIndexRange = self.wbducIndexList if isWideband else self.nbducIndexList + for index in ducIndexRange: + if ducConfDict.has_key(index): + confDict = ducConfDict[index] + confDict[configKeys.DUC_INDEX] = index + success &= self.setDucConfigurationNew(wideband=isWideband, **confDict) + # DDC group configuration + for ddcType in [configKeys.CONFIG_WBDDC_GROUP, configKeys.CONFIG_NBDDC_GROUP]: + # Flag for forcing the driver to query DDCs for status information + forceDdcQuery = False + isWideband = (ddcType == configKeys.CONFIG_WBDDC_GROUP) + ddcGroupConfDict = configDict2.get(configKeys.CONFIG_DDC_GROUP,{}).get(ddcType,{}) + ddcGroupIndexRange = self.wbddcGroupIndexList if isWideband else self.nbddcGroupIndexList + for index in ddcGroupIndexRange: + if ddcGroupConfDict.has_key(index): + confDict = ddcGroupConfDict[index] + confDict[configKeys.INDEX] = index + success &= self.setDdcGroupConfigurationNew(wideband=isWideband, **confDict) + # Force DDC query if DDC grouping configuration gets changed + forceDdcQuery = True + # This section forces hardware queries to update the corresponding DDC + # and DDC group configurations. + if forceDdcQuery: ddcDict = self.wbddcDict if isWideband else self.nbddcDict for i in self._getIndexList(None, ddcDict): ddcDict[i]._queryConfiguration() - ddcGroupDict = self.cddcGroupDict - for i in self._getIndexList(None, ddcGroupDict): - ddcGroupDict[i]._queryConfiguration() - # DUC configuration - for ducType in [configKeys.CONFIG_WBDUC_GROUP]: - # Flag for forcing the driver to query DUCs for status information - forceDucQuery = False - isWideband = (ducType == configKeys.CONFIG_WBDUC_GROUP) - ducGroupConfDict = configDict2.get(configKeys.CONFIG_DUC_GROUP,{}).get(ducType,{}) - ducGroupIndexRange = self.wbducGroupIndexList if isWideband else self.nbducGroupIndexList - for index in ducGroupIndexRange: - if ducGroupConfDict.has_key(index): - confDict = ducGroupConfDict[index] + ddcGroupDict = self.wbddcGroupDict if isWideband else self.nbddcGroupDict + for i in self._getIndexList(None, ddcGroupDict): + ddcGroupDict[i]._queryConfiguration() + # Combined DDC group configuration + for ddcType in [configKeys.CONFIG_COMBINED_DDC_GROUP]: + #self.logIfVerbose("[ndr551][setConfiguration()] Configure combined DDCs") + # Flag for forcing the driver to query DDCs for status information + forceDdcQuery = False + ddcGroupConfDict = configDict2.get(configKeys.CONFIG_DDC_GROUP,{}).get(ddcType,{}) + ddcGroupIndexRange = self.cddcGroupIndexList + for index in ddcGroupIndexRange: + if ddcGroupConfDict.has_key(index): + confDict = ddcGroupConfDict[index] + confDict[configKeys.INDEX] = index + #self.logIfVerbose("[ndr551][setConfiguration()] Combined DDC", index) + #self.logIfVerbose("[ndr551][setConfiguration()] %s" % confDict) + success &= self.setCombinedDdcGroupConfigurationNew(**confDict) + # Force DDC query if DDC grouping configuration gets changed + forceDdcQuery = True + # This section forces hardware queries to update the corresponding DDC + # and DDC group configurations. + if forceDdcQuery: + for isWideband in [True, False]: + ddcDict = self.wbddcDict if isWideband else self.nbddcDict + for i in self._getIndexList(None, ddcDict): + ddcDict[i]._queryConfiguration() + ddcGroupDict = self.cddcGroupDict + for i in self._getIndexList(None, ddcGroupDict): + ddcGroupDict[i]._queryConfiguration() + # DUC configuration + for ducType in [configKeys.CONFIG_WBDUC_GROUP]: + # Flag for forcing the driver to query DUCs for status information + forceDucQuery = False + isWideband = (ducType == configKeys.CONFIG_WBDUC_GROUP) + ducGroupConfDict = configDict2.get(configKeys.CONFIG_DUC_GROUP,{}).get(ducType,{}) + ducGroupIndexRange = self.wbducGroupIndexList if isWideband else self.nbducGroupIndexList + for index in ducGroupIndexRange: + if ducGroupConfDict.has_key(index): + confDict = ducGroupConfDict[index] + confDict[configKeys.INDEX] = index + success &= self.setDucGroupConfigurationNew(wideband=isWideband, **confDict) + # Force DUC query if DUC grouping configuration gets changed + forceDucQuery = True + # This section forces hardware queries to update the corresponding DUC + # and DUC group configurations. + if forceDucQuery: + ducDict = self.wbducDict if isWideband else self.nbducDict + for i in self._getIndexList(None, ducDict): + ducDict[i]._queryConfiguration() + ducGroupDict = self.wbducGroupDict if isWideband else self.nbducGroupDict + for i in self._getIndexList(None, ducGroupDict): + ducGroupDict[i]._queryConfiguration() + # FFT streaming configuration + fftStreamConfDict = configDict2.get(configKeys.CONFIG_FFT,{}) + for index in self.fftStreamIndexList: + if fftStreamConfDict.has_key(index): + confDict = fftStreamConfDict[index] + confDict[configKeys.FFT_INDEX] = index + success &= self.setFftStreamConfiguration(**confDict) + # Tuner group configuration + forceTunerQuery = False + tunerGroupConfDict = configDict2.get(configKeys.CONFIG_TUNER_GROUP,{}) + tunerGroupIndexRange = self.tunerGroupIndexList + for index in tunerGroupIndexRange: + if tunerGroupConfDict.has_key(index): + confDict = tunerGroupConfDict[index] confDict[configKeys.INDEX] = index - success &= self.setDucGroupConfigurationNew(wideband=isWideband, **confDict) - # Force DUC query if DUC grouping configuration gets changed - forceDucQuery = True - # This section forces hardware queries to update the corresponding DUC - # and DUC group configurations. - if forceDucQuery: - ducDict = self.wbducDict if isWideband else self.nbducDict - for i in self._getIndexList(None, ducDict): - ducDict[i]._queryConfiguration() - ducGroupDict = self.wbducGroupDict if isWideband else self.nbducGroupDict - for i in self._getIndexList(None, ducGroupDict): - ducGroupDict[i]._queryConfiguration() - # FFT streaming configuration - fftStreamConfDict = configDict2.get(configKeys.CONFIG_FFT,{}) - for index in self.fftStreamIndexList: - if fftStreamConfDict.has_key(index): - confDict = fftStreamConfDict[index] - confDict[configKeys.FFT_INDEX] = index - success &= self.setFftStreamConfiguration(**confDict) - # Tuner group configuration - forceTunerQuery = False - tunerGroupConfDict = configDict2.get(configKeys.CONFIG_TUNER_GROUP,{}) - tunerGroupIndexRange = self.tunerGroupIndexList - for index in tunerGroupIndexRange: - if tunerGroupConfDict.has_key(index): - confDict = tunerGroupConfDict[index] - confDict[configKeys.INDEX] = index - success &= self.setTunerGroupConfigurationNew(**confDict) - # Force tuner query if tuner grouping configuration gets changed - forceTunerQuery = True - if forceTunerQuery: - for i in self._getIndexList(None, self.tunerDict): - self.tunerDict[i]._queryConfiguration() - for i in self._getIndexList(None, self.tunerGroupDict): - self.tunerGroupDict[i]._queryConfiguration() - return success + success &= self.setTunerGroupConfigurationNew(**confDict) + # Force tuner query if tuner grouping configuration gets changed + forceTunerQuery = True + if forceTunerQuery: + for i in self._getIndexList(None, self.tunerDict): + self.tunerDict[i]._queryConfiguration() + for i in self._getIndexList(None, self.tunerGroupDict): + self.tunerGroupDict[i]._queryConfiguration() + return success ## # \brief Sets the radio configuration based on a sequence of configuration @@ -747,60 +783,64 @@ def setConfigurationByKeys(self, value=None, *keys): # # \copydetails CyberRadioDriver::IRadio::getConfiguration() def getConfiguration(self): - self.cmdErrorInfo = [] - ret = configKeys.Configurable.getConfiguration(self) - # Get tuner configuration - if self.numTuner > 0: - ret[configKeys.CONFIG_TUNER] = self.getTunerConfigurationNew() - # Get DDC configuration - if self.numWbddc > 0: - ret[configKeys.CONFIG_DDC] = {} - # -- Wideband - ret[configKeys.CONFIG_DDC][configKeys.CONFIG_WBDDC] = self.getDdcConfigurationNew(wideband=True) - if self.numNbddc > 0: - # -- Narrowband - ret[configKeys.CONFIG_DDC][configKeys.CONFIG_NBDDC] = self.getDdcConfigurationNew(wideband=False) - if self.numFftStream > 0: - ret[configKeys.CONFIG_FFT] = self.getFftStreamConfiguration() - # Get transmitter configuration - if self.numTxs > 0: - ret[configKeys.CONFIG_TX] = self.getTxConfigurationNew() - # Get DUC configuration - if self.numTxs > 0: - ret[configKeys.CONFIG_DUC] = {} - # -- Wideband - ret[configKeys.CONFIG_DUC][configKeys.CONFIG_WBDUC] = self.getDucConfigurationNew(wideband=True) - if self.numNbduc > 0: - # -- Narrowband - ret[configKeys.CONFIG_DDC][configKeys.CONFIG_NBDUC] = self.getDucConfigurationNew(wideband=False) - # Get DDC group configuration - if self.numWbddcGroups > 0: - ret[configKeys.CONFIG_DDC_GROUP] = {} - # -- Wideband - ret[configKeys.CONFIG_DDC_GROUP][configKeys.CONFIG_WBDDC_GROUP] = \ - self.getDdcGroupConfigurationNew(wideband=True) - if self.numNbddcGroups > 0: - # -- Narrowband - ret[configKeys.CONFIG_DDC_GROUP][configKeys.CONFIG_NBDDC_GROUP] = \ - self.getDdcGroupConfigurationNew(wideband=False) - elif self.numCddcGroups > 0: - ret[configKeys.CONFIG_DDC_GROUP] = {} - ret[configKeys.CONFIG_DDC_GROUP][configKeys.CONFIG_COMBINED_DDC_GROUP] = \ - self.getCombinedDdcGroupConfigurationNew() - # Get DUC group configuration - if self.numWbducGroups > 0: - ret[configKeys.CONFIG_DUC_GROUP] = {} - # -- Wideband - ret[configKeys.CONFIG_DUC_GROUP][configKeys.CONFIG_WBDUC_GROUP] = \ - self.getDucGroupConfigurationNew(wideband=True) -# if self.numNbducGroups > 0: -# # -- Narrowband -# ret[configKeys.CONFIG_DUC_GROUP][configKeys.CONFIG_NBDUC_GROUP] = \ -# self.getDucGroupConfigurationNew(wideband=False) - # Get tuner group configuration - if self.numTunerGroups > 0: - ret[configKeys.CONFIG_TUNER_GROUP] = \ - self.getTunerGroupConfigurationNew() + ret = None + if self.isCrddConnection: + ret = self._crddGetConfiguration() + else: + self.cmdErrorInfo = [] + ret = configKeys.Configurable.getConfiguration(self) + # Get tuner configuration + if self.numTuner > 0: + ret[configKeys.CONFIG_TUNER] = self.getTunerConfigurationNew() + # Get DDC configuration + if self.numWbddc > 0: + ret[configKeys.CONFIG_DDC] = {} + # -- Wideband + ret[configKeys.CONFIG_DDC][configKeys.CONFIG_WBDDC] = self.getDdcConfigurationNew(wideband=True) + if self.numNbddc > 0: + # -- Narrowband + ret[configKeys.CONFIG_DDC][configKeys.CONFIG_NBDDC] = self.getDdcConfigurationNew(wideband=False) + if self.numFftStream > 0: + ret[configKeys.CONFIG_FFT] = self.getFftStreamConfiguration() + # Get transmitter configuration + if self.numTxs > 0: + ret[configKeys.CONFIG_TX] = self.getTxConfigurationNew() + # Get DUC configuration + if self.numTxs > 0: + ret[configKeys.CONFIG_DUC] = {} + # -- Wideband + ret[configKeys.CONFIG_DUC][configKeys.CONFIG_WBDUC] = self.getDucConfigurationNew(wideband=True) + if self.numNbduc > 0: + # -- Narrowband + ret[configKeys.CONFIG_DDC][configKeys.CONFIG_NBDUC] = self.getDucConfigurationNew(wideband=False) + # Get DDC group configuration + if self.numWbddcGroups > 0: + ret[configKeys.CONFIG_DDC_GROUP] = {} + # -- Wideband + ret[configKeys.CONFIG_DDC_GROUP][configKeys.CONFIG_WBDDC_GROUP] = \ + self.getDdcGroupConfigurationNew(wideband=True) + if self.numNbddcGroups > 0: + # -- Narrowband + ret[configKeys.CONFIG_DDC_GROUP][configKeys.CONFIG_NBDDC_GROUP] = \ + self.getDdcGroupConfigurationNew(wideband=False) + elif self.numCddcGroups > 0: + ret[configKeys.CONFIG_DDC_GROUP] = {} + ret[configKeys.CONFIG_DDC_GROUP][configKeys.CONFIG_COMBINED_DDC_GROUP] = \ + self.getCombinedDdcGroupConfigurationNew() + # Get DUC group configuration + if self.numWbducGroups > 0: + ret[configKeys.CONFIG_DUC_GROUP] = {} + # -- Wideband + ret[configKeys.CONFIG_DUC_GROUP][configKeys.CONFIG_WBDUC_GROUP] = \ + self.getDucGroupConfigurationNew(wideband=True) + # if self.numNbducGroups > 0: + # # -- Narrowband + # ret[configKeys.CONFIG_DUC_GROUP][configKeys.CONFIG_NBDUC_GROUP] = \ + # self.getDucGroupConfigurationNew(wideband=False) + # Get tuner group configuration + if self.numTunerGroups > 0: + ret[configKeys.CONFIG_TUNER_GROUP] = \ + self.getTunerGroupConfigurationNew() return ret ## @@ -826,131 +866,134 @@ def queryConfiguration(self): def queryConfigurationByKeys(self, *keys): self.cmdErrorInfo = [] ret = {} - if len(keys) == 0: - ret = configKeys.Configurable.queryConfiguration(self) - # Get tuner configuration - if self.numTuner > 0: + if self.isCrddConnection: + ret = self._crddQueryConfigurationByKeys(*keys) + else: if len(keys) == 0: - ret[configKeys.CONFIG_TUNER] = self.queryTunerConfigurationNew(tunerIndex=None) - elif len(keys) > 0 and keys[0] == configKeys.CONFIG_TUNER: - tunerIndex = None if len(keys) == 1 else int(keys[1]) - ret[configKeys.CONFIG_TUNER] = self.queryTunerConfigurationNew(tunerIndex=tunerIndex) - # Get DDC configuration - if self.numWbddc > 0: - if len(keys) == 0 or keys[0] == configKeys.CONFIG_DDC: - ret[configKeys.CONFIG_DDC] = {} - # -- Wideband - if len(keys) < 2: - ret[configKeys.CONFIG_DDC][configKeys.CONFIG_WBDDC] = self.queryDdcConfigurationNew( - wideband=True, ddcIndex=None) - elif keys[1] == configKeys.CONFIG_WBDDC: - ddcIndex = None if len(keys) == 2 else int(keys[2]) - ret[configKeys.CONFIG_DDC][configKeys.CONFIG_WBDDC] = self.queryDdcConfigurationNew( - wideband=True, ddcIndex=ddcIndex) - # -- Narrowband - if self.numNbddc > 0: + ret = configKeys.Configurable.queryConfiguration(self) + # Get tuner configuration + if self.numTuner > 0: + if len(keys) == 0: + ret[configKeys.CONFIG_TUNER] = self.queryTunerConfigurationNew(tunerIndex=None) + elif len(keys) > 0 and keys[0] == configKeys.CONFIG_TUNER: + tunerIndex = None if len(keys) == 1 else int(keys[1]) + ret[configKeys.CONFIG_TUNER] = self.queryTunerConfigurationNew(tunerIndex=tunerIndex) + # Get DDC configuration + if self.numWbddc > 0: + if len(keys) == 0 or keys[0] == configKeys.CONFIG_DDC: + ret[configKeys.CONFIG_DDC] = {} + # -- Wideband if len(keys) < 2: - ret[configKeys.CONFIG_DDC][configKeys.CONFIG_NBDDC] = self.queryDdcConfigurationNew( - wideband=False, ddcIndex=None) - elif keys[1] == configKeys.CONFIG_NBDDC: + ret[configKeys.CONFIG_DDC][configKeys.CONFIG_WBDDC] = self.queryDdcConfigurationNew( + wideband=True, ddcIndex=None) + elif keys[1] == configKeys.CONFIG_WBDDC: ddcIndex = None if len(keys) == 2 else int(keys[2]) - ret[configKeys.CONFIG_DDC][configKeys.CONFIG_NBDDC] = self.queryDdcConfigurationNew( - wideband=False, ddcIndex=ddcIndex) - # Get FFT Stream configuration - if self.numFftStream > 0: - if len(keys) == 0: - ret[configKeys.CONFIG_FFT] = self.queryFftStreamConfiguration(fftStreamIndex=None) - elif len(keys) > 0 and keys[0] == configKeys.CONFIG_FFT: - fftStreamIndex = None if len(keys) == 1 else int(keys[1]) - ret[configKeys.CONFIG_FFT] = self.queryFftStreamConfiguration(fftStreamIndex=fftStreamIndex) - # Get transmitter configuration - if self.numTxs > 0: - if len(keys) == 0: - ret[configKeys.CONFIG_TX] = self.queryTxConfigurationNew(txIndex=None) - elif len(keys) > 0 and keys[0] == configKeys.CONFIG_TX: - txIndex = None if len(keys) == 1 else int(keys[1]) - ret[configKeys.CONFIG_TX] = self.queryTxConfigurationNew(txIndex=txIndex) - # Get DUC configuration - if self.numTxs > 0: - if len(keys) == 0 or keys[0] == configKeys.CONFIG_DUC: - ret[configKeys.CONFIG_DUC] = {} - # -- Wideband - if len(keys) < 2: - ret[configKeys.CONFIG_DUC][configKeys.CONFIG_WBDUC] = self.queryDucConfigurationNew( - wideband=True, ducIndex=None) - elif keys[1] == configKeys.CONFIG_WBDUC: - ducIndex = None if len(keys) == 2 else int(keys[2]) - ret[configKeys.CONFIG_DUC][configKeys.CONFIG_WBDUC] = self.queryDucConfigurationNew( - wideband=True, ducIndex=ducIndex) - # -- Narrowband - if self.numNbduc > 0: + ret[configKeys.CONFIG_DDC][configKeys.CONFIG_WBDDC] = self.queryDdcConfigurationNew( + wideband=True, ddcIndex=ddcIndex) + # -- Narrowband + if self.numNbddc > 0: + if len(keys) < 2: + ret[configKeys.CONFIG_DDC][configKeys.CONFIG_NBDDC] = self.queryDdcConfigurationNew( + wideband=False, ddcIndex=None) + elif keys[1] == configKeys.CONFIG_NBDDC: + ddcIndex = None if len(keys) == 2 else int(keys[2]) + ret[configKeys.CONFIG_DDC][configKeys.CONFIG_NBDDC] = self.queryDdcConfigurationNew( + wideband=False, ddcIndex=ddcIndex) + # Get FFT Stream configuration + if self.numFftStream > 0: + if len(keys) == 0: + ret[configKeys.CONFIG_FFT] = self.queryFftStreamConfiguration(fftStreamIndex=None) + elif len(keys) > 0 and keys[0] == configKeys.CONFIG_FFT: + fftStreamIndex = None if len(keys) == 1 else int(keys[1]) + ret[configKeys.CONFIG_FFT] = self.queryFftStreamConfiguration(fftStreamIndex=fftStreamIndex) + # Get transmitter configuration + if self.numTxs > 0: + if len(keys) == 0: + ret[configKeys.CONFIG_TX] = self.queryTxConfigurationNew(txIndex=None) + elif len(keys) > 0 and keys[0] == configKeys.CONFIG_TX: + txIndex = None if len(keys) == 1 else int(keys[1]) + ret[configKeys.CONFIG_TX] = self.queryTxConfigurationNew(txIndex=txIndex) + # Get DUC configuration + if self.numTxs > 0: + if len(keys) == 0 or keys[0] == configKeys.CONFIG_DUC: + ret[configKeys.CONFIG_DUC] = {} + # -- Wideband if len(keys) < 2: - ret[configKeys.CONFIG_DUC][configKeys.CONFIG_NBDUC] = self.queryDucConfigurationNew( - wideband=False, ducIndex=None) - elif keys[1] == configKeys.CONFIG_NBDUC: + ret[configKeys.CONFIG_DUC][configKeys.CONFIG_WBDUC] = self.queryDucConfigurationNew( + wideband=True, ducIndex=None) + elif keys[1] == configKeys.CONFIG_WBDUC: ducIndex = None if len(keys) == 2 else int(keys[2]) - ret[configKeys.CONFIG_DUC][configKeys.CONFIG_NBDUC] = self.queryDucConfigurationNew( - wideband=False, ducIndex=ducIndex) - # Get DDC group configuration - if any( [self.numWbddcGroups > 0, self.numNbddcGroups > 0, self.numCddcGroups > 0] ): - if len(keys) == 0 or keys[0] == configKeys.CONFIG_DDC_GROUP: - ret[configKeys.CONFIG_DDC_GROUP] = {} - # -- Wideband - if self.numWbddcGroups > 0: - if len(keys) < 2: - ret[configKeys.CONFIG_DDC_GROUP][configKeys.CONFIG_WBDDC_GROUP] = \ - self.queryDdcGroupConfigurationNew(wideband=True, ddcGroupIndex=None) - elif keys[1] == configKeys.CONFIG_WBDDC_GROUP: - ddcGroupIndex = None if len(keys) == 2 else int(keys[2]) - ret[configKeys.CONFIG_DDC_GROUP][configKeys.CONFIG_WBDDC_GROUP] = \ - self.queryDdcGroupConfigurationNew(wideband=True, ddcGroupIndex=ddcGroupIndex) - # -- Narrowband - if self.numNbddcGroups > 0: - if len(keys) < 2: - ret[configKeys.CONFIG_DDC_GROUP][configKeys.CONFIG_NBDDC_GROUP] = \ - self.queryDdcGroupConfigurationNew(wideband=False, ddcGroupIndex=None) - elif keys[1] == configKeys.CONFIG_NBDDC_GROUP: - ddcGroupIndex = None if len(keys) == 2 else int(keys[2]) - ret[configKeys.CONFIG_DDC_GROUP][configKeys.CONFIG_NBDDC_GROUP] = \ - self.queryDdcGroupConfigurationNew(wideband=False, ddcGroupIndex=ddcGroupIndex) - # -- Combined (wideband + narrowband) - if self.numCddcGroups > 0: - if len(keys) < 2: - ret[configKeys.CONFIG_DDC_GROUP][configKeys.CONFIG_COMBINED_DDC_GROUP] = \ - self.queryCombinedDdcGroupConfigurationNew(ddcGroupIndex=None) - elif keys[1] == configKeys.CONFIG_COMBINED_DDC_GROUP: - ddcGroupIndex = None if len(keys) == 2 else int(keys[2]) - ret[configKeys.CONFIG_DDC_GROUP][configKeys.CONFIG_COMBINED_DDC_GROUP] = \ - self.queryCombinedDdcGroupConfigurationNew(ddcGroupIndex=ddcGroupIndex) - # Get DUC group configuration - if any( [self.numWbducGroups > 0] ): - if len(keys) == 0 or keys[0] == configKeys.CONFIG_DUC_GROUP: - ret[configKeys.CONFIG_DUC_GROUP] = {} - # -- Wideband - if self.numWbducGroups > 0: - if len(keys) < 2: - ret[configKeys.CONFIG_DUC_GROUP][configKeys.CONFIG_WBDUC_GROUP] = \ - self.queryDucGroupConfigurationNew(wideband=True, ducGroupIndex=None) - elif keys[1] == configKeys.CONFIG_WBDUC_GROUP: - ducGroupIndex = None if len(keys) == 2 else int(keys[2]) - ret[configKeys.CONFIG_DUC_GROUP][configKeys.CONFIG_WBDUC_GROUP] = \ - self.queryDucGroupConfigurationNew(wideband=True, ducGroupIndex=ducGroupIndex) - # Get tuner group configuration - if self.numTunerGroups > 0: - if len(keys) == 0: - ret[configKeys.CONFIG_TUNER_GROUP] = self.queryTunerGroupConfigurationNew( - tunerGroupIndex=None) - elif len(keys) > 0 and keys[0] == configKeys.CONFIG_TUNER_GROUP: - tunerGroupIndex = None if len(keys) == 1 else int(keys[1]) - ret[configKeys.CONFIG_TUNER_GROUP] = self.queryTunerGroupConfigurationNew( - tunerGroupIndex=tunerGroupIndex) - # Query IP configuration - if len(keys) == 0 or keys[0] == configKeys.CONFIG_IP: - if len(keys) == 0: - ret[configKeys.CONFIG_IP] = self.queryIpConfigurationNew(gigEPortIndex=None) - elif len(keys) > 0 and keys[0] == configKeys.CONFIG_IP: - gigEPortIndex = None if len(keys) == 1 else int(keys[1]) - ret[configKeys.CONFIG_IP] = self.queryIpConfigurationNew(gigEPortIndex=gigEPortIndex) + ret[configKeys.CONFIG_DUC][configKeys.CONFIG_WBDUC] = self.queryDucConfigurationNew( + wideband=True, ducIndex=ducIndex) + # -- Narrowband + if self.numNbduc > 0: + if len(keys) < 2: + ret[configKeys.CONFIG_DUC][configKeys.CONFIG_NBDUC] = self.queryDucConfigurationNew( + wideband=False, ducIndex=None) + elif keys[1] == configKeys.CONFIG_NBDUC: + ducIndex = None if len(keys) == 2 else int(keys[2]) + ret[configKeys.CONFIG_DUC][configKeys.CONFIG_NBDUC] = self.queryDucConfigurationNew( + wideband=False, ducIndex=ducIndex) + # Get DDC group configuration + if any( [self.numWbddcGroups > 0, self.numNbddcGroups > 0, self.numCddcGroups > 0] ): + if len(keys) == 0 or keys[0] == configKeys.CONFIG_DDC_GROUP: + ret[configKeys.CONFIG_DDC_GROUP] = {} + # -- Wideband + if self.numWbddcGroups > 0: + if len(keys) < 2: + ret[configKeys.CONFIG_DDC_GROUP][configKeys.CONFIG_WBDDC_GROUP] = \ + self.queryDdcGroupConfigurationNew(wideband=True, ddcGroupIndex=None) + elif keys[1] == configKeys.CONFIG_WBDDC_GROUP: + ddcGroupIndex = None if len(keys) == 2 else int(keys[2]) + ret[configKeys.CONFIG_DDC_GROUP][configKeys.CONFIG_WBDDC_GROUP] = \ + self.queryDdcGroupConfigurationNew(wideband=True, ddcGroupIndex=ddcGroupIndex) + # -- Narrowband + if self.numNbddcGroups > 0: + if len(keys) < 2: + ret[configKeys.CONFIG_DDC_GROUP][configKeys.CONFIG_NBDDC_GROUP] = \ + self.queryDdcGroupConfigurationNew(wideband=False, ddcGroupIndex=None) + elif keys[1] == configKeys.CONFIG_NBDDC_GROUP: + ddcGroupIndex = None if len(keys) == 2 else int(keys[2]) + ret[configKeys.CONFIG_DDC_GROUP][configKeys.CONFIG_NBDDC_GROUP] = \ + self.queryDdcGroupConfigurationNew(wideband=False, ddcGroupIndex=ddcGroupIndex) + # -- Combined (wideband + narrowband) + if self.numCddcGroups > 0: + if len(keys) < 2: + ret[configKeys.CONFIG_DDC_GROUP][configKeys.CONFIG_COMBINED_DDC_GROUP] = \ + self.queryCombinedDdcGroupConfigurationNew(ddcGroupIndex=None) + elif keys[1] == configKeys.CONFIG_COMBINED_DDC_GROUP: + ddcGroupIndex = None if len(keys) == 2 else int(keys[2]) + ret[configKeys.CONFIG_DDC_GROUP][configKeys.CONFIG_COMBINED_DDC_GROUP] = \ + self.queryCombinedDdcGroupConfigurationNew(ddcGroupIndex=ddcGroupIndex) + # Get DUC group configuration + if any( [self.numWbducGroups > 0] ): + if len(keys) == 0 or keys[0] == configKeys.CONFIG_DUC_GROUP: + ret[configKeys.CONFIG_DUC_GROUP] = {} + # -- Wideband + if self.numWbducGroups > 0: + if len(keys) < 2: + ret[configKeys.CONFIG_DUC_GROUP][configKeys.CONFIG_WBDUC_GROUP] = \ + self.queryDucGroupConfigurationNew(wideband=True, ducGroupIndex=None) + elif keys[1] == configKeys.CONFIG_WBDUC_GROUP: + ducGroupIndex = None if len(keys) == 2 else int(keys[2]) + ret[configKeys.CONFIG_DUC_GROUP][configKeys.CONFIG_WBDUC_GROUP] = \ + self.queryDucGroupConfigurationNew(wideband=True, ducGroupIndex=ducGroupIndex) + # Get tuner group configuration + if self.numTunerGroups > 0: + if len(keys) == 0: + ret[configKeys.CONFIG_TUNER_GROUP] = self.queryTunerGroupConfigurationNew( + tunerGroupIndex=None) + elif len(keys) > 0 and keys[0] == configKeys.CONFIG_TUNER_GROUP: + tunerGroupIndex = None if len(keys) == 1 else int(keys[1]) + ret[configKeys.CONFIG_TUNER_GROUP] = self.queryTunerGroupConfigurationNew( + tunerGroupIndex=tunerGroupIndex) + # Query IP configuration + if len(keys) == 0 or keys[0] == configKeys.CONFIG_IP: + if len(keys) == 0: + ret[configKeys.CONFIG_IP] = self.queryIpConfigurationNew(gigEPortIndex=None) + elif len(keys) > 0 and keys[0] == configKeys.CONFIG_IP: + gigEPortIndex = None if len(keys) == 1 else int(keys[1]) + ret[configKeys.CONFIG_IP] = self.queryIpConfigurationNew(gigEPortIndex=gigEPortIndex) # Update the internal configuration dictionary based on query results self.configuration.update(ret) # Return the result @@ -973,6 +1016,8 @@ def _queryConfiguration(self): (self.rtvCmd, configKeys.REF_TUNING_VOLT), \ (self.fpgaStateCmd, configKeys.FPGA_STATE), \ (self.funCmd, configKeys.RADIO_FUNCTION), \ + (self.refCmd, configKeys.STATUS_PPS_SOURCE), \ + # (self.cntrlCmd, configKeys.CNTRL_IF_OUT), \ ]: if cmdClass is not None: cmd = cmdClass(parent=self, @@ -1004,6 +1049,8 @@ def _setConfiguration(self, confDict): (self.gpsCmd, configKeys.GPS_ENABLE), \ (self.rtvCmd, configKeys.REF_TUNING_VOLT), \ (self.fpgaStateCmd, configKeys.FPGA_STATE), \ + (self.refCmd, configKeys.STATUS_PPS_SOURCE), \ + (self.cntrlCmd, configKeys.CNTRL_IF_OUT), \ ]: cDict = { "parent": self, \ "verbose": self.verbose, \ @@ -1115,6 +1162,209 @@ def _dictSafeGet(self, dicty, default, *keys): ret = tmp[key] return ret + ## + # \internal + # \brief Initializes the radio handler object after connecting to crdd. + # + def _crddInitialize(self): + # Optionally, send crdd our client ID + if self.clientId is not None: + rsp = self._crddSendCommand(cmd="CLIENTID", data=self.clientId) + # Get the radio's current configuration from crdd + self._crddGetConfiguration() + pass + + ## + # \internal + # \brief Sends a command to crdd. + # \note This capability does not depend on whether the radio is JSON or not. + # \param cmd Command mnemonic + # \param data Data to send as a command parameter. What actually gets sent + # over the link is this object's string representation. Can be None, in + # which case only the command gets sent. + # \returns Either a list of response strings (if the command completed + # successfully), or None (if it did not). + def _crddSendCommand(self, cmd, data=None): + outCmd = self.crddCommandPrefix + str(cmd) + if data is not None: + outCmd += " " + str(data) + outCmd += "\n" + return self.sendCommand(outCmd) + + ## + # \internal + # \brief Unpacks the provided configuration dictionary, setting the + # configuration of all components. + # \param configuration Fully-specified configuration dictionary. + def _crddUnpackConfiguration(self, configuration): + # Unpack the full configuration + fullConfiguration = copy.deepcopy(configuration) + # -- Tuner configuration + cDict = fullConfiguration.pop(configKeys.CONFIG_TUNER, {}) + for index in cDict.keys(): + self.tunerDict[index].configuration = cDict[index] + # -- DDC configuration + cDict = fullConfiguration.pop(configKeys.CONFIG_DDC, {}) + for ddcType in cDict.keys(): + ddcDict = self.wbddcDict + if ddcType == "narrowband": + ddcDict = self.nbddcDict + for index in cDict[ddcType].keys(): + ddcDict[index].configuration = cDict[ddcType][index] + # -- FFT streams + cDict = fullConfiguration.pop(configKeys.CONFIG_FFT, {}) + for index in cDict.keys(): + self.fftStreamDict[index].configuration = cDict[index] + # -- TX configuration + cDict = fullConfiguration.pop(configKeys.CONFIG_TX, {}) + for index in cDict.keys(): + cDict2 = cDict[index].pop(configKeys.CONFIG_CW, {}) + for index2 in cDict2.keys(): + self.txDict[index].toneGenDict[index2].configuration = cDict2[index2] + self.txDict[index].configuration = cDict[index] + # -- DUC configuration + cDict = fullConfiguration.pop(configKeys.CONFIG_DUC, {}) + for ducType in cDict.keys(): + ducDict = self.wbducDict + if ducType == "narrowband": + ducDict = self.nbducDict + for index in cDict[ducType].keys(): + ducDict[index].configuration = cDict[ducType][index] + # -- DDC group configuration + cDict = fullConfiguration.pop(configKeys.CONFIG_DDC_GROUP, {}) + for ddcType in cDict.keys(): + ddcDict = self.wbddcGroupDict + if ddcType == "narrowband": + ddcDict = self.nbddcGroupDict + elif ddcType == "combined": + ddcDict = self.cddcGroupDict + for index in cDict[ddcType].keys(): + ddcDict[index].configuration = cDict[ddcType][index] + # -- WBDUC groups + cDict = fullConfiguration.pop(configKeys.CONFIG_DUC_GROUP, {}) + for ducType in cDict.keys(): + ducDict = self.wbducGroupDict + #if ducType == "narrowband": + # ducDict = self.nbducGroupDict + for index in cDict[ducType].keys(): + ducDict[index].configuration = cDict[ducType][index] + # -- Tuner groups + cDict = fullConfiguration.pop(configKeys.CONFIG_TUNER_GROUP, {}) + for index in cDict.keys(): + self.tunerGroupDict[index].configuration = cDict[index] + # -- What is left after all the popping are the radio-specific + # config items, and the IP config + self.configuration = fullConfiguration + pass + + ## + # \internal + # \brief Gets the radio's current configuration from crdd. + # \note This capability does not depend on whether the radio is JSON or not. + # \returns Either the returned configuration dictionary (if the command + # completed successfully), or an empty dictionary (if it did not). + def _crddGetConfiguration(self): + ret = {} + # Get the radio's current configuration from crdd + rsp = self._crddSendCommand(cmd="GETCFG", data=None) + # Deal with out-of-bound conditions + try: + if all( [ + rsp is not None, + rsp != "Empty Read", + rsp[0] != "TIMEOUT" + ] ): + # Get the returned full configuration by running the first response + # string (the config dict) through ast.literal_eval(). + ret = ast.literal_eval(rsp[0]) + # Unpack the full configuration + self._crddUnpackConfiguration(ret) + except: + pass + return ret + + ## + # \internal + # \brief Sets the radio's current configuration using crdd. + # \note This capability does not depend on whether the radio is JSON or not. + # \return True if all commands completed successfully, False otherwise. + # Use getLastCommandErrorInfo() to retrieve any error information. + def _crddSetConfiguration(self, configDict={}): + ret = False + # Get the radio's current configuration from crdd + rsp = self._crddSendCommand(cmd="SETCFG", data=configDict) + # Deal with out-of-bound conditions + try: + if all( [ + rsp is not None, + rsp != "Empty Read", + rsp[0] != "TIMEOUT" + ] ): + #self.log("[DBG] rsp =", str(rsp)) + # First response string: SUCCESS or ERROR (plus error info) + ret = ( rsp[0] == "SUCCESS" ) + if not ret: + # Grab the error info (serialized as a list of strings) + self.cmdErrorInfo = ast.literal_eval(rsp[0].replace("ERROR: ", "")) + # Second response string: Updated configuration dictionary string. + # Run this through ast.literal_eval(). + configuration = ast.literal_eval(rsp[1]) + # Unpack the full configuration + self._crddUnpackConfiguration(configuration) + except: + pass + return ret + + ## + # \internal + # \brief Queries the radio's current configuration from crdd. + # \note This capability does not depend on whether the radio is JSON or not. + # \param keys List of keys used to specify which configuration values to query. + # \returns Either the returned configuration dictionary (if the command + # completed successfully), or an empty dictionary (if it did not). + def _crddQueryConfigurationByKeys(self, *keys): + ret = {} + # Query the radio's current configuration from crdd + rsp = self._crddSendCommand(cmd="QUERYCFGK", data=list(keys)) + # Deal with out-of-bound conditions + try: + if all( [ + rsp is not None, + rsp != "Empty Read", + rsp[0] != "TIMEOUT" + ] ): + # Get the returned configuration by running the first response + # string (the config dict) through ast.literal_eval(). + ret = ast.literal_eval(rsp[0]) + except: + pass + return ret + + ## + # \internal + # \brief Helper method for converting Unicode strings to ASCII strings + # during the JSON conversion process. + # + # The JSON-formatted string will have elements whose names + # correspond to the names of this entity's attributes. + # + # \param data The entity being encoded as JSON. + @staticmethod + def encodeJsonAsAscii(data): + def _foo(item): + ret = item + if isinstance(item, unicode): + ret = item.encode('ascii') + elif isinstance(item, list): + ret = [ _foo(q) for q in item ] + elif isinstance(item, dict): + ret = { _foo(key): _foo(value) for key, value in item.iteritems() } + return ret + adjPairs = [] + for pair in data: + adjPairs.append( (_foo(pair[0]), _foo(pair[1])) ) + return dict(adjPairs) + ## # \brief Resets the radio. # @@ -1151,10 +1401,14 @@ def getPps(self): # \brief Sets the time for the next PPS rising edge on the radio. # # \copydetails CyberRadioDriver::IRadio::setTimeNextPps() - def setTimeNextPps(self,checkTime=False,useGpsTime=False): + def setTimeNextPps(self,checkTime=False,useGpsTime=False,newPpsTime=None): if self.ppsCmd is not None and self.utcCmd is not None: if self.getPps(): - if useGpsTime: + if newPpsTime is not None: + nextSecond = int( _radio.timeFromString(newPpsTime, utc=True) ) + cmd = self.utcCmd( parent=self, utcTime=str(nextSecond), + verbose=self.verbose, logFile=self.logFile ) + elif useGpsTime: cmd = self.utcCmd( parent=self, utcTime="g" ) else: nextSecond = int( math.floor( time.time() ) )+1 @@ -1420,6 +1674,23 @@ def setGpioOutputByIndex(self, index, value, duration, loop, go): else: return False + ## + # \brief Gets the current bandwith of the given tuner. + # \copydetails CyberRadioDriver::IRadio::getTunerBandwidth() + def getTunerBandwidth(self, tuner): + if tuner not in self.getTunerIndexRange(): + raise ValueError("Invalid tuner specified") + ret = self.tunerBandwidthConstant + if self.tunerBandwithSettable: + ifFilter = self.getConfigurationByKeys( + configKeys.CONFIG_TUNER, + tuner, + configKeys.TUNER_IF_FILTER + ) + if ifFilter is not None: + ret = ifFilter * 1e6 + return ret + ## # \brief Gets the name of the radio. # @@ -1500,6 +1771,15 @@ def getTunerAttenuationRes(cls): def getTunerIfFilterList(cls): return cls.tunerType.ifFilters + ## + # \brief Gets whether or not the radio supports setting tuner + # bandwidth + # + # \copydetails CyberRadioDriver::IRadio::isTunerBandwidthSettable() + @classmethod + def isTunerBandwidthSettable(cls): + return cls.tunerBandwithSettable + ## # \brief Gets the number of wideband DDCs on the radio. # @@ -3436,6 +3716,141 @@ def setLogFile(self, logFile): for obj in self.componentList: obj.setLogFile(logFile) + ## + # \internal + # \brief Converts a user-specified time string into a number of seconds + # since 1/1/70. + # + # The time string can be either: + # \li Absolute time, in any supported format + # \li Relative time specified as now{-n}, where n is a number of seconds + # \li Relative time specified as now{-[[H:]MM:]SS} + # \li "begin", which is the beginning of known time (1/1/70) + # \li "end", which is the end of trackable time and far beyond the + # useful life of this utility (01/18/2038) + # + # \throws RuntimeException if the time string format cannot be understood. + # \param timestr The time string. + # \param utc Whether or not the user's time string is in UTC time. + # \return The time, in number of seconds since the Epoch + @staticmethod + def timeFromString(timestr, utc=True): + ret = 0 + tm = None + tstr = timestr.strip() + if tstr == "": + ret = 0 + elif tstr == "begin": + ret = 0 + elif tstr == "end": + ret = sys.maxint + else: + if tstr.find('now') != -1: + tm = datetime.datetime.utcnow() if utc else datetime.datetime.now() + i = tstr.find('-') + if i != -1: + tmp = tstr[i+1:] + tm = tm - datetime.timedelta(seconds=_radio.timeSecsFromString(tmp)) + else: + # Replace strings "today" and "yesterday" + tmToday = datetime.datetime.utcnow() if utc else datetime.datetime.now() + tmYesterday = tmToday - datetime.timedelta(days=1) + dateStrToday = tmToday.strftime("%Y%m%d") + dateStrYesterday = tmYesterday.strftime("%Y%m%d") + tstr = tstr.replace("today", dateStrToday).replace("yesterday", dateStrYesterday) + # Try a series of known formats + # -- Formats are 5-tuples: (format string, width, needs year, needs month, needs day) + supportedFmts = [ \ + ('%Y-%m-%dT%H:%M:%S%z', 24, False, False, False), \ + ('%Y-%m-%dT%H:%M:%S', 19, False, False, False), \ + ('%Y%m%d:%H%M%S', 15, False, False, False), \ + ('%a %b %d %H:%M:%S %Y', 24, False, False, False), \ + ('%b %d %H:%M:%S', 15, True, False, False), \ + ('%b %d, %Y %I:%M:%S %p', 24, False, False, False), \ + ('%Y-%m-%d %H:%M:%S', 19, False, False, False), \ + ('%Y/%m/%d %H:%M:%S', 19, False, False, False), \ + ('%Y%m%d_%H%M%S', 15, False, False, False), \ + ('%m/%d/%Y %H:%M', 16, False, False, False), \ + ('%m/%d/%y %H:%M:%S', 17, False, False, False), \ + ('%Y%m%d', 8, False, False, False), \ + ('%Y-%m-%d', 10, False, False, False), \ + ('%H:%M:%S', 8, True, True, True), \ + ('%H%M%S', 6, True, True, True), \ + ] + for fmt in supportedFmts: + try: + tmp = tstr[:fmt[1]].strip() + #print "[DBG][timeFromString] Convert" + #print "[DBG][timeFromString] -- string:", tmp + #print "[DBG][timeFromString] -- format:", fmt[0] + tm = datetime.datetime.strptime(tmp, fmt[0]) + #print "[DBG][timeFromString] -- SUCCESS" + # Replace date items from today's date as needed by the format + # -- Day + if fmt[4]: + tm = tm.replace(day=tmToday.day) + # -- Month + if fmt[3]: + tm = tm.replace(month=tmToday.month) + # -- Year + if fmt[2]: + tm = tm.replace(year=tmToday.year) + # But if the resulting date is in the future, then we need to dial it + # back a year + if tm > tmToday: + tm = tm.replace(year=tmToday.year-1) + break + except: + #print "[DBG][timeFromString] -- FAILURE" + tm = None + if tm is not None: + ret = time.mktime(tm.timetuple()) + else: + raise RuntimeError("Improperly formatted time: \"" + tstr + "\"") + return ret + + ## + # Converts a time string ([+-][[H:]M:]S) to a time in seconds. + # + # \note Hours and minutes are not bounded in any way. These strings provide the + # same result: + # \li "7200" + # \li "120:00" + # \li "2:00:00" + # + # \throws RuntimeError if the time is formatted improperly. + # \param timeStr The time string. + # \return The number of seconds. + @staticmethod + def timeSecsFromString(timeStr): + hrs = 0 + mins = 0 + secs = 0 + sgn = 1 + try: + if "-" in timeStr: + sgn = -1 + tmp = timeStr.strip().translate(None, " +-") + if tmp != "": + vec = tmp.split(":") + if vec[-1] != "": + secs = int(vec[-1]) + else: + raise RuntimeError("Improperly formatted time: \"" + timeStr + "\"") + if len(vec) > 1: + if vec[-2] != "": + mins = int(vec[-2]) + else: + raise RuntimeError("Improperly formatted time: \"" + timeStr + "\"") + if len(vec) > 2: + if vec[-3] != "": + hrs = int(vec[-3]) + else: + raise RuntimeError("Improperly formatted time: \"" + timeStr + "\"") + except: + raise RuntimeError("Improperly formatted time: \"" + timeStr + "\"") + return ( sgn * (hrs * 3600 + mins * 60 + secs) ) + ## # \internal @@ -3650,5 +4065,3 @@ def _queryConfiguration(self): #-- End Radio Handler Objects --------------------------------------------------# #-- NOTE: Radio handler objects for supporting specific radios need to be # implemented under the CyberRadioDriver.radios package tree. - - diff --git a/cyberradiodriver/CyberRadioDriver/radios/__init__.py b/cyberradiodriver/CyberRadioDriver/radios/__init__.py index 4356ad4..8b47b22 100644 --- a/cyberradiodriver/CyberRadioDriver/radios/__init__.py +++ b/cyberradiodriver/CyberRadioDriver/radios/__init__.py @@ -8,7 +8,7 @@ # \author NH # \author DA # \author MN -# \copyright Copyright (c) 2017 CyberRadio Solutions, Inc. -# All rights reserved. +# \copyright Copyright (c) 2017-2020 CyberRadio Solutions, Inc. +# All rights reserved. # ############################################################### diff --git a/cyberradiodriver/CyberRadioDriver/radios/ndr301.py b/cyberradiodriver/CyberRadioDriver/radios/ndr301.py index 85e2fab..e10dcb8 100644 --- a/cyberradiodriver/CyberRadioDriver/radios/ndr301.py +++ b/cyberradiodriver/CyberRadioDriver/radios/ndr301.py @@ -5,8 +5,8 @@ # \author NH # \author DA # \author MN -# \copyright Copyright (c) 2017 CyberRadio Solutions, Inc. -# All rights reserved. +# \copyright Copyright (c) 2017-2020 CyberRadio Solutions, Inc. +# All rights reserved. ################################################################## # Imports from other modules in this package @@ -776,6 +776,9 @@ class ndr301(_radio): 2: "VITA-49 header disabled", 3: "VITA-49 header enabled, fractional timestamp in sample counts", } + ## \brief Does this radio support setting the tuner bandwidth? + tunerBandwithSettable = False + tunerBandwidthConstant = 75e6 validConfigurationKeywords = [configKeys.CONFIG_MODE, \ configKeys.REFERENCE_MODE, \ configKeys.FNR_MODE, \ diff --git a/cyberradiodriver/CyberRadioDriver/radios/ndr301ptt.py b/cyberradiodriver/CyberRadioDriver/radios/ndr301ptt.py index d9b96b2..26b7165 100644 --- a/cyberradiodriver/CyberRadioDriver/radios/ndr301ptt.py +++ b/cyberradiodriver/CyberRadioDriver/radios/ndr301ptt.py @@ -5,8 +5,8 @@ # \author NH # \author DA # \author MN -# \copyright Copyright (c) 2018 CyberRadio Solutions, Inc. -# All rights reserved. +# \copyright Copyright (c) 2017-2020 CyberRadio Solutions, Inc. +# All rights reserved. ################################################################## # Imports from other modules in this package @@ -232,7 +232,8 @@ def _queryConfiguration(self): configKeys.ENABLE, configKeys.DDC_STREAM_ID, configKeys.DDC_OUTPUT_FORMAT, - configKeys.DDC_SPECTRAL_FRAME_RATE]: + configKeys.DDC_SPECTRAL_FRAME_RATE, + configKeys.DDC_RF_INDEX]: self.configuration[key] = rspInfo.get(key, None) # if self.nbssCmd is not None: # cmd = self.nbssCmd(**{ "parent": self, @@ -316,6 +317,7 @@ def _setConfiguration(self, confDict): configKeys.INDEX: self.index, "verbose": self.verbose, "logFile": self.logFile }) + print "[DBG][WBSC set] cDict =", cDict cmd = self.cfgCmd(**cDict) ret &= cmd.send( self.callback, ) ret &= cmd.success @@ -478,11 +480,6 @@ def updateSets(self): # \implements CyberRadioDriver.IRadio class ndr301_ptt(ndr301): _name = "NDR301-PTT" - # ADCSR command doesn't exist for the PTT variant. The ADC rate - # for this variant is locked to 122.88 MHz. - adcsrCmd = None - adcRate = 122.88e6 - adcRateModes = { 1: 122.88e6 } validConfigurationKeywords = [configKeys.CONFIG_MODE, configKeys.REFERENCE_MODE, configKeys.FNR_MODE, @@ -496,10 +493,11 @@ class ndr301_ptt(ndr301): numNbddc = 50 nbddcType = ndr301ptt_nbddc nbddcIndexBase = 1 - # For now, only enable port 2 (the 19-Gig output) on the PTT variant, as - # port 1 (the 1-Gig output) is malfunctioning on the prototype. - numGigE = 1 - gigEIndexBase = 2 + # 2020/07/14 -- port 1 seems OK now -- DA + ## For now, only enable port 2 (the 10-Gig output) on the PTT variant, as + ## port 1 (the 1-Gig output) is malfunctioning on the prototype. + #numGigE = 1 + #gigEIndexBase = 2 numGigEDipEntries = 64 ## diff --git a/cyberradiodriver/CyberRadioDriver/radios/ndr304.py b/cyberradiodriver/CyberRadioDriver/radios/ndr304.py index 2a7dd1a..48433b4 100644 --- a/cyberradiodriver/CyberRadioDriver/radios/ndr304.py +++ b/cyberradiodriver/CyberRadioDriver/radios/ndr304.py @@ -5,8 +5,8 @@ # \author NH # \author DA # \author MN -# \copyright Copyright (c) 2017 CyberRadio Solutions, Inc. -# All rights reserved. +# \copyright Copyright (c) 2017-2020 CyberRadio Solutions, Inc. +# All rights reserved. ################################################################## # Imports from other modules in this package diff --git a/cyberradiodriver/CyberRadioDriver/radios/ndr308.py b/cyberradiodriver/CyberRadioDriver/radios/ndr308.py index 18b4a8a..efce190 100644 --- a/cyberradiodriver/CyberRadioDriver/radios/ndr308.py +++ b/cyberradiodriver/CyberRadioDriver/radios/ndr308.py @@ -1,12 +1,12 @@ #!/usr/bin/env python ################################################################## -# \package CyberRadioDriver.radios.ndr308 +# \package CyberRadioDriver.radios.ndr308 # \brief NDR308 Support # \author NH # \author DA # \author MN -# \copyright Copyright (c) 2017 G3 Technologies, Inc. All rights -# reserved. +# \copyright Copyright (c) 2017-2020 CyberRadio Solutions, Inc. +# All rights reserved. ################################################################## # Imports from other modules in this package @@ -72,7 +72,7 @@ class dip308(_commandBase): (configKeys.GIGE_SOURCE_PORT, int, False), \ (configKeys.GIGE_DEST_PORT, int, False), \ ] - + ## # \internal @@ -90,14 +90,14 @@ class sip308(_commandBase): (configKeys.GIGE_PORT_INDEX, int, False), \ (configKeys.IP_SOURCE, str, False), \ ] - + ## # \internal # \brief Status command bitmask values for the NDR308. # -# Static member "text" is a dictionary where the keys are bits in -# the status bitmask, and the values are text strings indicating what those +# Static member "text" is a dictionary where the keys are bits in +# the status bitmask, and the values are text strings indicating what those # bits mean when set. # class stat308Values(): @@ -157,7 +157,7 @@ class tstat308Values(): TQ1_COH_LO1_UNLOCKED = 0x100 TQ1_COH_LO2_UNLOCKED = 0x200 TQ1_100MHZ_REF_UNLOCKED = 0x400 - + RF5_LO1_UNLOCKED = 0x1000 RF5_LO2_UNLOCKED = 0x2000 RF6_LO1_UNLOCKED = 0x4000 @@ -169,7 +169,7 @@ class tstat308Values(): TQ2_COH_LO1_UNLOCKED = 0x100000 TQ2_COH_LO2_UNLOCKED = 0x200000 TQ2_100MHZ_REF_UNLOCKED = 0x400000 - + text = { RF1_LO1_UNLOCKED: "RF1 LO1 Unlocked", \ RF1_LO2_UNLOCKED: "RF1 LO2 Unlocked", \ @@ -216,10 +216,10 @@ class ndr308_tuner(_tuner): fifCmd = command.fif tadjCmd = command.tadj validConfigurationKeywords = [ - configKeys.TUNER_FREQUENCY, - configKeys.TUNER_ATTENUATION, + configKeys.TUNER_FREQUENCY, + configKeys.TUNER_ATTENUATION, configKeys.TUNER_RF_ATTENUATION, - configKeys.ENABLE, + configKeys.ENABLE, configKeys.TUNER_FILTER, configKeys.TUNER_TIMING_ADJ, ] @@ -230,19 +230,19 @@ class ndr308_tuner(_tuner): # \brief WBDDC component class for the NDR308. class ndr308_wbddc(_wbddc): _name = "WBDDC(NDR308)" - rateSet = { 0: 51.2e6, - 1: 25.6e6, - 2: 12.8e6, - 3: 102.4e6, - 4: 6.4e6, - 5: 3.2e6, + rateSet = { 0: 51.2e6, + 1: 25.6e6, + 2: 12.8e6, + 3: 102.4e6, + 4: 6.4e6, + 5: 3.2e6, } bwSet = { 0: 40e6, \ - 1: 0.8*25.6e6, - 2: 0.8*12.8e6, - 3: 40e6, - 4: 0.8*6.4e6, - 5: 0.8*3.2e6, + 1: 0.8*25.6e6, + 2: 0.8*12.8e6, + 3: 40e6, + 4: 0.8*6.4e6, + 5: 0.8*3.2e6, } dataFormat = { 3:DDC_DATA_FORMAT.REAL } # cfgCmd = command.wbddc308 @@ -251,11 +251,11 @@ class ndr308_wbddc(_wbddc): dportCmd = command.wbdp # OVERRIDE validConfigurationKeywords = [ - configKeys.ENABLE, - configKeys.DDC_RATE_INDEX, - configKeys.DDC_UDP_DESTINATION, - configKeys.DDC_VITA_ENABLE, - configKeys.DDC_STREAM_ID, + configKeys.ENABLE, + configKeys.DDC_RATE_INDEX, + configKeys.DDC_UDP_DESTINATION, + configKeys.DDC_VITA_ENABLE, + configKeys.DDC_STREAM_ID, configKeys.DDC_DATA_PORT, ] @@ -302,34 +302,34 @@ class ndr308_1_nbddc(_nbddc): frqCmd = None # OVERRIDE validConfigurationKeywords = [ - configKeys.ENABLE, - configKeys.DDC_FREQUENCY_OFFSET, - configKeys.DDC_RATE_INDEX, - configKeys.DDC_UDP_DESTINATION, - configKeys.DDC_VITA_ENABLE, - configKeys.DDC_STREAM_ID, + configKeys.ENABLE, + configKeys.DDC_FREQUENCY_OFFSET, + configKeys.DDC_RATE_INDEX, + configKeys.DDC_UDP_DESTINATION, + configKeys.DDC_VITA_ENABLE, + configKeys.DDC_STREAM_ID, ] # OVERRIDE ## # \protected - # Queries hardware to determine the object's current configuration. + # Queries hardware to determine the object's current configuration. def _queryConfiguration(self): if self.cfgCmd is not None: - cmd = self.cfgCmd(**{ "parent": self, + cmd = self.cfgCmd(**{ "parent": self, configKeys.INDEX: self.index, "query": True, - "verbose": self.verbose, + "verbose": self.verbose, "logFile": self.logFile }) cmd.send( self.callback, ) self._addLastCommandErrorInfo(cmd) rspInfo = cmd.getResponseInfo() #self.logIfVerbose("rspInfo =", rspInfo) if rspInfo is not None: - for key in [configKeys.ENABLE, - configKeys.DDC_RATE_INDEX, - configKeys.DDC_UDP_DESTINATION, - configKeys.DDC_VITA_ENABLE, + for key in [configKeys.ENABLE, + configKeys.DDC_RATE_INDEX, + configKeys.DDC_UDP_DESTINATION, + configKeys.DDC_VITA_ENABLE, configKeys.DDC_STREAM_ID]: self.configuration[key] = rspInfo.get(key, None) freq = rspInfo.get(configKeys.DDC_FREQUENCY_OFFSET, 0) @@ -340,28 +340,28 @@ def _queryConfiguration(self): # OVERRIDE ## # \protected - # Sets the component's current configuration. + # Sets the component's current configuration. def _setConfiguration(self, confDict): ret = True - keys = [configKeys.ENABLE, - configKeys.DDC_RATE_INDEX, - configKeys.DDC_UDP_DESTINATION, - configKeys.DDC_VITA_ENABLE, - configKeys.DDC_STREAM_ID, + keys = [configKeys.ENABLE, + configKeys.DDC_RATE_INDEX, + configKeys.DDC_UDP_DESTINATION, + configKeys.DDC_VITA_ENABLE, + configKeys.DDC_STREAM_ID, configKeys.DDC_FREQUENCY_OFFSET] if any([q in confDict for q in keys]): if self.cfgCmd is not None: cDict = {} if confDict.has_key(configKeys.DDC_FREQUENCY_OFFSET): confDict[configKeys.DDC_FREQUENCY_OFFSET] = adjustFrequency( - float(confDict[configKeys.DDC_FREQUENCY_OFFSET]), - self.frqRange, - self.frqRes, + float(confDict[configKeys.DDC_FREQUENCY_OFFSET]), + self.frqRange, + self.frqRes, self.frqUnits) self._dictUpdate(cDict, confDict, self.configuration, keys) - cDict.update({ "parent": self, + cDict.update({ "parent": self, configKeys.INDEX: self.index, - "verbose": self.verbose, + "verbose": self.verbose, "logFile": self.logFile }) cmd = self.cfgCmd(**cDict) ret &= cmd.send( self.callback, ) @@ -387,12 +387,12 @@ class ndr308_nbddc(ndr308_1_nbddc): dportCmd = command.nbdp # OVERRIDE validConfigurationKeywords = [ - configKeys.ENABLE, - configKeys.DDC_FREQUENCY_OFFSET, - configKeys.DDC_RATE_INDEX, - configKeys.DDC_UDP_DESTINATION, - configKeys.DDC_VITA_ENABLE, - configKeys.DDC_STREAM_ID, + configKeys.ENABLE, + configKeys.DDC_FREQUENCY_OFFSET, + configKeys.DDC_RATE_INDEX, + configKeys.DDC_UDP_DESTINATION, + configKeys.DDC_VITA_ENABLE, + configKeys.DDC_STREAM_ID, configKeys.NBDDC_RF_INDEX, configKeys.DDC_DATA_PORT, ] @@ -400,23 +400,23 @@ class ndr308_nbddc(ndr308_1_nbddc): # OVERRIDE ## # \protected - # Queries hardware to determine the object's current configuration. + # Queries hardware to determine the object's current configuration. def _queryConfiguration(self): if self.cfgCmd is not None: - cmd = self.cfgCmd(**{ "parent": self, + cmd = self.cfgCmd(**{ "parent": self, configKeys.INDEX: self.index, "query": True, - "verbose": self.verbose, + "verbose": self.verbose, "logFile": self.logFile }) cmd.send( self.callback, ) self._addLastCommandErrorInfo(cmd) rspInfo = cmd.getResponseInfo() #self.logIfVerbose("rspInfo =", rspInfo) if rspInfo is not None: -# for key in [configKeys.ENABLE, -# configKeys.DDC_RATE_INDEX, -# configKeys.DDC_UDP_DESTINATION, -# configKeys.DDC_VITA_ENABLE, +# for key in [configKeys.ENABLE, +# configKeys.DDC_RATE_INDEX, +# configKeys.DDC_UDP_DESTINATION, +# configKeys.DDC_VITA_ENABLE, # configKeys.DDC_STREAM_ID]: keys = [i[0] for i in self.cfgCmd.queryResponseData \ if i[0] != configKeys.INDEX] @@ -426,31 +426,31 @@ def _queryConfiguration(self): self.configuration[configKeys.DDC_FREQUENCY_OFFSET] = None if freq is None else \ freq * self.frqUnits if self.nbssCmd is not None: - cmd = self.nbssCmd(**{ "parent": self, + cmd = self.nbssCmd(**{ "parent": self, configKeys.INDEX: self.index, "query": True, - "verbose": self.verbose, + "verbose": self.verbose, "logFile": self.logFile }) cmd.send( self.callback, ) self._addLastCommandErrorInfo(cmd) rspInfo = cmd.getResponseInfo() #self.logIfVerbose("rspInfo =", rspInfo) if rspInfo is not None: - for key in [configKeys.NBDDC_RF_INDEX, + for key in [configKeys.NBDDC_RF_INDEX, ]: self.configuration[key] = rspInfo.get(key, None) if self.dportCmd is not None: - cmd = self.dportCmd(**{ "parent": self, + cmd = self.dportCmd(**{ "parent": self, configKeys.INDEX: self.index, "query": True, - "verbose": self.verbose, + "verbose": self.verbose, "logFile": self.logFile }) cmd.send( self.callback, ) self._addLastCommandErrorInfo(cmd) rspInfo = cmd.getResponseInfo() #self.logIfVerbose("rspInfo =", rspInfo) if rspInfo is not None: - for key in [configKeys.DDC_DATA_PORT, + for key in [configKeys.DDC_DATA_PORT, ]: self.configuration[key] = rspInfo.get(key, None) pass @@ -458,17 +458,17 @@ def _queryConfiguration(self): # OVERRIDE ## # \protected - # Sets the component's current configuration. + # Sets the component's current configuration. def _setConfiguration(self, confDict): ret = True if self.dportCmd is not None and \ configKeys.DDC_DATA_PORT in confDict: cDict = {} - self._dictUpdate(cDict, confDict, self.configuration, + self._dictUpdate(cDict, confDict, self.configuration, [configKeys.DDC_DATA_PORT]) - cDict.update({ "parent": self, + cDict.update({ "parent": self, configKeys.INDEX: self.index, - "verbose": self.verbose, + "verbose": self.verbose, "logFile": self.logFile }) cmd = self.dportCmd(**cDict) ret &= cmd.send( self.callback, ) @@ -483,11 +483,11 @@ def _setConfiguration(self, confDict): #print repr(self),"self.configuration =",self.configuration #print repr(self),"confDict =",confDict else: - keys = [configKeys.ENABLE, - configKeys.DDC_RATE_INDEX, - configKeys.DDC_UDP_DESTINATION, - configKeys.DDC_VITA_ENABLE, - configKeys.DDC_STREAM_ID, + keys = [configKeys.ENABLE, + configKeys.DDC_RATE_INDEX, + configKeys.DDC_UDP_DESTINATION, + configKeys.DDC_VITA_ENABLE, + configKeys.DDC_STREAM_ID, configKeys.DDC_FREQUENCY_OFFSET, ] if any([q in confDict for q in keys]): @@ -495,14 +495,14 @@ def _setConfiguration(self, confDict): cDict = {} if confDict.has_key(configKeys.DDC_FREQUENCY_OFFSET): confDict[configKeys.DDC_FREQUENCY_OFFSET] = adjustFrequency( - float(confDict[configKeys.DDC_FREQUENCY_OFFSET]), - self.frqRange, - self.frqRes, + float(confDict[configKeys.DDC_FREQUENCY_OFFSET]), + self.frqRange, + self.frqRes, self.frqUnits) self._dictUpdate(cDict, confDict, self.configuration, keys) - cDict.update({ "parent": self, + cDict.update({ "parent": self, configKeys.INDEX: self.index, - "verbose": self.verbose, + "verbose": self.verbose, "logFile": self.logFile }) cmd = self.cfgCmd(**cDict) ret &= cmd.send( self.callback, ) @@ -515,11 +515,11 @@ def _setConfiguration(self, confDict): if self.nbssCmd is not None and \ configKeys.NBDDC_RF_INDEX in confDict: cDict = {} - self._dictUpdate(cDict, confDict, self.configuration, + self._dictUpdate(cDict, confDict, self.configuration, [configKeys.NBDDC_RF_INDEX]) - cDict.update({ "parent": self, + cDict.update({ "parent": self, configKeys.INDEX: self.index, - "verbose": self.verbose, + "verbose": self.verbose, "logFile": self.logFile }) cmd = self.nbssCmd(**cDict) ret &= cmd.send( self.callback, ) @@ -554,13 +554,13 @@ class ndr308ts_nbddc(ndr308_nbddc): # \internal # \brief WBDDC group component class specific to the NDR308. # -# A WBDDC group component object maintains one WBDDC group on the radio. +# A WBDDC group component object maintains one WBDDC group on the radio. # class ndr308_wbddc_group(wbddc_group): _name = "WBDDCGroup(NDR308)" - ## \brief Group member index base (what number indices start at) + ## \brief Group member index base (what number indices start at) groupMemberIndexBase = 1 - ## \brief Number of potential group members + ## \brief Number of potential group members numGroupMembers = 8 @@ -568,13 +568,13 @@ class ndr308_wbddc_group(wbddc_group): # \internal # \brief NBDDC group component class specific to the NDR308. # -# A NBDDC group component object maintains one NBDDC group on the radio. +# A NBDDC group component object maintains one NBDDC group on the radio. # class ndr308_nbddc_group(nbddc_group): _name = "NBDDCGroup(NDR308)" - ## \brief Group member index base (what number indices start at) + ## \brief Group member index base (what number indices start at) groupMemberIndexBase = 1 - ## \brief Number of potential group members + ## \brief Number of potential group members numGroupMembers = 32 @@ -759,7 +759,7 @@ class ndr308_1(_radio): 2: "VITA-49 header disabled", 3: "VITA-49 header enabled, fractional timestamp in sample counts", } - + def configureDipTable(self,index,sip,dip,dmac,udpBase): success = True x = [ int(i) for i in dip.split(".") ] @@ -776,7 +776,7 @@ def configureDipTable(self,index,sip,dip,dmac,udpBase): if success: self.dipTable[index][i] = {"dip":dip,"dport":udpBase+i,"sport":udpBase+i,"sip":self.sipTable.get(index,None),} return success - + def getDipTableEntry(self,ifIndex=None,dipIndex=None): if ifIndex is None: return self.dipTable @@ -787,10 +787,10 @@ def getDipTableEntry(self,ifIndex=None,dipIndex=None): def disableTenGigFlowControl(self,): return self.setTenGigFlowControlStatus(False) - + def enableTenGigFlowControl(self,): return self.setTenGigFlowControlStatus(True) - + def setTenGigFlowControlStatus(self,enable=False): success = False if self.tgfcCmd is not None and self.tgfcCmd.settable: @@ -798,19 +798,19 @@ def setTenGigFlowControlStatus(self,enable=False): configKeys.CONFIG_IP: { } } - for gigEPortNum in xrange(self.gigEIndexBase, + for gigEPortNum in xrange(self.gigEIndexBase, self.gigEIndexBase + self.numGigE, 1): confDict[configKeys.CONFIG_IP][gigEPortNum] = { configKeys.GIGE_FLOW_CONTROL: 1 if enable else 0, } success = self.setConfiguration(confDict) return success - + def getTenGigFlowControlStatus(self,): status = {} if self.tgfcCmd is not None: confDict = self.getConfiguration()[configKeys.CONFIG_IP] - for gigEPortNum in xrange(self.gigEIndexBase, + for gigEPortNum in xrange(self.gigEIndexBase, self.gigEIndexBase + self.numGigE, 1): if configKeys.GIGE_FLOW_CONTROL in confDict[gigEPortNum]: status |= (confDict[gigEPortNum][configKeys.GIGE_FLOW_CONTROL] == 1) @@ -1331,7 +1331,7 @@ class ndr308_ts(ndr308): # \implements CyberRadioDriver.IRadio class ndr308a(ndr308): _name = "NDR308A" - + ## # \brief Radio handler class for the NDR318-TS. # @@ -1453,9 +1453,27 @@ class ndr308a(ndr308): #
  • #
    RadioName String
    \link CyberRadioDriver::radios::ndr301::ndr301 NDR301 \endlink"ndr301"
    \link CyberRadioDriver::radios::ndr301ptt::ndr301_ptt NDR301PTT \endlink"ndr301ptt"
    \link CyberRadioDriver::radios::ndr301ptt::ndr301_ptt NDR301PTT \endlink"ndr301-ptt"
    \link CyberRadioDriver::radios::internal::ndr303::ndr303 NDR303 \endlink"ndr303"
    \link CyberRadioDriver::radios::ndr304::ndr304 NDR304 \endlink"ndr304"
    \link CyberRadioDriver::radios::ndr308::ndr308_1 NDR308-1 \endlink"ndr308_1"
    3VITA-49 header enabled, fractional timestamp in sample counts
    # -# \implements CyberRadioDriver.IRadio +# \implements CyberRadioDriver.IRadio class ndr318_ts(ndr308a): _name = "NDR318-TS" - + +class ndr318(ndr308a): + _name = "NDR318" + +class ndr308_6(ndr308): + _name = "NDR308-6" + +class ndr318a(ndr318): + _name = "NDR318A" + numTuner = 4 + numTunerBoards = 1 + +class ndr814(ndr308): + _name = "NDR814" + +class ndr818(ndr318): + _name = "NDR818" + + if __name__ == '__main__': pass diff --git a/cyberradiodriver/CyberRadioDriver/radios/ndr354.py b/cyberradiodriver/CyberRadioDriver/radios/ndr354.py index 0b6a5f3..71bbbc1 100644 --- a/cyberradiodriver/CyberRadioDriver/radios/ndr354.py +++ b/cyberradiodriver/CyberRadioDriver/radios/ndr354.py @@ -5,8 +5,8 @@ # \author NH # \author DA # \author MN -# \copyright Copyright (c) 2017 CyberRadio Solutions, Inc. -# All rights reserved. +# \copyright Copyright (c) 2017-2020 CyberRadio Solutions, Inc. +# All rights reserved. ################################################################## # Imports from other modules in this package @@ -780,6 +780,8 @@ class ndr354(_radio): connectionModes = ["https"] defaultPort = 443 udpDestInfo = "Destination index" + tunerBandwithSettable = False + tunerBandwidthConstant = 125e6 ## # \brief The list of valid configuration keywords supported by this # object. Override in derived classes as needed. diff --git a/cyberradiodriver/CyberRadioDriver/radios/ndr357.py b/cyberradiodriver/CyberRadioDriver/radios/ndr357.py index b975d37..6e3dd22 100755 --- a/cyberradiodriver/CyberRadioDriver/radios/ndr357.py +++ b/cyberradiodriver/CyberRadioDriver/radios/ndr357.py @@ -5,8 +5,8 @@ # \author NH # \author DA # \author MN -# \copyright Copyright (c) 2017 CyberRadio Solutions, Inc. -# All rights reserved. +# \copyright Copyright (c) 2017-2020 CyberRadio Solutions, Inc. +# All rights reserved. ################################################################## # Imports from other modules in this package @@ -112,6 +112,7 @@ class ndr357_demod_ifSpec(ndr551_demod_ifSpec): # \code # configDict = { # "referenceMode": [0, 1], +# "ppsSource": [0, 1], # "function": [integer (meaning is radio-dependent], # "tunerConfiguration": { # 0: { diff --git a/cyberradiodriver/CyberRadioDriver/radios/ndr358.py b/cyberradiodriver/CyberRadioDriver/radios/ndr358.py index 7200815..b39cdf7 100644 --- a/cyberradiodriver/CyberRadioDriver/radios/ndr358.py +++ b/cyberradiodriver/CyberRadioDriver/radios/ndr358.py @@ -10,14 +10,14 @@ ################################################################## # Imports from other modules in this package -from CyberRadioDriver.radios.ndr551 import ndr551, \ - ndr551_tuner, \ - ndr551_wbddc, \ - ndr551_nbddc, \ - ndr551_ddc_group, \ - ndr551_ddc_ifSpec, \ - ndr551_adc_ifSpec, \ - ndr551_demod_ifSpec +from CyberRadioDriver.radios.ndr551 import ndr551, \ + ndr551_tuner, \ + ndr551_wbddc, \ + ndr551_nbddc, \ + ndr551_ddc_group, \ + ndr551_ddc_ifSpec, \ + ndr551_adc_ifSpec, \ + ndr551_demod_ifSpec from CyberRadioDriver.command import _jsonCommandBase, jsonConfig from CyberRadioDriver import configKeys # Imports from external modules @@ -484,6 +484,18 @@ class ndr358_recorder_wbddc(ndr358_wbddc): 43: 5e6, 42: 4e6, } + # sample size in 4 byte words + ssSet = { + 50: 1024, + 49: 1024, + 48: 1024, + 47: 1024, + 46: 1024, + 45: 1024, + 44: 1024, + 43: 1024, + 42: 1024, + } cfgCmd = wbddc358_recorder validConfigurationKeywords = [ configKeys.DDC_RF_INDEX, @@ -554,6 +566,26 @@ class ndr358_recorder_nbddc(ndr358_nbddc): 1: 0.4e3, 0: 0.2e3, } + # sample size in 4 byte words + ssSet = { + 16: 1280, + 15: 1280, + 14: 1280, + 13: 1280, + 12: 1280, + 11: 1280, + 10: 1280, + 9: 1280, + 8: 1280, + 7: 1280, + 6: 1280, + 5: 1280, + 4: 1280, + 3: 1280, + 2: 1280, + 1: 1280, + 0: 1280, + } cfgCmd = nbddc358_recorder validConfigurationKeywords = [ configKeys.DDC_RF_INDEX, @@ -974,5 +1006,394 @@ class ndr358_recorder(ndr358): fftStreamIndexBase = 0 +## +# \brief WBDDC configuration command specific to the NDR358 +# ALT_RX1 variant. +# +class wbddc358_altrx1(_jsonCommandBase): + mnemonic = "wbddc" + queryParamMap = { + configKeys.INDEX: "id", + configKeys.DDC_RF_INDEX: "rfch", + configKeys.DDC_OUTPUT_TYPE: "type", + configKeys.DDC_FREQUENCY_OFFSET: "offset", + configKeys.DDC_RATE_INDEX: "filter", + configKeys.ENABLE: "enable", + configKeys.DDC_GROUP_ID: "gddcid", + configKeys.DDC_STREAM_ID: "vita", + configKeys.DDC_LINK: "link", + configKeys.DDC_UDP_DESTINATION: "dest", + configKeys.DDC_DGC_MODE: "mode", + configKeys.DDC_DGC_GAIN: "dgv", + configKeys.DDC_DGC_UPPER_LIMIT: "dul", + configKeys.DDC_DGC_LOWER_LIMIT: "dll", + configKeys.DDC_DGC_TARGET_RANGE: "dtl", + configKeys.DDC_DGC_ATTACK_LIMIT: "dal", + configKeys.DDC_DGC_DECAY_LIMIT: "ddl", + configKeys.DDC_DGC_ATTACK_OFFSET: "dao", + configKeys.DDC_DGC_DECAY_OFFSET: "ddo", + configKeys.DDC_DGC_ATTACK_TIME: "datc", + configKeys.DDC_DGC_DECAY_TIME: "ddtc", + configKeys.DDC_DGC_ATTACK_TRIGGER: "dat", + configKeys.DDC_DGC_DECAY_TRIGGER: "ddt", + } + setParamMap = { + configKeys.INDEX: "id", + configKeys.DDC_RF_INDEX: "rfch", + configKeys.DDC_OUTPUT_TYPE: "type", + configKeys.DDC_FREQUENCY_OFFSET: "offset", + configKeys.DDC_RATE_INDEX: "filter", + configKeys.ENABLE: "enable", + configKeys.DDC_GROUP_ID: "gddcid", + configKeys.DDC_STREAM_ID: "vita", + configKeys.DDC_LINK: "link", + configKeys.DDC_UDP_DESTINATION: "dest", + configKeys.DDC_DGC_MODE: "mode", + configKeys.DDC_DGC_GAIN: "dgv", + configKeys.DDC_DGC_UPPER_LIMIT: "dul", + configKeys.DDC_DGC_LOWER_LIMIT: "dll", + configKeys.DDC_DGC_TARGET_RANGE: "dtl", + configKeys.DDC_DGC_ATTACK_LIMIT: "dal", + configKeys.DDC_DGC_DECAY_LIMIT: "ddl", + configKeys.DDC_DGC_ATTACK_OFFSET: "dao", + configKeys.DDC_DGC_DECAY_OFFSET: "ddo", + configKeys.DDC_DGC_ATTACK_TIME: "datc", + configKeys.DDC_DGC_DECAY_TIME: "ddtc", + configKeys.DDC_DGC_ATTACK_TRIGGER: "dat", + configKeys.DDC_DGC_DECAY_TRIGGER: "ddt", + } + + +## +# \brief NBDDC configuration command specific to the NDR358 +# ALT_RX1 variant. +# +class nbddc358_altrx1(_jsonCommandBase): + mnemonic = "nbddc" + queryParamMap = { + configKeys.INDEX: "id", + configKeys.DDC_RF_INDEX: "rfch", + configKeys.DDC_OUTPUT_TYPE: "type", + configKeys.DDC_FREQUENCY_OFFSET: "offset", + configKeys.DDC_DECIMATION: "decimation", + configKeys.DDC_RATE_INDEX: "filter", + configKeys.ENABLE: "enable", + configKeys.DDC_GROUP_ID: "gddcid", + configKeys.DDC_STREAM_ID: "vita", + configKeys.DDC_UDP_DESTINATION: "dest", + configKeys.DDC_DGC_MODE: "mode", + configKeys.DDC_DGC_GAIN: "dgv", + configKeys.DDC_DGC_UPPER_LIMIT: "dul", + configKeys.DDC_DGC_LOWER_LIMIT: "dll", + configKeys.DDC_DGC_TARGET_RANGE: "dtl", + configKeys.DDC_DGC_ATTACK_LIMIT: "dal", + configKeys.DDC_DGC_DECAY_LIMIT: "ddl", + configKeys.DDC_DGC_ATTACK_OFFSET: "dao", + configKeys.DDC_DGC_DECAY_OFFSET: "ddo", + configKeys.DDC_DGC_ATTACK_TIME: "datc", + configKeys.DDC_DGC_DECAY_TIME: "ddtc", + configKeys.DDC_DGC_ATTACK_TRIGGER: "dat", + configKeys.DDC_DGC_DECAY_TRIGGER: "ddt", + } + setParamMap = { + configKeys.INDEX: "id", + configKeys.DDC_RF_INDEX: "rfch", + configKeys.DDC_OUTPUT_TYPE: "type", + configKeys.DDC_FREQUENCY_OFFSET: "offset", + configKeys.DDC_DECIMATION: "decimation", + configKeys.DDC_RATE_INDEX: "filter", + configKeys.ENABLE: "enable", + configKeys.DDC_GROUP_ID: "gddcid", + configKeys.DDC_STREAM_ID: "vita", + configKeys.DDC_UDP_DESTINATION: "dest", + configKeys.DDC_DGC_MODE: "mode", + configKeys.DDC_DGC_GAIN: "dgv", + configKeys.DDC_DGC_UPPER_LIMIT: "dul", + configKeys.DDC_DGC_LOWER_LIMIT: "dll", + configKeys.DDC_DGC_TARGET_RANGE: "dtl", + configKeys.DDC_DGC_ATTACK_LIMIT: "dal", + configKeys.DDC_DGC_DECAY_LIMIT: "ddl", + configKeys.DDC_DGC_ATTACK_OFFSET: "dao", + configKeys.DDC_DGC_DECAY_OFFSET: "ddo", + configKeys.DDC_DGC_ATTACK_TIME: "datc", + configKeys.DDC_DGC_DECAY_TIME: "ddtc", + configKeys.DDC_DGC_ATTACK_TRIGGER: "dat", + configKeys.DDC_DGC_DECAY_TRIGGER: "ddt", + } + + +## +# \brief WBDDC component class for the NDR358 ALT_RX1 variant. +class ndr358_altrx1_wbddc(ndr358_wbddc): + _name = "WBDDC(NDR358-Altrx1)" + # OVERRIDES + rateSet = { + 58: 22.0e6, + 57: 20.0e6, + 56: 30.72e6, + 55: 23.04e6, + 54: 15.36e6, + 53: 7.68e6, + 52: 1.92e6, + 51: 1.2288e6, + 40: 128.0e6, + 39: 64.0e6, + 38: 32.0e6, + 37: 32.0e6, + 36: 16.0e6, + 35: 16.0e6, + 34: 16.0e6, + 33: 8.0e6, + 32: 8.0e6, + } + bwSet = { + 58: 22.0e6, + 57: 16.6e6, + 56: 20.0e6, + 55: 15.0e6, + 54: 10.0e6, + 53: 5.0e6, + 52: 1.4e6, + 51: 1.25e6, + 40: 80.0e6, + 39: 40.0e6, + 38: 25.0e6, + 37: 20.0e6, + 36: 12.5e6, + 35: 10.0e6, + 34: 8.0e6, + 33: 5.0e6, + 32: 4.0e6, + } + #sample size in 4-byte words + ssSet = { + 58: 1375, + 57: 1250, + 56: 960, + 55: 1080, + 54: 960, + 53: 960, + 52: 960, + 51: 960, + 40: 1000, + 39: 1000, + 38: 1000, + 37: 1000, + 36: 1000, + 35: 1000, + 34: 1000, + 33: 1000, + 32: 1000, + } + cfgCmd = wbddc358_altrx1 + validConfigurationKeywords = [ + configKeys.DDC_RF_INDEX, + configKeys.DDC_OUTPUT_TYPE, + configKeys.DDC_FREQUENCY_OFFSET, + configKeys.DDC_RATE_INDEX, + configKeys.ENABLE, + configKeys.DDC_GROUP_ID, + configKeys.DDC_STREAM_ID, + configKeys.DDC_LINK, + configKeys.DDC_UDP_DESTINATION, + configKeys.DDC_DGC_MODE, + configKeys.DDC_DGC_GAIN, + configKeys.DDC_DGC_UPPER_LIMIT, + configKeys.DDC_DGC_LOWER_LIMIT, + configKeys.DDC_DGC_TARGET_RANGE, + configKeys.DDC_DGC_ATTACK_LIMIT, + configKeys.DDC_DGC_DECAY_LIMIT, + configKeys.DDC_DGC_ATTACK_OFFSET, + configKeys.DDC_DGC_DECAY_OFFSET, + configKeys.DDC_DGC_ATTACK_TIME, + configKeys.DDC_DGC_DECAY_TIME, + configKeys.DDC_DGC_ATTACK_TRIGGER, + configKeys.DDC_DGC_DECAY_TRIGGER, + ] + + +## +# \brief NBDDC component class for the NDR358 ALT_RX1 variant. +class ndr358_altrx1_nbddc(ndr358_nbddc): + _name = "NBDDC(NDR358-Altrx1)" + # OVERRIDES + rateSet = { + 20: 250e3, + 16: 2000e3, + 15: 4000e3, + 14: 3200e3, + 13: 1280e3, + 12: 400e3, + 11: 256e3, + 10: 200e3, + 9: 128e3, + 8: 64e3, + 7: 32e3, + 6: 16e3, + 5: 8e3, + 4: 4e3, + 3: 2e3, + 2: 1e3, + 1: 0.5e3, + 0: 0.25e3, + } + bwSet = { + 20: 200e3, + 16: 1500e3, + 15: 3200e3, + 14: 2500e3, + 13: 1000e3, + 12: 300e3, + 11: 200e3, + 10: 150e3, + 9: 100e3, + 8: 50e3, + 7: 25e3, + 6: 12.5e3, + 5: 6.4e3, + 4: 3.2e3, + 3: 1.6e3, + 2: 0.8e3, + 1: 0.4e3, + 0: 0.2e3, + } + #sample size in 4-byte words + ssSet = { + 20: 1000, + 16: 1000, + 15: 1000, + 14: 1000, + 13: 1000, + 12: 1000, + 11: 1000, + 10: 1000, + 9: 1000, + 8: 1000, + 7: 1000, + 6: 1000, + 5: 1000, + 4: 1000, + 3: 1000, + 2: 1000, + 1: 1000, + 0: 1000, + } + cfgCmd = nbddc358_altrx1 + validConfigurationKeywords = [ + configKeys.DDC_RF_INDEX, + configKeys.DDC_OUTPUT_TYPE, + configKeys.DDC_FREQUENCY_OFFSET, + configKeys.DDC_DECIMATION, + configKeys.DDC_RATE_INDEX, + configKeys.ENABLE, + configKeys.DDC_GROUP_ID, + configKeys.DDC_STREAM_ID, + configKeys.DDC_UDP_DESTINATION, + configKeys.DDC_DGC_MODE, + configKeys.DDC_DGC_GAIN, + configKeys.DDC_DGC_UPPER_LIMIT, + configKeys.DDC_DGC_LOWER_LIMIT, + configKeys.DDC_DGC_TARGET_RANGE, + configKeys.DDC_DGC_ATTACK_LIMIT, + configKeys.DDC_DGC_DECAY_LIMIT, + configKeys.DDC_DGC_ATTACK_OFFSET, + configKeys.DDC_DGC_DECAY_OFFSET, + configKeys.DDC_DGC_ATTACK_TIME, + configKeys.DDC_DGC_DECAY_TIME, + configKeys.DDC_DGC_ATTACK_TRIGGER, + configKeys.DDC_DGC_DECAY_TRIGGER, + ] + + +## +# \internal +# \brief VITA 49 interface specification class for the NDR358 ALT_RX1 +# variant's WBDDC format. +# \note Some explanation for these values is probably in order. +# * The "header" includes not only the 7 words of the standard VITA +# packet header, but also the 5 words of the metadata included in +# each WBDDC payload. +# * The "tail" includes not only the standard VITA packet trailer, +# but also the trailer word within the WBDDC payload. +# * The definition of "payload" deviates from the ICD here, as we +# want the "payload" to be only the part of the packet that +# contains data samples. +# ** For WBDDC format, each 32-bit word contains one 16-bit I/16-bit Q +# sample, so the number of samples is getVitaPayloadSize("wbddc") / 4. +# *** The payload size varies based on the filter. Five different +# payload sizes are present - 960*4, 1000*4, 1080*4, 1250*4, 1375*4. +class ndr358_altrx1_wbddc_ifSpec(ndr358_ddc_ifSpec): + headerSizeWords = 12 + payloadSizeWords = 960 + tailSizeWords = 2 + byteOrder = "big" + + +## +# \internal +# \brief VITA 49 interface specification class for the NDR358 Recorder +# variant's NBDDC format. +# \note Some explanation for these values is probably in order. +# * The "header" includes not only the 7 words of the standard VITA +# packet header, but also the 5 words of the metadata included in +# each NBDDC payload. +# * The "tail" includes not only the standard VITA packet trailer, +# but also the trailer word within the NBDDC payload. +# * The definition of "payload" deviates from the ICD here, as we +# want the "payload" to be only the part of the packet that +# contains data samples. +# ** For NBDDC format, each 32-bit word contains one 16-bit I/16-bit Q +# sample, so the number of samples is getVitaPayloadSize("nbddc") / 4. +class ndr358_altrx1_nbddc_ifSpec(ndr358_ddc_ifSpec): + headerSizeWords = 12 + payloadSizeWords = 1000 + tailSizeWords = 2 + byteOrder = "big" + + +## +# +# \section VITA_Notes_NDR358Rec VITA 49 Notes +# +# When dealing with VITA 49 payloads, we have historically relied on the +# following convention: +# * getVitaHeaderSize() provides how many bytes contain metadata information +# at the beginning of the packet +# * getVitaPayloadSize() provides how many bytes contain data samples +# * getVitaTailSize() provides how many bytes contain metadata information +# at the end of the packet +# +# For NDR551-class radios, this convention requires us to deviate, not only +# from the VITA 49 standard, but also from the NDR551 ICD itself. +# * The getVitaHeaderSize(), getVitaPayloadSize(), and getVitaTailSize() +# methods use the payloadType argument to differentiate between the +# three supported payload formats. +# * WBDDC format: "wbddc" +# * NBDDC format: "nbddc" +# * The "header" includes not only the 7 words of the standard VITA +# packet header, but also the 5 words of the metadata included in +# each payload. +# * The "tail" includes not only the standard VITA packet trailer, +# but also the trailer word within the payload. +# * The definition of "payload" deviates from the ICD here, as we +# want the "payload" to be only the part of the packet that +# contains data samples. +# ** For WBDDC format, each 32-bit word contains one 16-bit I/16-bit Q +# sample, so the number of samples is getVitaPayloadSize("wbddc") / 4. +# ** For NBDDC format, each 32-bit word contains one 16-bit I/16-bit Q +# sample, so the number of samples is getVitaPayloadSize("nbddc") / 4. +# +# \implements CyberRadioDriver.IRadio +class ndr358_altrx1(ndr358): + _name = "NDR358-ALTRX1" + wbddcType = ndr358_altrx1_wbddc + nbddcType = ndr358_altrx1_nbddc + ifSpec = ndr358_altrx1_wbddc_ifSpec + ifSpecMap = { + "wbddc": ndr358_altrx1_wbddc_ifSpec, + "nbddc": ndr358_altrx1_nbddc_ifSpec, + } + + if __name__ == '__main__': pass diff --git a/cyberradiodriver/CyberRadioDriver/radios/ndr364.py b/cyberradiodriver/CyberRadioDriver/radios/ndr364.py index c2fc3e9..3b61bac 100644 --- a/cyberradiodriver/CyberRadioDriver/radios/ndr364.py +++ b/cyberradiodriver/CyberRadioDriver/radios/ndr364.py @@ -5,8 +5,8 @@ # \author NH # \author DA # \author MN -# \copyright Copyright (c) 2017 CyberRadio Solutions, Inc. -# All rights reserved. +# \copyright Copyright (c) 2017-2020 CyberRadio Solutions, Inc. +# All rights reserved. ################################################################## # Imports from other modules in this package @@ -780,6 +780,8 @@ class ndr364(_radio): connectionModes = ["https"] defaultPort = 443 udpDestInfo = "Destination index" + tunerBandwithSettable = False + tunerBandwidthConstant = 125e6 ## # \brief The list of valid configuration keywords supported by this # object. Override in derived classes as needed. @@ -856,7 +858,7 @@ class ndr364_wbddc_radio(ndr364): class ndr364_nbddc_radio(ndr364): _name = "NDR364-NBDDC" -class ndr364_ccf_radio(ndr364): +class ndr364_ccf(ndr364): _name = "NDR364-CCF" ifSpec = ndr364_ccf_ifSpec diff --git a/cyberradiodriver/CyberRadioDriver/radios/ndr378.py b/cyberradiodriver/CyberRadioDriver/radios/ndr378.py new file mode 100644 index 0000000..dc68d16 --- /dev/null +++ b/cyberradiodriver/CyberRadioDriver/radios/ndr378.py @@ -0,0 +1,279 @@ +#!/usr/bin/env python +################################################################## +# \package CyberRadioDriver.radios.ndr378 +# \brief NDR378 Support +# \author NH +# \author DA +# \author MN +# \copyright Copyright (c) 2017 CyberRadio Solutions, Inc. +# All rights reserved. +################################################################## + +# Imports from other modules in this package +from CyberRadioDriver.radios.ndr551 import ndr551, \ + ndr551_tuner, \ + ndr551_wbddc, \ + ndr551_nbddc, \ + ndr551_ddc_group, \ + ndr551_ddc_ifSpec, \ + ndr551_adc_ifSpec, \ + ndr551_demod_ifSpec +from CyberRadioDriver.command import _jsonCommandBase, jsonConfig +from CyberRadioDriver import configKeys +# Imports from external modules +# Python standard library imports + +## +# \brief Tuner component class for the NDR378. +# +class ndr378_tuner(ndr551_tuner): + _name = "Tuner(NDR378)" + frqRange = (20e6,6e9) + +## +# \brief WBDDC component class for the NDR378. +class ndr378_wbddc(ndr551_wbddc): + _name = "WBDDC(NDR378)" + +## +# \brief NBDDC component class for the NDR378. +class ndr378_nbddc(ndr551_nbddc): + _name = "NBDDC(NDR378)" + +## +# \brief NBDDC component class for the NDR378. +class ndr378_ddc_group(ndr551_ddc_group): + _name = "DDCGroup(NDR378)" + +## +# \internal +# \brief VITA 49 interface specification class for the NDR378's DDC format. +# \note Some explanation for these values is probably in order. +# * The "header" includes not only the 7 words of the standard VITA +# packet header, but also the 5 words of the metadata included in +# each DDC payload. +# * The "tail" includes not only the standard VITA packet trailer, +# but also the trailer word within the DDC payload. +# * The definition of "payload" deviates from the ICD here, as we +# want the "payload" to be only the part of the packet that +# contains data samples. +# ** For DDC format, each 32-bit word contains one 16-bit I/16-bit Q +# sample, so the number of samples is getVitaPayloadSize("ddc") / 4. +class ndr378_ddc_ifSpec(ndr551_ddc_ifSpec): + pass + + +## +# \internal +# \brief VITA 49 interface specification class for NDR378's ADC format. +# \note Some explanation for these values is probably in order. +# * The "header" includes not only the 7 words of the standard VITA +# packet header, but also the 5 words of the metadata included in +# each ADC payload. +# * The "tail" includes not only the standard VITA packet trailer, +# but also the trailer word within the ADC payload. +# * The definition of "payload" deviates from the ICD here, as we +# want the "payload" to be only the part of the packet that +# contains data samples. +# ** For ADC format, each 32-bit word contains two 16-bit ADC samples, +# so the number of samples is getVitaPayloadSize("adc") / 2. +class ndr378_adc_ifSpec(ndr551_adc_ifSpec): + pass + + +## +# \internal +# \brief VITA 49 interface specification class for the NDR378's demod format. +# \note Some explanation for these values is probably in order. +# * The "header" includes not only the 7 words of the standard VITA +# packet header, but also the 5 words of the metadata included in +# each demod payload. +# * The "tail" includes not only the standard VITA packet trailer, +# but also the trailer word within the demod payload. +# * The definition of "payload" deviates from the ICD here, as we +# want the "payload" to be only the part of the packet that +# contains data samples. +# ** For demod format, each 32-bit word contains two 16-bit demod samples, +# so the number of samples is getVitaPayloadSize("demod") / 2. +class ndr378_demod_ifSpec(ndr551_demod_ifSpec): + pass + + +## +# \brief Radio handler class for the NDR378. +# +# This class implements the CyberRadioDriver.IRadio interface. +# +# \section ConnectionModes_NDR378 Connection Modes +# +# "udp" +# +# \section RadioConfig_NDR378 Radio Configuration Options +# +# \code +# configDict = { +# "referenceMode": [0, 1], +# "function": [integer (meaning is radio-dependent], +# "tunerConfiguration": { +# 0: { +# "preselectorBypass": [True, False], +# "frequency": [20000000.0-6000000000.0, step 1000000.0], +# "attenuation": [0.0-40.0, step 1.0], +# "enable": [True, False], +# "ifFilter": [3, 10, 40, 80], +# "delay": [0.0-1.0, step 8e-6], +# "fnr": [True, False], +# "gainMode": ["auto", "manual", "freeze"], +# "asp": [-40.0-0.0, step 1.0], +# "aul": [-40.0-0.0, step 1.0], +# "all": [-40.0-0.0, step 1.0], +# "aat": [1.0-128.0, step 1.0], +# "adt": [1.0-128.0, step 1.0], +# "aas": [0.0-40.0, step 1.0], +# "ads": [0.0-40.0, step 1.0], +# "aal": [1.0-30.0, step 1.0], +# "adl": [1.0-30.0, step 1.0], +# }, +# ...7 (repeat for each tuner) +# }, +# "ddcConfiguration": { +# "wideband": { +# 0: { +# "enable": [True, False], +# "rfIndex": ["0", "1", "2", "3"], +# "outputType": ["iq", "raw"], +# "frequency": [-40e6-40e6, step 1e3], +# "decimation": [1, 2, 4, 8, 16], +# "filterIndex": [32-63, step 1], +# "oversampling": [1, 2, 4], +# "startTime": [start time], +# "samples": [samples], +# "udpDest": [UDP destination table index], +# "groupId": [0-15, step 1], +# "streamId": [stream ID], +# "link": [0, 1, 2, 3], +# "gainMode": ["auto", "manual", "freeze"], +# "dgv": [0.0-96.0, step 1.0], +# "dul": [0.0-96.0, step 1.0], +# "dll": [0.0-96.0, step 1.0], +# "dtl": [-96.0-0.0, step 0.5], +# "dal": [0.0-30.0, step 0.5], +# "ddl": [0.0-30.0, step 0.5], +# "dao": [0.0-24.0, step 0.5], +# "ddo": [0.0-24.0, step 0.5], +# "datc": [10-3000, step 10], +# "ddtc": [10-3000, step 10], +# "dat": [1-100, step 1], +# "ddt": [1-100, step 1], +# }, +# ...7 (repeat for each WBDDC) +# }, +# "narrowband": { +# 0: { +# "enable": [True, False], +# "frequency": [-40e6-40e6, step 1e3], +# "rfIndex": ["0", "1", "2", "3"], +# "filterIndex": [0-31 step 1, 64-4095 step 1], +# "cic0": [4-500, step 1], +# "cic1": [1, 4-500, step 1], +# "oversampling": [1, 2, 4, 8, 16], +# "demod": ["none", "cw", "fm", "am", "usb", "lsb"], +# "demodGain": [gain], +# "audioDecimation": [True, False], +# "bfo": [-12e3-12e3, step 1], +# "startTime": [ISO 8601 time string], +# "samples": [number of samples], +# "udpDest": [UDP destination table index], +# "groupId": [0-15, step 1], +# "streamId": [stream ID], +# "gainMode": ["auto", "manual", "freeze"], +# "dgv": [0.0-96.0, step 1.0], +# "dul": [0.0-96.0, step 1.0], +# "dll": [0.0-96.0, step 1.0], +# "dtl": [-96.0-0.0, step 0.5], +# "dal": [0.0-30.0, step 0.5], +# "ddl": [0.0-30.0, step 0.5], +# "dao": [0.0-24.0, step 0.5], +# "ddo": [0.0-24.0, step 0.5], +# "datc": [10-3000, step 10], +# "ddtc": [10-3000, step 10], +# "dat": [1-100, step 1], +# "ddt": [1-100, step 1], +# }, +# ...63 (repeat for each NBDDC) +# }, +# }, +# "ipConfiguration": { +# 0: { +# "destIP": { +# 0: { +# "ipAddr": [IP address], +# "macAddr": [MAC address], +# "destPort": [port], +# "arp": [True, False], +# }, +# ...63 (repeat for each UDP destination index) +# }, +# "sourceIP": { +# "ipAddr": [IP address], +# "macAddr": [MAC address], +# "netmask": [netmask], +# "sourcePort": [port], +# }, +# }, +# ...3 (repeat for each 10-Gigabit Ethernet port) +# }, +# } +# \endcode +# +# \section VITA_Notes_NDR378 VITA 49 Notes +# +# When dealing with VITA 49 payloads, we have historically relied on the +# following convention: +# * getVitaHeaderSize() provides how many bytes contain metadata information +# at the beginning of the packet +# * getVitaPayloadSize() provides how many bytes contain data samples +# * getVitaTailSize() provides how many bytes contain metadata information +# at the end of the packet +# +# For NDR551-class radios, this convention requires us to deviate, not only +# from the VITA 49 standard, but also from the NDR551 ICD itself. +# * The getVitaHeaderSize(), getVitaPayloadSize(), and getVitaTailSize() +# methods use the payloadType argument to differentiate between the +# three supported payload formats. +# * DDC format: "ddc" +# * ADC format: "adc" +# * Demod format: "demod" +# * The "header" includes not only the 7 words of the standard VITA +# packet header, but also the 5 words of the metadata included in +# each payload. +# * The "tail" includes not only the standard VITA packet trailer, +# but also the trailer word within the payload. +# * The definition of "payload" deviates from the ICD here, as we +# want the "payload" to be only the part of the packet that +# contains data samples. +# ** For ADC format, each 32-bit word contains two 16-bit ADC samples, +# so the number of samples is getVitaPayloadSize("adc") / 2. +# ** For DDC format, each 32-bit word contains one 16-bit I/16-bit Q +# sample, so the number of samples is getVitaPayloadSize("ddc") / 4. +# ** For demod format, each 32-bit word contains two 16-bit demod samples, +# so the number of samples is getVitaPayloadSize("demod") / 2. +# +# \implements CyberRadioDriver.IRadio +class ndr378(ndr551): + _name = "NDR378" + ifSpec = ndr378_ddc_ifSpec + ifSpecMap = { + "ddc": ndr378_ddc_ifSpec, + "adc": ndr378_adc_ifSpec, + "demod": ndr378_demod_ifSpec, + } + tunerType = ndr378_tuner + numTuner = 8 + wbddcType = ndr378_wbddc + numWbddc = 8 + nbddcType = ndr378_nbddc + cddcGroupType = None + + + diff --git a/cyberradiodriver/CyberRadioDriver/radios/ndr511.py b/cyberradiodriver/CyberRadioDriver/radios/ndr511.py new file mode 100755 index 0000000..a85700f --- /dev/null +++ b/cyberradiodriver/CyberRadioDriver/radios/ndr511.py @@ -0,0 +1,266 @@ +################################################################## +# \package CyberRadioDriver.radios.ndr511 +# \brief NDR511 Support +# \author BS +# \copyright Copyright (c) 2017 CyberRadio Solutions, Inc. +# All rights reserved. +################################################################## + +# Imports from other modules in this package +from CyberRadioDriver import configKeys +from CyberRadioDriver.command import _jsonCommandBase, jsonConfig +from CyberRadioDriver.components import _tuner, adjustFrequency, adjustAttenuation +from CyberRadioDriver.radio import _ifSpec, _radio, funJSON + +# Imports from external modules +# Python standard library imports +import json +import math +import time, datetime +import traceback + + + +class tuner511(_jsonCommandBase): + mnemonic = "tuner" + queryParamMap = { + configKeys.TUNER_INDEX: "id", + configKeys.TUNER_BAND: "band", + configKeys.TUNER_ATTENUATION: "atten", + configKeys.ENABLE: "enable" + } + setParamMap = { + configKeys.TUNER_INDEX: "id", + configKeys.TUNER_BAND: "band", + configKeys.TUNER_ATTENUATION: "atten", + configKeys.ENABLE: "enable" + } +## +# Status Query command specific to the NDR551. +# +class status511(_jsonCommandBase): + mnemonic = "status" + settable = False + queryParamMap = { + configKeys.VERINFO_MODEL: "model", + configKeys.VERINFO_SN: "sn", + configKeys.VERINFO_UNITREV: "unit", + configKeys.VERINFO_SW: "sw", + configKeys.STATUS_TUNERS: "tuners", + configKeys.VERINFO_FW: "fw", + configKeys.STATUS_ERROR: "error", + configKeys.STATUS_PRI_MAC: "pmac", + configKeys.STATUS_TEMP: "temp", + configKeys.STATUS_10MHZ_REF: "cfg10m", + configKeys.STATUS_10MHZ_REF_STATUS: "status10m", + configKeys.STATUS_ONTIME: "ontime", + configKeys.STATUS_MEM: "mem", + configKeys.STATUS_LINK0: "link0up", + configKeys.STATUS_TUNER0_LO1: "ch1lo", + configKeys.STATUS_TUNER1_LO1: "ch2lo", + configKeys.STATUS_FPGA_TEMP: "fpgatemp", + } + +## +# Reference mode command specific to the NDR562. +# +class ref511(_jsonCommandBase): + mnemonic = "ref" + queryParamMap = { + configKeys.REFERENCE_MODE: "cfg10m" + } + setParamMap = { + configKeys.REFERENCE_MODE: "cfg10m" + } + +## +# \brief Tuner component class for the NDR562. +# + +class ndr511_tuner(_tuner): + _name = "Tuner(NDR511)" + frqRange = (17e9,42e9) + frqRes = 10e6 + attRange = (0.0,40.0) + attRes = 1.0 + frqCmd = tuner511 + attCmd = tuner511 + agc = False + defaultPort = 19091 + + validConfigurationKeywords = [ + configKeys.TUNER_BAND, + configKeys.TUNER_ATTENUATION, + configKeys.ENABLE, + configKeys.TUNER_FNR, + ] + + def __init__(self,*args,**kwargs): + _tuner.__init__(self,*args,**kwargs) + + # OVERRIDE + ## + # \protected + # Queries hardware to determine the object's current configuration. + def _queryConfiguration(self): + # Call the base-class implementation + configKeys.Configurable._queryConfiguration(self) + # Override + if self.frqCmd is not None: + cmd = self.frqCmd(**{ "parent": self, + configKeys.TUNER_INDEX: self.index, + "query": True, + "verbose": self.verbose, + "logFile": self.logFile }) + cmd.send( self.callback, ) + self._addLastCommandErrorInfo(cmd) + rspInfo = cmd.getResponseInfo() + if rspInfo is not None: + for key in self.validConfigurationKeywords: + val = rspInfo.get(key, None) + if val is not None: + self.configuration[key] = val + pass + + # OVERRIDE + ## + # \protected + # Issues hardware commands to set the object's current configuration. + def _setConfiguration(self, confDict): + ret = True + if self.frqCmd is not None: + cDict = { "parent": self, + configKeys.TUNER_INDEX: self.index, + "verbose": self.verbose, + "logFile": self.logFile } + for key in [configKeys.ENABLE, + configKeys.TUNER_FNR, + ]: + if key in confDict: + cDict[key] = confDict[key] + if configKeys.TUNER_FREQUENCY in confDict: + freqIn = float(confDict.get(configKeys.TUNER_FREQUENCY, 0)) + freqAdj = adjustFrequency(freqIn, self.frqRange, + self.frqRes, self.frqUnits) + cDict[configKeys.TUNER_FREQUENCY] = freqAdj + if configKeys.TUNER_ATTENUATION in confDict or configKeys.TUNER_RF_ATTENUATION in confDict: + rfAttIn = float(confDict.get(configKeys.TUNER_RF_ATTENUATION, + confDict.get(configKeys.TUNER_ATTENUATION, 0))) + rfAttAdj = adjustAttenuation(rfAttIn, self.attRange, + self.attRes, 1) + cDict[configKeys.TUNER_ATTENUATION] = rfAttAdj + cmd = self.frqCmd(**cDict) + ret &= cmd.send( self.callback, ) + ret &= cmd.success + self._addLastCommandErrorInfo(cmd) + if ret: + if configKeys.TUNER_FREQUENCY in confDict: + self.configuration[configKeys.TUNER_FREQUENCY] = freqAdj * self.frqUnits + if configKeys.TUNER_ATTENUATION in confDict or configKeys.TUNER_RF_ATTENUATION in confDict: + self.configuration[configKeys.TUNER_ATTENUATION] = rfAttAdj + self.configuration[configKeys.TUNER_RF_ATTENUATION] = rfAttAdj + for key in [configKeys.ENABLE, + configKeys.TUNER_FNR, + ]: + if key in confDict: + self.configuration[key] = confDict[key] + pass + return ret + +## +# \brief Radio handler class for the NDR562. +# +# This class implements the CyberRadioDriver.IRadio interface. +# +# \section ConnectionModes_NDR562 Connection Modes +# +# "udp" +# +# \section RadioConfig_NDR562 Radio Configuration Options +# +# \code +# configDict = { +# "referenceMode": [0, 1], +# "tunerConfiguration": { +# 0: { +# "band": [0-5], +# "attenuation": [0.0-40.0, step 0.5], +# "enable": [True, False], +# }, +# 1: { +# "band": [0-5], +# "attenuation": [0.0-40.0, step 0.5], +# "enable": [True, False], +# } +# }, +# } +# \endcode +# +# \implements CyberRadioDriver.IRadio +class ndr511(_radio): + _name = "NDR511" + json = True + ifSpec = None + ifSpecMap = {} + tunerType = ndr511_tuner + wbddcType = None + nbddcType = None + cddcGroupType = None + statQry = status511 + refCmd = ref511 + sipCmd = None + dipCmd = None + numGigE = 0 + numTuner = 2 + numNbddc = 0 + numWbddc = 0 + numCddcGroups = 0 + connectionModes = ["udp"] + defaultPort = 19091 + + idnQry = None + verQry = None + hrevQry = None + cfgCmd = None + rbypCmd = None + sipCmd = None + dipCmd = None + smacCmd = None + dmacCmd = None + calfCmd = None + + + refModes = {0:"Internal 10MHz",1:"External 10MHz"} + ## + # \brief The list of valid configuration keywords supported by this + # object. Override in derived classes as needed. + validConfigurationKeywords = [configKeys.REFERENCE_MODE] + + # OVERRIDE + ## + # \brief Returns version information for the radio. + # + # \copydetails CyberRadioDriver::IRadio::getVersionInfo() + def getVersionInfo(self): + # Query hardware for details if we don't have them already + keys = [configKeys.VERINFO_MODEL, configKeys.VERINFO_SN, + configKeys.VERINFO_SW, configKeys.VERINFO_FW, + configKeys.VERINFO_REF, configKeys.VERINFO_UNITREV, + configKeys.VERINFO_HW] + if not all([self.versionInfo.has_key(key) for key in keys]): + cmd = self.statQry(parent=self, + query=True, + verbose=self.verbose, logFile=self.logFile) + cmd.send( self.sendCommand, ) + self._addLastCommandErrorInfo(cmd) + rspInfo = cmd.getResponseInfo() + if rspInfo is not None: + self._dictUpdate(self.versionInfo, rspInfo, {}, keys) + for key in keys: + if not self.versionInfo.has_key(key): + self.versionInfo[key] = "N/A" + return self.versionInfo + + +if __name__ == '__main__': + pass diff --git a/cyberradiodriver/CyberRadioDriver/radios/ndr551.py b/cyberradiodriver/CyberRadioDriver/radios/ndr551.py index 19a9f5d..384e9a9 100644 --- a/cyberradiodriver/CyberRadioDriver/radios/ndr551.py +++ b/cyberradiodriver/CyberRadioDriver/radios/ndr551.py @@ -5,8 +5,8 @@ # \author NH # \author DA # \author MN -# \copyright Copyright (c) 2017 CyberRadio Solutions, Inc. -# All rights reserved. +# \copyright Copyright (c) 2017-2020 CyberRadio Solutions, Inc. +# All rights reserved. ################################################################## # Imports from other modules in this package @@ -19,6 +19,8 @@ # Imports from external modules # Python standard library imports import json +import math +import time, datetime import traceback @@ -264,7 +266,8 @@ class status551(_jsonCommandBase): configKeys.STATUS_10MHZ_REF: "cfg10m", configKeys.STATUS_10MHZ_REF_STATUS: "status10m", configKeys.STATUS_PPS_SOURCE: "cfg1pps", - configKeys.STATUS_PPS: "status1pps", + #configKeys.STATUS_PPS: "status1pps", + configKeys.STATUS_PPS: "statuspps", configKeys.STATUS_ONTIME: "ontime", configKeys.STATUS_MEM: "mem", configKeys.STATUS_LINK0: "link0up", @@ -308,6 +311,15 @@ class reset551(_jsonCommandBase): configKeys.RESET_TYPE: "reboot", } +class ifOut551(_jsonCommandBase): + mnemonic = "cntrl" + queryable = False + # queryParamMap = { + # configKeys.CNTRL_IF_OUT: "ifout", + # } + setParamMap = { + configKeys.CNTRL_IF_OUT: "ifout", + } ## # Reference mode command specific to the NDR551. @@ -315,11 +327,20 @@ class reset551(_jsonCommandBase): class ref551(_jsonCommandBase): mnemonic = "ref" queryParamMap = { - configKeys.REFERENCE_MODE: "cfg10m", - } + configKeys.REFERENCE_MODE: "cfg10m", + configKeys.STATUS_PPS_SOURCE: "cfg1pps", + configKeys.TIME_UTC: "timeset", + # Interesting that qref doesn't get the noise generator -- DA + #configKeys.NOISE_GENERATOR: "noise", + configKeys.NOISE_STATE: "nstate" + } setParamMap = { - configKeys.REFERENCE_MODE: "cfg10m", - } + configKeys.REFERENCE_MODE: "cfg10m", + configKeys.STATUS_PPS_SOURCE: "cfg1pps", + configKeys.TIME_UTC: "timeset", + configKeys.NOISE_GENERATOR: "noise", + configKeys.NOISE_STATE: "nstate" + } ## @@ -438,7 +459,7 @@ class ndr551_tuner(_tuner): frqUnits = 1 attRange = (0.0,40.0) attRes = 1.0 - ifFilter = [3, 10, 40, 80] + ifFilters = [3, 10, 40, 80] agc = False # The NDR551 has one tuner command that sets all tuner parameters. frqCmd = tuner551 @@ -468,6 +489,7 @@ class ndr551_tuner(_tuner): configKeys.TUNER_AGC_DECAY_STEP, configKeys.TUNER_AGC_ATTACK_LIMIT, configKeys.TUNER_AGC_DECAY_LIMIT, + configKeys.TUNER_PRESELECT_BYPASS, ] def __init__(self,*args,**kwargs): @@ -523,6 +545,7 @@ def _setConfiguration(self, confDict): configKeys.TUNER_AGC_DECAY_STEP, configKeys.TUNER_AGC_ATTACK_LIMIT, configKeys.TUNER_AGC_DECAY_LIMIT, + configKeys.TUNER_PRESELECT_BYPASS, ]: if key in confDict: cDict[key] = confDict[key] @@ -562,6 +585,7 @@ def _setConfiguration(self, confDict): configKeys.TUNER_AGC_DECAY_STEP, configKeys.TUNER_AGC_ATTACK_LIMIT, configKeys.TUNER_AGC_DECAY_LIMIT, + configKeys.TUNER_PRESELECT_BYPASS, ]: if key in confDict: self.configuration[key] = confDict[key] @@ -1023,6 +1047,7 @@ class ndr551_demod_ifSpec(_ifSpec): # \code # configDict = { # "referenceMode": [0, 1], +# "ppsSource": [0, 1], # "function": [integer (meaning is radio-dependent], # "tunerConfiguration": { # 0: { @@ -1221,13 +1246,33 @@ class ndr551(_radio): dmacCmd = None calfCmd = None resetCmd = reset551 + cntrlCmd = ifOut551 funCmd = funJSON refModes = {0:"Internal 10MHz",1:"External 10MHz"} ppsModes = {0:"Internal 1PPS", 1:"External 1PPS"} + noiseGens = {0: "RF Tuner", 1: "Microwave"} rbypModes = {} connectionModes = ["udp"] defaultPort = 19091 udpDestInfo = "Destination index" + tunerBandwithSettable = True + tunerBandwidthConstant = 80e6 + + # OVERRIDE + ## + # \brief The list of valid configuration keywords supported by this + # object. Override in derived classes as needed. + validConfigurationKeywords = [configKeys.CONFIG_MODE, + configKeys.REFERENCE_MODE, + configKeys.BYPASS_MODE, + configKeys.CALIB_FREQUENCY, + configKeys.FNR_MODE, + configKeys.GPS_ENABLE, + configKeys.REF_TUNING_VOLT, + configKeys.GIGE_FLOW_CONTROL, + configKeys.RADIO_FUNCTION, + configKeys.STATUS_PPS_SOURCE, + ] # OVERRIDE ## @@ -1254,6 +1299,61 @@ def getVersionInfo(self): self.versionInfo[key] = "N/A" return self.versionInfo + # OVERRIDE + ## + # \brief Sets the time for the next PPS rising edge on the radio. + # + # \copydetails CyberRadioDriver::IRadio::setTimeNextPps() + def setTimeNextPps(self,checkTime=False,useGpsTime=False,newPpsTime=None): + if self.refCmd is not None: + # 551-class radios don't have an internal GPS that they can + # use to set time, so the useGpsTime parameter has no effect + if newPpsTime is not None: + nextSecond = int( _radio.timeFromString(newPpsTime, utc=True) ) + #if useGpsTime: + # cmd = self.utcCmd( parent=self, utcTime="g" ) + #else: + # nextSecond = int( math.floor( time.time() ) )+1 + # cmd = self.utcCmd( parent=self, utcTime=str(nextSecond), + # verbose=self.verbose, logFile=self.logFile ) + else: + nextSecond = int( math.floor( time.time() ) )+1 + # The new UTC time needs to be in ISO 8601 format for these radios + newUtcTime = datetime.datetime.utcfromtimestamp(nextSecond).isoformat() + cmd = self.refCmd( parent=self, utcTime=newUtcTime, + verbose=self.verbose, logFile=self.logFile ) + cmd.send( self.sendCommand, timeout=cmd.timeout ) + if checkTime: + radioUtc = self.getTimeNextPps() + self.logIfVerbose("Set time = %d & Query time = %d" % (nextSecond,radioUtc)) + return radioUtc==nextSecond + else: + return cmd.success + else: + return False + + # OVERRIDE + ## + # \brief Gets the current radio time. + # + # \copydetails CyberRadioDriver::IRadio::getTimeNow() + def getTimeNow(self): + if self.refCmd is not None: + cmd = self.refCmd( parent=self, query=True, + verbose=self.verbose, logFile=self.logFile ) + cmd.send( self.sendCommand, timeout=cmd.timeout ) + return cmd.getResponseInfo().get(configKeys.TIME_UTC, None) + else: + return None + + # OVERRIDE + ## + # \brief Gets the time for the next PPS rising edge on the radio. + # + # \copydetails CyberRadioDriver::IRadio::getTimeNextPps() + def getTimeNextPps(self): + return self.getTimeNow() + # OVERRIDE ## # \brief Sets DDC configuration (old-style). diff --git a/cyberradiodriver/CyberRadioDriver/radios/ndr562.py b/cyberradiodriver/CyberRadioDriver/radios/ndr562.py index b750b1e..cef402e 100644 --- a/cyberradiodriver/CyberRadioDriver/radios/ndr562.py +++ b/cyberradiodriver/CyberRadioDriver/radios/ndr562.py @@ -5,8 +5,8 @@ # \author NH # \author DA # \author MN -# \copyright Copyright (c) 2017 CyberRadio Solutions, Inc. -# All rights reserved. +# \copyright Copyright (c) 2017-2020 CyberRadio Solutions, Inc. +# All rights reserved. ################################################################## # Imports from other modules in this package @@ -186,7 +186,8 @@ class status562(_jsonCommandBase): configKeys.STATUS_10MHZ_REF: "cfg10m", configKeys.STATUS_10MHZ_REF_STATUS: "status10m", configKeys.STATUS_PPS_SOURCE: "cfg1pps", - configKeys.STATUS_PPS: "status1pps", + #configKeys.STATUS_PPS: "status1pps", + configKeys.STATUS_PPS: "statuspps", configKeys.STATUS_ONTIME: "ontime", configKeys.STATUS_MEM: "mem", configKeys.STATUS_LINK0: "link0up", @@ -230,6 +231,16 @@ class pps562(_jsonCommandBase): configKeys.TIME_UTC: "timeset", configKeys.NOISE_STATE: "nstate" } + +class ifout562(_jsonCommandBase): + mnemonic = "cntrl" + queryParamMap = { + configKeys.CNTRL_IF_OUT: "ifout", + } + setParamMap = { + configKeys.CNTRL_IF_OUT: "ifout", + } + ## # \brief Radio handler class for the NDR562. # @@ -244,6 +255,7 @@ class pps562(_jsonCommandBase): # \code # configDict = { # "referenceMode": [0, 1], +# "ppsSource": [0, 1], # "function": [integer (meaning is radio-dependent], # "tunerConfiguration": { # 0: { @@ -359,6 +371,8 @@ class ndr562(ndr551): refCmd = ref562 sipCmd = cfge40g562 dipCmd = e40g562 + cntrlCmd = ifout562 + funCmd = None #ppsCmd = pps562 numGigE = 1 numTuner = 2 @@ -370,7 +384,8 @@ class ndr562(ndr551): # object. Override in derived classes as needed. validConfigurationKeywords = [configKeys.REFERENCE_MODE, \ configKeys.TIME_UTC, \ - configKeys.STATUS_PPS_SOURCE + configKeys.STATUS_PPS_SOURCE, \ + configKeys.CNTRL_IF_OUT ] diff --git a/cyberradiodriver/CyberRadioDriver/radios/ndr601.py b/cyberradiodriver/CyberRadioDriver/radios/ndr601.py index 1fbf5c2..e0847cd 100644 --- a/cyberradiodriver/CyberRadioDriver/radios/ndr601.py +++ b/cyberradiodriver/CyberRadioDriver/radios/ndr601.py @@ -5,8 +5,8 @@ # \author NH # \author DA # \author MN -# \copyright Copyright (c) 2017 CyberRadio Solutions, Inc. -# All rights reserved. +# \copyright Copyright (c) 2017-2020 CyberRadio Solutions, Inc. +# All rights reserved. ################################################################## # Imports from other modules in this package diff --git a/cyberradiodriver/CyberRadioDriver/radios/ndr651.py b/cyberradiodriver/CyberRadioDriver/radios/ndr651.py index c50a6e3..eefd687 100644 --- a/cyberradiodriver/CyberRadioDriver/radios/ndr651.py +++ b/cyberradiodriver/CyberRadioDriver/radios/ndr651.py @@ -5,8 +5,8 @@ # \author NH # \author DA # \author MN -# \copyright Copyright (c) 2017 G3 Technologies, Inc. All rights -# reserved. +# \copyright Copyright (c) 2017-2020 CyberRadio Solutions, Inc. +# All rights reserved. ################################################################## # Imports from other modules in this package diff --git a/cyberradiodriver/CyberRadioDriver/transport.py b/cyberradiodriver/CyberRadioDriver/transport.py index 8929af7..de529a8 100755 --- a/cyberradiodriver/CyberRadioDriver/transport.py +++ b/cyberradiodriver/CyberRadioDriver/transport.py @@ -7,28 +7,29 @@ # \author NH # \author DA # \author MN -# \copyright Copyright (c) 2017 CyberRadio Solutions, Inc. -# All rights reserved. +# \copyright Copyright (c) 2017-2020 CyberRadio Solutions, Inc. +# All rights reserved. # ############################################################### # Imports from other modules in this package import command import log +import ndrcert # Imports from external modules +import requests +import requests.packages import serial # Python standard library imports import datetime import errno +import json import select import socket import sys import time import traceback #from time import gmtime, strftime -import requests -import ndrcert -import json ## # Radio transport class. @@ -39,7 +40,7 @@ class radio_transport(log._logger): _name = "transportXXX" ## Default timeout value for transactions managed over this transport. - defaultTimeout = 1.0 + defaultTimeout = 10.0 ## Default port used for TCP and UDP connections defaultPort = 8617 ## Default baud rate used for TTY connections @@ -51,8 +52,9 @@ class radio_transport(log._logger): # \param parent The parent object that manages this transport. # \param verbose Verbose mode (Boolean) # \param logCtrl A GUI control that receives log output (GUI-dependent) - # \param json Whether the transport should expect JSON-formatted commands - # and responses (Boolean). + # \param json Whether or not the transport uses JSON by default. Callers + # can override this setting in sendCommand() as needed (for example, in + # sending commands to crdd). # \param logFile An open file or file-like object to be used for log output. # If not provided, this defaults to standard output. # \param timeout Timeout for the transport (seconds). If this is None, @@ -78,10 +80,6 @@ def __init__(self,parent,verbose=False,logCtrl=None,json=False, self.lastTx = 0 self.lastRx = 0 self.isJson = json - if json: - self.rxFunction = self.receiveJson - else: - self.rxFunction = self.receiveCli self.connectError = "" self.httpStr = "" self.timeout = timeout @@ -100,6 +98,20 @@ def __del__(self,): def __str__(self): return self._name + ## + # \internal + # \brief Gets the appropriate receive function, depending on whether or not + # JSON is in use. + # \param useJson Whether or not to use JSON. If this is None, use the + # transport's default JSON setting. + # \returns A Callable referencing the receive function to use. + def getRxFunction(self, useJson=None): + usingJson = self.isJson if useJson is None else useJson + if usingJson: + return self.receiveJson + else: + return self.receiveCli + ## # Connects the transport and tests the connection. # @@ -322,9 +334,11 @@ def isConnected(self,): # \param clearRx Whether to make sure that the receive buffer is clear before # sending the command. # \param timeout Timeout, in seconds. If this is None, never time out. + # \param useJson Whether or not to use JSON for transport. If this is None, + # use the transport's default setting. # \return Whether the transport is still connected. #def sendCommand(self,cmd,clearRx=True): - def sendCommand(self,cmd,clearRx=False, timeout=None): + def sendCommand(self,cmd,clearRx=False, timeout=None, useJson=None): try: delta = datetime.timedelta(seconds=0,microseconds=0) if self.lastTx == 0: @@ -333,7 +347,7 @@ def sendCommand(self,cmd,clearRx=False, timeout=None): delta = datetime.datetime.now() - self.lastTx self.lastTx = datetime.datetime.now() if clearRx: - rx = self.receive(timeout=0.0) + rx = self.receive(timeout=0.0, useJson=useJson) if len(rx)>0: self.logIfVerbose("** Rx(%s)%s: %s" % ( self.transportIdent(), \ datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f"), \ @@ -542,10 +556,15 @@ def receiveJsonTcp(self,timeout=None): # use the default timeout value for the transport. # \return The list of received data strings. def receiveCli(self,timeout=None): + #self.log("[DBG] receiveCli called") rx = [] inString = "" + myTimeout = float(timeout) if timeout is not None else self.timeout + #self.log("[DBG] receiveCli -- myTimeout:", myTimeout) + #self.log("[DBG] receiveCli -- selectInput:", self.selectInput) try: while True: + #self.log("[DBG] receiveCli -- pass") delta = datetime.timedelta(seconds=0) if self.lastRx == 0: self.lastRx = datetime.datetime.now() @@ -556,13 +575,14 @@ def receiveCli(self,timeout=None): # exception. We need to trap that case and keep selecting if that happens. ins = self.selectInput try: - ins,outs,excepts = self.select(self.selectInput,[],[],float(timeout) if timeout is not None else self.defaultTimeout) + ins,outs,excepts = self.select(self.selectInput,[],[],myTimeout) except select.error as ex: if ex[0] == errno.EINTR: pass else: raise if ins: + #self.log("[DBG] receiveCli -- data found") if self.tcp is not None: inString = self.tcp.recv(8192) elif self.tty is not None: @@ -585,10 +605,11 @@ def receiveCli(self,timeout=None): rx.append( "\nDISCONNECTED\n" ) break else: - if timeout is not None and timeout>0: + #self.log("[DBG] receiveCli -- nothing") + if myTimeout is not None and myTimeout>0: self.logIfVerbose("** Rx(%s)%s: %s" % (self.transportIdent(),datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f"),"!! TIMEOUT !!")) rx.append( "\nTIMEOUT\n" ) - break + break except: self.logIfVerbose(traceback.format_exc()) #traceback.print_exc() @@ -603,34 +624,37 @@ def receiveCli(self,timeout=None): ) return [" ".join(i.strip().split()) for i in "".join(rx).replace(">","").split("\n") if i.strip()] - # Basic function for receiving - requires self.rxFunction to point to the appropriate method for the radio! ## # Receives data over the transport. # - # The format of the received data depends on whether the "json" flag - # was set at construction time. + # The format of the received data depends on whether JSON is in use. # # \param timeout The timeout value to use for receiving data. If None, # use the default timeout value for the transport. - # \return If json=True, a JSON-formatted string; if json=False, a list of + # \param useJson Whether or not to use JSON for transport. If this is + # None, use the transport's default setting (set at construction + # time). + # \return If using JSON, a JSON-formatted string; if not, a list of # received data strings. - def receive(self,timeout=None): - return self.rxFunction(timeout=timeout) + def receive(self, timeout=None, useJson=None): + return self.getRxFunction(useJson)(timeout=timeout) ## # Sends a command and receives the response over the transport. # - # The format of the received data depends on whether the "json" flag - # was set at construction time. + # The format of the received data depends on whether JSON is in use. # # \param cmd The command string to send out over the transport. # \param timeout The timeout value to use for receiving data. If None, # use the default timeout value for the transport. - # \return If json=True, a JSON-formatted string; if json=False, a list of + # \param useJson Whether or not to use JSON for transport. If this is + # None, use the transport's default setting (set at construction + # time). + # \return If using JSON, a JSON-formatted string; if not, a list of # received data strings. - def sendCommandAndReceive(self,cmd,timeout=None): - if self.sendCommand(str(cmd), timeout=timeout): - return self.receive(timeout) + def sendCommandAndReceive(self, cmd, timeout=None, useJson=None): + if self.sendCommand(str(cmd), timeout=timeout, useJson=useJson): + return self.receive(timeout, useJson=useJson) ## # \internal diff --git a/cyberradiodriver/cyberradiodriver.spec b/cyberradiodriver/cyberradiodriver.spec index b5b2071..fbcadf0 100644 --- a/cyberradiodriver/cyberradiodriver.spec +++ b/cyberradiodriver/cyberradiodriver.spec @@ -23,6 +23,9 @@ %define __os_install_post %{python27_os_install_post} %define _datadir /usr/share %endif +%if "RPM_PKG_OSRPM_PKG_OS_VER" == "centos8" +%define __python /usr/bin/python2 +%endif Summary: CyberRadio Solutions, Inc., NDR-series Radio Control Driver Name: RPM_PKG_NAME diff --git a/gr-CyberRadio/debian/postinst b/gr-CyberRadio/debian/postinst index ce686c0..5576115 100644 --- a/gr-CyberRadio/debian/postinst +++ b/gr-CyberRadio/debian/postinst @@ -75,3 +75,10 @@ t.start() echo "SKIPPING $TEMPLATE" fi done + +if [ -f /etc/sysctl.d/uhd-usrp2.conf ] +then + mv -v /etc/sysctl.d/uhd-usrp2.conf /etc/sysctl.d/90-uhd-usrp2.conf +fi +sysctl -p /etc/sysctl.d/98-gr-cyberradio.conf + diff --git a/gr-CyberRadio/gr-cyberradio.spec b/gr-CyberRadio/gr-cyberradio.spec index 0b714f7..30b5e30 100644 --- a/gr-CyberRadio/gr-cyberradio.spec +++ b/gr-CyberRadio/gr-cyberradio.spec @@ -52,7 +52,7 @@ fi # -- CMake project: Both the "%cmake" and "%{__make}" steps # -- Autotools project: TBD # -- Python project: None (the install step takes care of this) -%cmake . -DPACKAGE_VERSION=RPM_PKG_VERSION +cmake . -DPACKAGE_VERSION=RPM_PKG_VERSION -DCMAKE_INSTALL_PREFIX=/usr %{__make} %{?_smp_mflags} %install diff --git a/gr-CyberRadio/grc/CyberRadio_generic_ddc_control_block.xml b/gr-CyberRadio/grc/CyberRadio_generic_ddc_control_block.xml index dac3eec..6a701a6 100644 --- a/gr-CyberRadio/grc/CyberRadio_generic_ddc_control_block.xml +++ b/gr-CyberRadio/grc/CyberRadio_generic_ddc_control_block.xml @@ -34,8 +34,9 @@ if $activeRepeatPackets is not None: set_index($index) set_enable($enable) set_wideband($wideband) - set_rate($rate) - set_mode($mode) + set_rate_and_mode($rate, $mode) + + set_freq($freq) set_rfSource($rfSource) set_rfFreq($rfFreq) diff --git a/gr-CyberRadio/grc/CyberRadio_generic_tuner_control_block.xml b/gr-CyberRadio/grc/CyberRadio_generic_tuner_control_block.xml index 3fb1187..c05d820 100644 --- a/gr-CyberRadio/grc/CyberRadio_generic_tuner_control_block.xml +++ b/gr-CyberRadio/grc/CyberRadio_generic_tuner_control_block.xml @@ -11,6 +11,7 @@ $freq, $attenuation, $filter, + $ifout, $group, $otherArgs, $debug @@ -24,6 +25,7 @@ set_attenuation($attenuation) set_filter($filter) set_otherArgs($otherArgs) + set_ifout($ifout) Radio Object radioObj @@ -63,6 +65,13 @@ 1 int part + + + IF Output + ifout + False + bool + part Tuner Group diff --git a/gr-CyberRadio/lib/snapshot_vector_source_impl.cc b/gr-CyberRadio/lib/snapshot_vector_source_impl.cc index 26902ea..74ea8d0 100644 --- a/gr-CyberRadio/lib/snapshot_vector_source_impl.cc +++ b/gr-CyberRadio/lib/snapshot_vector_source_impl.cc @@ -62,7 +62,13 @@ namespace gr { (d_radio_type.compare("ndr308-ts")==0) || (d_radio_type.compare("ndr318-ts")==0) || (d_radio_type.compare("ndr318")==0) || + (d_radio_type.compare("ndr318a")==0) || (d_radio_type.compare("ndr308a")==0) || + (d_radio_type.compare("ndr308-1")==0) || + (d_radio_type.compare("ndr308-4")==0) || + (d_radio_type.compare("ndr308-6")==0) || + (d_radio_type.compare("ndr814")==0) || + (d_radio_type.compare("ndr818")==0) || (d_radio_type.compare("ndr651")==0) || (d_radio_type.compare("ndr804")==0) || (d_radio_type.compare("ndr804-ptt")==0) || @@ -80,7 +86,7 @@ namespace gr { this->rxVec[2].iov_base = new char[ sizeof(struct Vita49Trailer) ]; this->rxVec[2].iov_len = sizeof(struct Vita49Trailer); } else if ( (d_radio_type.compare("ndr301")==0) || - (d_radio_type.compare("ndr301-ptt")==0) ) { + (d_radio_type.compare("ndr301-ptt")==0) ) { this->set_iqSwap(true); this->set_byteSwap(false); this->d_samples_per_frame = 2048; @@ -105,7 +111,8 @@ namespace gr { this->rxVec[2].iov_base = new char[ sizeof(struct Vita49Trailer) ]; this->rxVec[2].iov_len = sizeof(struct Vita49Trailer); - } else if ((d_radio_type.compare("ndr364")==0)||(d_radio_type.compare("ndr354")==0)) { + } else if ( (d_radio_type.compare("ndr364")==0) || + (d_radio_type.compare("ndr354")==0)) { this->set_iqSwap(false); this->set_byteSwap(true); @@ -116,7 +123,22 @@ namespace gr { this->rxVec[2].iov_base = new char[ 1 ]; this->rxVec[2].iov_len = 1; - } else if ((d_radio_type.compare("ndr551")==0)||(d_radio_type.compare("ndr358")==0)||(d_radio_type.compare("ndr357")==0)) { + } + else if ( d_radio_type.compare("ndr364-ccf")==0 ) { + this->set_iqSwap(false); + this->set_byteSwap(true); + + this->d_samples_per_frame = 2048; + + this->rxVec[0].iov_base = new char[ 20 ]; + this->rxVec[0].iov_len = 20; + + this->rxVec[2].iov_base = new char[ 1 ]; + this->rxVec[2].iov_len = 1; + } else if ( (d_radio_type.compare("ndr551")==0) || + (d_radio_type.compare("ndr358")==0) || + (d_radio_type.compare("ndr357")==0) || + (d_radio_type.compare("ndr378")==0) ) { this->set_iqSwap(false); this->set_byteSwap(true); this->d_samples_per_frame = 1024; @@ -144,6 +166,30 @@ namespace gr { this->set_iqSwap(false); this->set_byteSwap(true); this->d_samples_per_frame = 1280; + + //~ this->_parseHeader = this->_parseHeaderNdr551; + + this->rxVec[0].iov_base = new char[ 48 ]; + this->rxVec[0].iov_len = 48; + + this->rxVec[2].iov_base = new char[ sizeof(struct Vita49Trailer) ]; + this->rxVec[2].iov_len = sizeof(struct Vita49Trailer); + } else if ( d_radio_type.compare("ndr358-recorder-wb") == 0 ) { + this->set_iqSwap(false); + this->set_byteSwap(true); + this->d_samples_per_frame = 1024; + + //~ this->_parseHeader = this->_parseHeaderNdr551; + + this->rxVec[0].iov_base = new char[ 48 ]; + this->rxVec[0].iov_len = 48; + + this->rxVec[2].iov_base = new char[ sizeof(struct Vita49Trailer) ]; + this->rxVec[2].iov_len = sizeof(struct Vita49Trailer); + } else if ( d_radio_type.compare("ndr358-recorder-nb") == 0 ) { + this->set_iqSwap(false); + this->set_byteSwap(true); + this->d_samples_per_frame = 1280; //~ this->_parseHeader = this->_parseHeaderNdr551; @@ -279,7 +325,7 @@ namespace gr { //~ perror("couldn't set recv buf size."); //~ return -1; //~ } - + while (setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, &recv_buffer_size, sizeof(unsigned long long)) == -1) { std::cerr << "Couldn't set recv buf size = " << recv_buffer_size << "." << std::endl; recv_buffer_size <<= 1; @@ -349,12 +395,12 @@ namespace gr { data_pointer_print += 3; data_to_print = *data_pointer_print; // check if the Over-Range Indicator is set - if (data_to_print == 0x2000){ - //printf ("%2x\n", data_to_print); + if (data_to_print == 0x2000){ + //printf ("%2x\n", data_to_print); // if status message was already sent, do not send it again if (this->program_starting == true) { this->program_starting = false; - printf ("%2x\n", data_to_print); + printf ("%2x\n", data_to_print); txStatusMsg(); } } @@ -362,7 +408,7 @@ namespace gr { // if Over-Range Condition does not exist anymore, setup flags appropriately this->program_starting = true; } - + // Copy IQ data to output if (this->d_bswap32) { volk_32u_byteswap((uint32_t*)(this->rxVec[1].iov_base), this->d_samples_per_frame); diff --git a/gr-CyberRadio/python/generic_ddc_control_block.py b/gr-CyberRadio/python/generic_ddc_control_block.py index c0c6a18..23dbc02 100644 --- a/gr-CyberRadio/python/generic_ddc_control_block.py +++ b/gr-CyberRadio/python/generic_ddc_control_block.py @@ -74,6 +74,7 @@ def __init__(self, generic_radio_control_block.__init__(self, radioObj=radioObj, debug=debug) self.log.debug("hello") self.freqUnits = 1 + self.arp = False self.log.debug("%s.__init__(radioObj=%r, index=%r, rate=%s)"%(self._name,radioObj,index,rate)) @@ -122,14 +123,17 @@ def getDipConf(self,dipIndex): crd.configKeys.GIGE_SOURCE_PORT:self.index+(10000 if self.wideband else 20000), crd.configKeys.GIGE_DEST_PORT:self.udpPort, }, - }, + }, + crd.configKeys.IP_SOURCE : { + crd.configKeys.GIGE_SOURCE_PORT : self.udpPort, + } } if self.localInterface is not None and len(self.localInterface)>0: dmac, dip = crd.getInterfaceAddresses(self.localInterface) self.log.debug( "interface = {0}, dmac = {1}, dip = {2}".format(self.localInterface, dmac, dip,) ) temp = [int(i) for i in dip.split(".")] temp[-1] = (~temp[-1])&0xff - #~ sip = ".".join(str(i) for i in temp) + sip = ".".join(str(i) for i in temp) for radioInterface in interfaceList: #~ dipConfDict = { #~ radioInterface: { @@ -146,6 +150,14 @@ def getDipConf(self,dipIndex): #~ } dipConfDict[radioInterface][crd.configKeys.IP_DEST][dipIndex][crd.configKeys.GIGE_MAC_ADDR] = dmac dipConfDict[radioInterface][crd.configKeys.IP_DEST][dipIndex][crd.configKeys.GIGE_IP_ADDR] = dip + dipConfDict[radioInterface][crd.configKeys.IP_SOURCE][crd.configKeys.GIGE_IP_ADDR] = sip + dipConfDict[radioInterface][crd.configKeys.IP_SOURCE][crd.configKeys.GIGE_SOURCE_PORT] = self.udpPort + else: + if any(i in self.radioObj.name.lower() for i in ("562","358","551","357")): + self.log.debug("self.arp: {0}".format(self.arp)) + if self.arp == True: + # since an interface was not provided, try to ARP it for the destination. + dipConfDict[radioInterface][crd.configKeys.IP_DEST][dipIndex][crd.configKeys.GIGE_ARP] = True return dipConfDict @@ -223,14 +235,17 @@ def updateConfig(self,param=None): ddcConfDict[ crd.configKeys.DDC_VITA_ENABLE ] = vitaVal elif param=="rate": ddcConfDict[ rateKey ] = self.rate + elif param=="mode": + ddcConfDict[ crd.configKeys.DDC_OUTPUT_FORMAT ] = self.mode + elif param=="rate&mode": + ddcConfDict[ rateKey ] = self.rate + ddcConfDict[ crd.configKeys.DDC_OUTPUT_FORMAT ] = self.mode elif param=="freq": ddcConfDict[ crd.configKeys.DDC_FREQUENCY_OFFSET ] = self.ddcFreq sendFreqMsgFlag = True elif param=="rfSource": if self.radioObj.isDdcSelectableSource(self.wideband): ddcConfDict[ crd.configKeys.DDC_RF_INDEX ] = self.rfSource - elif param=="mode": - ddcConfDict[ crd.configKeys.DDC_OUTPUT_FORMAT ] = self.mode elif param=="phaseOffset" and ("364" in self.radioObj.name.lower()) and (self.phaseOffset is not None): ddcConfDict[ crd.configKeys.DDC_PHASE_OFFSET ] = self.phaseOffset elif param=="totalRepeatPackets" and ("364" in self.radioObj.name.lower()) and (self.totalRepeatPackets is not None): @@ -245,10 +260,7 @@ def updateConfig(self,param=None): if ddcConfDict is not None: confDict[crd.configKeys.CONFIG_DDC] = { ddcType: { self.index: ddcConfDict } } if dipConfDict is not None: - if "562" in self.radioObj.name.lower(): - pass - else: - confDict[crd.configKeys.CONFIG_IP] = dipConfDict + confDict[crd.configKeys.CONFIG_IP] = dipConfDict self.log.debug( json.dumps(confDict, sort_keys=True) ) if self.radioObj.isConnected(): self.radioObj.setConfiguration(confDict) @@ -349,6 +361,33 @@ def set_mode(self, mode=0): def get_mode(self,): return self.mode + + def set_rate_and_mode(self, rate=0, mode=None): + update = False + + if self._init or not hasattr(self, "mode"): + self.mode = mode + self.log.debug("%s.set_rate_and_mode: %s -> %s"%(self._name, repr(self.mode), repr(mode),)) + elif mode!=self.mode: + self.log.debug("%s.set_rate_and_mode: %s -> %s"%(self._name, repr(self.mode), repr(mode),)) + self.mode = mode + update = True + else: + self.log.debug("%s.set_rate_and_mode: %s == %s"%(self._name, repr(self.mode), repr(mode),)) + + if self._init or not hasattr(self, "rate"): + self.rate = rate + self.log.debug("%s.set_rate_and_mode: %s -> %s"%(self._name, "n/a", repr(rate),)) + elif rate!=self.rate: + self.log.debug("%s.set_rate_and_mode: %s -> %s"%(self._name, repr(self.rate), repr(rate),)) + self.rate = rate + update = True + else: + self.log.debug("%s.set_rate_and_mode: %s == %s"%(self._name, repr(self.rate), repr(rate),)) + + if update: + self.updateConfig("rate&mode") + ## Setter & getter for mode def set_phaseOffset(self, phaseOffset=None): @@ -502,6 +541,7 @@ def get_udpPort(self,): ## Setter & getter for otherArgs def set_otherArgs(self, otherArgs={}): self.freqUnits = otherArgs.get("freqUnits", self.freqUnits) + self.arp = otherArgs.get("arp", self.arp) def get_otherArgs(self,): return self.otherArgs diff --git a/gr-CyberRadio/python/generic_radio_control_block.py b/gr-CyberRadio/python/generic_radio_control_block.py index ac6b749..3ee6df5 100644 --- a/gr-CyberRadio/python/generic_radio_control_block.py +++ b/gr-CyberRadio/python/generic_radio_control_block.py @@ -101,7 +101,7 @@ def __init__(self, radioObj, debug=False, **kwargs): self.message_port_register_in(self.msgPort_enable) self.set_msg_handler(self.msgPort_enable, self.rxEnableMsg) if self._portEnable_enableTx: - self.log.debug("Enabling enable message reception") + self.log.debug("Enabling enable message transmission") self.message_port_register_out(self.msgPort_enable) ## Setup ports for frequency messaging @@ -111,7 +111,7 @@ def __init__(self, radioObj, debug=False, **kwargs): self.message_port_register_in(self.msgPort_freq) self.set_msg_handler(self.msgPort_freq, self.rxFreqMsg) if self._portEnable_freqTx: - self.log.debug("Enabling freq message reception") + self.log.debug("Enabling freq message transmission") self.message_port_register_out(self.msgPort_freq) ## Setup ports for UDP block messaging @@ -121,7 +121,7 @@ def __init__(self, radioObj, debug=False, **kwargs): self.message_port_register_in(self.msgPort_udp) self.set_msg_handler(self.msgPort_udp, self.rxUdpMsg) if self._portEnable_udpTx: - self.log.debug("Enabling UDP message reception") + self.log.debug("Enabling UDP message transmission") self.message_port_register_out(self.msgPort_udp) def __del__(self,): diff --git a/gr-CyberRadio/python/generic_tuner_control_block.py b/gr-CyberRadio/python/generic_tuner_control_block.py index 93800e6..158a606 100644 --- a/gr-CyberRadio/python/generic_tuner_control_block.py +++ b/gr-CyberRadio/python/generic_tuner_control_block.py @@ -43,6 +43,7 @@ def __init__(self, freq=0, attenuation=0, filter=1, + ifout=False, group=None, otherArgs={}, debug=False, @@ -67,6 +68,7 @@ def __init__(self, self.set_filter(filter) self.set_group(group) self.set_otherArgs(otherArgs) + self.set_ifout(ifout) self.updateConfig() self._init = False @@ -78,7 +80,7 @@ def updateConfig(self,param=None): if (self._init and param is None) or ((not self._init) and (param=="index")): confDict = { crd.configKeys.CONFIG_TUNER: { self.index: {crd.configKeys.TUNER_FREQUENCY:int(self.rfFreq*1e6), crd.configKeys.TUNER_ATTENUATION:self.attenuation, - crd.configKeys.TUNER_IF_FILTER: self.filter, + crd.configKeys.TUNER_IF_FILTER: self.filter, # crd.configKeys.ENABLE: self.enable, } } } if ( isinstance(self.group,int) and (self.group>=0) ): @@ -96,6 +98,8 @@ def updateConfig(self,param=None): confDict = { crd.configKeys.CONFIG_TUNER: { self.index: { crd.configKeys.TUNER_COHERENT_GROUP: self.group, } } } elif param=="enable": confDict = { crd.configKeys.CONFIG_TUNER: { self.index: { crd.configKeys.ENABLE: self.enable, } } } + elif param=="ifout": + confDict = { crd.configKeys.CNTRL_IF_OUT: self.ifOut } if confDict is not None: self.log.debug( json.dumps(confDict, sort_keys=True) ) if self.radioObj.isConnected(): @@ -193,6 +197,15 @@ def set_otherArgs(self, otherArgs={}): self.freqUnits = otherArgs.get("freqUnits", self.freqUnits) self.tunerGroup = otherArgs.get("group", None) + def set_ifout(self, ifout): + if self._init or not hasattr(self, "ifOut"): + self.ifOut = ifout + self.log.debug("%s.set_ifout: %s -> %s at init"%(self._name, repr(self.ifOut), repr(ifout),)) + elif ifout != self.ifOut: + self.log.debug("%s.set_ifout: %s -> %s"%(self._name, repr(self.ifOut), repr(ifout),)) + self.ifOut = ifout + self.updateConfig("ifout") + def get_otherArgs(self,): return self.otherArgs diff --git a/gr-CyberRadio/swig/CyberRadio_swig.i b/gr-CyberRadio/swig/CyberRadio_swig.i index 67b1e2b..ec2eafe 100644 --- a/gr-CyberRadio/swig/CyberRadio_swig.i +++ b/gr-CyberRadio/swig/CyberRadio_swig.i @@ -17,7 +17,6 @@ #include "CyberRadio/vector_keep_m_in_n.h" #include "CyberRadio/vector_nlog10_ff.h" #include "CyberRadio/vita_udp_rx.h" -#include "CyberRadio/zero_copy_source.h" #include "CyberRadio/ndr651_sink.h" #include "CyberRadio/snapshot_vector_source.h" #include "CyberRadio/NDR651_sync_sink.h" @@ -46,8 +45,6 @@ GR_SWIG_BLOCK_MAGIC2(CyberRadio, vector_nlog10_ff); %include "CyberRadio/vita_udp_rx.h" GR_SWIG_BLOCK_MAGIC2(CyberRadio, vita_udp_rx); -%include "CyberRadio/zero_copy_source.h" -GR_SWIG_BLOCK_MAGIC2(CyberRadio, zero_copy_source); %include "CyberRadio/ndr651_sink.h" GR_SWIG_BLOCK_MAGIC2(CyberRadio, ndr651_sink); diff --git a/gr-CyberRadio/version.txt b/gr-CyberRadio/version.txt index 78a3290..9f33a0d 100644 --- a/gr-CyberRadio/version.txt +++ b/gr-CyberRadio/version.txt @@ -1,2 +1,2 @@ gr-cyberradio -20.02.18e +20.09.02 diff --git a/libcyberradio/.autotools b/libcyberradio/.autotools index 3246891..0c44299 100644 --- a/libcyberradio/.autotools +++ b/libcyberradio/.autotools @@ -29,6 +29,7 @@