1
|
|
###############################################################################
|
2
|
|
# pyrpl - DSP servo controller for quantum optics with the RedPitaya
|
3
|
|
# Copyright (C) 2014-2016 Leonhard Neuhaus (neuhaus@spectro.jussieu.fr)
|
4
|
|
#
|
5
|
|
# This program is free software: you can redistribute it and/or modify
|
6
|
|
# it under the terms of the GNU General Public License as published by
|
7
|
|
# the Free Software Foundation, either version 3 of the License, or
|
8
|
|
# (at your option) any later version.
|
9
|
|
#
|
10
|
|
# This program is distributed in the hope that it will be useful,
|
11
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
12
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
13
|
|
# GNU General Public License for more details.
|
14
|
|
#
|
15
|
|
# You should have received a copy of the GNU General Public License
|
16
|
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
17
|
|
###############################################################################
|
18
|
|
|
19
|
3
|
from . import redpitaya_client
|
20
|
3
|
from . import hardware_modules as rp
|
21
|
3
|
from .sshshell import SshShell
|
22
|
3
|
from .pyrpl_utils import get_unique_name_list_from_class_list, update_with_typeconversion
|
23
|
3
|
from .memory import MemoryTree
|
24
|
3
|
from .errors import ExpectedPyrplError
|
25
|
3
|
from .widgets.startup_widget import HostnameSelectorWidget
|
26
|
|
|
27
|
3
|
import logging
|
28
|
3
|
import os
|
29
|
3
|
import random
|
30
|
3
|
import socket
|
31
|
3
|
from time import sleep
|
32
|
3
|
import numpy as np
|
33
|
|
|
34
|
3
|
from paramiko import SSHException
|
35
|
3
|
from scp import SCPClient, SCPException
|
36
|
3
|
from collections import OrderedDict
|
37
|
|
|
38
|
|
# input is the wrong function in python 2
|
39
|
3
|
try:
|
40
|
3
|
raw_input
|
41
|
2
|
except NameError: # Python 3
|
42
|
2
|
raw_input = input
|
43
|
|
|
44
|
|
# default parameters for redpitaya object creation
|
45
|
3
|
defaultparameters = dict(
|
46
|
|
hostname='', #'192.168.1.100', # the ip or hostname of the board, '' triggers gui
|
47
|
|
port=2222, # port for PyRPL datacommunication
|
48
|
|
sshport=22, # port of ssh server - default 22
|
49
|
|
user='root',
|
50
|
|
password='root',
|
51
|
|
delay=0.05, # delay between ssh commands - console is too slow otherwise
|
52
|
|
autostart=True, # autostart the client?
|
53
|
|
reloadserver=False, # reinstall the server at startup if not necessary?
|
54
|
|
reloadfpga=True, # reload the fpga bitfile at startup?
|
55
|
|
serverbinfilename='fpga.bin', # name of the binfile on the server
|
56
|
|
serverdirname = "//opt//pyrpl//", # server directory for server app and bitfile
|
57
|
|
leds_off=True, # turn off all GPIO lets at startup (improves analog performance)
|
58
|
|
frequency_correction=1.0, # actual FPGA frequency is 125 MHz * frequency_correction
|
59
|
|
timeout=1, # timeout in seconds for ssh communication
|
60
|
|
monitor_server_name='monitor_server', # name of the server program on redpitaya
|
61
|
|
silence_env=False) # suppress all environment variables that may override the configuration?
|
62
|
|
|
63
|
|
|
64
|
3
|
class RedPitaya(object):
|
65
|
3
|
cls_modules = [rp.HK, rp.AMS, rp.Scope, rp.Sampler, rp.Asg0, rp.Asg1] + \
|
66
|
|
[rp.Pwm] * 2 + [rp.Iq] * 3 + [rp.Pid] * 3 + [rp.Trig] + [ rp.IIR]
|
67
|
|
|
68
|
3
|
def __init__(self, config=None, # configfile is needed to store parameters. None simulates one
|
69
|
|
**kwargs):
|
70
|
|
""" this class provides the basic interface to the redpitaya board
|
71
|
|
|
72
|
|
The constructor installs and starts the communication interface on the RedPitaya
|
73
|
|
at 'hostname' that allows remote control and readout
|
74
|
|
|
75
|
|
'config' is the config file or MemoryTree of the config file. All keyword arguments
|
76
|
|
may be specified in the branch 'redpitaya' of this config file. Alternatively,
|
77
|
|
they can be overwritten by keyword arguments at the function call.
|
78
|
|
|
79
|
|
'config=None' specifies that no persistent config file is saved on the disc.
|
80
|
|
|
81
|
|
Possible keyword arguments and their defaults are:
|
82
|
|
hostname='192.168.1.100', # the ip or hostname of the board
|
83
|
|
port=2222, # port for PyRPL datacommunication
|
84
|
|
sshport=22, # port of ssh server - default 22
|
85
|
|
user='root',
|
86
|
|
password='root',
|
87
|
|
delay=0.05, # delay between ssh commands - console is too slow otherwise
|
88
|
|
autostart=True, # autostart the client?
|
89
|
|
reloadserver=False, # reinstall the server at startup if not necessary?
|
90
|
|
reloadfpga=True, # reload the fpga bitfile at startup?
|
91
|
|
filename='fpga//red_pitaya.bin', # name of the bitfile for the fpga, None is default file
|
92
|
|
serverbinfilename='fpga.bin', # name of the binfile on the server
|
93
|
|
serverdirname = "//opt//pyrpl//", # server directory for server app and bitfile
|
94
|
|
leds_off=True, # turn off all GPIO lets at startup (improves analog performance)
|
95
|
|
frequency_correction=1.0, # actual FPGA frequency is 125 MHz * frequency_correction
|
96
|
|
timeout=3, # timeout in seconds for ssh communication
|
97
|
|
monitor_server_name='monitor_server', # name of the server program on redpitaya
|
98
|
|
silence_env=False) # suppress all environment variables that may override the configuration?
|
99
|
|
|
100
|
|
if you are experiencing problems, try to increase delay, or try
|
101
|
|
logging.getLogger().setLevel(logging.DEBUG)"""
|
102
|
3
|
self.logger = logging.getLogger(name=__name__)
|
103
|
|
#self.license()
|
104
|
|
# make or retrieve the config file
|
105
|
3
|
if isinstance(config, MemoryTree):
|
106
|
3
|
self.c = config
|
107
|
|
else:
|
108
|
3
|
self.c = MemoryTree(config)
|
109
|
|
# get the parameters right (in order of increasing priority):
|
110
|
|
# first defaults, then environment variables, config file, and command
|
111
|
|
# line arguments
|
112
|
3
|
self.parameters = defaultparameters
|
113
|
|
# get parameters from os.environment variables
|
114
|
3
|
if not self.parameters['silence_env']:
|
115
|
3
|
for k in self.parameters.keys():
|
116
|
3
|
if "REDPITAYA_"+k.upper() in os.environ:
|
117
|
3
|
newvalue = os.environ["REDPITAYA_"+k.upper()]
|
118
|
3
|
oldvalue = self.parameters[k]
|
119
|
3
|
self.parameters[k] = type(oldvalue)(newvalue)
|
120
|
3
|
if k == "password": # do not show the password on the screen
|
121
|
3
|
oldvalue = "********"
|
122
|
3
|
newvalue = "********"
|
123
|
3
|
self.logger.debug("Variable %s with value %s overwritten "
|
124
|
|
"by environment variable REDPITAYA_%s "
|
125
|
|
"with value %s. Use argument "
|
126
|
|
"'silence_env=True' if this is not "
|
127
|
|
"desired!",
|
128
|
|
k, oldvalue, k.upper(), newvalue)
|
129
|
|
# settings from config file
|
130
|
3
|
try:
|
131
|
3
|
update_with_typeconversion(self.parameters, self.c._get_or_create('redpitaya')._data)
|
132
|
0
|
except BaseException as e:
|
133
|
0
|
self.logger.warning("An error occured during the loading of your "
|
134
|
|
"Red Pitaya settings from the config file: %s",
|
135
|
|
e)
|
136
|
|
# settings from class initialisation
|
137
|
3
|
update_with_typeconversion(self.parameters, kwargs)
|
138
|
|
# get connection settings from gui/command line if missing
|
139
|
3
|
if self.parameters['hostname'] is None or self.parameters['hostname']=='':
|
140
|
0
|
gui = 'gui' not in self.c._keys() or self.c.gui
|
141
|
0
|
if gui:
|
142
|
0
|
self.logger.info("Please choose the hostname of "
|
143
|
|
"your Red Pitaya in the hostname "
|
144
|
|
"selector window!")
|
145
|
0
|
startup_widget = HostnameSelectorWidget()
|
146
|
0
|
hostname_kwds = startup_widget.get_kwds()
|
147
|
|
else:
|
148
|
0
|
hostname = raw_input('Enter hostname [192.168.1.100]: ')
|
149
|
0
|
hostname = '192.168.1.100' if hostname == '' else hostname
|
150
|
0
|
hostname_kwds = dict(hostname=hostname)
|
151
|
0
|
if not "sshport" in kwargs:
|
152
|
0
|
sshport = raw_input('Enter sshport [22]: ')
|
153
|
0
|
sshport = 22 if sshport == '' else int(sshport)
|
154
|
0
|
hostname_kwds['sshport'] = sshport
|
155
|
0
|
if not 'user' in kwargs:
|
156
|
0
|
user = raw_input('Enter username [root]: ')
|
157
|
0
|
user = 'root' if user == '' else user
|
158
|
0
|
hostname_kwds['user'] = user
|
159
|
0
|
if not 'password' in kwargs:
|
160
|
0
|
password = raw_input('Enter password [root]: ')
|
161
|
0
|
password = 'root' if password == '' else password
|
162
|
0
|
hostname_kwds['password'] = password
|
163
|
0
|
self.parameters.update(hostname_kwds)
|
164
|
|
|
165
|
|
# optional: write configuration back to config file
|
166
|
3
|
self.c["redpitaya"] = self.parameters
|
167
|
|
|
168
|
|
# save default port definition for possible automatic port change
|
169
|
3
|
self.parameters['defaultport'] = self.parameters['port']
|
170
|
|
# frequency_correction is accessed by child modules
|
171
|
3
|
self.frequency_correction = self.parameters['frequency_correction']
|
172
|
|
# memorize whether server is running - nearly obsolete
|
173
|
3
|
self._serverrunning = False
|
174
|
3
|
self.client = None # client class
|
175
|
3
|
self._slaves = [] # slave interfaces to same redpitaya
|
176
|
3
|
self.modules = OrderedDict() # all submodules
|
177
|
|
|
178
|
|
# provide option to simulate a RedPitaya
|
179
|
3
|
if self.parameters['hostname'] in ['_FAKE_REDPITAYA_', '_FAKE_']:
|
180
|
0
|
self.startdummyclient()
|
181
|
0
|
self.logger.warning("Simulating RedPitaya because (hostname=="
|
182
|
|
+self.parameters["hostname"]+"). Incomplete "
|
183
|
|
"functionality possible. ")
|
184
|
0
|
return
|
185
|
3
|
elif self.parameters['hostname'] in ['_NONE_']:
|
186
|
0
|
self.modules = []
|
187
|
0
|
self.logger.warning("No RedPitaya created (hostname=="
|
188
|
|
+ self.parameters["hostname"] + ")."
|
189
|
|
" No hardware modules are available. ")
|
190
|
0
|
return
|
191
|
|
# connect to the redpitaya board
|
192
|
3
|
self.start_ssh()
|
193
|
|
# start other stuff
|
194
|
0
|
if self.parameters['reloadfpga']: # flash fpga
|
195
|
0
|
self.update_fpga()
|
196
|
0
|
if self.parameters['reloadserver']: # reinstall server app
|
197
|
0
|
self.installserver()
|
198
|
0
|
if self.parameters['autostart']: # start client
|
199
|
0
|
self.start()
|
200
|
0
|
self.logger.info('Successfully connected to Redpitaya with hostname '
|
201
|
|
'%s.'%self.ssh.hostname)
|
202
|
0
|
self.parent = self
|
203
|
|
|
204
|
3
|
def start_ssh(self, attempt=0):
|
205
|
|
"""
|
206
|
|
Extablishes an ssh connection to the RedPitaya board
|
207
|
|
|
208
|
|
returns True if a successful connection has been established
|
209
|
|
"""
|
210
|
3
|
try:
|
211
|
|
# close pre-existing connection if necessary
|
212
|
3
|
self.end_ssh()
|
213
|
3
|
except:
|
214
|
3
|
pass
|
215
|
3
|
if self.parameters['hostname'] == "_FAKE_REDPITAYA_":
|
216
|
|
# simulation mode - start without connecting
|
217
|
0
|
self.logger.warning("(Re-)starting client in dummy mode...")
|
218
|
0
|
self.startdummyclient()
|
219
|
0
|
return True
|
220
|
|
else: # normal mode - establish ssh connection and
|
221
|
3
|
try:
|
222
|
|
# start ssh connection
|
223
|
3
|
self.ssh = SshShell(hostname=self.parameters['hostname'],
|
224
|
|
sshport=self.parameters['sshport'],
|
225
|
|
user=self.parameters['user'],
|
226
|
|
password=self.parameters['password'],
|
227
|
|
delay=self.parameters['delay'],
|
228
|
|
timeout=self.parameters['timeout'])
|
229
|
|
# test ssh connection for exceptions
|
230
|
0
|
self.ssh.ask()
|
231
|
3
|
except BaseException as e: # connection problem
|
232
|
3
|
if attempt < 3:
|
233
|
|
# try to connect up to 3 times
|
234
|
3
|
return self.start_ssh(attempt=attempt+1)
|
235
|
|
else: # even multiple attempts did not work
|
236
|
3
|
raise ExpectedPyrplError(
|
237
|
|
"\nCould not connect to the Red Pitaya device with "
|
238
|
|
"the following parameters: \n\n"
|
239
|
|
"\thostname: %s\n"
|
240
|
|
"\tssh port: %s\n"
|
241
|
|
"\tusername: %s\n"
|
242
|
|
"\tpassword: ****\n\n"
|
243
|
|
"Please confirm that the device is reachable by typing "
|
244
|
|
"its hostname/ip address into a web browser and "
|
245
|
|
"checking that a page is displayed. \n\n"
|
246
|
|
"Error message: %s" % (self.parameters["hostname"],
|
247
|
|
self.parameters["sshport"],
|
248
|
|
self.parameters["user"],
|
249
|
|
e))
|
250
|
|
else:
|
251
|
|
# everything went well, connection is established
|
252
|
|
# also establish scp connection
|
253
|
0
|
self.ssh.startscp()
|
254
|
0
|
return True
|
255
|
|
|
256
|
3
|
def switch_led(self, gpiopin=0, state=False):
|
257
|
0
|
self.ssh.ask("echo " + str(gpiopin) + " > /sys/class/gpio/export")
|
258
|
0
|
sleep(self.parameters['delay'])
|
259
|
0
|
self.ssh.ask(
|
260
|
|
"echo out > /sys/class/gpio/gpio" +
|
261
|
|
str(gpiopin) +
|
262
|
|
"/direction")
|
263
|
0
|
sleep(self.parameters['delay'])
|
264
|
0
|
if state:
|
265
|
0
|
state = "1"
|
266
|
|
else:
|
267
|
0
|
state = "0"
|
268
|
0
|
self.ssh.ask("echo " + state + " > /sys/class/gpio/gpio" +
|
269
|
|
str(gpiopin) + "/value")
|
270
|
0
|
sleep(self.parameters['delay'])
|
271
|
|
|
272
|
3
|
def update_fpga(self, filename=None):
|
273
|
0
|
if filename is None:
|
274
|
0
|
try:
|
275
|
0
|
source = self.parameters['filename']
|
276
|
0
|
except KeyError:
|
277
|
0
|
source = None
|
278
|
0
|
self.end()
|
279
|
0
|
sleep(self.parameters['delay'])
|
280
|
0
|
self.ssh.ask('rw')
|
281
|
0
|
sleep(self.parameters['delay'])
|
282
|
0
|
self.ssh.ask('mkdir ' + self.parameters['serverdirname'])
|
283
|
0
|
sleep(self.parameters['delay'])
|
284
|
0
|
if source is None or not os.path.isfile(source):
|
285
|
0
|
if source is not None:
|
286
|
0
|
self.logger.warning('Desired bitfile "%s" does not exist. Using default file.',
|
287
|
|
source)
|
288
|
0
|
source = os.path.join(os.path.abspath(os.path.dirname(__file__)), 'fpga', 'red_pitaya.bin')
|
289
|
0
|
if not os.path.isfile(source):
|
290
|
0
|
raise IOError("Wrong filename",
|
291
|
|
"The fpga bitfile was not found at the expected location. Try passing the arguments "
|
292
|
|
"dirname=\"c://github//pyrpl//pyrpl//\" adapted to your installation directory of pyrpl "
|
293
|
|
"and filename=\"red_pitaya.bin\"! Current dirname: "
|
294
|
|
+ self.parameters['dirname'] +
|
295
|
|
" current filename: "+self.parameters['filename'])
|
296
|
0
|
for i in range(3):
|
297
|
0
|
try:
|
298
|
0
|
self.ssh.scp.put(source,
|
299
|
|
os.path.join(self.parameters['serverdirname'],
|
300
|
|
self.parameters['serverbinfilename']))
|
301
|
0
|
except (SCPException, SSHException):
|
302
|
|
# try again before failing
|
303
|
0
|
self.start_ssh()
|
304
|
0
|
sleep(self.parameters['delay'])
|
305
|
|
else:
|
306
|
0
|
break
|
307
|
|
# kill all other servers to prevent reading while fpga is flashed
|
308
|
0
|
self.end()
|
309
|
0
|
self.ssh.ask('killall nginx')
|
310
|
0
|
self.ssh.ask('systemctl stop redpitaya_nginx') # for 0.94 and higher
|
311
|
0
|
self.ssh.ask('cat '
|
312
|
|
+ os.path.join(self.parameters['serverdirname'], self.parameters['serverbinfilename'])
|
313
|
|
+ ' > //dev//xdevcfg')
|
314
|
0
|
sleep(self.parameters['delay'])
|
315
|
0
|
self.ssh.ask('rm -f '+ os.path.join(self.parameters['serverdirname'], self.parameters['serverbinfilename']))
|
316
|
0
|
self.ssh.ask("nginx -p //opt//www//")
|
317
|
0
|
self.ssh.ask('systemctl start redpitaya_nginx') # for 0.94 and higher #needs test
|
318
|
0
|
sleep(self.parameters['delay'])
|
319
|
0
|
self.ssh.ask('ro')
|
320
|
|
|
321
|
3
|
def fpgarecentlyflashed(self):
|
322
|
0
|
self.ssh.ask()
|
323
|
0
|
result =self.ssh.ask("echo $(($(date +%s) - $(date +%s -r \""
|
324
|
|
+ os.path.join(self.parameters['serverdirname'], self.parameters['serverbinfilename']) +"\")))")
|
325
|
0
|
age = None
|
326
|
0
|
for line in result.split('\n'):
|
327
|
0
|
try:
|
328
|
0
|
age = int(line.strip())
|
329
|
0
|
except:
|
330
|
0
|
pass
|
331
|
|
else:
|
332
|
0
|
break
|
333
|
0
|
if not age:
|
334
|
0
|
self.logger.debug("Could not retrieve bitfile age from: %s",
|
335
|
|
result)
|
336
|
0
|
return False
|
337
|
0
|
elif age > 10:
|
338
|
0
|
self.logger.debug("Found expired bitfile. Age: %s", age)
|
339
|
0
|
return False
|
340
|
|
else:
|
341
|
0
|
self.logger.debug("Found recent bitfile. Age: %s", age)
|
342
|
0
|
return True
|
343
|
|
|
344
|
3
|
def installserver(self):
|
345
|
0
|
self.endserver()
|
346
|
0
|
sleep(self.parameters['delay'])
|
347
|
0
|
self.ssh.ask('rw')
|
348
|
0
|
sleep(self.parameters['delay'])
|
349
|
0
|
self.ssh.ask('mkdir ' + self.parameters['serverdirname'])
|
350
|
0
|
sleep(self.parameters['delay'])
|
351
|
0
|
self.ssh.ask("cd " + self.parameters['serverdirname'])
|
352
|
|
#try both versions
|
353
|
0
|
for serverfile in ['monitor_server','monitor_server_0.95']:
|
354
|
0
|
sleep(self.parameters['delay'])
|
355
|
0
|
try:
|
356
|
0
|
self.ssh.scp.put(
|
357
|
|
os.path.join(os.path.abspath(os.path.dirname(__file__)), 'monitor_server', serverfile),
|
358
|
|
self.parameters['serverdirname'] + self.parameters['monitor_server_name'])
|
359
|
0
|
except (SCPException, SSHException):
|
360
|
0
|
self.logger.exception("Upload error. Try again after rebooting your RedPitaya..")
|
361
|
0
|
sleep(self.parameters['delay'])
|
362
|
0
|
self.ssh.ask('chmod 755 ./'+self.parameters['monitor_server_name'])
|
363
|
0
|
sleep(self.parameters['delay'])
|
364
|
0
|
self.ssh.ask('ro')
|
365
|
0
|
result = self.ssh.ask("./"+self.parameters['monitor_server_name']+" "+ str(self.parameters['port']))
|
366
|
0
|
sleep(self.parameters['delay'])
|
367
|
0
|
result += self.ssh.ask()
|
368
|
0
|
if not "sh" in result:
|
369
|
0
|
self.logger.debug("Server application started on port %d",
|
370
|
|
self.parameters['port'])
|
371
|
0
|
return self.parameters['port']
|
372
|
|
else: # means we tried the wrong binary version. make sure server is not running and try again with next file
|
373
|
0
|
self.endserver()
|
374
|
|
|
375
|
|
#try once more on a different port
|
376
|
0
|
if self.parameters['port'] == self.parameters['defaultport']:
|
377
|
0
|
self.parameters['port'] = random.randint(self.parameters['defaultport'],50000)
|
378
|
0
|
self.logger.warning("Problems to start the server application. Trying again with a different port number %d",self.parameters['port'])
|
379
|
0
|
return self.installserver()
|
380
|
|
|
381
|
0
|
self.logger.error("Server application could not be started. Try to recompile monitor_server on your RedPitaya (see manual). ")
|
382
|
0
|
return None
|
383
|
|
|
384
|
3
|
def startserver(self):
|
385
|
0
|
self.endserver()
|
386
|
0
|
sleep(self.parameters['delay'])
|
387
|
0
|
if self.fpgarecentlyflashed():
|
388
|
0
|
self.logger.info("FPGA is being flashed. Please wait for 2 "
|
389
|
|
"seconds.")
|
390
|
0
|
sleep(2.0)
|
391
|
0
|
result = self.ssh.ask(self.parameters['serverdirname']+"/"+self.parameters['monitor_server_name']
|
392
|
|
+" "+ str(self.parameters['port']))
|
393
|
0
|
if not "sh" in result: # sh in result means we tried the wrong binary version
|
394
|
0
|
self.logger.debug("Server application started on port %d",
|
395
|
|
self.parameters['port'])
|
396
|
0
|
self._serverrunning = True
|
397
|
0
|
return self.parameters['port']
|
398
|
|
#something went wrong
|
399
|
0
|
return self.installserver()
|
400
|
|
|
401
|
3
|
def endserver(self):
|
402
|
0
|
try:
|
403
|
0
|
self.ssh.ask('\x03') #exit running server application
|
404
|
0
|
except:
|
405
|
0
|
self.logger.exception("Server not responding...")
|
406
|
0
|
if 'pitaya' in self.ssh.ask():
|
407
|
0
|
self.logger.debug('>') # formerly 'console ready'
|
408
|
0
|
sleep(self.parameters['delay'])
|
409
|
|
# make sure no other monitor_server blocks the port
|
410
|
0
|
self.ssh.ask('killall ' + self.parameters['monitor_server_name'])
|
411
|
0
|
self._serverrunning = False
|
412
|
|
|
413
|
3
|
def endclient(self):
|
414
|
0
|
del self.client
|
415
|
0
|
self.client = None
|
416
|
|
|
417
|
3
|
def start(self):
|
418
|
0
|
if self.parameters['leds_off']:
|
419
|
0
|
self.switch_led(gpiopin=0, state=False)
|
420
|
0
|
self.switch_led(gpiopin=7, state=False)
|
421
|
0
|
self.startserver()
|
422
|
0
|
sleep(self.parameters['delay'])
|
423
|
0
|
self.startclient()
|
424
|
|
|
425
|
3
|
def end(self):
|
426
|
0
|
self.endserver()
|
427
|
0
|
self.endclient()
|
428
|
|
|
429
|
3
|
def end_ssh(self):
|
430
|
3
|
self.ssh.channel.close()
|
431
|
|
|
432
|
3
|
def end_all(self):
|
433
|
0
|
self.end()
|
434
|
0
|
self.end_ssh()
|
435
|
|
|
436
|
3
|
def restart(self):
|
437
|
0
|
self.end()
|
438
|
0
|
self.start()
|
439
|
|
|
440
|
3
|
def restartserver(self, port=None):
|
441
|
|
"""restart the server. usually executed when client encounters an error"""
|
442
|
0
|
if port is not None:
|
443
|
0
|
if port < 0: #code to try a random port
|
444
|
0
|
self.parameters['port'] = random.randint(2223,50000)
|
445
|
|
else:
|
446
|
0
|
self.parameters['port'] = port
|
447
|
0
|
return self.startserver()
|
448
|
|
|
449
|
3
|
def license(self):
|
450
|
0
|
self.logger.info("""\r\n pyrpl Copyright (C) 2014-2017 Leonhard Neuhaus
|
451
|
|
This program comes with ABSOLUTELY NO WARRANTY; for details read the file
|
452
|
|
"LICENSE" in the source directory. This is free software, and you are
|
453
|
|
welcome to redistribute it under certain conditions; read the file
|
454
|
|
"LICENSE" in the source directory for details.\r\n""")
|
455
|
|
|
456
|
3
|
def startclient(self):
|
457
|
0
|
self.client = redpitaya_client.MonitorClient(
|
458
|
|
self.parameters['hostname'], self.parameters['port'], restartserver=self.restartserver)
|
459
|
0
|
self.makemodules()
|
460
|
0
|
self.logger.debug("Client started successfully. ")
|
461
|
|
|
462
|
3
|
def startdummyclient(self):
|
463
|
0
|
self.client = redpitaya_client.DummyClient()
|
464
|
0
|
self.makemodules()
|
465
|
|
|
466
|
3
|
def makemodule(self, name, cls):
|
467
|
0
|
module = cls(self, name)
|
468
|
0
|
setattr(self, name, module)
|
469
|
0
|
self.modules[name] = module
|
470
|
|
|
471
|
3
|
def makemodules(self):
|
472
|
|
"""
|
473
|
|
Automatically generates modules from the list RedPitaya.cls_modules
|
474
|
|
"""
|
475
|
0
|
names = get_unique_name_list_from_class_list(self.cls_modules)
|
476
|
0
|
for cls, name in zip(self.cls_modules, names):
|
477
|
0
|
self.makemodule(name, cls)
|
478
|
|
|
479
|
3
|
def make_a_slave(self, port=None, monitor_server_name=None, gui=False):
|
480
|
0
|
if port is None:
|
481
|
0
|
port = self.parameters['port'] + len(self._slaves)*10 + 1
|
482
|
0
|
if monitor_server_name is None:
|
483
|
0
|
monitor_server_name = self.parameters['monitor_server_name'] + str(port)
|
484
|
0
|
slaveparameters = dict(self.parameters)
|
485
|
0
|
slaveparameters.update(dict(
|
486
|
|
port=port,
|
487
|
|
autostart=True,
|
488
|
|
reloadfpga=False,
|
489
|
|
reloadserver=False,
|
490
|
|
monitor_server_name=monitor_server_name,
|
491
|
|
silence_env=True))
|
492
|
0
|
r = RedPitaya(**slaveparameters) #gui=gui)
|
493
|
0
|
r._master = self
|
494
|
0
|
self._slaves.append(r)
|
495
|
0
|
return r
|