diff --git a/Makefile b/Makefile
index fe9d66e..9069a50 100644
--- a/Makefile
+++ b/Makefile
@@ -1,19 +1,19 @@
# Copyright (C) 2011 Associated Universities, Inc. Washington DC, USA.
-#
+#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
-#
+#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
-#
+#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-#
+#
# Correspondence concerning GBT software should be addressed as follows:
# GBT Operations
# National Radio Astronomy Observatory
@@ -24,7 +24,7 @@ CC = g++
AR = ar
DOXY = doxygen
CFLAGS = -c -Wall -fPIC -DLINUX
-LDFLAGS =
+LDFLAGS =
SOURCES = ValonSynth.cc Serial.cc
OBJECTS = $(SOURCES:.cc=.o)
PLATFORM = LINUX
@@ -52,4 +52,4 @@ clean:
.PHONY: clobber
clobber: clean
- rm -rf $(STARGET) $(DTARGET)
\ No newline at end of file
+ rm -rf $(STARGET) $(DTARGET)
diff --git a/README-Python.md b/README-Python.md
new file mode 100644
index 0000000..0216de1
--- /dev/null
+++ b/README-Python.md
@@ -0,0 +1,52 @@
+# Valon Synth
+
+## Installation
+
+In order to use the Python code, it is necessary to build the C++
+library first:
+
+ $ make
+
+This should create a `libValonSynth.so` shared object.
+
+The Python software can now be installed for development use. As a
+first step, create a Python virtual environment.
+
+ $ virtualenv venv
+
+Optionally, activate it; the steps below assumes that the virtual
+environment has not been activated.
+
+Use the virtual environment to setup the package:
+
+ $ ./venv/bin/pip install -r requirements.txt
+
+To be able to use the package, we also need to be able to import it.
+Normally the source directory name matches the package name, but
+unfortunately in this instance it doesn't. We create a symbolic link to
+fudge it.
+
+ $ ln -s src valon_synth
+
+## Communication checks
+
+We provide a example script that tests basic communications. It
+requires knowledge of the (USB-connected) serial port the Valon is
+connected to. In Linux, plug in both USB plugs on the Valon, and do
+
+ $ dmesg
+
+The last lines in the log should be similar to the following:
+
+ usb 5-1: FTDI USB Serial Device converter now attached to ttyUSB0
+
+This indicates the port we are interested in is `/dev/ttyUSB0`, which
+coincidentally is the default port in the communications test example
+script.
+
+To run the communications check, simply do:
+
+ $ ./venv/bin/python example/commtest.py --port /dev/ttyUSB0
+
+Feel free to replace `/dev/ttyUSB0` in the command shown above with your
+locally identified port.
diff --git a/Serial.cc b/Serial.cc
index cf2674f..56a62d6 100644
--- a/Serial.cc
+++ b/Serial.cc
@@ -1,19 +1,19 @@
//# Copyright (C) 2011 Associated Universities, Inc. Washington DC, USA.
-//#
+//#
//# This program is free software; you can redistribute it and/or modify
//# it under the terms of the GNU General Public License as published by
//# the Free Software Foundation; either version 2 of the License, or
//# (at your option) any later version.
-//#
+//#
//# This program is distributed in the hope that it will be useful, but
//# WITHOUT ANY WARRANTY; without even the implied warranty of
//# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
//# General Public License for more details.
-//#
+//#
//# You should have received a copy of the GNU General Public License
//# along with this program; if not, write to the Free Software
//# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-//#
+//#
//# Correspondence concerning GBT software should be addressed as follows:
//# GBT Operations
//# National Radio Astronomy Observatory
@@ -121,7 +121,7 @@ int Serial::serial_write(const unsigned char *output_buffer,
}
-int Serial::serial_read(unsigned char *input_buffer, const int &number_of_bytes,
+int Serial::serial_read(unsigned char *input_buffer, const int &number_of_bytes,
const int timeo_us)
{
int bytes_received = 0;
@@ -156,19 +156,19 @@ int Serial::serial_read(unsigned char *input_buffer, const int &number_of_bytes,
&input_buffer[bytes_received],
#endif
(number_of_bytes - bytes_received));
-
- // was an error condition present?
+
+ // was an error condition present?
if (read_bytes < 0)
{
// Flush input buffer.
#if defined (SOLARIS) || defined (LINUX)
- ioctl(the_serial_port, TCFLSH, 0);
+ ioctl(the_serial_port, TCIFLUSH, 0);
#else
ioctl(the_serial_port, FIORFLUSH, 0);
#endif
return(read_bytes);
}
-
+
bytes_received += read_bytes;
if (the_input_mode == Serial::canonical && bytes_received > 0)
@@ -207,7 +207,7 @@ int Serial::open_serial_port(const char *port_name)
{
// Flush serial port.
#if defined (SOLARIS) || defined (LINUX)
- ioctl(the_serial_port, TCFLSH, 0);
+ ioctl(the_serial_port, TCIOFLUSH, 0);
#endif
#if defined(VXWORKS)
ioctl(the_serial_port, FIOFLUSH, 0);
@@ -234,11 +234,11 @@ int Serial::update_parity(const Serial::parity_choices &parity)
switch (parity)
{
case Serial::odd:
- the_termios.c_cflag |= (PARODD | PARENB);
+ the_termios.c_cflag |= (PARODD | PARENB);
break;
case Serial::even:
- the_termios.c_cflag |= PARENB;
- the_termios.c_cflag &= ~(PARODD);
+ the_termios.c_cflag |= PARENB;
+ the_termios.c_cflag &= ~(PARODD);
break;
case Serial::none:
the_termios.c_cflag &= ~PARENB;
@@ -288,7 +288,7 @@ int Serial::update_baud_rate(const int &baud_rate)
cerr << "Cannot set baud rate" << endl;
return (-1);
}
-
+
speed_t speed;
switch (baud_rate)
@@ -602,7 +602,7 @@ int Serial::set_raw_input_mode()
// as BS-SP-BS.
the_termios.c_lflag &= ~(ICANON | ISIG | ECHO | ECHOE);
the_termios.c_iflag &= ~(INPCK | ISTRIP);
-
+
if (tcsetattr(the_serial_port, TCSAFLUSH, &the_termios) != 0)
{
// TBF: Error message
@@ -646,7 +646,7 @@ int Serial::set_canonical_input_mode()
// Enable canonical mode, enable echoing of input characters, enable
// echoing of erase character as BS-SP-BS.
the_termios.c_lflag |= (ICANON | ECHO | ECHOE);
-
+
if (tcsetattr(the_serial_port, TCSAFLUSH, &the_termios) != 0)
{
// TBF: Error message
@@ -691,19 +691,19 @@ int Serial::set_other_flags()
the_termios.c_lflag &= ~IEXTEN;
// input flags:-
- // Send a SIGINT when a break condition is detected, map CR to NL,
+ // Send a SIGINT when a break condition is detected, map CR to NL,
the_termios.c_iflag &= ~(BRKINT | ICRNL);
-
+
// control flags:-
// Setting CLOCAL and CREAD ensures that the program will not become
// the owner of the port and the serial interface driver will read
// incoming data bytes.
the_termios.c_cflag |= (CLOCAL | CREAD);
-
+
// output flags:-
// Turn off the output processing
the_termios.c_oflag &= ~(OPOST);
-
+
// Set up 0 character minimum with no timeout.
the_termios.c_cc[VMIN] = 0;
the_termios.c_cc[VTIME] = 0;
diff --git a/Serial.h b/Serial.h
index af360ea..aff619f 100644
--- a/Serial.h
+++ b/Serial.h
@@ -1,19 +1,19 @@
//# Copyright (C) 2011 Associated Universities, Inc. Washington DC, USA.
-//#
+//#
//# This program is free software; you can redistribute it and/or modify
//# it under the terms of the GNU General Public License as published by
//# the Free Software Foundation; either version 2 of the License, or
//# (at your option) any later version.
-//#
+//#
//# This program is distributed in the hope that it will be useful, but
//# WITHOUT ANY WARRANTY; without even the implied warranty of
//# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
//# General Public License for more details.
-//#
+//#
//# You should have received a copy of the GNU General Public License
//# along with this program; if not, write to the Free Software
//# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-//#
+//#
//# Correspondence concerning GBT software should be addressed as follows:
//# GBT Operations
//# National Radio Astronomy Observatory
@@ -26,13 +26,13 @@
//
-// This class provides a vehicle for serial communication on the vxWorks,
+// This class provides a vehicle for serial communication on the vxWorks,
// Linux, and Solaris platforms.
//
//
-// The configuration of the serial port that you wish to use (i.e.
-// baud rate, parity, port name, etc).
+// The configuration of the serial port that you wish to use (i.e.
+// baud rate, parity, port name, etc).
//
//
@@ -41,7 +41,7 @@
//
//
-// This class provides a portable way to use the serial port for
+// This class provides a portable way to use the serial port for
// program communication. The two main member functions that enable this
// communication are read and write. Other member functions are provided
// to configure the serial port as needed. The default serial port
@@ -69,13 +69,13 @@
//
// The valid choices for input mode are raw and canonical. These are
// defined via the enumeration input_choices below. Raw mode processes
-// the characters as they are typed. Canonical mode handles the
+// the characters as they are typed. Canonical mode handles the
// characters on a line by line basis - i.e. it waits for the '/n'
// character before reading/writing.
//
//
-// To contain all serial communication needs across multiple platforms
+// To contain all serial communication needs across multiple platforms
// within a single class.
//
@@ -134,7 +134,7 @@ class Serial
// -1 on failure.
int set_stop_bits(const int &stop_bits);
- // set_hardware_flow_control accepts either 0 = No hardware flow
+ // set_hardware_flow_control accepts either 0 = No hardware flow
// control or 1 = Hardware flow control. If the input parameter is
// neither 0 nor 1, hardware flow control is disabled. Returns 0 on
// success, -1 on failure.
@@ -177,7 +177,7 @@ class Serial
input_choices the_input_mode;
//
- // These member functions set up parameters for the serial port over
+ // These member functions set up parameters for the serial port over
// which the user of this class has no control.
//
int open_serial_port(const char *port_name);
@@ -193,7 +193,7 @@ class Serial
virtual int serial_write(const unsigned char *output_buffer,
const int &number_of_bytes);
virtual int serial_read(unsigned char *input_buffer,
- const int &number_of_bytes,
+ const int &number_of_bytes,
const int timeout_usec = 200000);
virtual int update_parity(const parity_choices &parity);
virtual int update_baud_rate(const int &baud_rate);
@@ -215,7 +215,7 @@ inline int Serial::write(const unsigned char *output_buffer,
}
-inline int Serial::read(unsigned char *input_buffer, const int &number_of_bytes,
+inline int Serial::read(unsigned char *input_buffer, const int &number_of_bytes,
const int tmo_usec)
{
return (serial_read(input_buffer, number_of_bytes, tmo_usec));
diff --git a/ValonSynth.cc b/ValonSynth.cc
index d1ca213..495503b 100644
--- a/ValonSynth.cc
+++ b/ValonSynth.cc
@@ -1,19 +1,19 @@
//# Copyright (C) 2011 Associated Universities, Inc. Washington DC, USA.
-//#
+//#
//# This program is free software; you can redistribute it and/or modify
//# it under the terms of the GNU General Public License as published by
//# the Free Software Foundation; either version 2 of the License, or
//# (at your option) any later version.
-//#
+//#
//# This program is distributed in the hope that it will be useful, but
//# WITHOUT ANY WARRANTY; without even the implied warranty of
//# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
//# General Public License for more details.
-//#
+//#
//# You should have received a copy of the GNU General Public License
//# along with this program; if not, write to the Free Software
//# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-//#
+//#
//# Correspondence concerning GBT software should be addressed as follows:
//# GBT Operations
//# National Radio Astronomy Observatory
diff --git a/ValonSynth.h b/ValonSynth.h
index 2b917ee..4afe50c 100644
--- a/ValonSynth.h
+++ b/ValonSynth.h
@@ -1,19 +1,19 @@
//# Copyright (C) 2011 Associated Universities, Inc. Washington DC, USA.
-//#
+//#
//# This program is free software; you can redistribute it and/or modify
//# it under the terms of the GNU General Public License as published by
//# the Free Software Foundation; either version 2 of the License, or
//# (at your option) any later version.
-//#
+//#
//# This program is distributed in the hope that it will be useful, but
//# WITHOUT ANY WARRANTY; without even the implied warranty of
//# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
//# General Public License for more details.
-//#
+//#
//# You should have received a copy of the GNU General Public License
//# along with this program; if not, write to the Free Software
//# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-//#
+//#
//# Correspondence concerning GBT software should be addressed as follows:
//# GBT Operations
//# National Radio Astronomy Observatory
@@ -33,20 +33,20 @@
/**
* Interface to a Valon 5007 dual synthesizer.
- *
+ *
* The reference signal, reference select, and flash commands are shared between
* synthesizers. All other settings are independent, so a synthesizer must be
* specified when getting and setting values. Frequency values are specified in
* MegaHertz (MHz) unless otherwise noted.
- *
+ *
* \section calculations Calculations
- *
+ *
* The output frequency of the synthesizer is controlled by a number of
* parameters. The relationship between these parameters may be expressed by the
* following equations. \f$EPDF\f$ is the Effective Phase Detector Frequency and is
* the reference frequency(?) after applying the relevant options. (doubler,
* halver and divider)
- *
+ *
* \f[
* 1 \le dbf=2^n \le 16
* \f]
@@ -62,11 +62,11 @@
* \f[
* mod = \lfloor\frac{EPDF}{channel\_spacing}+0.5\rfloor
* \f]
- *
+ *
* \f$frac\f$ and \f$mod\f$ are a ratio, and can be reduced to the simplest
* fraction after the calculations above. To compute the output frequency, use
* the following equation.
- *
+ *
* \f[
* frequency = (ncount+\frac{frac}{mod})\times\frac{EPDF}{dbf}
* \f]
@@ -79,7 +79,7 @@ class ValonSynth
* referenced.
**/
enum Synthesizer { A = 0x00, B = 0x08 };
-
+
/**
* Holds various options used to control the operation of a synthesizer.
**/
@@ -90,17 +90,17 @@ class ValonSynth
* this mode it is in "low noise" mode.
**/
bool low_spur;
-
+
/**
* The reference frequency doubler is active.
**/
bool double_ref;
-
+
/**
* The reference frequency halver is active.
**/
bool half_ref;
-
+
/**
* The reference frequency divider value;
**/
@@ -116,7 +116,7 @@ class ValonSynth
* Minimum frequency the VCO is capable of producing.
**/
uint16_t min;
-
+
/**
* Maximum frequency the VCO is capable of producing.
**/
@@ -133,14 +133,14 @@ class ValonSynth
* \name Methods relating to output frequency
* \{
**/
-
+
/**
* Read the current settings from the synthesizer.
* @param[in] synth The synthesizer to be read.
* @return Frequency in MHz.
**/
float get_frequency(enum Synthesizer synth);
-
+
/**
* Read the current settings from the synthesizer.
* @param[in] synth The synthesizer to be read.
@@ -148,7 +148,7 @@ class ValonSynth
* @return True on succesful completion.
**/
bool get_frequency(enum Synthesizer synth, float &frequency);
-
+
/**
* Set the synthesizer to the desired frequency, or best approximation based
* on channel spacing. See the section on \ref calculations.
@@ -165,14 +165,14 @@ class ValonSynth
* \name Methods relating to the reference frequency
* \{
**/
-
+
/**
* Read the current reference frequency. This is shared between the two
* channels.
* @return The reference frequency in Hz.
**/
uint32_t get_reference();
-
+
/**
* Read the current reference frequency. This is shared between the two
* channels.
@@ -180,7 +180,7 @@ class ValonSynth
* @return True on successful completion.
**/
bool get_reference(uint32_t &reference);
-
+
/**
* Set the synthesizer reference frequency. This does not change the actual
* reference frequency of the synthesizer for either internal or external
@@ -225,12 +225,12 @@ class ValonSynth
/**
* \}
* \name Members relating to the synthesizer options
- *
+ *
* Note that although the reference frequency is shared these options are
* specific to a particular synthesizer.
* \{
**/
-
+
/**
* Read the current options for a synthesizer.
* @param[in] synth The synthesizer to be read.
@@ -238,7 +238,7 @@ class ValonSynth
* @return True on successful completion.
**/
bool get_options(enum Synthesizer synth, struct options &opts);
-
+
/**
* Set the options for a synthesizer.
* @param[in] synth The synthesizer to be set.
@@ -252,13 +252,13 @@ class ValonSynth
* \name Methods relating to the reference source
* \{
**/
-
+
/**
* Read the current reference source.
* @return True if external, false if internal.
**/
bool get_ref_select();
-
+
/**
* Read the current reference source.
* @param[out] e_not_i Receives the refernce source. True if external,
@@ -266,7 +266,7 @@ class ValonSynth
* @return True on successful completion.
**/
bool get_ref_select(bool &e_not_i);
-
+
/**
* Set the reference source.
* @param[in] e_not_i True for external, false for internal.
@@ -279,7 +279,7 @@ class ValonSynth
* \name Methods relating to the voltage controlled oscillator
* \{
**/
-
+
/**
* Read the current range of the VCO.
* @param[in] synth The synthesizer to be read.
@@ -287,7 +287,7 @@ class ValonSynth
* @return True on successful completion.
**/
bool get_vco_range(enum Synthesizer synth, vco_range &vcor);
-
+
/**
* Set the range of the VCO. This affects the allowable frequency range of
* the output. See \ref calculations for details.
@@ -302,7 +302,7 @@ class ValonSynth
* \name Methods relating to phase lock.
* \{
**/
-
+
/**
* Read the current state of phase lock.
* @param[in] synth The synthesizer to be read.
@@ -323,7 +323,7 @@ class ValonSynth
* \name Methods relating to synthesizer labels.
* \{
**/
-
+
/**
* Read the current label of the specified synthesizer.
* @param[in] synth The synthesizer to be read.
@@ -332,7 +332,7 @@ class ValonSynth
* @return True on successful completion.
**/
bool get_label(enum Synthesizer synth, char *label);
-
+
/**
* Set the label of the specified synthesizer.
* @param[in] synth The synthesizer to be read.
@@ -344,7 +344,7 @@ class ValonSynth
/**
* \}
**/
-
+
/**
* Copies all current settings for both synthesizers to non-volatile flash
* memory.
@@ -379,7 +379,7 @@ class ValonSynth
void pack_short(uint16_t num, uint8_t *bytes);
void unpack_int(const uint8_t *bytes, uint32_t &num);
void unpack_short(const uint8_t *bytes, uint16_t &num);
-
+
Serial s;
};
diff --git a/example/commtest.py b/example/commtest.py
new file mode 100755
index 0000000..2d43317
--- /dev/null
+++ b/example/commtest.py
@@ -0,0 +1,61 @@
+#! /usr/bin/env python
+
+from optparse import OptionParser
+import time
+
+import valon_synth
+from valon_synth import SYNTH_B
+
+
+# Simple example of using the Valon Synth directly
+def main(port):
+ print """
+Connect a Valon 5007 to a spectrum analyser -- a 20dB attenuator is used.
+The Valon 5007 is specified to have a range of 137 MHz to 4400MHz.
+"""
+ raw_input('Enter to connect to Valon')
+
+ # MTS uses only one of the available synthesizers (currently SYNTH 2)
+ synth = valon_synth.Synthesizer(port, timeout=None, checksum=True)
+
+ if synth.get_rf_level(SYNTH_B) != -4:
+ synth.set_rf_level(SYNTH_B, -4)
+
+ # Set CW signal frequency
+ synth.set_frequency(SYNTH_B, freq=137, chan_spacing=1.)
+ print 'CW frequency set to %s MHz' % synth.get_frequency(SYNTH_B)
+ raw_input('Enter to continue')
+
+ print 'Setting Valon to Low Spur Mode'
+ synth.set_options(SYNTH_B, low_spur=1)
+ raw_input('Enter to continue')
+
+ print 'Settings Valon to Low Noise Mode'
+ synth.set_options(SYNTH_B, low_spur=0)
+ raw_input('Enter to continue')
+
+ print 'Sweep over frequencies 137MHz to 1500MHz'
+ for freq_mhz in range(137, 1500, 20):
+ synth.set_frequency(SYNTH_B, freq=freq_mhz, chan_spacing=1.)
+ print 'CW frequency set to %s MHz' % synth.get_frequency(SYNTH_B)
+ raw_input('Enter to continue')
+
+ print 'Sweep over frequencies 137MHz to 4400MHz'
+ raw_input('Enter to continue')
+ for freq_mhz in range(137, 4400, 100):
+ synth.set_frequency(SYNTH_B, freq=freq_mhz, chan_spacing=1.)
+ print 'CW frequency set to %s MHz' % synth.get_frequency(SYNTH_B)
+ time.sleep(1)
+
+
+if __name__ == '__main__':
+ parser = OptionParser(version="%prog 0.1")
+ parser.add_option('-p', '--port',
+ action='store',
+ dest='tty',
+ default='/dev/ttyUSB0',
+ help="Set Serial Port, default is '%default'.")
+ (opts, _) = parser.parse_args()
+ main(opts.tty)
+
+# -fin-
diff --git a/requirements.txt b/requirements.txt
new file mode 100644
index 0000000..de620ec
--- /dev/null
+++ b/requirements.txt
@@ -0,0 +1,2 @@
+# development requirements
+--editable .
diff --git a/setup.py b/setup.py
index dc4ec10..e80f2c5 100644
--- a/setup.py
+++ b/setup.py
@@ -7,5 +7,5 @@
maintainer = 'NRAO',
packages = ['valon_synth'],
package_dir = {'valon_synth': 'src'},
- requires = ['pyserial'],
+ install_requires = ['pyserial'],
)
diff --git a/src/__init__.py b/src/__init__.py
index ebcfb4c..a497480 100644
--- a/src/__init__.py
+++ b/src/__init__.py
@@ -1,23 +1,23 @@
# Copyright (C) 2011 Associated Universities, Inc. Washington DC, USA.
-#
+#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
-#
+#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
-#
+#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-#
+#
# Correspondence concerning GBT software should be addressed as follows:
-# GBT Operations
-# National Radio Astronomy Observatory
-# P. O. Box 2
-# Green Bank, WV 24944-0002 USA
+# GBT Operations
+# National Radio Astronomy Observatory
+# P. O. Box 2
+# Green Bank, WV 24944-0002 USA
-from valon_synth import Synthesizer, SYNTH_A, SYNTH_B, INT_REF, EXT_REF
+from valon_synth import Synthesizer, SYNTH_A, SYNTH_B, INT_REF, EXT_REF # noqa
diff --git a/src/valon_synth.py b/src/valon_synth.py
index 04822bf..6bf6dcb 100644
--- a/src/valon_synth.py
+++ b/src/valon_synth.py
@@ -1,28 +1,26 @@
# Copyright (C) 2011 Associated Universities, Inc. Washington DC, USA.
-#
+#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
-#
+#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
-#
+#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-#
+#
# Correspondence concerning GBT software should be addressed as follows:
-# GBT Operations
-# National Radio Astronomy Observatory
-# P. O. Box 2
-# Green Bank, WV 24944-0002 USA
+# GBT Operations
+# National Radio Astronomy Observatory
+# P. O. Box 2
+# Green Bank, WV 24944-0002 USA
-"""
-Provides a serial interface to the Valon 500x.
-"""
+"""Provides a serial interface to the Valon 500x."""
# Python modules
import struct
@@ -32,9 +30,10 @@
__author__ = "Patrick Brandt"
__copyright__ = "Copyright 2011, Associated Universities, Inc."
-__credits__ = ["Patrick Brandt, Stewart Rumley, Steven Stark"]
+__credits__ = ["Patrick Brandt, Stewart Rumley, Steven Stark, Glenn Jones,"
+ " Jack Hickish, Deneys Maartens"]
__license__ = "GPL"
-#__version__ = "1.0"
+__version__ = "1.0"
__maintainer__ = "Patrick Brandt"
@@ -48,13 +47,19 @@
ACK = 0x06
NACK = 0x15
+
def _generate_checksum(data):
"Generate a checksum for the data provided."
return chr(sum([ord(b) for b in data]) % 256)
+
def _verify_checksum(data, checksum):
"Verify a checksum for the data provided."
- return (_generate_checksum(data) == checksum)
+ if _generate_checksum(data) != checksum:
+ print 'checksum failure'
+ return False
+ return True
+
def _pack_freq_registers(ncount, frac, mod, dbf, old_data):
"Do bit packing for the frequency setting registers."
@@ -68,6 +73,7 @@ def _pack_freq_registers(ncount, frac, mod, dbf, old_data):
reg4 |= (dbf_table.get(dbf, 0)) << 20
return struct.pack('>IIIIII', reg0, reg1, reg2, reg3, reg4, reg5)
+
def _unpack_freq_registers(data):
"Do bit unpacking for the frequency setting registers."
dbf_rev_table = {0: 1, 1: 2, 2: 4, 3: 8, 4: 16}
@@ -78,16 +84,18 @@ def _unpack_freq_registers(data):
dbf = dbf_rev_table.get((reg4 >> 20) & 0x07, 1)
return ncount, frac, mod, dbf
+
class Synthesizer:
"""A simple interface to the Valon 500x synthesizer."""
- def __init__(self, port):
+ def __init__(self, port, timeout=1.0, checksum=False):
self.conn = serial.Serial(None, 9600, serial.EIGHTBITS,
serial.PARITY_NONE, serial.STOPBITS_ONE)
- self.conn.setPort(port)
+ self.conn.port = port
+ self.conn.timeout = timeout
+ self.do_checksum = checksum
def get_frequency(self, synth):
- """
- Returns the current output frequency for the selected synthesizer.
+ """Returns the current output frequency for the selected synthesizer.
@param synth : synthesizer this command affects (0 for 1, 8 for 2).
@type synth : int
@@ -96,21 +104,23 @@ def get_frequency(self, synth):
"""
self.conn.open()
data = struct.pack('>B', 0x80 | synth)
- self.conn.write(data)
- data = self.conn.read(24)
- checksum = self.conn.read(1)
- self.conn.close()
- #_verify_checksum(data, checksum)
+ try:
+ self.conn.write(data)
+ data = self.conn.read(24)
+ checksum = self.conn.read(1)
+ finally:
+ self.conn.close()
+ if self.do_checksum:
+ _verify_checksum(data, checksum)
ncount, frac, mod, dbf = _unpack_freq_registers(data)
epdf = self._get_epdf(synth)
return (ncount + float(frac) / mod) * epdf / dbf
- def set_frequency(self, synth, freq, chan_spacing = 10.):
- """
- Sets the synthesizer to the desired frequency
+ def set_frequency(self, synth, freq, chan_spacing=10.):
+ """Sets the synthesizer to the desired frequency.
- Sets to the closest possible frequency, depending on the channel spacing.
- Range is determined by the minimum and maximum VCO frequency.
+ Sets to the closest possible frequency, depending on the channel
+ spacing. Range is determined by the minimum and maximum VCO frequency.
@param synth : synthesizer this command affects (0 for 1, 8 for 2).
@type synth : int
@@ -143,37 +153,52 @@ def set_frequency(self, synth, freq, chan_spacing = 10.):
mod = 1
self.conn.open()
data = struct.pack('>B', 0x80 | synth)
- self.conn.write(data)
- old_data = self.conn.read(24)
- checksum = self.conn.read(1)
- #_verify_checksum(old_data, checksum)
+ try:
+ self.conn.write(data)
+ old_data = self.conn.read(24)
+ checksum = self.conn.read(1)
+ except:
+ self.conn.close()
+ raise
+ if self.do_checksum:
+ _verify_checksum(old_data, checksum)
data = struct.pack('>B24s', 0x00 | synth,
_pack_freq_registers(ncount, frac, mod,
dbf, old_data))
checksum = _generate_checksum(data)
- self.conn.write(data + checksum)
- data = self.conn.read(1)
- self.conn.close()
+ try:
+ self.conn.write(data + checksum)
+ data = self.conn.read(1)
+ finally:
+ self.conn.close()
ack = struct.unpack('>B', data)[0]
return ack == ACK
def get_reference(self):
- """
- Get reference frequency in MHz
+ """Get reference frequency in MHz.
+
+ @param No input parameters
+
+ @return Int: Reference input frequency (MHz)
"""
self.conn.open()
data = struct.pack('>B', 0x81)
- self.conn.write(data)
- data = self.conn.read(4)
- checksum = self.conn.read(1)
- self.conn.close()
- #_verify_checksum(data, checksum)
+ try:
+ self.conn.write(data)
+ data = self.conn.read(4)
+ checksum = self.conn.read(1)
+ finally:
+ self.conn.close()
+ if self.do_checksum:
+ _verify_checksum(data, checksum)
freq = struct.unpack('>I', data)[0]
return freq
def set_reference(self, freq):
- """
- Set reference frequency in MHz
+ """Set reference frequency in MHz.
+
+ For the 5007: this value must be between 5 MHz and 150 MHz, according
+ to the data sheet.
@param freq : frequency in MHz
@type freq : float
@@ -183,15 +208,18 @@ def set_reference(self, freq):
self.conn.open()
data = struct.pack('>BI', 0x01, freq)
checksum = _generate_checksum(data)
- self.conn.write(data + checksum)
- data = self.conn.read(1)
- self.conn.close()
+ try:
+ self.conn.write(data + checksum)
+ data = self.conn.read(1)
+ finally:
+ self.conn.close()
ack = struct.unpack('>B', data)[0]
return ack == ACK
def get_rf_level(self, synth):
- """
- Returns RF level in dBm
+ """Returns RF level in dBm.
+
+ The current output power level can be one of four values: -4, -1, 2, 5
@param synth : synthesizer address, 0 or 8
@type synth : int
@@ -201,19 +229,88 @@ def get_rf_level(self, synth):
rfl_table = {0: -4, 1: -1, 2: 2, 3: 5}
self.conn.open()
data = struct.pack('>B', 0x80 | synth)
- self.conn.write(data)
- data = self.conn.read(24)
- checksum = self.conn.read(1)
- self.conn.close()
- #_verify_checksum(data, checksum)
+ try:
+ self.conn.write(data)
+ data = self.conn.read(24)
+ checksum = self.conn.read(1)
+ finally:
+ self.conn.close()
+ if self.do_checksum:
+ _verify_checksum(data, checksum)
_, _, _, _, reg4, _ = struct.unpack('>IIIIII', data)
rfl = (reg4 >> 3) & 0x03
rf_level = rfl_table.get(rfl)
return rf_level
- def set_rf_level(self, synth, rf_level):
+ def rf_disable(self, synth):
"""
- Set RF level
+ Disable RF output.
+
+ @param synth : synthesizer address, 0 or 8
+ @type synth : int
+ """
+ self.conn.open()
+ data = struct.pack('>B', 0x80 | synth)
+ try:
+ self.conn.write(data)
+ data = self.conn.read(24)
+ checksum = self.conn.read(1)
+ except:
+ self.conn.close()
+ raise
+ if self.do_checksum:
+ _verify_checksum(data, checksum)
+ reg0, reg1, reg2, reg3, reg4, reg5 = struct.unpack('>IIIIII', data)
+ reg4 &= 0xffffffdf # RF Output power up
+ reg4 |= 1 << 9 # VCO power down
+ data = struct.pack('>BIIIIII', 0x00 | synth,
+ reg0, reg1, reg2, reg3, reg4, reg5)
+ checksum = _generate_checksum(data)
+ try:
+ self.conn.write(data + checksum)
+ data = self.conn.read(1)
+ finally:
+ self.conn.close()
+ ack = struct.unpack('>B', data)[0]
+ return ack == ACK
+
+ def rf_enable(self, synth):
+ """
+ Enable RF output.
+
+ @param synth : synthesizer address, 0 or 8
+ @type synth : int
+ """
+ self.conn.open()
+ data = struct.pack('>B', 0x80 | synth)
+ try:
+ self.conn.write(data)
+ data = self.conn.read(24)
+ checksum = self.conn.read(1)
+ except:
+ self.conn.close()
+ raise
+ if self.do_checksum:
+ _verify_checksum(data, checksum)
+ reg0, reg1, reg2, reg3, reg4, reg5 = struct.unpack('>IIIIII', data)
+ reg4 &= 0xfffff7ff # VCO power up
+ reg4 |= 1 << 5 # RF Output power up
+ data = struct.pack('>BIIIIII', 0x00 | synth,
+ reg0, reg1, reg2, reg3, reg4, reg5)
+ checksum = _generate_checksum(data)
+ try:
+ self.conn.write(data + checksum)
+ data = self.conn.read(1)
+ finally:
+ self.conn.close()
+ ack = struct.unpack('>B', data)[0]
+ return ack == ACK
+
+ def set_rf_level(self, synth, rf_level):
+ """Set RF level.
+
+ Allows user to select one of four output power levels: -4, -1, 2, 5
+ These levels corresponds approximately to some preset output power.
@param synth : synthesizer address, 0 or 8
@type synth : int
@@ -229,25 +326,57 @@ def set_rf_level(self, synth, rf_level):
return False
self.conn.open()
data = struct.pack('>B', 0x80 | synth)
- self.conn.write(data)
- data = self.conn.read(24)
- checksum = self.conn.read(1)
- #_verify_checksum(data, checksum)
+ try:
+ self.conn.write(data)
+ data = self.conn.read(24)
+ checksum = self.conn.read(1)
+ except:
+ self.conn.close()
+ raise
+ if self.do_checksum:
+ _verify_checksum(data, checksum)
reg0, reg1, reg2, reg3, reg4, reg5 = struct.unpack('>IIIIII', data)
reg4 &= 0xffffffe7
reg4 |= (rfl & 0x03) << 3
data = struct.pack('>BIIIIII', 0x00 | synth,
- reg0, reg1, reg2, reg3, reg4, reg5)
+ reg0, reg1, reg2, reg3, reg4, reg5)
checksum = _generate_checksum(data)
- self.conn.write(data + checksum)
- data = self.conn.read(1)
- self.conn.close()
+ try:
+ self.conn.write(data + checksum)
+ data = self.conn.read(1)
+ finally:
+ self.conn.close()
ack = struct.unpack('>B', data)[0]
return ack == ACK
def get_options(self, synth):
- """
- Get options tuple:
+ """Get options tuple:
+
+ Output a Tuple of 4 parameters, which can be 0 (disabled) or 1(enabled)
+
+ - double: The reference doubler is used to enable a multiply by 2
+ function before the internal reference divider.
+
+ Enable the doubler when using a 5 MHz external reference frequency.
+ When using the internal 10 MHz reference the doubler should be
+ disabled.
+
+ - half: The reference divide by 2 is used to enable a divide by 2
+ function after the intercal reference divider.
+
+ When enabled, the input to phase-frequency detector will have a 50%
+ duty cycle which will allow for faster lock up time. In order to use
+ this mode a 20 MHz external reference would have to be available.
+ For normal operations set the reference div by 2 to disabled.
+
+ - r: reference frequency divisor
+
+ - spur: Low noise mode vs Low spur mode.
+
+ Low noise mode affects the operation of the fractional synthesizer,
+ and this mode will produce the lowest phase noise but there may be
+ some spurious output signals. Low spur mode will reduce spurious
+ output response but the overall phase noise will be higher.
bool double: if True, reference frequency is doubled
bool half: if True, reference frequency is halved
@@ -262,11 +391,14 @@ def get_options(self, synth):
"""
self.conn.open()
data = struct.pack('>B', 0x80 | synth)
- self.conn.write(data)
- data = self.conn.read(24)
- checksum = self.conn.read(1)
- self.conn.close()
- #_verify_checksum(data, checksum)
+ try:
+ self.conn.write(data)
+ data = self.conn.read(24)
+ checksum = self.conn.read(1)
+ finally:
+ self.conn.close()
+ if self.do_checksum:
+ _verify_checksum(data, checksum)
_, _, reg2, _, _, _ = struct.unpack('>IIIIII', data)
low_spur = ((reg2 >> 30) & 1) & ((reg2 >> 29) & 1)
double = (reg2 >> 25) & 1
@@ -274,10 +406,8 @@ def get_options(self, synth):
divider = (reg2 >> 14) & 0x03ff
return double, half, divider, low_spur
- def set_options(self, synth, double = 0, half = 0, divider = 1,
- low_spur = 0):
- """
- Set options.
+ def set_options(self, synth, double=0, half=0, divider=1, low_spur=0):
+ """Set options.
double and half both True is same as both False.
@@ -301,42 +431,53 @@ def set_options(self, synth, double = 0, half = 0, divider = 1,
"""
self.conn.open()
data = struct.pack('>B', 0x80 | synth)
- self.conn.write(data)
- data = self.conn.read(24)
- checksum = self.conn.read(1)
- #_verify_checksum(data, checksum)
+ try:
+ self.conn.write(data)
+ data = self.conn.read(24)
+ checksum = self.conn.read(1)
+ except:
+ self.conn.close()
+ raise
+ if self.do_checksum:
+ _verify_checksum(data, checksum)
reg0, reg1, reg2, reg3, reg4, reg5 = struct.unpack('>IIIIII', data)
reg2 &= 0x9c003fff
reg2 |= (((low_spur & 1) << 30) | ((low_spur & 1) << 29) |
((double & 1) << 25) | ((half & 1) << 24) |
((divider & 0x03ff) << 14))
data = struct.pack('>BIIIIII', 0x00 | synth,
- reg0, reg1, reg2, reg3, reg4, reg5)
+ reg0, reg1, reg2, reg3, reg4, reg5)
checksum = _generate_checksum(data)
- self.conn.write(data + checksum)
- data = self.conn.read(1)
- self.conn.close()
+ try:
+ self.conn.write(data + checksum)
+ data = self.conn.read(1)
+ finally:
+ self.conn.close()
ack = struct.unpack('>B', data)[0]
return ack == ACK
def get_ref_select(self):
"""Returns the currently selected reference clock.
- Returns 1 if the external reference is selected, 0 otherwise.
+ @param No input parameters
+
+ @return: 1 if the external reference is selected, 0 otherwise.
"""
self.conn.open()
data = struct.pack('>B', 0x86)
- self.conn.write(data)
- data = self.conn.read(1)
- checksum = self.conn.read(1)
- self.conn.close()
- #_verify_checksum(data, checksum)
+ try:
+ self.conn.write(data)
+ data = self.conn.read(1)
+ checksum = self.conn.read(1)
+ finally:
+ self.conn.close()
+ if self.do_checksum:
+ _verify_checksum(data, checksum)
is_ext = struct.unpack('>B', data)[0]
return is_ext & 1
- def set_ref_select(self, e_not_i = 1):
- """
- Selects either internal or external reference clock.
+ def set_ref_select(self, e_not_i=1):
+ """Selects either internal or external reference clock.
@param e_not_i : 1 (external) or 0 (internal); default 1
@type e_not_i : int
@@ -346,33 +487,44 @@ def set_ref_select(self, e_not_i = 1):
self.conn.open()
data = struct.pack('>BB', 0x06, e_not_i & 1)
checksum = _generate_checksum(data)
- self.conn.write(data + checksum)
- data = self.conn.read(1)
- self.conn.close()
+ try:
+ self.conn.write(data + checksum)
+ data = self.conn.read(1)
+ finally:
+ self.conn.close()
ack = struct.unpack('>B', data)[0]
return ack == ACK
def get_vco_range(self, synth):
- """
- Returns (min, max) VCO range tuple.
+ """Returns (min, max) VCO range tuple.
+
+ The VCO Frequency Range information is used to limit and check the
+ resulting VCO output frequency, entered in the set frequency request
+ function.
@param synth : synthesizer base address
@type synth : int
- @return: min,max in MHz
+ @return: Tuple: (lowest VCO output frequency, highest VCO output
+ frequency) in MHz
"""
self.conn.open()
data = struct.pack('>B', 0x83 | synth)
- self.conn.write(data)
- data = self.conn.read(4)
- checksum = self.conn.read(1)
- self.conn.close()
- #_verify_checksum(data, checksum)
+ try:
+ self.conn.write(data)
+ data = self.conn.read(4)
+ checksum = self.conn.read(1)
+ finally:
+ self.conn.close()
+ if self.do_checksum:
+ _verify_checksum(data, checksum)
return struct.unpack('>HH', data)
def set_vco_range(self, synth, low, high):
- """
- Sets VCO range.
+ """Sets VCO range.
+
+ Set the minimum and maximum frequency range of the selected synthesizer
+ VCO.
@param synth : synthesizer base address
@type synth : int
@@ -388,15 +540,16 @@ def set_vco_range(self, synth, low, high):
self.conn.open()
data = struct.pack('>BHH', 0x03 | synth, low, high)
checksum = _generate_checksum(data)
- self.conn.write(data + checksum)
- data = self.conn.read(1)
- self.conn.close()
+ try:
+ self.conn.write(data + checksum)
+ data = self.conn.read(1)
+ finally:
+ self.conn.close()
ack = struct.unpack('>B', data)[0]
return ack == ACK
def get_phase_lock(self, synth):
- """
- Get phase lock status
+ """Get phase lock status.
@param synth : synthesizer base address
@type synth : int
@@ -405,18 +558,23 @@ def get_phase_lock(self, synth):
"""
self.conn.open()
data = struct.pack('>B', 0x86 | synth)
- self.conn.write(data)
- data = self.conn.read(1)
- checksum = self.conn.read(1)
- self.conn.close()
- #_verify_checksum(data, checksum)
- mask = (synth << 1) or 0x20
+ try:
+ self.conn.write(data)
+ data = self.conn.read(1)
+ checksum = self.conn.read(1)
+ finally:
+ self.conn.close()
+ if self.do_checksum:
+ _verify_checksum(data, checksum)
+ if synth == SYNTH_A:
+ mask = 1 << 4
+ else:
+ mask = 1 << 5
lock = struct.unpack('>B', data)[0] & mask
return lock > 0
def get_label(self, synth):
- """
- Get synthesizer label or name
+ """Get synthesizer label or name.
@param synth : synthesizer base address
@type synth : int
@@ -425,21 +583,23 @@ def get_label(self, synth):
"""
self.conn.open()
data = struct.pack('>B', 0x82 | synth)
- self.conn.write(data)
- data = self.conn.read(16)
- checksum = self.conn.read(1)
- self.conn.close()
- #_verify_checksum(data, checksum)
+ try:
+ self.conn.write(data)
+ data = self.conn.read(16)
+ checksum = self.conn.read(1)
+ finally:
+ self.conn.close()
+ if self.do_checksum:
+ _verify_checksum(data, checksum)
return data
def set_label(self, synth, label):
- """
- Set synthesizer label or name
+ """Set synthesizer label or name.
@param synth : synthesizer base address
@type synth : int
- @param label : up to 16 data of text
+ @param label : up to 16 bytes of text
@type label : str
@return: True if success (bool)
@@ -447,39 +607,52 @@ def set_label(self, synth, label):
self.conn.open()
data = struct.pack('>B16s', 0x02 | synth, label)
checksum = _generate_checksum(data)
- self.conn.write(data + checksum)
- data = self.conn.read(1)
- self.conn.close()
+ try:
+ self.conn.write(data + checksum)
+ data = self.conn.read(1)
+ finally:
+ self.conn.close()
ack = struct.unpack('>B', data)[0]
return ack == ACK
def flash(self):
- """
- Flash current settings for both synthesizers into non-volatile memory.
+ """Flash current settings for both synthesizers into non-volatile
+ memory.
+
+ The next time the board is powered up, the registers will be set to the
+ values in the non-volatile flash memory. If the board is powered down
+ before the write flash command command is issued, all the data in the
+ registers will be lost.
@return: True if success (bool)
"""
self.conn.open()
data = struct.pack('>B', 0x40)
checksum = _generate_checksum(data)
- self.conn.write(data + checksum)
- data = self.conn.read(1)
- self.conn.close()
+ try:
+ self.conn.write(data + checksum)
+ data = self.conn.read(1)
+ finally:
+ self.conn.close()
ack = struct.unpack('>B', data)[0]
return ack == ACK
def _get_epdf(self, synth):
- """
- Returns effective phase detector frequency.
+ """Returns effective phase detector frequency.
This is the reference frequency with options applied.
+
+ @param synth : synthesizer base address
+ @type synth : int
+
+ @return: frequency
"""
reference = self.get_reference() / 1e6
double, half, divider, _ = self.get_options(synth)
- if(double):
+ if (double):
reference *= 2.0
- if(half):
+ if (half):
reference /= 2.0
- if(divider > 1):
+ if (divider > 1):
reference /= divider
return reference