-
Notifications
You must be signed in to change notification settings - Fork 4
/
valon_katcp.py
341 lines (265 loc) · 13.1 KB
/
valon_katcp.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
######################################################################
#
# valon_katcp.py -- Valon over KATCP support. Duck typed after the
# Synthesizer object in valon_synth.
#
# Copyright (C) 2013 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
#
######################################################################
class ValonException(Exception):
def __init__(self, message):
Exception.__init__(self, message)
class ValonKATCP(object):
"""
A Valon synth class modeled after the 'valon_synth' module, but
which communicates with a Valon installed on a ROACH via KATCP.
ValonKATCP(r, serial_port)
* *r:* corr.katcp_wrapper.FpgaClient object. This object is used for
KATCP communications to the ROACH. It is expected to be
initialized.
* *serial_port:* A string, the device name of the serial port
(i.e. ``/dev/ttyS0``)
"""
def __init__(self, r, serial_port):
"""
__init__(self, r, serial_port)
Initializes the ValonKATCP class.
"""
self.roach = r
"""The KATCP client object"""
self.timeout = 5
"""The default timeout for katcp requests for this module"""
self._set_serial_port(serial_port)
def _get_synth_val(self, s):
"""
_get_synth_val(self, s)
For interchangeability with the valon_synth module this class
assumes throughout that the parameter *s* is an integer, either
0 for SYNTH_A or 8 for SYNTH_B. However, KATCP expects a case
insensitive string 'synth_a' or 'synth_b' This function converts
from 0 or 8 to 'synth_a' or 'synth_b'. It throws a *KeyError* if
the input isn't 0 or 8.
"""
try:
return {0x00: 'synth_a', 0x08: 'synth_b'}[s]
except KeyError:
raise ValonException("The 'synth' parameter was given as %s. It must be an"
" integer either 0x00 (SYNTH_A) or 0x08 (SYNTH_B)" % str(s))
def _set_serial_port(self, port):
"""
_set_serial_port(self, port)
* *port:* a string denoting the serial device, i.e. ``/dev/ttyS0``
Sets the serial port on the ROACH that the Valon is connected to.
"""
# reply, informs = self.roach._request("valon-new-port", self.timeout, port)
reply, informs = self.roach._request("valon-new-port", port)
if reply.arguments[0] != 'ok':
raise ValonException("Unable to set serial port %s" % port)
def flash(self):
"""
flash(self)
Writes frequencies to valon non-volatile memory.
"""
# reply, informs = self.roach._request("valon-flash", self.timeout)
reply, informs = self.roach._request("valon-flash")
def get_frequency(self, synth):
"""
get_frequency(self, synth)
* *synth:* An integer, 0x00 for SYNTH_A, and 0x08 for SYNTH_B
Returns the current output frequency for the specified synthesizer.
"""
# reply, informs = self.roach._request("valon-get-frequency", self.timeout,
# self._get_synth_val(synth))
reply, informs = self.roach._request("valon-get-frequency",
self._get_synth_val(synth))
if reply.arguments[0] != 'ok':
raise ValonException("Unable to retrieve frequency for %s", self._get_synth_val(synth))
else:
return float(reply.arguments[2])
def get_label(self, synth):
"""
get_label(self, synth)
* *synth:* An integer, 0x00 for SYNTH_A, and 0x08 for SYNTH_B
Returns the currently set label for 'synth'.
"""
# reply, informs = self.roach._request("valon-get-label", self.timeout,
# self._get_synth_val(synth))
reply, informs = self.roach._request("valon-get-label",
self._get_synth_val(synth))
return reply.arguments[1].rstrip()
def get_options(self, synth):
"""
get_options(self, synth)
* *synth:* An integer, 0x00 for SYNTH_A, and 0x08 for SYNTH_B
Returns the option flags/values for the specified
synthesizer. They are returned as a tuple of 4 elements:
0. Ref frequency doubler flag. When set, the reference frequency doubler is active.
1. Ref frequency halver flag: When set, the reference frequency halver is active.
2. Integer value, the reference frequency divider value.
3. 'Low spur' mode flag. When not set, the synth is in 'low noise' mode.
"""
# reply, informs = self.roach._request("valon-get-options", self.timeout,
# self._get_synth_val(synth))
reply, informs = self.roach._request("valon-get-options",
self._get_synth_val(synth))
return (int(reply.arguments[3]), int(reply.arguments[4]), int(reply.arguments[5]), int(reply.arguments[2]))
def get_phase_lock(self, synth):
"""
get_phase_lock(self, synth)
* *synth:* An integer, 0x00 for SYNTH_A, and 0x08 for SYNTH_B
Returns *True* if the specified synthesizer is phase locked to
its reference, *False* if not.
"""
# reply, informs = self.roach._request("valon-get-phase-lock", self.timeout,
# self._get_synth_val(synth))
reply, informs = self.roach._request("valon-get-phase-lock",
self._get_synth_val(synth))
return int(reply.arguments[1]) == 1
def get_ref_select(self):
"""
get_ref_select(self)
Returns *1* if external reference frequency is selected, *0* if
internal reference is selected.
"""
# reply, informs = self.roach._request("valon-get-ref-select", self.timeout)
reply, informs = self.roach._request("valon-get-ref-select")
return int(reply.arguments[1])
def get_reference(self):
"""
get_reference(self)
Returns the set reference frequency value. This is not the
actual reference frequency, but the value that has been sent to
the Valon as the current reference frequency.
"""
# reply, informs = self.roach._request('valon-get-reference', self.timeout)
reply, informs = self.roach._request('valon-get-reference')
return int(reply.arguments[1])
def get_rf_level(self, synth):
"""
get_rf_level(self, synth)
* *synth:* An integer, 0x00 for SYNTH_A, and 0x08 for SYNTH_B
Returns the output RF level setting in dBm for the specified
synthesizer.
"""
# reply, informs = self.roach._request('valon-get-rf-level', self.timeout,
# self._get_synth_val(synth))
reply, informs = self.roach._request('valon-get-rf-level',
self._get_synth_val(synth))
return int(reply.arguments[2])
def get_vco_range(self, synth):
"""
get_vco_range(self, synth)
* *synth:* An integer, 0x00 for SYNTH_A, and 0x08 for SYNTH_B
Returns a tuple of the VCO range, (min, max)
"""
# reply, informs = self.roach._request('valon-get-vco-range', self.timeout,
# self._get_synth_val(synth))
reply, informs = self.roach._request('valon-get-vco-range',
self._get_synth_val(synth))
return (int(reply.arguments[2]), int(reply.arguments[3]))
def set_frequency(self, synth, frequency, chan_spacing = 10.0):
"""
set_frequency(self, synth)
* *synth:* An integer, 0x00 for SYNTH_A, and 0x08 for SYNTH_B
* *frequency:* A floating point value, the frequency in MHz.
* *chan_spacing:* A floating point value, the resolution of the
setting, in Hz. This defaults to 10 Hz.
Sets the output frequency of the specified synthesizer. Returns
*True* on success.
"""
# reply, informs = self.roach._request('valon-set-frequency', self.timeout,
# self._get_synth_val(synth), frequency, chan_spacing)
reply, informs = self.roach._request('valon-set-frequency',
self._get_synth_val(synth), frequency, chan_spacing)
return reply.arguments[0] == 'ok'
def set_label(self, synth, new_label):
"""
set_label(self, synth, new_label)
* *synth:* An integer, 0x00 for SYNTH_A, and 0x08 for SYNTH_B
* *new_label:* A string; only the first 16 characters will be used.
Gives a custom label to the specified synthesizer.
"""
# reply, informs = self.roach._request('valon-set-label', self.timeout,
# self._get_synth_val(synth), new_label)
reply, informs = self.roach._request('valon-set-label',
self._get_synth_val(synth), new_label)
return reply.arguments[0] == 'ok'
def set_options(self, synth, double=0, half=0, r=1, low_spur=0):
"""set_options(self, synth, double=0, half=0, r=1, low_spur=0)
* *synth:* An integer, 0x00 for SYNTH_A, and 0x08 for SYNTH_B
* *double:* Set to 1 to double the reference frequency, default = 0
* *half:* Set to 1 to halve the reference frequency, default = 0
* *r:* Reference frequency multiplier, default = 1
* *low_spur:* Set to 1 to use 'low spur' mode, clear to use 'low noise' mode. Default = 0
Sets the synthesizer options.
"""
# reply, informs = self.roach._request('valon-set-options', self.timeout,
# self._get_synth_val(synth),
# low_spur, double, half, r)
reply, informs = self.roach._request('valon-set-options',
self._get_synth_val(synth),
low_spur, double, half, r)
return reply.arguments[0] == 'ok'
def set_ref_select(self, external):
"""set_ref_select(self, external)
* *external:* External reference flag, an integer number. Set to 1 for external ref, 0 for internal ref.
Sets the reference frequency source to external or internal.
"""
reply, informs = self.roach._request('valon-set-ref-select',
external)
return reply.arguments[0] == 'ok'
def set_reference(self, ref_freq):
"""set_reference(self, ref_freq)
* *ref_freq:* the reference frequency being used, in Hz.
Tells the Valon synthesizer module of the reference frequency
being used.
"""
reply, informs = self.roach._request('valon-set-reference',
ref_freq)
return reply.arguments[0] == 'ok'
def set_rf_level(self, synth, rf_level):
"""
set_rf_level(self, synth, rf_level)
* *synth:* An integer, 0x00 for SYNTH_A, and 0x08 for SYNTH_B
* *rf_level:* The new level, in dBm. This must be one of -4, -1,
2, and 5, or the function will return *False* and not set the
level.
Sets the output RF level in dBm for the specified synthesizer.
"""
allowed_levels = (-4, -1, 2, 5)
if rf_level in allowed_levels:
reply, informs = self.roach._request('valon-set-rf-level',
self._get_synth_val(synth), rf_level)
return reply.arguments[0] == 'ok'
return False
def set_vco_range(self, synth, low, high):
"""
set_vco_range(self, synth, low, high)
* *synth:* An integer, 0x00 for SYNTH_A, and 0x08 for SYNTH_B
* *low:* Minimum frequency the VCO is capable of producing.
* *high:* Maximum frequency the VCO is capable of producing.
Sets the specified synthesizer's VCO range.
"""
reply, informs = self.roach._request('valon-set-vco-range',
self._get_synth_val(synth), low, high)
return reply.arguments[0] == 'ok'