##// END OF EJS Templates
Update RC control methods, add change_ip for RC, fix win_reference for sub-baudio...
Juan C. Espinoza -
r236:7c5422f0dc5b
parent child
Show More
@@ -1,734 +1,751
1 1
2 import requests
2 3 from datetime import datetime
3 4 from django.template.base import kwarg_re
4 5
5 6 try:
6 7 from polymorphic.models import PolymorphicModel
7 8 except:
8 9 from polymorphic import PolymorphicModel
9 10
10 11 from django.db import models
11 12 from django.core.urlresolvers import reverse
12 13 from django.shortcuts import get_object_or_404
13 14
14 15 from devices.dds import api as dds_api
15 16
16 17 EXP_STATES = (
17 18 (0,'Error'), #RED
18 19 (1,'Configured'), #BLUE
19 20 (2,'Running'), #GREEN
20 21 (3,'Scheduled'), #YELLOW
21 22 (4,'Not Configured'), #WHITE
22 23 )
23 24
24 25 CONF_TYPES = (
25 26 (0, 'Active'),
26 27 (1, 'Historical'),
27 28 )
28 29
29 30 DEV_STATES = (
30 31 (0, 'No connected'),
31 32 (1, 'Connected'),
32 33 (2, 'Configured'),
33 34 (3, 'Running'),
34 35 (4, 'Unknown'),
35 36 )
36 37
37 38 DEV_TYPES = (
38 39 ('', 'Select a device type'),
39 40 ('rc', 'Radar Controller'),
40 41 ('dds', 'Direct Digital Synthesizer'),
41 42 ('jars', 'Jicamarca Radar Acquisition System'),
42 43 ('usrp', 'Universal Software Radio Peripheral'),
43 44 ('cgs', 'Clock Generator System'),
44 45 ('abs', 'Automatic Beam Switching'),
45 46 )
46 47
47 48 DEV_PORTS = {
48 49 'rc' : 2000,
49 50 'dds' : 2000,
50 51 'jars' : 2000,
51 52 'usrp' : 2000,
52 53 'cgs' : 8080,
53 54 'abs' : 8080
54 55 }
55 56
56 57 RADAR_STATES = (
57 58 (0, 'No connected'),
58 59 (1, 'Connected'),
59 60 (2, 'Configured'),
60 61 (3, 'Running'),
61 62 (4, 'Scheduled'),
62 63 )
63 64
64 65
65 66 class Location(models.Model):
66 67
67 68 name = models.CharField(max_length = 30)
68 69 description = models.TextField(blank=True, null=True)
69 70
70 71 class Meta:
71 72 db_table = 'db_location'
72 73
73 74 def __str__(self):
74 75 return u'%s' % self.name
75 76
76 77 def get_absolute_url(self):
77 78 return reverse('url_location', args=[str(self.id)])
78 79
79 80
80 81 class DeviceType(models.Model):
81 82
82 83 name = models.CharField(max_length = 10, choices = DEV_TYPES, default = 'rc')
83 84 sequence = models.PositiveSmallIntegerField(default=1000)
84 85 description = models.TextField(blank=True, null=True)
85 86
86 87 class Meta:
87 88 db_table = 'db_device_types'
88 89
89 90 def __str__(self):
90 91 return u'%s' % self.get_name_display()
91 92
92 93 class Device(models.Model):
93 94
94 95 device_type = models.ForeignKey(DeviceType, on_delete=models.CASCADE)
95 96 location = models.ForeignKey(Location, on_delete=models.CASCADE)
96 97
97 98 name = models.CharField(max_length=40, default='')
98 99 ip_address = models.GenericIPAddressField(protocol='IPv4', default='0.0.0.0')
99 100 port_address = models.PositiveSmallIntegerField(default=2000)
100 101 description = models.TextField(blank=True, null=True)
101 102 status = models.PositiveSmallIntegerField(default=0, choices=DEV_STATES)
102 103
103 104 class Meta:
104 105 db_table = 'db_devices'
105 106
106 107 def __str__(self):
107 108 return u'[{}]: {}'.format(self.device_type.name.upper(),
108 109 self.name)
109 110
110 111 def get_status(self):
111 112 return self.status
112 113
113 114 @property
114 115 def status_color(self):
115 116 color = 'muted'
116 117 if self.status == 0:
117 118 color = "danger"
118 119 elif self.status == 1:
119 120 color = "warning"
120 121 elif self.status == 2:
121 122 color = "info"
122 123 elif self.status == 3:
123 124 color = "success"
124 125
125 126 return color
126 127
127 128 def url(self, path=None):
128 129
129 130 if path:
130 131 return 'http://{}:{}/{}/'.format(self.ip_address, self.port_address, path)
131 132 else:
132 133 return 'http://{}:{}/'.format(self.ip_address, self.port_address)
133 134
134 135 def get_absolute_url(self):
135 136
136 137 return reverse('url_device', args=[str(self.id)])
137 138
138 139 def change_ip(self, ip_address, mask, gateway, **kwargs):
139 140
140 141 if self.device_type.name=='dds':
141 try:
142 #if True:
142 try:
143 143 answer = dds_api.change_ip(ip = self.ip_address,
144 144 port = self.port_address,
145 145 new_ip = ip_address,
146 146 mask = mask,
147 147 gateway = gateway)
148 148 if answer[0]=='1':
149 self.message = 'DDS - {}'.format(answer)
149 self.message = '25|DDS - {}'.format(answer)
150 150 self.ip_address = ip_address
151 151 self.save()
152 152 else:
153 self.message = 'DDS - {}'.format(answer)
153 self.message = '30|DDS - {}'.format(answer)
154 154 return False
155 155 except Exception as e:
156 self.message = str(e)
156 self.message = '40|{}'.format(str(e))
157 157 return False
158
159 elif self.device_type.name=='rc':
160 payload = {'ip': ip_address,
161 'dns': kwargs.get('dns', '8.8.8.8'),
162 'gateway': gateway,
163 'subnet': mask}
164 req = requests.post(self.url('changeip'), data=payload)
165 try:
166 answer = req.json()
167 if answer['changeip']=='ok':
168 self.message = '25|IP succesfully changed'
169 self.ip_address = ip_address
170 self.save()
171 else:
172 self.message = '30|An error ocuur when changing IP'
173 except Exception as e:
174 self.message = '40|{}'.format(str(e))
158 175 else:
159 176 self.message = 'Not implemented'
160 177 return False
161 178
162 179 return True
163 180
164 181
165 182 class Campaign(models.Model):
166 183
167 184 template = models.BooleanField(default=False)
168 185 name = models.CharField(max_length=60, unique=True)
169 186 start_date = models.DateTimeField(blank=True, null=True)
170 187 end_date = models.DateTimeField(blank=True, null=True)
171 188 tags = models.CharField(max_length=40)
172 189 description = models.TextField(blank=True, null=True)
173 190 experiments = models.ManyToManyField('Experiment', blank=True)
174 191
175 192 class Meta:
176 193 db_table = 'db_campaigns'
177 194 ordering = ('name',)
178 195
179 196 def __str__(self):
180 197 if self.template:
181 198 return u'{} (template)'.format(self.name)
182 199 else:
183 200 return u'{}'.format(self.name)
184 201
185 202 def parms_to_dict(self):
186 203
187 204 import json
188 205
189 206 parameters = {}
190 207 exp_parameters = {}
191 208 experiments = Experiment.objects.filter(campaign = self)
192 209
193 210 i=1
194 211 for experiment in experiments:
195 212 exp_parameters['experiment-'+str(i)] = json.loads(experiment.parms_to_dict())
196 213 i += 1
197 214
198 215
199 216 parameters['experiments'] = exp_parameters
200 217 parameters['end_date'] = self.end_date.strftime("%Y-%m-%d")
201 218 parameters['start_date'] = self.start_date.strftime("%Y-%m-%d")
202 219 parameters['campaign'] = self.__str__()
203 220 parameters['tags'] =self.tags
204 221
205 222 parameters = json.dumps(parameters, indent=2, sort_keys=False)
206 223
207 224 return parameters
208 225
209 226 def import_from_file(self, fp):
210 227
211 228 import os, json
212 229
213 230 parms = {}
214 231
215 232 path, ext = os.path.splitext(fp.name)
216 233
217 234 if ext == '.json':
218 235 parms = json.loads(fp.read())
219 236
220 237 return parms
221 238
222 239 def dict_to_parms(self, parms, CONF_MODELS):
223 240
224 241 experiments = Experiment.objects.filter(campaign = self)
225 242 configurations = Configuration.objects.filter(experiment = experiments)
226 243
227 244 if configurations:
228 245 for configuration in configurations:
229 246 configuration.delete()
230 247
231 248 if experiments:
232 249 for experiment in experiments:
233 250 experiment.delete()
234 251
235 252 for parms_exp in parms['experiments']:
236 253 location = Location.objects.get(name = parms['experiments'][parms_exp]['radar'])
237 254 new_exp = Experiment(
238 255 name = parms['experiments'][parms_exp]['experiment'],
239 256 location = location,
240 257 start_time = parms['experiments'][parms_exp]['start_time'],
241 258 end_time = parms['experiments'][parms_exp]['end_time'],
242 259 )
243 260 new_exp.save()
244 261 new_exp.dict_to_parms(parms['experiments'][parms_exp],CONF_MODELS)
245 262 new_exp.save()
246 263
247 264 self.name = parms['campaign']
248 265 self.start_date = parms['start_date']
249 266 self.end_date = parms['end_date']
250 267 self.tags = parms['tags']
251 268 self.experiments.add(new_exp)
252 269 self.save()
253 270
254 271 return self
255 272
256 273 def get_experiments_by_radar(self, radar=None):
257 274
258 275 ret = []
259 276 if radar:
260 277 locations = Location.objects.filter(pk=radar)
261 278 else:
262 279 locations = set([e.location for e in self.experiments.all()])
263 280
264 281 for loc in locations:
265 282 dum = {}
266 283 dum['name'] = loc.name
267 284 dum['id'] = loc.pk
268 285 dum['experiments'] = [e for e in self.experiments.all() if e.location==loc]
269 286 ret.append(dum)
270 287
271 288 return ret
272 289
273 290 def get_absolute_url(self):
274 291 return reverse('url_campaign', args=[str(self.id)])
275 292
276 293 def get_absolute_url_edit(self):
277 294 return reverse('url_edit_campaign', args=[str(self.id)])
278 295
279 296 def get_absolute_url_export(self):
280 297 return reverse('url_export_campaign', args=[str(self.id)])
281 298
282 299 def get_absolute_url_import(self):
283 300 return reverse('url_import_campaign', args=[str(self.id)])
284 301
285 302
286 303
287 304 class RunningExperiment(models.Model):
288 305 radar = models.OneToOneField('Location', on_delete=models.CASCADE)
289 306 running_experiment = models.ManyToManyField('Experiment', blank = True)
290 307 status = models.PositiveSmallIntegerField(default=0, choices=RADAR_STATES)
291 308
292 309
293 310 class Experiment(models.Model):
294 311
295 312 template = models.BooleanField(default=False)
296 313 name = models.CharField(max_length=40, default='', unique=True)
297 314 location = models.ForeignKey('Location', null=True, blank=True, on_delete=models.CASCADE)
298 315 start_time = models.TimeField(default='00:00:00')
299 316 end_time = models.TimeField(default='23:59:59')
300 317 status = models.PositiveSmallIntegerField(default=4, choices=EXP_STATES)
301 318
302 319 class Meta:
303 320 db_table = 'db_experiments'
304 321 ordering = ('template', 'name')
305 322
306 323 def __str__(self):
307 324 if self.template:
308 325 return u'%s (template)' % (self.name)
309 326 else:
310 327 return u'%s' % (self.name)
311 328
312 329 @property
313 330 def radar_system(self):
314 331 return self.location
315 332
316 333 def clone(self, **kwargs):
317 334
318 335 confs = Configuration.objects.filter(experiment=self, type=0)
319 336 self.pk = None
320 337 self.name = '{} [{:%Y/%m/%d}]'.format(self.name, datetime.now())
321 338 for attr, value in kwargs.items():
322 339 setattr(self, attr, value)
323 340
324 341 self.save()
325 342
326 343 for conf in confs:
327 344 conf.clone(experiment=self, template=False)
328 345
329 346 return self
330 347
331 348 def start(self):
332 349 '''
333 350 Configure and start experiments's devices
334 351 '''
335 352
336 353 result = 2
337 354
338 355 confs = Configuration.objects.filter(experiment=self).order_by('device__device_type__sequence')
339 356 for i in range(0,len(confs)): #ABS-CGS-DDS-RC-JARS
340 357 if i==0:
341 358 for conf in confs:
342 359 if conf.device.device_type.name == 'abs':
343 360 conf.start_device()
344 361 break
345 362 if i==1:
346 363 for conf in confs:
347 364 if conf.device.device_type.name == 'cgs':
348 365 conf.start_device()
349 366 break
350 367 if i==2:
351 368 for conf in confs:
352 369 if conf.device.device_type.name == 'dds':
353 370 conf.start_device()
354 371 break
355 372 if i==3:
356 373 for conf in confs:
357 374 if conf.device.device_type.name == 'rc':
358 375 conf.start_device()
359 376 break
360 377 if i==4:
361 378 for conf in confs:
362 379 if conf.device.device_type.name == 'jars':
363 380 conf.start_device()
364 381 break
365 382 #if conf.start_device():
366 383 # result &= 2
367 384 #else:
368 385 # result &= 0
369 386 else:
370 387 result &= 0
371 388
372 389 return result
373 390
374 391 def stop(self):
375 392 '''
376 393 Stop experiments's devices
377 394 '''
378 395
379 396 result = 1
380 397
381 398 confs = Configuration.objects.filter(experiment=self).order_by('-device__device_type__sequence')
382 399 for i in range(0,len(confs)):
383 400 if i==0:
384 401 for conf in confs:
385 402 if conf.device.device_type.name == 'abs':
386 403 conf.stop_device()
387 404 break
388 405 if i==1:
389 406 for conf in confs:
390 407 if conf.device.device_type.name == 'jars':
391 408 conf.stop_device()
392 409 break
393 410 if i==2:
394 411 for conf in confs:
395 412 if conf.device.device_type.name == 'dds':
396 413 conf.stop_device()
397 414 break
398 415 if i==3:
399 416 for conf in confs:
400 417 if conf.device.device_type.name == 'cgs':
401 418 conf.stop_device()
402 419 break
403 420 if i==4:
404 421 for conf in confs:
405 422 if conf.device.device_type.name == 'rc':
406 423 conf.stop_device()
407 424 break
408 425 #result &= 1
409 426 else:
410 427 result &= 0
411 428
412 429 return result
413 430
414 431 def get_status(self):
415 432
416 433 confs = Configuration.objects.filter(experiment=self)
417 434
418 435 total = confs.aggregate(models.Sum('device__status'))['device__status__sum']
419 436
420 437 if total==2*confs.count():
421 438 status = 1
422 439 elif total == 3*confs.count():
423 440 status = 2
424 441 else:
425 442 status = 0
426 443
427 444 if self.status<>3:
428 445 self.status = status
429 446 self.save()
430 447
431 448 def status_color(self):
432 449 color = 'muted'
433 450 if self.status == 0:
434 451 color = "danger"
435 452 elif self.status == 1:
436 453 color = "info"
437 454 elif self.status == 2:
438 455 color = "success"
439 456 elif self.status == 3:
440 457 color = "warning"
441 458
442 459 return color
443 460
444 461 def parms_to_dict(self):
445 462
446 463 import json
447 464
448 465 configurations = Configuration.objects.filter(experiment=self)
449 466 conf_parameters = {}
450 467 parameters={}
451 468
452 469 for configuration in configurations:
453 470 if 'cgs' in configuration.device.device_type.name:
454 471 conf_parameters['cgs'] = configuration.parms_to_dict()
455 472 if 'dds' in configuration.device.device_type.name:
456 473 conf_parameters['dds'] = configuration.parms_to_dict()
457 474 if 'rc' in configuration.device.device_type.name:
458 475 conf_parameters['rc'] = configuration.parms_to_dict()
459 476 if 'jars' in configuration.device.device_type.name:
460 477 conf_parameters['jars'] = configuration.parms_to_dict()
461 478 if 'usrp' in configuration.device.device_type.name:
462 479 conf_parameters['usrp'] = configuration.parms_to_dict()
463 480 if 'abs' in configuration.device.device_type.name:
464 481 conf_parameters['abs'] = configuration.parms_to_dict()
465 482
466 483 parameters['configurations'] = conf_parameters
467 484 parameters['end_time'] = self.end_time.strftime("%H:%M:%S")
468 485 parameters['start_time'] = self.start_time.strftime("%H:%M:%S")
469 486 parameters['radar'] = self.radar_system.name
470 487 parameters['experiment'] = self.name
471 488 parameters = json.dumps(parameters, indent=2)
472 489
473 490 return parameters
474 491
475 492 def import_from_file(self, fp):
476 493
477 494 import os, json
478 495
479 496 parms = {}
480 497
481 498 path, ext = os.path.splitext(fp.name)
482 499
483 500 if ext == '.json':
484 501 parms = json.loads(fp.read().decode('utf-8'))
485 502
486 503 return parms
487 504
488 505 def dict_to_parms(self, parms, CONF_MODELS):
489 506
490 507 configurations = Configuration.objects.filter(experiment=self)
491 508
492 509 if configurations:
493 510 for configuration in configurations:
494 511 configuration.delete()
495 512
496 513 for conf_type in parms['configurations']:
497 514 #--For ABS Device:
498 515 #--For USRP Device:
499 516 #--For JARS Device:
500 517 if conf_type == 'jars':
501 518 device = get_object_or_404(Device, pk=parms['configurations']['jars']['device_id'])
502 519 DevConfModel = CONF_MODELS[conf_type]
503 520 confjars_form = DevConfModel(
504 521 experiment = self,
505 522 name = 'JARS',
506 523 device=device,
507 524 )
508 525 confjars_form.dict_to_parms(parms['configurations']['jars'])
509 526 confjars_form.save()
510 527 #--For RC Device:
511 528 if conf_type == 'rc':
512 529 device = get_object_or_404(Device, pk=parms['configurations']['rc']['device_id'])
513 530 DevConfModel = CONF_MODELS[conf_type]
514 531 confrc_form = DevConfModel(
515 532 experiment = self,
516 533 name = 'RC',
517 534 device=device,
518 535 )
519 536 confrc_form.dict_to_parms(parms['configurations']['rc'])
520 537 confrc_form.save()
521 538 #--For DDS Device:
522 539 if conf_type == 'dds':
523 540 device = get_object_or_404(Device, pk=parms['configurations']['dds']['device_id'])
524 541 DevConfModel = CONF_MODELS[conf_type]
525 542 confdds_form = DevConfModel(
526 543 experiment = self,
527 544 name = 'DDS',
528 545 device=device,
529 546 )
530 547 confdds_form.dict_to_parms(parms['configurations']['dds'])
531 548 confdds_form.save()
532 549 #--For CGS Device:
533 550 if conf_type == 'cgs':
534 551 device = get_object_or_404(Device, pk=parms['configurations']['cgs']['device_id'])
535 552 DevConfModel = CONF_MODELS[conf_type]
536 553 confcgs_form = DevConfModel(
537 554 experiment = self,
538 555 name = 'CGS',
539 556 device=device,
540 557 )
541 558 confcgs_form.dict_to_parms(parms['configurations']['cgs'])
542 559 confcgs_form.save()
543 560
544 561 location = Location.objects.get(name = parms['radar'])
545 562 self.name = parms['experiment']
546 563 self.location = location
547 564 self.start_time = parms['start_time']
548 565 self.end_time = parms['end_time']
549 566 self.save()
550 567
551 568 return self
552 569
553 570 def get_absolute_url(self):
554 571 return reverse('url_experiment', args=[str(self.id)])
555 572
556 573 def get_absolute_url_edit(self):
557 574 return reverse('url_edit_experiment', args=[str(self.id)])
558 575
559 576 def get_absolute_url_import(self):
560 577 return reverse('url_import_experiment', args=[str(self.id)])
561 578
562 579 def get_absolute_url_export(self):
563 580 return reverse('url_export_experiment', args=[str(self.id)])
564 581
565 582
566 583 class Configuration(PolymorphicModel):
567 584
568 585 template = models.BooleanField(default=False)
569 586
570 587 name = models.CharField(verbose_name="Configuration Name", max_length=40, default='')
571 588
572 589 experiment = models.ForeignKey('Experiment', verbose_name='Experiment', null=True, blank=True, on_delete=models.CASCADE)
573 590 device = models.ForeignKey('Device', verbose_name='Device', null=True, on_delete=models.CASCADE)
574 591
575 592 type = models.PositiveSmallIntegerField(default=0, choices=CONF_TYPES)
576 593
577 594 created_date = models.DateTimeField(auto_now_add=True)
578 595 programmed_date = models.DateTimeField(auto_now=True)
579 596
580 597 parameters = models.TextField(default='{}')
581 598
582 599 message = ""
583 600
584 601 class Meta:
585 602 db_table = 'db_configurations'
586 603
587 604 def __str__(self):
588 605
589 606 device = '{}:'.format(self.device.device_type.name.upper())
590 607
591 608 if 'mix' in [f.name for f in self._meta.get_fields()]:
592 609 if self.mix:
593 610 device = '{} MIXED:'.format(self.device.device_type.name.upper())
594 611
595 612 if self.template:
596 613 return u'{} {} (template)'.format(device, self.name)
597 614 else:
598 615 return u'{} {}'.format(device, self.name)
599 616
600 617 def clone(self, **kwargs):
601 618
602 619 self.pk = None
603 620 self.id = None
604 621 for attr, value in kwargs.items():
605 622 setattr(self, attr, value)
606 623
607 624 self.save()
608 625
609 626 return self
610 627
611 628 def parms_to_dict(self):
612 629
613 630 parameters = {}
614 631
615 632 for key in self.__dict__.keys():
616 633 parameters[key] = getattr(self, key)
617 634
618 635 return parameters
619 636
620 637 def parms_to_text(self):
621 638
622 639 raise NotImplementedError("This method should be implemented in %s Configuration model" %str(self.device.device_type.name).upper())
623 640
624 641
625 642 def parms_to_binary(self):
626 643
627 644 raise NotImplementedError("This method should be implemented in %s Configuration model" %str(self.device.device_type.name).upper())
628 645
629 646
630 647 def dict_to_parms(self, parameters):
631 648
632 649 if type(parameters) != type({}):
633 650 return
634 651
635 652 for key in parameters.keys():
636 653 setattr(self, key, parameters[key])
637 654
638 655 def export_to_file(self, format="json"):
639 656
640 657 import json
641 658
642 659 content_type = ''
643 660
644 661 if format == 'text':
645 662 content_type = 'text/plain'
646 663 filename = '%s_%s.%s' %(self.device.device_type.name, self.name, self.device.device_type.name)
647 664 content = self.parms_to_text()
648 665
649 666 if format == 'binary':
650 667 content_type = 'application/octet-stream'
651 668 filename = '%s_%s.bin' %(self.device.device_type.name, self.name)
652 669 content = self.parms_to_binary()
653 670
654 671 if not content_type:
655 672 content_type = 'application/json'
656 673 filename = '%s_%s.json' %(self.device.device_type.name, self.name)
657 674 content = json.dumps(self.parms_to_dict(), indent=2)
658 675
659 676 fields = {'content_type':content_type,
660 677 'filename':filename,
661 678 'content':content
662 679 }
663 680
664 681 return fields
665 682
666 683 def import_from_file(self, fp):
667 684
668 685 import os, json
669 686
670 687 parms = {}
671 688
672 689 path, ext = os.path.splitext(fp.name)
673 690
674 691 if ext == '.json':
675 692 parms = json.load(fp)
676 693
677 694 return parms
678 695
679 696 def status_device(self):
680 697
681 698 self.message = 'Function not implemented'
682 699 return False
683 700
684 701
685 702 def stop_device(self):
686 703
687 704 self.message = 'Function not implemented'
688 705 return False
689 706
690 707
691 708 def start_device(self):
692 709
693 710 self.message = 'Function not implemented'
694 711 return False
695 712
696 713
697 714 def write_device(self, parms):
698 715
699 716 self.message = 'Function not implemented'
700 717 return False
701 718
702 719
703 720 def read_device(self):
704 721
705 722 self.message = 'Function not implemented'
706 723 return False
707 724
708 725
709 726 def get_absolute_url(self):
710 727 return reverse('url_%s_conf' % self.device.device_type.name, args=[str(self.id)])
711 728
712 729 def get_absolute_url_edit(self):
713 730 return reverse('url_edit_%s_conf' % self.device.device_type.name, args=[str(self.id)])
714 731
715 732 def get_absolute_url_import(self):
716 733 return reverse('url_import_dev_conf', args=[str(self.id)])
717 734
718 735 def get_absolute_url_export(self):
719 736 return reverse('url_export_dev_conf', args=[str(self.id)])
720 737
721 738 def get_absolute_url_write(self):
722 739 return reverse('url_write_dev_conf', args=[str(self.id)])
723 740
724 741 def get_absolute_url_read(self):
725 742 return reverse('url_read_dev_conf', args=[str(self.id)])
726 743
727 744 def get_absolute_url_start(self):
728 745 return reverse('url_start_dev_conf', args=[str(self.id)])
729 746
730 747 def get_absolute_url_stop(self):
731 748 return reverse('url_stop_dev_conf', args=[str(self.id)])
732 749
733 750 def get_absolute_url_status(self):
734 751 return reverse('url_status_dev_conf', args=[str(self.id)])
@@ -1,1664 +1,1665
1 1 from datetime import datetime
2 2
3 3 from django.shortcuts import render, redirect, get_object_or_404, HttpResponse
4 4 from django.utils.safestring import mark_safe
5 5 from django.http import HttpResponseRedirect
6 6 from django.core.urlresolvers import reverse
7 7 from django.db.models import Q
8 8 from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
9 9 from django.contrib import messages
10 10 from django.http.request import QueryDict
11 11
12 12 try:
13 13 from urllib.parse import urlencode
14 14 except ImportError:
15 15 from urllib import urlencode
16 16
17 17 from .forms import CampaignForm, ExperimentForm, DeviceForm, ConfigurationForm, LocationForm, UploadFileForm, DownloadFileForm, OperationForm, NewForm
18 18 from .forms import OperationSearchForm, FilterForm, ChangeIpForm
19 19
20 20 from .tasks import task_start, task_stop
21 21
22 22 from apps.rc.forms import RCConfigurationForm, RCLineCode
23 23 from apps.dds.forms import DDSConfigurationForm
24 24 from apps.jars.forms import JARSConfigurationForm
25 25 from apps.cgs.forms import CGSConfigurationForm
26 26 from apps.abs.forms import ABSConfigurationForm
27 27 from apps.usrp.forms import USRPConfigurationForm
28 28
29 29 from .models import Campaign, Experiment, Device, Configuration, Location, RunningExperiment
30 30 from apps.cgs.models import CGSConfiguration
31 31 from apps.jars.models import JARSConfiguration, EXPERIMENT_TYPE
32 32 from apps.usrp.models import USRPConfiguration
33 33 from apps.abs.models import ABSConfiguration
34 34 from apps.rc.models import RCConfiguration, RCLine, RCLineType
35 35 from apps.dds.models import DDSConfiguration
36 36
37 37 from django.contrib.auth.decorators import login_required
38 38 from django.contrib.auth.decorators import user_passes_test
39 39 from django.contrib.admin.views.decorators import staff_member_required
40 40
41 41 import ast
42 42
43 43 CONF_FORMS = {
44 44 'rc': RCConfigurationForm,
45 45 'dds': DDSConfigurationForm,
46 46 'jars': JARSConfigurationForm,
47 47 'cgs': CGSConfigurationForm,
48 48 'abs': ABSConfigurationForm,
49 49 'usrp': USRPConfigurationForm,
50 50 }
51 51
52 52 CONF_MODELS = {
53 53 'rc': RCConfiguration,
54 54 'dds': DDSConfiguration,
55 55 'jars': JARSConfiguration,
56 56 'cgs': CGSConfiguration,
57 57 'abs': ABSConfiguration,
58 58 'usrp': USRPConfiguration,
59 59 }
60 60
61 61 MIX_MODES = {
62 62 '0': 'P',
63 63 '1': 'S',
64 64 }
65 65
66 66 MIX_OPERATIONS = {
67 67 '0': 'OR',
68 68 '1': 'XOR',
69 69 '2': 'AND',
70 70 '3': 'NAND',
71 71 }
72 72
73 73 def index(request):
74 74 kwargs = {'no_sidebar':True}
75 75
76 76 return render(request, 'index.html', kwargs)
77 77
78 78
79 79 def locations(request):
80 80
81 81 page = request.GET.get('page')
82 82 order = ('name',)
83 83
84 84 kwargs = get_paginator(Location, page, order)
85 85
86 86 kwargs['keys'] = ['name', 'description']
87 87 kwargs['title'] = 'Radar System'
88 88 kwargs['suptitle'] = 'List'
89 89 kwargs['no_sidebar'] = True
90 90
91 91 return render(request, 'base_list.html', kwargs)
92 92
93 93
94 94 def location(request, id_loc):
95 95
96 96 location = get_object_or_404(Location, pk=id_loc)
97 97
98 98 kwargs = {}
99 99 kwargs['location'] = location
100 100 kwargs['location_keys'] = ['name', 'description']
101 101
102 102 kwargs['title'] = 'Location'
103 103 kwargs['suptitle'] = 'Details'
104 104
105 105 return render(request, 'location.html', kwargs)
106 106
107 107
108 108 @user_passes_test(lambda u:u.is_staff)
109 109 def location_new(request):
110 110
111 111 if request.method == 'GET':
112 112 form = LocationForm()
113 113
114 114 if request.method == 'POST':
115 115 form = LocationForm(request.POST)
116 116
117 117 if form.is_valid():
118 118 form.save()
119 119 return redirect('url_locations')
120 120
121 121 kwargs = {}
122 122 kwargs['form'] = form
123 123 kwargs['title'] = 'Radar System'
124 124 kwargs['suptitle'] = 'New'
125 125 kwargs['button'] = 'Create'
126 126
127 127 return render(request, 'base_edit.html', kwargs)
128 128
129 129
130 130 @user_passes_test(lambda u:u.is_staff)
131 131 def location_edit(request, id_loc):
132 132
133 133 location = get_object_or_404(Location, pk=id_loc)
134 134
135 135 if request.method=='GET':
136 136 form = LocationForm(instance=location)
137 137
138 138 if request.method=='POST':
139 139 form = LocationForm(request.POST, instance=location)
140 140
141 141 if form.is_valid():
142 142 form.save()
143 143 return redirect('url_locations')
144 144
145 145 kwargs = {}
146 146 kwargs['form'] = form
147 147 kwargs['title'] = 'Location'
148 148 kwargs['suptitle'] = 'Edit'
149 149 kwargs['button'] = 'Update'
150 150
151 151 return render(request, 'base_edit.html', kwargs)
152 152
153 153
154 154 @user_passes_test(lambda u:u.is_staff)
155 155 def location_delete(request, id_loc):
156 156
157 157 location = get_object_or_404(Location, pk=id_loc)
158 158
159 159 if request.method=='POST':
160 160
161 161 if request.user.is_staff:
162 162 location.delete()
163 163 return redirect('url_locations')
164 164
165 165 messages.error(request, 'Not enough permission to delete this object')
166 166 return redirect(location.get_absolute_url())
167 167
168 168 kwargs = {
169 169 'title': 'Delete',
170 170 'suptitle': 'Location',
171 171 'object': location,
172 172 'previous': location.get_absolute_url(),
173 173 'delete': True
174 174 }
175 175
176 176 return render(request, 'confirm.html', kwargs)
177 177
178 178
179 179 def devices(request):
180 180
181 181 page = request.GET.get('page')
182 182 order = ('device_type', 'name')
183 183
184 184 kwargs = get_paginator(Device, page, order)
185 185 kwargs['keys'] = ['name', 'ip_address', 'port_address', 'device_type']
186 186 kwargs['title'] = 'Device'
187 187 kwargs['suptitle'] = 'List'
188 188 kwargs['no_sidebar'] = True
189 189
190 190 return render(request, 'base_list.html', kwargs)
191 191
192 192
193 193 def device(request, id_dev):
194 194
195 195 device = get_object_or_404(Device, pk=id_dev)
196 196
197 197 kwargs = {}
198 198 kwargs['device'] = device
199 199 kwargs['device_keys'] = ['device_type', 'name', 'ip_address', 'port_address', 'description']
200 200
201 201 kwargs['title'] = 'Device'
202 202 kwargs['suptitle'] = 'Details'
203 203
204 204 return render(request, 'device.html', kwargs)
205 205
206 206
207 207 @user_passes_test(lambda u:u.is_staff)
208 208 def device_new(request):
209 209
210 210 if request.method == 'GET':
211 211 form = DeviceForm()
212 212
213 213 if request.method == 'POST':
214 214 form = DeviceForm(request.POST)
215 215
216 216 if form.is_valid():
217 217 form.save()
218 218 return redirect('url_devices')
219 219
220 220 kwargs = {}
221 221 kwargs['form'] = form
222 222 kwargs['title'] = 'Device'
223 223 kwargs['suptitle'] = 'New'
224 224 kwargs['button'] = 'Create'
225 225
226 226 return render(request, 'base_edit.html', kwargs)
227 227
228 228
229 229 @user_passes_test(lambda u:u.is_staff)
230 230 def device_edit(request, id_dev):
231 231
232 232 device = get_object_or_404(Device, pk=id_dev)
233 233
234 234 if request.method=='GET':
235 235 form = DeviceForm(instance=device)
236 236
237 237 if request.method=='POST':
238 238 form = DeviceForm(request.POST, instance=device)
239 239
240 240 if form.is_valid():
241 241 form.save()
242 242 return redirect(device.get_absolute_url())
243 243
244 244 kwargs = {}
245 245 kwargs['form'] = form
246 246 kwargs['title'] = 'Device'
247 247 kwargs['suptitle'] = 'Edit'
248 248 kwargs['button'] = 'Update'
249 249
250 250 return render(request, 'base_edit.html', kwargs)
251 251
252 252
253 253 @user_passes_test(lambda u:u.is_staff)
254 254 def device_delete(request, id_dev):
255 255
256 256 device = get_object_or_404(Device, pk=id_dev)
257 257
258 258 if request.method=='POST':
259 259
260 260 if request.user.is_staff:
261 261 device.delete()
262 262 return redirect('url_devices')
263 263
264 264 messages.error(request, 'Not enough permission to delete this object')
265 265 return redirect(device.get_absolute_url())
266 266
267 267 kwargs = {
268 268 'title': 'Delete',
269 269 'suptitle': 'Device',
270 270 'object': device,
271 271 'previous': device.get_absolute_url(),
272 272 'delete': True
273 273 }
274 274
275 275 return render(request, 'confirm.html', kwargs)
276 276
277 277
278 278 @user_passes_test(lambda u:u.is_staff)
279 279 def device_change_ip(request, id_dev):
280 280
281 281 device = get_object_or_404(Device, pk=id_dev)
282 282
283 283 if request.method=='POST':
284 284
285 285 if request.user.is_staff:
286 286 device.change_ip(**request.POST.dict())
287 messages.success(request, device.message)
287 level, message = device.message.split('|')
288 messages.add_message(request, level, message)
288 289 else:
289 290 messages.error(request, 'Not enough permission to delete this object')
290 291 return redirect(device.get_absolute_url())
291 292
292 293 kwargs = {
293 294 'title': 'Device',
294 295 'suptitle': 'Change IP',
295 296 'object': device,
296 297 'previous': device.get_absolute_url(),
297 298 'form': ChangeIpForm(initial={'ip_address':device.ip_address}),
298 299 'message' : ' ',
299 300 }
300 301
301 302 return render(request, 'confirm.html', kwargs)
302 303
303 304
304 305 def campaigns(request):
305 306
306 307 page = request.GET.get('page')
307 308 order = ('start_date',)
308 309 filters = request.GET.copy()
309 310
310 311 kwargs = get_paginator(Campaign, page, order, filters)
311 312
312 313 form = FilterForm(initial=request.GET, extra_fields=['range_date', 'tags','template'])
313 314 kwargs['keys'] = ['name', 'start_date', 'end_date']
314 315 kwargs['title'] = 'Campaign'
315 316 kwargs['suptitle'] = 'List'
316 317 kwargs['no_sidebar'] = True
317 318 kwargs['form'] = form
318 319 filters.pop('page', None)
319 320 kwargs['q'] = urlencode(filters)
320 321
321 322 return render(request, 'base_list.html', kwargs)
322 323
323 324
324 325 def campaign(request, id_camp):
325 326
326 327 campaign = get_object_or_404(Campaign, pk=id_camp)
327 328 experiments = Experiment.objects.filter(campaign=campaign)
328 329
329 330 form = CampaignForm(instance=campaign)
330 331
331 332 kwargs = {}
332 333 kwargs['campaign'] = campaign
333 334 kwargs['campaign_keys'] = ['template', 'name', 'start_date', 'end_date', 'tags', 'description']
334 335
335 336 kwargs['experiments'] = experiments
336 337 kwargs['experiment_keys'] = ['name', 'radar_system', 'start_time', 'end_time']
337 338
338 339 kwargs['title'] = 'Campaign'
339 340 kwargs['suptitle'] = 'Details'
340 341
341 342 kwargs['form'] = form
342 343 kwargs['button'] = 'Add Experiment'
343 344
344 345 return render(request, 'campaign.html', kwargs)
345 346
346 347
347 348 @user_passes_test(lambda u:u.is_staff)
348 349 def campaign_new(request):
349 350
350 351 kwargs = {}
351 352
352 353 if request.method == 'GET':
353 354
354 355 if 'template' in request.GET:
355 356 if request.GET['template']=='0':
356 357 form = NewForm(initial={'create_from':2},
357 358 template_choices=Campaign.objects.filter(template=True).values_list('id', 'name'))
358 359 else:
359 360 kwargs['button'] = 'Create'
360 361 kwargs['experiments'] = Configuration.objects.filter(experiment=request.GET['template'])
361 362 kwargs['experiment_keys'] = ['name', 'start_time', 'end_time']
362 363 camp = Campaign.objects.get(pk=request.GET['template'])
363 364 form = CampaignForm(instance=camp,
364 365 initial={'name':'{} [{:%Y/%m/%d}]'.format(camp.name, datetime.now()),
365 366 'template':False})
366 367 elif 'blank' in request.GET:
367 368 kwargs['button'] = 'Create'
368 369 form = CampaignForm()
369 370 else:
370 371 form = NewForm()
371 372
372 373 if request.method == 'POST':
373 374 kwargs['button'] = 'Create'
374 375 post = request.POST.copy()
375 376 experiments = []
376 377
377 378 for id_exp in post.getlist('experiments'):
378 379 exp = Experiment.objects.get(pk=id_exp)
379 380 new_exp = exp.clone(template=False)
380 381 experiments.append(new_exp)
381 382
382 383 post.setlist('experiments', [])
383 384
384 385 form = CampaignForm(post)
385 386
386 387 if form.is_valid():
387 388 campaign = form.save()
388 389 for exp in experiments:
389 390 campaign.experiments.add(exp)
390 391 campaign.save()
391 392 return redirect('url_campaign', id_camp=campaign.id)
392 393
393 394 kwargs['form'] = form
394 395 kwargs['title'] = 'Campaign'
395 396 kwargs['suptitle'] = 'New'
396 397
397 398 return render(request, 'campaign_edit.html', kwargs)
398 399
399 400
400 401 @user_passes_test(lambda u:u.is_staff)
401 402 def campaign_edit(request, id_camp):
402 403
403 404 campaign = get_object_or_404(Campaign, pk=id_camp)
404 405
405 406 if request.method=='GET':
406 407 form = CampaignForm(instance=campaign)
407 408
408 409 if request.method=='POST':
409 410 exps = campaign.experiments.all().values_list('pk', flat=True)
410 411 post = request.POST.copy()
411 412 new_exps = post.getlist('experiments')
412 413 post.setlist('experiments', [])
413 414 form = CampaignForm(post, instance=campaign)
414 415
415 416 if form.is_valid():
416 417 camp = form.save()
417 418 for id_exp in new_exps:
418 419 if int(id_exp) in exps:
419 420 exps.pop(id_exp)
420 421 else:
421 422 exp = Experiment.objects.get(pk=id_exp)
422 423 if exp.template:
423 424 camp.experiments.add(exp.clone(template=False))
424 425 else:
425 426 camp.experiments.add(exp)
426 427
427 428 for id_exp in exps:
428 429 camp.experiments.remove(Experiment.objects.get(pk=id_exp))
429 430
430 431 return redirect('url_campaign', id_camp=id_camp)
431 432
432 433 kwargs = {}
433 434 kwargs['form'] = form
434 435 kwargs['title'] = 'Campaign'
435 436 kwargs['suptitle'] = 'Edit'
436 437 kwargs['button'] = 'Update'
437 438
438 439 return render(request, 'campaign_edit.html', kwargs)
439 440
440 441
441 442 @user_passes_test(lambda u:u.is_staff)
442 443 def campaign_delete(request, id_camp):
443 444
444 445 campaign = get_object_or_404(Campaign, pk=id_camp)
445 446
446 447 if request.method=='POST':
447 448 if request.user.is_staff:
448 449
449 450 for exp in campaign.experiments.all():
450 451 for conf in Configuration.objects.filter(experiment=exp):
451 452 conf.delete()
452 453 exp.delete()
453 454 campaign.delete()
454 455
455 456 return redirect('url_campaigns')
456 457
457 458 messages.error(request, 'Not enough permission to delete this object')
458 459 return redirect(campaign.get_absolute_url())
459 460
460 461 kwargs = {
461 462 'title': 'Delete',
462 463 'suptitle': 'Campaign',
463 464 'object': campaign,
464 465 'previous': campaign.get_absolute_url(),
465 466 'delete': True
466 467 }
467 468
468 469 return render(request, 'confirm.html', kwargs)
469 470
470 471
471 472 @user_passes_test(lambda u:u.is_staff)
472 473 def campaign_export(request, id_camp):
473 474
474 475 campaign = get_object_or_404(Campaign, pk=id_camp)
475 476 content = campaign.parms_to_dict()
476 477 content_type = 'application/json'
477 478 filename = '%s_%s.json' %(campaign.name, campaign.id)
478 479
479 480 response = HttpResponse(content_type=content_type)
480 481 response['Content-Disposition'] = 'attachment; filename="%s"' %filename
481 482 response.write(content)
482 483
483 484 return response
484 485
485 486
486 487 @user_passes_test(lambda u:u.is_staff)
487 488 def campaign_import(request, id_camp):
488 489
489 490 campaign = get_object_or_404(Campaign, pk=id_camp)
490 491
491 492 if request.method == 'GET':
492 493 file_form = UploadFileForm()
493 494
494 495 if request.method == 'POST':
495 496 file_form = UploadFileForm(request.POST, request.FILES)
496 497
497 498 if file_form.is_valid():
498 499
499 500 parms = campaign.import_from_file(request.FILES['file'])
500 501
501 502 if parms:
502 503 parms['name'] = parms['campaign']
503 504
504 505 new_camp = campaign.dict_to_parms(parms, CONF_MODELS)
505 506
506 507 messages.success(request, "Parameters imported from: '%s'." %request.FILES['file'].name)
507 508
508 509 return redirect(new_camp.get_absolute_url_edit())
509 510
510 511 messages.error(request, "Could not import parameters from file")
511 512
512 513 kwargs = {}
513 514 kwargs['title'] = 'Campaign'
514 515 kwargs['form'] = file_form
515 516 kwargs['suptitle'] = 'Importing file'
516 517 kwargs['button'] = 'Import'
517 518
518 519 return render(request, 'campaign_import.html', kwargs)
519 520
520 521
521 522 def experiments(request):
522 523
523 524 page = request.GET.get('page')
524 525 order = ('location',)
525 526 filters = request.GET.copy()
526 527
527 528 kwargs = get_paginator(Experiment, page, order, filters)
528 529
529 530 form = FilterForm(initial=request.GET, extra_fields=['tags','template'])
530 531
531 532 kwargs['keys'] = ['name', 'radar_system', 'start_time', 'end_time']
532 533 kwargs['title'] = 'Experiment'
533 534 kwargs['suptitle'] = 'List'
534 535 kwargs['no_sidebar'] = True
535 536 kwargs['form'] = form
536 537 filters.pop('page', None)
537 538 kwargs['q'] = urlencode(filters)
538 539
539 540 return render(request, 'base_list.html', kwargs)
540 541
541 542
542 543 def experiment(request, id_exp):
543 544
544 545 experiment = get_object_or_404(Experiment, pk=id_exp)
545 546
546 547 configurations = Configuration.objects.filter(experiment=experiment, type=0)
547 548
548 549 kwargs = {}
549 550
550 551 kwargs['experiment_keys'] = ['template', 'radar_system', 'name', 'start_time', 'end_time']
551 552 kwargs['experiment'] = experiment
552 553
553 554 kwargs['configuration_keys'] = ['name', 'device__ip_address', 'device__port_address', 'device__status']
554 555 kwargs['configurations'] = configurations
555 556
556 557 kwargs['title'] = 'Experiment'
557 558 kwargs['suptitle'] = 'Details'
558 559
559 560 kwargs['button'] = 'Add Configuration'
560 561
561 562 ###### SIDEBAR ######
562 563 kwargs.update(sidebar(experiment=experiment))
563 564
564 565 return render(request, 'experiment.html', kwargs)
565 566
566 567
567 568 @user_passes_test(lambda u:u.is_staff)
568 569 def experiment_new(request, id_camp=None):
569 570
570 571 kwargs = {}
571 572
572 573 if request.method == 'GET':
573 574 if 'template' in request.GET:
574 575 if request.GET['template']=='0':
575 576 form = NewForm(initial={'create_from':2},
576 577 template_choices=Experiment.objects.filter(template=True).values_list('id', 'name'))
577 578 else:
578 579 kwargs['button'] = 'Create'
579 580 kwargs['configurations'] = Configuration.objects.filter(experiment=request.GET['template'])
580 581 kwargs['configuration_keys'] = ['name', 'device__name', 'device__ip_address', 'device__port_address']
581 582 exp=Experiment.objects.get(pk=request.GET['template'])
582 583 form = ExperimentForm(instance=exp,
583 584 initial={'name': '{} [{:%Y/%m/%d}]'.format(exp.name, datetime.now()),
584 585 'template': False})
585 586 elif 'blank' in request.GET:
586 587 kwargs['button'] = 'Create'
587 588 form = ExperimentForm()
588 589 else:
589 590 form = NewForm()
590 591
591 592 if request.method == 'POST':
592 593 form = ExperimentForm(request.POST)
593 594 if form.is_valid():
594 595 experiment = form.save()
595 596
596 597 if 'template' in request.GET:
597 598 configurations = Configuration.objects.filter(experiment=request.GET['template'], type=0)
598 599 for conf in configurations:
599 600 conf.clone(experiment=experiment, template=False)
600 601
601 602 return redirect('url_experiment', id_exp=experiment.id)
602 603
603 604 kwargs['form'] = form
604 605 kwargs['title'] = 'Experiment'
605 606 kwargs['suptitle'] = 'New'
606 607
607 608 return render(request, 'experiment_edit.html', kwargs)
608 609
609 610
610 611 @user_passes_test(lambda u:u.is_staff)
611 612 def experiment_edit(request, id_exp):
612 613
613 614 experiment = get_object_or_404(Experiment, pk=id_exp)
614 615
615 616 if request.method == 'GET':
616 617 form = ExperimentForm(instance=experiment)
617 618
618 619 if request.method=='POST':
619 620 form = ExperimentForm(request.POST, instance=experiment)
620 621
621 622 if form.is_valid():
622 623 experiment = form.save()
623 624 return redirect('url_experiment', id_exp=experiment.id)
624 625
625 626 kwargs = {}
626 627 kwargs['form'] = form
627 628 kwargs['title'] = 'Experiment'
628 629 kwargs['suptitle'] = 'Edit'
629 630 kwargs['button'] = 'Update'
630 631
631 632 return render(request, 'experiment_edit.html', kwargs)
632 633
633 634
634 635 @user_passes_test(lambda u:u.is_staff)
635 636 def experiment_delete(request, id_exp):
636 637
637 638 experiment = get_object_or_404(Experiment, pk=id_exp)
638 639
639 640 if request.method=='POST':
640 641 if request.user.is_staff:
641 642 for conf in Configuration.objects.filter(experiment=experiment):
642 643 conf.delete()
643 644 experiment.delete()
644 645 return redirect('url_experiments')
645 646
646 647 messages.error(request, 'Not enough permission to delete this object')
647 648 return redirect(experiment.get_absolute_url())
648 649
649 650 kwargs = {
650 651 'title': 'Delete',
651 652 'suptitle': 'Experiment',
652 653 'object': experiment,
653 654 'previous': experiment.get_absolute_url(),
654 655 'delete': True
655 656 }
656 657
657 658 return render(request, 'confirm.html', kwargs)
658 659
659 660
660 661 @user_passes_test(lambda u:u.is_staff)
661 662 def experiment_export(request, id_exp):
662 663
663 664 experiment = get_object_or_404(Experiment, pk=id_exp)
664 665 content = experiment.parms_to_dict()
665 666 content_type = 'application/json'
666 667 filename = '%s_%s.json' %(experiment.name, experiment.id)
667 668
668 669 response = HttpResponse(content_type=content_type)
669 670 response['Content-Disposition'] = 'attachment; filename="%s"' %filename
670 671 response.write(content)
671 672
672 673 return response
673 674
674 675
675 676 @user_passes_test(lambda u:u.is_staff)
676 677 def experiment_import(request, id_exp):
677 678
678 679 experiment = get_object_or_404(Experiment, pk=id_exp)
679 680 configurations = Configuration.objects.filter(experiment=experiment)
680 681
681 682 if request.method == 'GET':
682 683 file_form = UploadFileForm()
683 684
684 685 if request.method == 'POST':
685 686 file_form = UploadFileForm(request.POST, request.FILES)
686 687
687 688 if file_form.is_valid():
688 689
689 690 parms = experiment.import_from_file(request.FILES['file'])
690 691
691 692 if parms:
692 693
693 694 new_exp = experiment.dict_to_parms(parms, CONF_MODELS)
694 695
695 696 messages.success(request, "Parameters imported from: '%s'." %request.FILES['file'].name)
696 697
697 698 return redirect(new_exp.get_absolute_url_edit())
698 699
699 700 messages.error(request, "Could not import parameters from file")
700 701
701 702 kwargs = {}
702 703 kwargs['title'] = 'Experiment'
703 704 kwargs['form'] = file_form
704 705 kwargs['suptitle'] = 'Importing file'
705 706 kwargs['button'] = 'Import'
706 707
707 708 kwargs.update(sidebar(experiment=experiment))
708 709
709 710 return render(request, 'experiment_import.html', kwargs)
710 711
711 712
712 713 @user_passes_test(lambda u:u.is_staff)
713 714 def experiment_mix(request, id_exp):
714 715
715 716 experiment = get_object_or_404(Experiment, pk=id_exp)
716 717 rc_confs = [conf for conf in RCConfiguration.objects.filter(experiment=id_exp,
717 718 mix=False)]
718 719
719 720 if len(rc_confs)<2:
720 721 messages.warning(request, 'You need at least two RC Configurations to make a mix')
721 722 return redirect(experiment.get_absolute_url())
722 723
723 724 mix_confs = RCConfiguration.objects.filter(experiment=id_exp, mix=True)
724 725
725 726 if mix_confs:
726 727 mix = mix_confs[0]
727 728 else:
728 729 mix = RCConfiguration(experiment=experiment,
729 730 device=rc_confs[0].device,
730 731 ipp=rc_confs[0].ipp,
731 732 clock_in=rc_confs[0].clock_in,
732 733 clock_divider=rc_confs[0].clock_divider,
733 734 mix=True,
734 735 parameters='')
735 736 mix.save()
736 737
737 738 line_type = RCLineType.objects.get(name='mix')
738 739 for i in range(len(rc_confs[0].get_lines())):
739 740 line = RCLine(rc_configuration=mix, line_type=line_type, channel=i)
740 741 line.save()
741 742
742 743 initial = {'name': mix.name,
743 744 'result': parse_mix_result(mix.parameters),
744 745 'delay': 0,
745 746 'mask': [0,1,2,3,4,5,6,7]
746 747 }
747 748
748 749 if request.method=='GET':
749 750 form = RCMixConfigurationForm(confs=rc_confs, initial=initial)
750 751
751 752 if request.method=='POST':
752 753 result = mix.parameters
753 754
754 755 if '{}|'.format(request.POST['experiment']) in result:
755 756 messages.error(request, 'Configuration already added')
756 757 else:
757 758 if 'operation' in request.POST:
758 759 operation = MIX_OPERATIONS[request.POST['operation']]
759 760 else:
760 761 operation = ' '
761 762
762 763 mode = MIX_MODES[request.POST['mode']]
763 764
764 765 if result:
765 766 result = '{}-{}|{}|{}|{}|{}'.format(mix.parameters,
766 767 request.POST['experiment'],
767 768 mode,
768 769 operation,
769 770 float(request.POST['delay']),
770 771 parse_mask(request.POST.getlist('mask'))
771 772 )
772 773 else:
773 774 result = '{}|{}|{}|{}|{}'.format(request.POST['experiment'],
774 775 mode,
775 776 operation,
776 777 float(request.POST['delay']),
777 778 parse_mask(request.POST.getlist('mask'))
778 779 )
779 780
780 781 mix.parameters = result
781 782 mix.name = request.POST['name']
782 783 mix.save()
783 784 mix.update_pulses()
784 785
785 786 initial['result'] = parse_mix_result(result)
786 787 initial['name'] = mix.name
787 788
788 789 form = RCMixConfigurationForm(initial=initial, confs=rc_confs)
789 790
790 791
791 792 kwargs = {
792 793 'title': 'Experiment',
793 794 'suptitle': 'Mix Configurations',
794 795 'form' : form,
795 796 'extra_button': 'Delete',
796 797 'button': 'Add',
797 798 'cancel': 'Back',
798 799 'previous': experiment.get_absolute_url(),
799 800 'id_exp':id_exp,
800 801
801 802 }
802 803
803 804 return render(request, 'experiment_mix.html', kwargs)
804 805
805 806
806 807 @user_passes_test(lambda u:u.is_staff)
807 808 def experiment_mix_delete(request, id_exp):
808 809
809 810 conf = RCConfiguration.objects.get(experiment=id_exp, mix=True)
810 811 values = conf.parameters.split('-')
811 812 conf.parameters = '-'.join(values[:-1])
812 813 conf.save()
813 814
814 815 return redirect('url_mix_experiment', id_exp=id_exp)
815 816
816 817
817 818
818 819 def experiment_summary(request, id_exp):
819 820
820 821 import json
821 822 import ast
822 823
823 824 experiment = get_object_or_404(Experiment, pk=id_exp)
824 825 experiment_data = json.loads(experiment.parms_to_dict())
825 826 configurations = Configuration.objects.filter(experiment=experiment, type=0)
826 827
827 828 kwargs = {}
828 829
829 830 kwargs['experiment_keys'] = ['radar_system', 'name', 'start_time', 'end_time']
830 831 kwargs['experiment'] = experiment
831 832
832 833 kwargs['configuration_keys'] = ['name', 'device__ip_address', 'device__port_address', 'device__status']
833 834 kwargs['configurations'] = configurations
834 835 kwargs['experiment_data'] = experiment_data
835 836
836 837 kwargs['title'] = 'Experiment Summary'
837 838 kwargs['suptitle'] = 'Details'
838 839
839 840 kwargs['button'] = 'Verify Parameters'
840 841
841 842 jars_conf = False
842 843 rc_conf = False
843 844
844 845 for configuration in configurations:
845 846 #-------------------- JARS -----------------------:
846 847 if configuration.device.device_type.name == 'jars':
847 848 jars_conf = True
848 849 kwargs['jars_conf'] = jars_conf
849 850 kwargs['exp_type'] = EXPERIMENT_TYPE[configuration.exp_type][1]
850 851 channels_number = configuration.channels_number
851 852 exp_type = configuration.exp_type
852 853 fftpoints = configuration.fftpoints
853 854 filter_parms = configuration.filter_parms
854 855 filter_parms = ast.literal_eval(filter_parms)
855 856 spectral_number = configuration.spectral_number
856 857
857 858 #--------------------- RC ----------------------:
858 859 if configuration.device.device_type.name == 'rc':
859 860 rc_conf = True
860 861 kwargs['rc_conf'] = rc_conf
861 862 rc_lines = experiment_data['configurations']['rc']['lines']
862 863 ipp = configuration.ipp
863 864 if experiment_data['configurations']['rc']['mix'] == 'True':
864 865 code = ''
865 866 else:
866 867 code = rc_lines[3]['code']
867 868
868 869 kwargs['code'] = code
869 870
870 871 #---Jueves 01-12-2016---
871 872
872 873 lines = configuration.get_lines()
873 874
874 875 if lines:
875 876
876 877 #TX Delays (TAU)
877 878 rc_delays_num = 0
878 879 rc_delays = ''
879 880 tx_lines = configuration.get_lines(line_type__name='tx')
880 881 for tx_line in tx_lines:
881 882 if len(tx_lines) < 2:
882 883 rc_delay = json.loads(tx_line.params)
883 884 rc_delays = rc_delays+tx_line.get_name()+': '+rc_delay['delays']+'\n'
884 885 delay = ast.literal_eval(rc_delay['delays'])
885 886 if isinstance(delay,int):
886 887 rc_delays_num += 1
887 888 else:
888 889 rc_delays_num += len(delay)
889 890 else:
890 891 rc_delay = json.loads(tx_line.params)
891 892 rc_delays = rc_delays+tx_line.get_name()+': '+rc_delay['delays']+'\n'
892 893 delay = ast.literal_eval(rc_delay['delays'])
893 894 if isinstance(delay,int):
894 895 rc_delays_num += 1
895 896 else:
896 897 rc_delays_num += len(delay)
897 898
898 899 #TX: TXA - TXB...
899 900 for tx_line in tx_lines:
900 901 tx_line.name = tx_line.get_name()
901 902 tx_line_parameters = json.loads(tx_line.params)
902 903 tx_line.parameters = tx_line_parameters
903 904
904 905 #WINDOWS
905 906 windows_lines = configuration.get_lines(line_type__name='windows')
906 907 for windows_line in windows_lines:
907 908 windows_line.name = windows_line.get_name()
908 909 windows_data = json.loads(windows_line.params)
909 910 windows_params = windows_data['params'][0]
910 911 h0 = str(windows_params['first_height'])
911 912 dh = str(windows_params['resolution'])
912 913 nsa = str(windows_params['number_of_samples'])
913 914 windows_line.parameters = 'Ho=' + h0 +'km\nDH=' + dh +'km\nNSA=' + nsa
914 915
915 916 #CODES
916 917 code_lines = configuration.get_lines(line_type__name='codes')
917 918 for code_line in code_lines:
918 919 code_line.name = code_line.get_name()
919 920 line_params = json.loads(code_line.params)
920 921 rccode = RCLineCode.objects.get(pk=int(line_params['code']))
921 922 code_line.code_name = rccode.name
922 923
923 924 #PROG_PULSES
924 925 progpulses_lines = configuration.get_lines(line_type__name='prog_pulses')
925 926 for progpulses_line in progpulses_lines:
926 927 progpulses_line.name = progpulses_line.get_name()
927 928 progpulses_parameters = json.loads(progpulses_line.params)
928 929 progpulses_parameters = progpulses_parameters['params'][0]
929 930 progpulses_line.parameters = 'Begin: '+str(progpulses_parameters['begin'])+' (Units)\nEnd: '+str(progpulses_parameters['end'])+' (Units)'
930 931
931 932
932 933
933 934 #kwargs['kwargs_channels'] = sorted(kwargs_channels, reverse=True)
934 935 kwargs['lines'] = sorted(lines, reverse=True)
935 936 kwargs['rc_delays'] = rc_delays
936 937 kwargs['rc_delays_num'] = rc_delays_num
937 938 kwargs['tx_lines'] = tx_lines
938 939 kwargs['windows_lines'] = windows_lines
939 940 kwargs['code_lines'] = code_lines
940 941 kwargs['progpulses_lines'] = progpulses_lines
941 942
942 943
943 944 #--FIN: Jueves 01-12-2016---
944 945
945 946 #-------------------- DDS -----------------------:
946 947 if configuration.device.device_type.name == 'dds':
947 948 dds_conf = True
948 949 kwargs['dds_conf'] = dds_conf
949 950
950 951 #------ RC & JARS ------:
951 952 ipp = 937.5 #
952 953 nsa = 200#
953 954 dh = 1.5 #
954 955 channels_number = 5 #
955 956
956 957 if rc_conf and jars_conf:
957 958 if exp_type == 0: #Short
958 959 bytes = 2
959 960 b = nsa*2*bytes*channels_number
960 961 else: #Float
961 962 bytes = 4
962 963 channels = channels_number + spectral_number
963 964 b = nsa*2*bytes*fftpoints*channels
964 965
965 966 ipps = (ipp*pow(10,-6))/0.15
966 967 GB = 1048576.0*1024.0
967 968 Hour = 3600
968 969 rate = b/ipps
969 970 rate = rate *(1/GB)*(Hour)
970 971 kwargs['rate'] = str(rate)+" GB/h"
971 972 else:
972 973 kwargs['rate'] = ''
973 974
974 975 ###### SIDEBAR ######
975 976 kwargs.update(sidebar(experiment=experiment))
976 977
977 978 return render(request, 'experiment_summary.html', kwargs)
978 979
979 980
980 981 @user_passes_test(lambda u:u.is_staff)
981 982 def experiment_verify(request, id_exp):
982 983
983 984 import json
984 985 import ast
985 986
986 987 experiment = get_object_or_404(Experiment, pk=id_exp)
987 988 experiment_data = json.loads(experiment.parms_to_dict())
988 989 configurations = Configuration.objects.filter(experiment=experiment, type=0)
989 990
990 991 kwargs = {}
991 992
992 993 kwargs['experiment_keys'] = ['template', 'radar_system', 'name', 'start_time', 'end_time']
993 994 kwargs['experiment'] = experiment
994 995
995 996 kwargs['configuration_keys'] = ['name', 'device__ip_address', 'device__port_address', 'device__status']
996 997 kwargs['configurations'] = configurations
997 998 kwargs['experiment_data'] = experiment_data
998 999
999 1000 kwargs['title'] = 'Verify Experiment'
1000 1001 kwargs['suptitle'] = 'Parameters'
1001 1002
1002 1003 kwargs['button'] = 'Update'
1003 1004
1004 1005 jars_conf = False
1005 1006 rc_conf = False
1006 1007 dds_conf = False
1007 1008
1008 1009 for configuration in configurations:
1009 1010 #-------------------- JARS -----------------------:
1010 1011 if configuration.device.device_type.name == 'jars':
1011 1012 jars_conf = True
1012 1013 jars = configuration
1013 1014 kwargs['jars_conf'] = jars_conf
1014 1015 filter_parms = configuration.filter_parms
1015 1016 filter_parms = ast.literal_eval(filter_parms)
1016 1017 kwargs['filter_parms'] = filter_parms
1017 1018 #--Sampling Frequency
1018 1019 clock = filter_parms['clock']
1019 1020 filter_2 = filter_parms['filter_2']
1020 1021 filter_5 = filter_parms['filter_5']
1021 1022 filter_fir = filter_parms['filter_fir']
1022 1023 samp_freq_jars = clock/filter_2/filter_5/filter_fir
1023 1024
1024 1025 kwargs['samp_freq_jars'] = samp_freq_jars
1025 1026 kwargs['jars'] = configuration
1026 1027
1027 1028 #--------------------- RC ----------------------:
1028 1029 if configuration.device.device_type.name == 'rc':
1029 1030 rc_conf = True
1030 1031 rc = configuration
1031 1032 rc_parms = configuration.parms_to_dict()
1032 1033 if rc_parms['mix'] == 'True':
1033 1034 pass
1034 1035 else:
1035 1036 rc_lines = rc_parms['lines']
1036 1037 dh = rc_lines[6]['params'][0]['resolution']
1037 1038 #--Sampling Frequency
1038 1039 samp_freq_rc = 0.15/dh
1039 1040 kwargs['samp_freq_rc'] = samp_freq_rc
1040 1041
1041 1042 kwargs['rc_conf'] = rc_conf
1042 1043 kwargs['rc'] = configuration
1043 1044
1044 1045 #-------------------- DDS ----------------------:
1045 1046 if configuration.device.device_type.name == 'dds':
1046 1047 dds_conf = True
1047 1048 dds = configuration
1048 1049 dds_parms = configuration.parms_to_dict()
1049 1050
1050 1051 kwargs['dds_conf'] = dds_conf
1051 1052 kwargs['dds'] = configuration
1052 1053
1053 1054
1054 1055 #------------Validation------------:
1055 1056 #Clock
1056 1057 if dds_conf and rc_conf and jars_conf:
1057 1058 if float(filter_parms['clock']) != float(rc_parms['clock_in']) and float(rc_parms['clock_in']) != float(dds_parms['clock']):
1058 1059 messages.warning(request, "Devices don't have the same clock.")
1059 1060 elif rc_conf and jars_conf:
1060 1061 if float(filter_parms['clock']) != float(rc_parms['clock_in']):
1061 1062 messages.warning(request, "Devices don't have the same clock.")
1062 1063 elif rc_conf and dds_conf:
1063 1064 if float(rc_parms['clock_in']) != float(dds_parms['clock']):
1064 1065 messages.warning(request, "Devices don't have the same clock.")
1065 1066 if float(samp_freq_rc) != float(dds_parms['frequencyA']):
1066 1067 messages.warning(request, "Devices don't have the same Frequency A.")
1067 1068
1068 1069
1069 1070 #------------POST METHOD------------:
1070 1071 if request.method == 'POST':
1071 1072 if request.POST['suggest_clock']:
1072 1073 try:
1073 1074 suggest_clock = float(request.POST['suggest_clock'])
1074 1075 except:
1075 1076 messages.warning(request, "Invalid value in CLOCK IN.")
1076 1077 return redirect('url_verify_experiment', id_exp=experiment.id)
1077 1078 else:
1078 1079 suggest_clock = ""
1079 1080 if suggest_clock:
1080 1081 if rc_conf:
1081 1082 rc.clock_in = suggest_clock
1082 1083 rc.save()
1083 1084 if jars_conf:
1084 1085 filter_parms = jars.filter_parms
1085 1086 filter_parms = ast.literal_eval(filter_parms)
1086 1087 filter_parms['clock'] = suggest_clock
1087 1088 jars.filter_parms = json.dumps(filter_parms)
1088 1089 jars.save()
1089 1090 kwargs['filter_parms'] = filter_parms
1090 1091 if dds_conf:
1091 1092 dds.clock = suggest_clock
1092 1093 dds.save()
1093 1094
1094 1095 if request.POST['suggest_frequencyA']:
1095 1096 try:
1096 1097 suggest_frequencyA = float(request.POST['suggest_frequencyA'])
1097 1098 except:
1098 1099 messages.warning(request, "Invalid value in FREQUENCY A.")
1099 1100 return redirect('url_verify_experiment', id_exp=experiment.id)
1100 1101 else:
1101 1102 suggest_frequencyA = ""
1102 1103 if suggest_frequencyA:
1103 1104 if jars_conf:
1104 1105 filter_parms = jars.filter_parms
1105 1106 filter_parms = ast.literal_eval(filter_parms)
1106 1107 filter_parms['fch'] = suggest_frequencyA
1107 1108 jars.filter_parms = json.dumps(filter_parms)
1108 1109 jars.save()
1109 1110 kwargs['filter_parms'] = filter_parms
1110 1111 if dds_conf:
1111 1112 dds.frequencyA_Mhz = request.POST['suggest_frequencyA']
1112 1113 dds.save()
1113 1114
1114 1115 ###### SIDEBAR ######
1115 1116 kwargs.update(sidebar(experiment=experiment))
1116 1117
1117 1118
1118 1119
1119 1120
1120 1121
1121 1122 return render(request, 'experiment_verify.html', kwargs)
1122 1123
1123 1124
1124 1125 @user_passes_test(lambda u:u.is_staff)
1125 1126 def parse_mix_result(s):
1126 1127
1127 1128 values = s.split('-')
1128 1129 html = 'EXP MOD OPE DELAY MASK\r\n'
1129 1130
1130 1131 if not values or values[0] in ('', ' '):
1131 1132 return mark_safe(html)
1132 1133
1133 1134 for i, value in enumerate(values):
1134 1135 if not value:
1135 1136 continue
1136 1137 pk, mode, operation, delay, mask = value.split('|')
1137 1138 conf = RCConfiguration.objects.get(pk=pk)
1138 1139 if i==0:
1139 1140 html += '{:20.18}{:3}{:4}{:9}km{:>6}\r\n'.format(
1140 1141 conf.name,
1141 1142 mode,
1142 1143 ' ',
1143 1144 delay,
1144 1145 mask)
1145 1146 else:
1146 1147 html += '{:20.18}{:3}{:4}{:9}km{:>6}\r\n'.format(
1147 1148 conf.name,
1148 1149 mode,
1149 1150 operation,
1150 1151 delay,
1151 1152 mask)
1152 1153
1153 1154 return mark_safe(html)
1154 1155
1155 1156 def parse_mask(l):
1156 1157
1157 1158 values = []
1158 1159
1159 1160 for x in range(8):
1160 1161 if '{}'.format(x) in l:
1161 1162 values.append(1)
1162 1163 else:
1163 1164 values.append(0)
1164 1165
1165 1166 values.reverse()
1166 1167
1167 1168 return int(''.join([str(x) for x in values]), 2)
1168 1169
1169 1170
1170 1171 def dev_confs(request):
1171 1172
1172 1173
1173 1174 page = request.GET.get('page')
1174 1175 order = ('type', 'device__device_type', 'experiment')
1175 1176 filters = request.GET.copy()
1176 1177
1177 1178 kwargs = get_paginator(Configuration, page, order, filters)
1178 1179
1179 1180 form = FilterForm(initial=request.GET, extra_fields=['tags','template'])
1180 1181 kwargs['keys'] = ['name', 'experiment', 'type', 'programmed_date']
1181 1182 kwargs['title'] = 'Configuration'
1182 1183 kwargs['suptitle'] = 'List'
1183 1184 kwargs['no_sidebar'] = True
1184 1185 kwargs['form'] = form
1185 1186 filters.pop('page', None)
1186 1187 kwargs['q'] = urlencode(filters)
1187 1188
1188 1189 return render(request, 'base_list.html', kwargs)
1189 1190
1190 1191
1191 1192 def dev_conf(request, id_conf):
1192 1193
1193 1194 conf = get_object_or_404(Configuration, pk=id_conf)
1194 1195
1195 1196 return redirect(conf.get_absolute_url())
1196 1197
1197 1198
1198 1199 @user_passes_test(lambda u:u.is_staff)
1199 1200 def dev_conf_new(request, id_exp=0, id_dev=0):
1200 1201
1201 1202 initial = {}
1202 1203 kwargs = {}
1203 1204
1204 1205 if id_exp!=0:
1205 1206 initial['experiment'] = id_exp
1206 1207
1207 1208 if id_dev!=0:
1208 1209 initial['device'] = id_dev
1209 1210
1210 1211 if request.method == 'GET':
1211 1212
1212 1213 if id_dev:
1213 1214 kwargs['button'] = 'Create'
1214 1215 device = Device.objects.get(pk=id_dev)
1215 1216 DevConfForm = CONF_FORMS[device.device_type.name]
1216 1217 initial['name'] = request.GET['name']
1217 1218 form = DevConfForm(initial=initial)
1218 1219 else:
1219 1220 if 'template' in request.GET:
1220 1221 if request.GET['template']=='0':
1221 1222 choices = [(conf.pk, '{}'.format(conf)) for conf in Configuration.objects.filter(template=True)]
1222 1223 form = NewForm(initial={'create_from':2},
1223 1224 template_choices=choices)
1224 1225 else:
1225 1226 kwargs['button'] = 'Create'
1226 1227 conf = Configuration.objects.get(pk=request.GET['template'])
1227 1228 id_dev = conf.device.pk
1228 1229 DevConfForm = CONF_FORMS[conf.device.device_type.name]
1229 1230 form = DevConfForm(instance=conf,
1230 1231 initial={'name': '{} [{:%Y/%m/%d}]'.format(conf.name, datetime.now()),
1231 1232 'template': False,
1232 1233 'experiment':id_exp})
1233 1234 elif 'blank' in request.GET:
1234 1235 kwargs['button'] = 'Create'
1235 1236 form = ConfigurationForm(initial=initial)
1236 1237 else:
1237 1238 form = NewForm()
1238 1239
1239 1240 if request.method == 'POST':
1240 1241
1241 1242 device = Device.objects.get(pk=request.POST['device'])
1242 1243 DevConfForm = CONF_FORMS[device.device_type.name]
1243 1244
1244 1245 form = DevConfForm(request.POST)
1245 1246 kwargs['button'] = 'Create'
1246 1247 if form.is_valid():
1247 1248 conf = form.save()
1248 1249
1249 1250 if 'template' in request.GET and conf.device.device_type.name=='rc':
1250 1251 lines = RCLine.objects.filter(rc_configuration=request.GET['template'])
1251 1252 for line in lines:
1252 1253 line.clone(rc_configuration=conf)
1253 1254
1254 1255 if conf.device.device_type.name=='jars':
1255 1256 conf.add_parms_to_filter()
1256 1257
1257 1258 return redirect('url_dev_conf', id_conf=conf.pk)
1258 1259
1259 1260 kwargs['id_exp'] = id_exp
1260 1261 kwargs['form'] = form
1261 1262 kwargs['title'] = 'Configuration'
1262 1263 kwargs['suptitle'] = 'New'
1263 1264
1264 1265
1265 1266 if id_dev != 0:
1266 1267 device = Device.objects.get(pk=id_dev)
1267 1268 kwargs['device'] = device.device_type.name
1268 1269
1269 1270 return render(request, 'dev_conf_edit.html', kwargs)
1270 1271
1271 1272
1272 1273 @user_passes_test(lambda u:u.is_staff)
1273 1274 def dev_conf_edit(request, id_conf):
1274 1275
1275 1276 conf = get_object_or_404(Configuration, pk=id_conf)
1276 1277
1277 1278 DevConfForm = CONF_FORMS[conf.device.device_type.name]
1278 1279
1279 1280 if request.method=='GET':
1280 1281 form = DevConfForm(instance=conf)
1281 1282
1282 1283 if request.method=='POST':
1283 1284 form = DevConfForm(request.POST, instance=conf)
1284 1285
1285 1286 if form.is_valid():
1286 1287 form.save()
1287 1288 return redirect('url_dev_conf', id_conf=id_conf)
1288 1289
1289 1290 kwargs = {}
1290 1291 kwargs['form'] = form
1291 1292 kwargs['title'] = 'Device Configuration'
1292 1293 kwargs['suptitle'] = 'Edit'
1293 1294 kwargs['button'] = 'Update'
1294 1295
1295 1296 ###### SIDEBAR ######
1296 1297 kwargs.update(sidebar(conf=conf))
1297 1298
1298 1299 return render(request, '%s_conf_edit.html' % conf.device.device_type.name, kwargs)
1299 1300
1300 1301
1301 1302 @user_passes_test(lambda u:u.is_staff)
1302 1303 def dev_conf_start(request, id_conf):
1303 1304
1304 1305 conf = get_object_or_404(Configuration, pk=id_conf)
1305 1306
1306 1307 if conf.start_device():
1307 1308 messages.success(request, conf.message)
1308 1309 else:
1309 1310 messages.error(request, conf.message)
1310 1311
1311 1312 #conf.status_device()
1312 1313
1313 1314 return redirect(conf.get_absolute_url())
1314 1315
1315 1316
1316 1317 @user_passes_test(lambda u:u.is_staff)
1317 1318 def dev_conf_stop(request, id_conf):
1318 1319
1319 1320 conf = get_object_or_404(Configuration, pk=id_conf)
1320 1321
1321 1322 if conf.stop_device():
1322 1323 messages.success(request, conf.message)
1323 1324 else:
1324 1325 messages.error(request, conf.message)
1325 1326
1326 1327 #conf.status_device()
1327 1328
1328 1329 return redirect(conf.get_absolute_url())
1329 1330
1330 1331
1331 1332 def dev_conf_status(request, id_conf):
1332 1333
1333 1334 conf = get_object_or_404(Configuration, pk=id_conf)
1334 1335
1335 1336 if conf.status_device():
1336 1337 messages.success(request, conf.message)
1337 1338 else:
1338 1339 messages.error(request, conf.message)
1339 1340
1340 1341 return redirect(conf.get_absolute_url())
1341 1342
1342 1343
1343 1344 @user_passes_test(lambda u:u.is_staff)
1344 1345 def dev_conf_write(request, id_conf):
1345 1346
1346 1347 conf = get_object_or_404(Configuration, pk=id_conf)
1347 1348
1348 1349 if conf.write_device():
1349 1350 messages.success(request, conf.message)
1350 1351 conf.clone(type=1, template=False)
1351 1352 else:
1352 1353 messages.error(request, conf.message)
1353 1354
1354 1355 return redirect(conf.get_absolute_url())
1355 1356
1356 1357
1357 1358 @user_passes_test(lambda u:u.is_staff)
1358 1359 def dev_conf_read(request, id_conf):
1359 1360
1360 1361 conf = get_object_or_404(Configuration, pk=id_conf)
1361 1362
1362 1363 DevConfForm = CONF_FORMS[conf.device.device_type.name]
1363 1364
1364 1365 if request.method=='GET':
1365 1366
1366 1367 parms = conf.read_device()
1367 1368 #conf.status_device()
1368 1369
1369 1370 if not parms:
1370 1371 messages.error(request, conf.message)
1371 1372 return redirect(conf.get_absolute_url())
1372 1373
1373 1374 form = DevConfForm(initial=parms, instance=conf)
1374 1375
1375 1376 if request.method=='POST':
1376 1377 form = DevConfForm(request.POST, instance=conf)
1377 1378
1378 1379 if form.is_valid():
1379 1380 form.save()
1380 1381 return redirect(conf.get_absolute_url())
1381 1382
1382 1383 messages.error(request, "Parameters could not be saved")
1383 1384
1384 1385 kwargs = {}
1385 1386 kwargs['id_dev'] = conf.id
1386 1387 kwargs['form'] = form
1387 1388 kwargs['title'] = 'Device Configuration'
1388 1389 kwargs['suptitle'] = 'Parameters read from device'
1389 1390 kwargs['button'] = 'Save'
1390 1391
1391 1392 ###### SIDEBAR ######
1392 1393 kwargs.update(sidebar(conf=conf))
1393 1394
1394 1395 return render(request, '%s_conf_edit.html' %conf.device.device_type.name, kwargs)
1395 1396
1396 1397
1397 1398 @user_passes_test(lambda u:u.is_staff)
1398 1399 def dev_conf_import(request, id_conf):
1399 1400
1400 1401 conf = get_object_or_404(Configuration, pk=id_conf)
1401 1402 DevConfForm = CONF_FORMS[conf.device.device_type.name]
1402 1403
1403 1404 if request.method == 'GET':
1404 1405 file_form = UploadFileForm()
1405 1406
1406 1407 if request.method == 'POST':
1407 1408 file_form = UploadFileForm(request.POST, request.FILES)
1408 1409
1409 1410 if file_form.is_valid():
1410 1411
1411 1412 parms = conf.import_from_file(request.FILES['file'])
1412 1413
1413 1414 if parms:
1414 1415 messages.success(request, "Parameters imported from: '%s'." %request.FILES['file'].name)
1415 1416 form = DevConfForm(initial=parms, instance=conf)
1416 1417
1417 1418 kwargs = {}
1418 1419 kwargs['id_dev'] = conf.id
1419 1420 kwargs['form'] = form
1420 1421 kwargs['title'] = 'Device Configuration'
1421 1422 kwargs['suptitle'] = 'Parameters imported'
1422 1423 kwargs['button'] = 'Save'
1423 1424 kwargs['action'] = conf.get_absolute_url_edit()
1424 1425 kwargs['previous'] = conf.get_absolute_url()
1425 1426
1426 1427 ###### SIDEBAR ######
1427 1428 kwargs.update(sidebar(conf=conf))
1428 1429
1429 1430 return render(request, '%s_conf_edit.html' % conf.device.device_type.name, kwargs)
1430 1431
1431 1432 messages.error(request, "Could not import parameters from file")
1432 1433
1433 1434 kwargs = {}
1434 1435 kwargs['id_dev'] = conf.id
1435 1436 kwargs['title'] = 'Device Configuration'
1436 1437 kwargs['form'] = file_form
1437 1438 kwargs['suptitle'] = 'Importing file'
1438 1439 kwargs['button'] = 'Import'
1439 1440
1440 1441 kwargs.update(sidebar(conf=conf))
1441 1442
1442 1443 return render(request, 'dev_conf_import.html', kwargs)
1443 1444
1444 1445
1445 1446 @user_passes_test(lambda u:u.is_staff)
1446 1447 def dev_conf_export(request, id_conf):
1447 1448
1448 1449 conf = get_object_or_404(Configuration, pk=id_conf)
1449 1450
1450 1451 if request.method == 'GET':
1451 1452 file_form = DownloadFileForm(conf.device.device_type.name)
1452 1453
1453 1454 if request.method == 'POST':
1454 1455 file_form = DownloadFileForm(conf.device.device_type.name, request.POST)
1455 1456
1456 1457 if file_form.is_valid():
1457 1458 fields = conf.export_to_file(format = file_form.cleaned_data['format'])
1458 1459
1459 1460 response = HttpResponse(content_type=fields['content_type'])
1460 1461 response['Content-Disposition'] = 'attachment; filename="%s"' %fields['filename']
1461 1462 response.write(fields['content'])
1462 1463
1463 1464 return response
1464 1465
1465 1466 messages.error(request, "Could not export parameters")
1466 1467
1467 1468 kwargs = {}
1468 1469 kwargs['id_dev'] = conf.id
1469 1470 kwargs['title'] = 'Device Configuration'
1470 1471 kwargs['form'] = file_form
1471 1472 kwargs['suptitle'] = 'Exporting file'
1472 1473 kwargs['button'] = 'Export'
1473 1474
1474 1475 return render(request, 'dev_conf_export.html', kwargs)
1475 1476
1476 1477
1477 1478 @user_passes_test(lambda u:u.is_staff)
1478 1479 def dev_conf_delete(request, id_conf):
1479 1480
1480 1481 conf = get_object_or_404(Configuration, pk=id_conf)
1481 1482
1482 1483 if request.method=='POST':
1483 1484 if request.user.is_staff:
1484 1485 conf.delete()
1485 1486 return redirect('url_dev_confs')
1486 1487
1487 1488 messages.error(request, 'Not enough permission to delete this object')
1488 1489 return redirect(conf.get_absolute_url())
1489 1490
1490 1491 kwargs = {
1491 1492 'title': 'Delete',
1492 1493 'suptitle': 'Experiment',
1493 1494 'object': conf,
1494 1495 'previous': conf.get_absolute_url(),
1495 1496 'delete': True
1496 1497 }
1497 1498
1498 1499 return render(request, 'confirm.html', kwargs)
1499 1500
1500 1501
1501 1502 def sidebar(**kwargs):
1502 1503
1503 1504 side_data = {}
1504 1505
1505 1506 conf = kwargs.get('conf', None)
1506 1507 experiment = kwargs.get('experiment', None)
1507 1508
1508 1509 if not experiment:
1509 1510 experiment = conf.experiment
1510 1511
1511 1512 if experiment:
1512 1513 side_data['experiment'] = experiment
1513 1514 campaign = experiment.campaign_set.all()
1514 1515 if campaign:
1515 1516 side_data['campaign'] = campaign[0]
1516 1517 experiments = campaign[0].experiments.all()
1517 1518 else:
1518 1519 experiments = [experiment]
1519 1520 configurations = experiment.configuration_set.filter(type=0)
1520 1521 side_data['side_experiments'] = experiments
1521 1522 side_data['side_configurations'] = configurations
1522 1523
1523 1524 return side_data
1524 1525
1525 1526 def get_paginator(model, page, order, filters={}, n=10):
1526 1527
1527 1528 kwargs = {}
1528 1529 query = Q()
1529 1530 if isinstance(filters, QueryDict):
1530 1531 filters = filters.dict()
1531 1532 [filters.pop(key) for key in filters.keys() if filters[key] in ('', ' ')]
1532 1533 filters.pop('page', None)
1533 1534
1534 1535 if 'template' in filters:
1535 1536 filters['template'] = True
1536 1537 if 'start_date' in filters:
1537 1538 filters['start_date__gte'] = filters.pop('start_date')
1538 1539 if 'end_date' in filters:
1539 1540 filters['start_date__lte'] = filters.pop('end_date')
1540 1541 if 'tags' in filters:
1541 1542 tags = filters.pop('tags')
1542 1543 fields = [f.name for f in model._meta.get_fields()]
1543 1544
1544 1545 if 'tags' in fields:
1545 1546 query = query | Q(tags__icontains=tags)
1546 1547 if 'name' in fields:
1547 1548 query = query | Q(name__icontains=tags)
1548 1549 if 'location' in fields:
1549 1550 query = query | Q(location__name__icontains=tags)
1550 1551 if 'device' in fields:
1551 1552 query = query | Q(device__device_type__name__icontains=tags)
1552 1553
1553 1554 object_list = model.objects.filter(query, **filters).order_by(*order)
1554 1555 paginator = Paginator(object_list, n)
1555 1556
1556 1557 try:
1557 1558 objects = paginator.page(page)
1558 1559 except PageNotAnInteger:
1559 1560 objects = paginator.page(1)
1560 1561 except EmptyPage:
1561 1562 objects = paginator.page(paginator.num_pages)
1562 1563
1563 1564 kwargs['objects'] = objects
1564 1565 kwargs['offset'] = (int(page)-1)*n if page else 0
1565 1566
1566 1567 return kwargs
1567 1568
1568 1569 def operation(request, id_camp=None):
1569 1570
1570 1571 kwargs = {}
1571 1572 kwargs['title'] = 'Radars Operation'
1572 1573 kwargs['no_sidebar'] = True
1573 1574 campaigns = Campaign.objects.filter(start_date__lte=datetime.now(),
1574 1575 end_date__gte=datetime.now()).order_by('-start_date')
1575 1576
1576 1577
1577 1578 if id_camp:
1578 1579 campaign = get_object_or_404(Campaign, pk = id_camp)
1579 1580 form = OperationForm(initial={'campaign': campaign.id}, campaigns=campaigns)
1580 1581 kwargs['campaign'] = campaign
1581 1582 else:
1582 1583 form = OperationForm(campaigns=campaigns)
1583 1584 kwargs['form'] = form
1584 1585 return render(request, 'operation.html', kwargs)
1585 1586
1586 1587 #---Experiment
1587 1588 keys = ['id', 'name', 'start_time', 'end_time', 'status']
1588 1589 kwargs['experiment_keys'] = keys[1:]
1589 1590 kwargs['experiments'] = experiments
1590 1591 #---Radar
1591 1592 kwargs['locations'] = campaign.get_experiments_by_radar()
1592 1593 kwargs['form'] = form
1593 1594
1594 1595 return render(request, 'operation.html', kwargs)
1595 1596
1596 1597
1597 1598 @login_required
1598 1599 def radar_start(request, id_camp, id_radar):
1599 1600
1600 1601 campaign = get_object_or_404(Campaign, pk = id_camp)
1601 1602 experiments = campaign.get_experiments_by_radar(id_radar)[0]['experiments']
1602 1603 now = datetime.utcnow()
1603 1604
1604 1605 for exp in experiments:
1605 1606 date = datetime.combine(datetime.now().date(), exp.start_time)
1606 1607
1607 1608 if exp.status == 2:
1608 1609 messages.warning(request, 'Experiment {} already running'.format(exp))
1609 1610 continue
1610 1611
1611 1612 if exp.status == 3:
1612 1613 messages.warning(request, 'Experiment {} already programmed'.format(exp))
1613 1614 continue
1614 1615
1615 1616 if date>campaign.end_date or date<campaign.start_date:
1616 1617 messages.warning(request, 'Experiment {} out of date'.format(exp))
1617 1618 continue
1618 1619
1619 1620 if now>=date:
1620 1621 task = task_start.delay(exp.pk)
1621 1622 exp.status = task.wait()
1622 1623 if exp.status==0:
1623 1624 messages.error(request, 'Experiment {} not start'.format(exp))
1624 1625 if exp.status==2:
1625 1626 messages.success(request, 'Experiment {} started'.format(exp))
1626 1627 else:
1627 1628 task = task_start.apply_async((exp.pk,), eta=date)
1628 1629 exp.status = 3
1629 1630 messages.success(request, 'Experiment {} programmed to start at {}'.format(exp, date))
1630 1631
1631 1632 exp.save()
1632 1633
1633 1634 return HttpResponseRedirect(reverse('url_operation', args=[id_camp]))
1634 1635
1635 1636
1636 1637 @login_required
1637 1638 def radar_stop(request, id_camp, id_radar):
1638 1639
1639 1640 campaign = get_object_or_404(Campaign, pk = id_camp)
1640 1641 experiments = campaign.get_experiments_by_radar(id_radar)[0]['experiments']
1641 1642
1642 1643 for exp in experiments:
1643 1644
1644 1645 if exp.status == 2:
1645 1646 task = task_stop.delay(exp.pk)
1646 1647 exp.status = task.wait()
1647 1648 messages.warning(request, 'Experiment {} stopped'.format(exp))
1648 1649 exp.save()
1649 1650 else:
1650 1651 messages.error(request, 'Experiment {} not running'.format(exp))
1651 1652
1652 1653 return HttpResponseRedirect(reverse('url_operation', args=[id_camp]))
1653 1654
1654 1655
1655 1656 @login_required
1656 1657 def radar_refresh(request, id_camp, id_radar):
1657 1658
1658 1659 campaign = get_object_or_404(Campaign, pk = id_camp)
1659 1660 experiments = campaign.get_experiments_by_radar(id_radar)[0]['experiments']
1660 1661
1661 1662 for exp in experiments:
1662 1663 exp.get_status()
1663 1664
1664 1665 return HttpResponseRedirect(reverse('url_operation', args=[id_camp]))
@@ -1,952 +1,969
1 1
2 2 import ast
3 3 import json
4 4 import requests
5 5 import numpy as np
6 6 from base64 import b64encode
7 7 from struct import pack
8 8
9 9 from django.db import models
10 10 from django.core.urlresolvers import reverse
11 11 from django.core.validators import MinValueValidator, MaxValueValidator
12 12
13 13 from apps.main.models import Configuration
14 14 from devices.rc import api
15 15 from .utils import RCFile
16 16
17 17 # Create your models here.
18 18
19 19 LINE_TYPES = (
20 20 ('none', 'Not used'),
21 21 ('tr', 'Transmission/reception selector signal'),
22 22 ('tx', 'A modulating signal (Transmission pulse)'),
23 23 ('codes', 'BPSK modulating signal'),
24 24 ('windows', 'Sample window signal'),
25 25 ('sync', 'Synchronizing signal'),
26 26 ('flip', 'IPP related periodic signal'),
27 27 ('prog_pulses', 'Programmable pulse'),
28 28 ('mix', 'Mixed line'),
29 29 )
30 30
31 31
32 32 SAMPLING_REFS = (
33 33 ('none', 'No Reference'),
34 34 ('begin_baud', 'Begin of the first baud'),
35 35 ('first_baud', 'Middle of the first baud'),
36 36 ('sub_baud', 'Middle of the sub-baud')
37 37 )
38 38
39 39 DAT_CMDS = {
40 40 # Pulse Design commands
41 41 'DISABLE' : 0, # Disables pulse generation
42 42 'ENABLE' : 24, # Enables pulse generation
43 43 'DELAY_START' : 40, # Write delay status to memory
44 44 'FLIP_START' : 48, # Write flip status to memory
45 45 'SAMPLING_PERIOD' : 64, # Establish Sampling Period
46 46 'TX_ONE' : 72, # Output '0' in line TX
47 47 'TX_ZERO' : 88, # Output '0' in line TX
48 48 'SW_ONE' : 104, # Output '0' in line SW
49 49 'SW_ZERO' : 112, # Output '1' in line SW
50 50 'RESTART': 120, # Restarts CR8 Firmware
51 51 'CONTINUE' : 253, # Function Unknown
52 52 # Commands available to new controllers
53 53 # In Pulse Design Executable, the clock divisor code is written as 12 at the start, but it should be written as code 22(below) just before the final enable.
54 54 'CLOCK_DIVISOR_INIT' : 12, # Specifies Clock Divisor. Legacy command, ignored in the actual .dat conversion
55 55 'CLOCK_DIVISOR_LAST' : 22, # Specifies Clock Divisor (default 60 if not included) syntax: 255,22 254,N-1.
56 56 'CLOCK_DIVIDER' : 8,
57 57 }
58 58
59 59
60 60 class RCConfiguration(Configuration):
61 61
62 62 ipp = models.FloatField(verbose_name='IPP [Km]', validators=[MinValueValidator(1), MaxValueValidator(9000)], default=300)
63 63 ntx = models.PositiveIntegerField(verbose_name='Number of TX', validators=[MinValueValidator(1), MaxValueValidator(400)], default=1)
64 64 clock_in = models.FloatField(verbose_name='Clock in [MHz]', validators=[MinValueValidator(1), MaxValueValidator(80)], default=1)
65 65 clock_divider = models.PositiveIntegerField(verbose_name='Clock divider', validators=[MinValueValidator(1), MaxValueValidator(256)], default=1)
66 66 clock = models.FloatField(verbose_name='Clock Master [MHz]', blank=True, default=1)
67 67 time_before = models.PositiveIntegerField(verbose_name='Time before [&mu;S]', default=12)
68 68 time_after = models.PositiveIntegerField(verbose_name='Time after [&mu;S]', default=1)
69 69 sync = models.PositiveIntegerField(verbose_name='Synchro delay', default=0)
70 70 sampling_reference = models.CharField(verbose_name='Sampling Reference', choices=SAMPLING_REFS, default='none', max_length=40)
71 71 control_tx = models.BooleanField(verbose_name='Control Switch TX', default=False)
72 72 control_sw = models.BooleanField(verbose_name='Control Switch SW', default=False)
73 73 total_units = models.PositiveIntegerField(default=0)
74 74 mix = models.BooleanField(default=False)
75 75
76 76 class Meta:
77 77 db_table = 'rc_configurations'
78 78
79 79 def get_absolute_url_plot(self):
80 80 return reverse('url_plot_rc_pulses', args=[str(self.id)])
81 81
82 82 def get_absolute_url_import(self):
83 83 return reverse('url_import_rc_conf', args=[str(self.id)])
84 84
85 85 @property
86 86 def ipp_unit(self):
87 87
88 88 return '{} ({})'.format(self.ipp, int(self.ipp*self.km2unit))
89 89
90 90 @property
91 91 def us2unit(self):
92 92
93 93 return self.clock_in/self.clock_divider
94 94
95 95 @property
96 96 def km2unit(self):
97 97
98 98 return 20./3*(self.clock_in/self.clock_divider)
99 99
100 100 def clone(self, **kwargs):
101 101
102 102 lines = self.get_lines()
103 103 self.pk = None
104 104 self.id = None
105 105 for attr, value in kwargs.items():
106 106 setattr(self, attr, value)
107 107 self.save()
108 108
109 109 for line in lines:
110 110 line.clone(rc_configuration=self)
111 111
112 112 return self
113 113
114 114 def get_lines(self, **kwargs):
115 115 '''
116 116 Retrieve configuration lines
117 117 '''
118 118
119 119 return RCLine.objects.filter(rc_configuration=self.pk, **kwargs)
120 120
121 121
122 122 def clean_lines(self):
123 123 '''
124 124 '''
125 125
126 126 empty_line = RCLineType.objects.get(name='none')
127 127
128 128 for line in self.get_lines():
129 129 line.line_type = empty_line
130 130 line.params = '{}'
131 131 line.save()
132 132
133 133 def parms_to_dict(self):
134 134 '''
135 135 '''
136 136
137 137 ignored = ('parameters', 'type', 'polymorphic_ctype', 'configuration_ptr',
138 138 'created_date', 'programmed_date')
139 139
140 140 data = {}
141 141 for field in self._meta.fields:
142 142 if field.name in ignored:
143 143 continue
144 144 data[field.name] = '{}'.format(field.value_from_object(self))
145 145
146 146 data['device_id'] = data.pop('device')
147 147 data['lines'] = []
148 148
149 149 for line in self.get_lines():
150 150 line_data = json.loads(line.params)
151 151 if 'TX_ref' in line_data and line_data['TX_ref'] not in (0, '0'):
152 152 line_data['TX_ref'] = RCLine.objects.get(pk=line_data['TX_ref']).get_name()
153 153 if 'code' in line_data:
154 154 line_data['code'] = RCLineCode.objects.get(pk=line_data['code']).name
155 155 line_data['type'] = line.line_type.name
156 156 line_data['name'] = line.get_name()
157 157 data['lines'].append(line_data)
158 158
159 159 data['delays'] = self.get_delays()
160 160 data['pulses'] = self.get_pulses()
161 161
162 162 return data
163 163
164 164 def dict_to_parms(self, data):
165 165 '''
166 166 '''
167 167
168 168 self.name = data['name']
169 169 self.ipp = float(data['ipp'])
170 170 self.ntx = int(data['ntx'])
171 171 self.clock_in = float(data['clock_in'])
172 172 self.clock_divider = int(data['clock_divider'])
173 173 self.clock = float(data['clock'])
174 174 self.time_before = data['time_before']
175 175 self.time_after = data['time_after']
176 176 self.sync = data['sync']
177 177 self.sampling_reference = data['sampling_reference']
178 178 self.total_units = self.ipp*self.ntx*self.km2unit
179 179 self.save()
180 180 self.clean_lines()
181 181
182 182 lines = []
183 183 positions = {'tx':0, 'tr':0}
184 184
185 185 for i, line_data in enumerate(data['lines']):
186 186 name = line_data.pop('name', '')
187 187 line_type = RCLineType.objects.get(name=line_data.pop('type'))
188 188 if line_type.name=='codes':
189 189 code = RCLineCode.objects.get(name=line_data['code'])
190 190 line_data['code'] = code.pk
191 191 line = RCLine.objects.filter(rc_configuration=self, channel=i)
192 192 if line:
193 193 line = line[0]
194 194 line.line_type = line_type
195 195 line.params = json.dumps(line_data)
196 196 else:
197 197 line = RCLine(rc_configuration=self, line_type=line_type,
198 198 params=json.dumps(line_data),
199 199 channel=i)
200 200
201 201 if line_type.name=='tx':
202 202 line.position = positions['tx']
203 203 positions['tx'] += 1
204 204
205 205 if line_type.name=='tr':
206 206 line.position = positions['tr']
207 207 positions['tr'] += 1
208 208
209 209 line.save()
210 210 lines.append(line)
211 211
212 212 for line, line_data in zip(lines, data['lines']):
213 213 if 'TX_ref' in line_data:
214 214 params = json.loads(line.params)
215 215 if line_data['TX_ref'] in (0, '0'):
216 216 params['TX_ref'] = '0'
217 217 else:
218 218 params['TX_ref'] = [l.pk for l in lines if l.line_type.name=='tx' and line_data['TX_ref'] in l.get_name()][0]
219 219 line.params = json.dumps(params)
220 220 line.save()
221 221
222 222
223 223 def get_delays(self):
224 224
225 225 pulses = [line.pulses_as_points() for line in self.get_lines()]
226 226 points = [tup for tups in pulses for tup in tups]
227 227 points = set([x for tup in points for x in tup])
228 228 points = list(points)
229 229 points.sort()
230 230
231 231 if points[0]!=0:
232 232 points.insert(0, 0)
233 233
234 234 return [points[i+1]-points[i] for i in range(len(points)-1)]
235 235
236 236
237 237 def get_pulses(self, binary=True):
238 238
239 pulses = [line.pulses_as_points() for line in self.get_lines()]
240 points = [tup for tups in pulses for tup in tups]
241 points = set([x for tup in points for x in tup])
239
240 pulses = [line.pulses_as_points() for line in self.get_lines()]
241 tuples = [tup for tups in pulses for tup in tups]
242 points = set([x for tup in tuples for x in tup])
242 243 points = list(points)
243 points.sort()
244
245 line_points = [line.pulses_as_points() for line in self.get_lines()]
246 #line_points = [[(x, x+y) for x,y in tups] for tups in line_points]
247 line_points = [[t for x in tups for t in x] for tups in line_points]
248 states = [[1 if x in tups else 0 for tups in line_points] for x in points]
244 points.sort()
245 states = []
246 last = [0 for x in pulses]
247
248 for x in points:
249 dum = []
250 for i,tups in enumerate(pulses):
251 ups = [tup[0] for tup in tups]
252 dws = [tup[1] for tup in tups]
253 if x in ups:
254 dum.append(1)
255 elif x in dws:
256 dum.append(0)
257 else:
258 dum.append(last[i])
259 states.append(dum)
260 last = dum
249 261
250 262 if binary:
251 states.reverse()
252 states = [int(''.join([str(x) for x in flips]), 2) for flips in states]
253
263 ret = []
264 for flips in states:
265 flips.reverse()
266 ret.append(int(''.join([str(x) for x in flips]), 2))
267 states = ret
268
254 269 return states[:-1]
255 270
256 271 def add_cmd(self, cmd):
257 272
258 273 if cmd in DAT_CMDS:
259 274 return (255, DAT_CMDS[cmd])
260 275
261 276 def add_data(self, value):
262 277
263 278 return (254, value-1)
264 279
265 280 def parms_to_binary(self, dat=True):
266 281 '''
267 282 Create "dat" stream to be send to CR
268 283 '''
269 284
270 285 data = bytearray()
271 286 # create header
272 287 data.extend(self.add_cmd('DISABLE'))
273 288 data.extend(self.add_cmd('CONTINUE'))
274 289 data.extend(self.add_cmd('RESTART'))
275 290
276 291 if self.control_sw:
277 292 data.extend(self.add_cmd('SW_ONE'))
278 293 else:
279 294 data.extend(self.add_cmd('SW_ZERO'))
280 295
281 296 if self.control_tx:
282 297 data.extend(self.add_cmd('TX_ONE'))
283 298 else:
284 299 data.extend(self.add_cmd('TX_ZERO'))
285 300
286 301 # write divider
287 302 data.extend(self.add_cmd('CLOCK_DIVIDER'))
288 303 data.extend(self.add_data(self.clock_divider))
289 304
290 305 # write delays
291 306 data.extend(self.add_cmd('DELAY_START'))
292 307 # first delay is always zero
293 308 data.extend(self.add_data(1))
294 309
295 310 delays = self.get_delays()
296 311
297 312 for delay in delays:
298 313 while delay>252:
299 314 data.extend(self.add_data(253))
300 315 delay -= 253
301 316 data.extend(self.add_data(int(delay)))
302 317
303 318 # write flips
304 319 data.extend(self.add_cmd('FLIP_START'))
305 320
306 321 states = self.get_pulses(binary=False)
307 322
308 323 for flips, delay in zip(states, delays):
309 324 flips.reverse()
310 325 flip = int(''.join([str(x) for x in flips]), 2)
311 326 data.extend(self.add_data(flip+1))
312 327 while delay>252:
313 328 data.extend(self.add_data(1))
314 329 delay -= 253
315 330
316 331 # write sampling period
317 332 data.extend(self.add_cmd('SAMPLING_PERIOD'))
318 333 wins = self.get_lines(line_type__name='windows')
319 334 if wins:
320 335 win_params = json.loads(wins[0].params)['params']
321 336 if win_params:
322 337 dh = int(win_params[0]['resolution']*self.km2unit)
323 338 else:
324 339 dh = 1
325 340 else:
326 341 dh = 1
327 342 data.extend(self.add_data(dh))
328 343
329 344 # write enable
330 345 data.extend(self.add_cmd('ENABLE'))
331 346
332 347 if not dat:
333 348 return data
334 349
335 350 return '\n'.join(['{}'.format(x) for x in data])
336 351
337 352
338 353 def update_from_file(self, filename):
339 354 '''
340 355 Update instance from file
341 356 '''
342 357
343 358 f = RCFile(filename)
344 359 self.dict_to_parms(f.data)
345 360 self.update_pulses()
346 361
347 362 def update_pulses(self):
348 363
349 364 for line in self.get_lines():
350 365 line.update_pulses()
351 366
352 367 def plot_pulses2(self, km=False):
353 368
354 369 import matplotlib.pyplot as plt
355 370 from bokeh.resources import CDN
356 371 from bokeh.embed import components
357 372 from bokeh.mpl import to_bokeh
358 373 from bokeh.models.tools import WheelZoomTool, ResetTool, PanTool, HoverTool, SaveTool
359 374
360 375 lines = self.get_lines()
361 376
362 377 N = len(lines)
363 378 npoints = self.total_units/self.km2unit if km else self.total_units
364 379 fig = plt.figure(figsize=(12, 2+N*0.5))
365 380 ax = fig.add_subplot(111)
366 381 labels = ['IPP']
367 382
368 383 for i, line in enumerate(lines):
369 384 labels.append(line.get_name(channel=True))
370 385 l = ax.plot((0, npoints),(N-i-1, N-i-1))
371 386 points = [(tup[0], tup[1]-tup[0]) for tup in line.pulses_as_points(km=km) if tup!=(0,0)]
372 387 ax.broken_barh(points, (N-i-1, 0.5),
373 388 edgecolor=l[0].get_color(), facecolor='none')
374 389
375 390 n = 0
376 391 f = ((self.ntx+50)/100)*5 if ((self.ntx+50)/100)*10>0 else 2
377 392 for x in np.arange(0, npoints, self.ipp if km else self.ipp*self.km2unit):
378 393 if n%f==0:
379 394 ax.text(x, N, '%s' % n, size=10)
380 395 n += 1
381 396
382 397
383 398 labels.reverse()
384 399 ax.set_yticks(range(len(labels)))
385 400 ax.set_yticklabels(labels)
386 401 ax.set_xlabel = 'Units'
387 402 plot = to_bokeh(fig, use_pandas=False)
388 403 plot.tools = [PanTool(dimensions=['width']), WheelZoomTool(dimensions=['width']), ResetTool(), SaveTool()]
389 404 plot.toolbar_location="above"
390 405
391 406 return components(plot, CDN)
392 407
393 408 def plot_pulses(self, km=False):
394 409
395 410 from bokeh.plotting import figure
396 411 from bokeh.resources import CDN
397 412 from bokeh.embed import components
398 413 from bokeh.models import FixedTicker, PrintfTickFormatter
399 414 from bokeh.models.tools import WheelZoomTool, ResetTool, PanTool, HoverTool, SaveTool
400 415 from bokeh.models.sources import ColumnDataSource
401 416
402 417 lines = self.get_lines().reverse()
403 418
404 419 N = len(lines)
405 420 npoints = self.total_units/self.km2unit if km else self.total_units
406 421 ipp = self.ipp if km else self.ipp*self.km2unit
407 422
408 423 hover = HoverTool(tooltips=[("Line", "@name"),
409 424 ("IPP", "@ipp"),
410 425 ("X", "@left")])
411 426
412 427 tools = [PanTool(dimensions=['width']),
413 428 WheelZoomTool(dimensions=['width']),
414 429 hover, SaveTool()]
415 430
416 431 plot = figure(width=1000,
417 432 height=40+N*50,
418 433 y_range = (0, N),
419 434 tools=tools,
420 435 toolbar_location='above',
421 436 toolbar_sticky=False,)
422 437
423 438 plot.xaxis.axis_label = 'Km' if km else 'Units'
424 439 plot.xaxis[0].formatter = PrintfTickFormatter(format='%d')
425 440 plot.yaxis.axis_label = 'Pulses'
426 441 plot.yaxis[0].ticker=FixedTicker(ticks=list(range(N)))
427 442 plot.yaxis[0].formatter = PrintfTickFormatter(format='Line %d')
428 443
429 444 for i, line in enumerate(lines):
430 445
431 446 points = [tup for tup in line.pulses_as_points(km=km) if tup!=(0,0)]
432 447
433 448 source = ColumnDataSource(data = dict(
434 449 bottom = [i for tup in points],
435 450 top = [i+0.5 for tup in points],
436 451 left = [tup[0] for tup in points],
437 452 right = [tup[1] for tup in points],
438 453 ipp = [int(tup[0]/ipp) for tup in points],
439 454 name = [line.get_name() for tup in points]
440 455 ))
441 456
442 457 plot.quad(
443 458 bottom = 'bottom',
444 459 top = 'top',
445 460 left = 'left',
446 461 right = 'right',
447 462 source = source,
448 463 fill_alpha = 0,
449 464 #line_color = 'blue',
450 465 )
451 466
452 467 plot.line([0, npoints], [i, i])#, color='blue')
453 468
454 469 return components(plot, CDN)
455 470
456 471 def status_device(self):
457 472
458 473 try:
459 474 self.device.status = 0
460 475 req = requests.get(self.device.url('status'))
461 476 payload = req.json()
462 if payload['status']=='ok':
477 if payload['status']=='enabled':
478 self.device.status = 3
479 elif payload['status']=='disabled':
463 480 self.device.status = 2
464 481 else:
465 482 self.device.status = 1
466 483 self.device.save()
467 484 self.message = payload['status']
468 485 return False
469 486 except Exception as e:
470 487 if 'No route to host' not in str(e):
471 488 self.device.status = 4
472 489 self.device.save()
473 490 self.message = str(e)
474 491 return False
475 492
476 493 self.device.save()
477 494 return True
478 495
479 496 def reset_device(self):
480 497
481 498 try:
482 499 req = requests.post(self.device.url('reset'))
483 500 payload = req.json()
484 501 if payload['reset']=='ok':
485 502 self.message = 'RC restarted'
486 503 else:
487 504 self.message = 'RC restart not ok'
488 505 self.device.status = 4
489 506 self.device.save()
490 507 except Exception as e:
491 508 self.message = str(e)
492 509 return False
493 510
494 511 return True
495 512
496 513 def stop_device(self):
497 514
498 515 try:
499 516 req = requests.post(self.device.url('stop'))
500 517 payload = req.json()
501 518 if payload['stop']=='ok':
502 519 self.device.status = 2
503 520 self.device.save()
504 521 self.message = 'RC stopped'
505 522 else:
506 523 self.message = 'RC stop not ok'
507 524 self.device.status = 4
508 525 self.device.save()
509 526 return False
510 527 except Exception as e:
511 528 if 'No route to host' not in str(e):
512 529 self.device.status = 4
513 530 else:
514 531 self.device.status = 0
515 532 self.message = str(e)
516 533 self.device.save()
517 534 return False
518 535
519 536 return True
520 537
521 538 def start_device(self):
522 539
523 540 try:
524 541 req = requests.post(self.device.url('start'))
525 542 payload = req.json()
526 543 if payload['start']=='ok':
527 544 self.device.status = 3
528 545 self.device.save()
529 546 self.message = 'RC running'
530 547 else:
531 548 self.message = 'RC start not ok'
532 549 return False
533 550 except Exception as e:
534 551 if 'No route to host' not in str(e):
535 552 self.device.status = 4
536 553 else:
537 554 self.device.status = 0
538 555 self.message = str(e)
539 556 self.device.save()
540 557 return False
541 558
542 559 return True
543 560
544 561 def write_device(self):
545 562
546 563 values = zip(self.get_pulses(),
547 564 [x-1 for x in self.get_delays()])
548 payload = ''
549 565
550 for tup in values:
551 vals = pack('<HH', *tup)
552 payload += '\x05'+vals[0]+'\x04'+vals[1]+'\x05'+vals[2]+'\x05'+vals[3]
566 data = bytearray()
567 #reset
568 data.extend((128, 0))
569 #disable
570 data.extend((129, 0))
571 #divider
572 data.extend((131, self.clock_divider-1))
573 #enable writing
574 data.extend((139, 62))
575
576 last = 0
577 for tup in values:
578 vals = pack('<HH', last^tup[0], tup[1])
579 last = tup[0]
580 data.extend((133, vals[1], 132, vals[0], 133, vals[3], 132, vals[2]))
581
582 #enable
583 data.extend((129, 1))
553 584
554 585 try:
555 ## reset
556 if not self.reset_device():
557 return False
558 ## stop
559 if not self.stop_device():
560 return False
561 ## write clock divider
562 req = requests.post(self.device.url('divisor'),
563 {'divisor': '{:d}'.format(self.clock_divider-1)})
564 payload = req.json()
565 if payload['divisor']=='ok':
566 self.message = 'Error configuring RC clock divider'
567 return False
568 ## write pulses & delays
569 req = requests.post(self.device.url('write'), data=b64encode(payload))
586 req = requests.post(self.device.url('write'), data=b64encode(data))
570 587 payload = req.json()
571 588 if payload['write']=='ok':
572 589 self.device.status = 2
573 590 self.device.save()
574 591 self.message = 'RC configured'
575 592 else:
576 self.device.status = 4
593 self.device.status = 1
577 594 self.device.save()
578 595 self.message = 'RC write not ok'
579 596 return False
580 597
581 598 except Exception as e:
582 599 if 'No route to host' not in str(e):
583 600 self.device.status = 4
584 601 else:
585 602 self.device.status = 0
586 603 self.message = str(e)
587 604 self.device.save()
588 605 return False
589 606
590 607 return True
591 608
592 609
593 610 class RCLineCode(models.Model):
594 611
595 612 name = models.CharField(max_length=40)
596 613 bits_per_code = models.PositiveIntegerField(default=0)
597 614 number_of_codes = models.PositiveIntegerField(default=0)
598 615 codes = models.TextField(blank=True, null=True)
599 616
600 617 class Meta:
601 618 db_table = 'rc_line_codes'
602 619 ordering = ('name',)
603 620
604 621 def __str__(self):
605 622 return u'%s' % self.name
606 623
607 624
608 625 class RCLineType(models.Model):
609 626
610 627 name = models.CharField(choices=LINE_TYPES, max_length=40)
611 628 description = models.TextField(blank=True, null=True)
612 629 params = models.TextField(default='[]')
613 630
614 631 class Meta:
615 632 db_table = 'rc_line_types'
616 633
617 634 def __str__(self):
618 635 return u'%s - %s' % (self.name.upper(), self.get_name_display())
619 636
620 637
621 638 class RCLine(models.Model):
622 639
623 640 rc_configuration = models.ForeignKey(RCConfiguration, on_delete=models.CASCADE)
624 641 line_type = models.ForeignKey(RCLineType)
625 642 channel = models.PositiveIntegerField(default=0)
626 643 position = models.PositiveIntegerField(default=0)
627 644 params = models.TextField(default='{}')
628 645 pulses = models.TextField(default='')
629 646
630 647 class Meta:
631 648 db_table = 'rc_lines'
632 649 ordering = ['channel']
633 650
634 651 def __str__(self):
635 652 if self.rc_configuration:
636 653 return u'%s - %s' % (self.rc_configuration, self.get_name())
637 654
638 655 def clone(self, **kwargs):
639 656
640 657 self.pk = None
641 658
642 659 for attr, value in kwargs.items():
643 660 setattr(self, attr, value)
644 661
645 662 self.save()
646 663
647 664 return self
648 665
649 666 def get_name(self, channel=False):
650 667
651 668 chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
652 669 s = ''
653 670
654 671 if self.line_type.name in ('tx',):
655 672 s = chars[self.position]
656 673 elif self.line_type.name in ('codes', 'windows', 'tr'):
657 674 if 'TX_ref' in json.loads(self.params):
658 675 pk = json.loads(self.params)['TX_ref']
659 676 if pk in (0, '0'):
660 677 s = ','.join(chars[l.position] for l in self.rc_configuration.get_lines(line_type__name='tx'))
661 678 else:
662 679 ref = RCLine.objects.get(pk=pk)
663 680 s = chars[ref.position]
664 681 s = '({})'.format(s)
665 682
666 683 s = '{}{}'.format(self.line_type.name.upper(), s)
667 684
668 685 if channel:
669 686 return '{} {}'.format(s, self.channel)
670 687 else:
671 688 return s
672 689
673 690 def get_lines(self, **kwargs):
674 691
675 692 return RCLine.objects.filter(rc_configuration=self.rc_configuration, **kwargs)
676 693
677 694 def pulses_as_array(self):
678 695
679 696 y = np.zeros(self.rc_configuration.total_units)
680 697
681 698 for tup in ast.literal_eval(self.pulses):
682 699 y[tup[0]:tup[1]] = 1
683 700
684 701 return y.astype(np.int8)
685 702
686 703 def pulses_as_points(self, km=False):
687 704
688 705 if km:
689 706 unit2km = 1/self.rc_configuration.km2unit
690 707 return [(tup[0]*unit2km, tup[1]*unit2km) for tup in ast.literal_eval(self.pulses)]
691 708 else:
692 709 return ast.literal_eval(self.pulses)
693 710
694 711 def get_win_ref(self, params, tx_id, km2unit):
695 712
696 713 ref = self.rc_configuration.sampling_reference
697 714 codes = [line for line in self.get_lines(line_type__name='codes') if int(json.loads(line.params)['TX_ref'])==int(tx_id)]
698 715
699 716 if codes:
700 717 tx_width = float(json.loads(RCLine.objects.get(pk=tx_id).params)['pulse_width'])*km2unit/len(json.loads(codes[0].params)['codes'][0])
701 718 else:
702 719 tx_width = float(json.loads(RCLine.objects.get(pk=tx_id).params)['pulse_width'])*km2unit
703
704 if ref=='first_baud':
705 return int(1 + (tx_width + 1)/2 + params['first_height']*km2unit - params['resolution']*km2unit)
706 elif ref=='sub_baud':
707 return int(1 + params['first_height']*km2unit - params['resolution']*km2unit/2)
720
721 if ref=='first_baud':
722 return int(1 + round((tx_width + 1)/2 + params['first_height']*km2unit - params['resolution']*km2unit))
723 elif ref=='sub_baud':
724 return int(1 + round(params['first_height']*km2unit - params['resolution']*km2unit/2))
708 725 else:
709 726 return 0
710 727
711 728 def update_pulses(self):
712 729 '''
713 730 Update pulses field
714 731 '''
715 732
716 733 km2unit = self.rc_configuration.km2unit
717 734 us2unit = self.rc_configuration.us2unit
718 735 ipp = self.rc_configuration.ipp
719 736 ntx = int(self.rc_configuration.ntx)
720 737 ipp_u = int(ipp*km2unit)
721 738 total = ipp_u*ntx if self.rc_configuration.total_units==0 else self.rc_configuration.total_units
722 739 y = []
723 740
724 741 if self.line_type.name=='tr':
725 742 tr_params = json.loads(self.params)
726 743
727 744 if tr_params['TX_ref'] in ('0', 0):
728 745 txs = self.get_lines(line_type__name='tx')
729 746 else:
730 747 txs = RCLine.objects.filter(pk=tr_params['TX_ref'])
731 748
732 749 for tx in txs:
733 750 params = json.loads(tx.params)
734 751
735 752 if float(params['pulse_width'])==0:
736 753 continue
737 754 delays = [float(d)*km2unit for d in params['delays'].split(',') if d]
738 755 width = float(params['pulse_width'])*km2unit+int(self.rc_configuration.time_before*us2unit)
739 756 before = 0
740 757 after = int(self.rc_configuration.time_after*us2unit)
741 758
742 759 y_tx = self.points(ntx, ipp_u, width,
743 760 delay=delays,
744 761 before=before,
745 762 after=after,
746 763 sync=self.rc_configuration.sync)
747 764
748 765 ranges = params['range'].split(',')
749 766
750 767 if len(ranges)>0 and ranges[0]!='0':
751 768 y_tx = self.mask_ranges(y_tx, ranges)
752 769
753 770 tr_ranges = tr_params['range'].split(',')
754 771
755 772 if len(tr_ranges)>0 and tr_ranges[0]!='0':
756 773 y_tx = self.mask_ranges(y_tx, tr_ranges)
757 774
758 775 y.extend(y_tx)
759 776
760 777 self.pulses = str(y)
761 778 y = self.array_to_points(self.pulses_as_array())
762 779
763 780 elif self.line_type.name=='tx':
764 781 params = json.loads(self.params)
765 782 delays = [float(d)*km2unit for d in params['delays'].split(',') if d]
766 783 width = float(params['pulse_width'])*km2unit
767 784
768 785 if width>0:
769 786 before = int(self.rc_configuration.time_before*us2unit)
770 787 after = 0
771 788
772 789 y = self.points(ntx, ipp_u, width,
773 790 delay=delays,
774 791 before=before,
775 792 after=after,
776 793 sync=self.rc_configuration.sync)
777 794
778 795 ranges = params['range'].split(',')
779 796
780 797 if len(ranges)>0 and ranges[0]!='0':
781 798 y = self.mask_ranges(y, ranges)
782 799
783 800 elif self.line_type.name=='flip':
784 801 n = float(json.loads(self.params)['number_of_flips'])
785 802 width = n*ipp*km2unit
786 803 y = self.points(int((ntx+1)/(2*n)), ipp_u*n*2, width)
787 804
788 805 elif self.line_type.name=='codes':
789 806 params = json.loads(self.params)
790 807 tx = RCLine.objects.get(pk=params['TX_ref'])
791 808 tx_params = json.loads(tx.params)
792 809 delays = [float(d)*km2unit for d in tx_params['delays'].split(',') if d]
793 810 f = int(float(tx_params['pulse_width'])*km2unit/len(params['codes'][0]))
794 811 codes = [(np.fromstring(''.join([s*f for s in code]), dtype=np.uint8)-48).astype(np.int8) for code in params['codes']]
795 812 codes = [self.array_to_points(code) for code in codes]
796 813 n = len(codes)
797 814
798 815 for i, tup in enumerate(tx.pulses_as_points()):
799 816 code = codes[i%n]
800 817 y.extend([(c[0]+tup[0], c[1]+tup[0]) for c in code])
801 818
802 819 ranges = tx_params['range'].split(',')
803 820 if len(ranges)>0 and ranges[0]!='0':
804 821 y = self.mask_ranges(y, ranges)
805 822
806 823 elif self.line_type.name=='sync':
807 824 params = json.loads(self.params)
808 825 n = ipp_u*ntx
809 826 if params['invert'] in ('1', 1):
810 827 y = [(n-1, n)]
811 828 else:
812 829 y = [(0, 1)]
813 830
814 831 elif self.line_type.name=='prog_pulses':
815 832 params = json.loads(self.params)
816 833 if int(params['periodic'])==0:
817 834 nntx = 1
818 835 nipp = ipp_u*ntx
819 836 else:
820 837 nntx = ntx
821 838 nipp = ipp_u
822 839
823 840 if 'params' in params and len(params['params'])>0:
824 841 for p in params['params']:
825 842 y_pp = self.points(nntx, nipp,
826 843 p['end']-p['begin'],
827 844 before=p['begin'])
828 845
829 846 y.extend(y_pp)
830 847
831 848 elif self.line_type.name=='windows':
832 849 params = json.loads(self.params)
833 850
834 851 if 'params' in params and len(params['params'])>0:
835 852 tr_params = json.loads(self.get_lines(line_type__name='tr')[0].params)
836 853 tr_ranges = tr_params['range'].split(',')
837 854 for p in params['params']:
838 855 y_win = self.points(ntx, ipp_u,
839 856 p['resolution']*p['number_of_samples']*km2unit,
840 before=int(self.rc_configuration.time_before*us2unit)+self.get_win_ref(p, params['TX_ref'], km2unit),
841 sync=self.rc_configuration.sync)
857 before=int(self.rc_configuration.time_before*us2unit),
858 sync=self.get_win_ref(p, params['TX_ref'], km2unit))
842 859
843 860 if len(tr_ranges)>0 and tr_ranges[0]!='0':
844 861 y_win = self.mask_ranges(y_win, tr_ranges)
845 862
846 863 y.extend(y_win)
847 864
848 865 elif self.line_type.name=='mix':
849 866 values = self.rc_configuration.parameters.split('-')
850 867 confs = [RCConfiguration.objects.get(pk=value.split('|')[0]) for value in values]
851 868 modes = [value.split('|')[1] for value in values]
852 869 ops = [value.split('|')[2] for value in values]
853 870 delays = [value.split('|')[3] for value in values]
854 871 masks = [value.split('|')[4] for value in values]
855 872 mask = list('{:8b}'.format(int(masks[0])))
856 873 mask.reverse()
857 874 if mask[self.channel] in ('0', '', ' '):
858 875 y = np.zeros(confs[0].total_units, dtype=np.int8)
859 876 else:
860 877 y = confs[0].get_lines(channel=self.channel)[0].pulses_as_array()
861 878
862 879 for i in range(1, len(values)):
863 880 mask = list('{:8b}'.format(int(masks[i])))
864 881 mask.reverse()
865 882
866 883 if mask[self.channel] in ('0', '', ' '):
867 884 continue
868 885 Y = confs[i].get_lines(channel=self.channel)[0].pulses_as_array()
869 886 delay = float(delays[i])*km2unit
870 887
871 888 if modes[i]=='P':
872 889 if delay>0:
873 890 if delay<self.rc_configuration.ipp*km2unit and len(Y)==len(y):
874 891 y_temp = np.empty_like(Y)
875 892 y_temp[:delay] = 0
876 893 y_temp[delay:] = Y[:-delay]
877 894 elif delay+len(Y)>len(y):
878 895 y_new = np.zeros(delay+len(Y), dtype=np.int8)
879 896 y_new[:len(y)] = y
880 897 y = y_new
881 898 y_temp = np.zeros(delay+len(Y), dtype=np.int8)
882 899 y_temp[-len(Y):] = Y
883 900 elif delay+len(Y)==len(y):
884 901 y_temp = np.zeros(delay+len(Y))
885 902 y_temp[-len(Y):] = Y
886 903 elif delay+len(Y)<len(y):
887 904 y_temp = np.zeros(len(y), dtype=np.int8)
888 905 y_temp[delay:delay+len(Y)] = Y
889 906
890 907 if ops[i]=='OR':
891 908 y = y | y_temp
892 909 elif ops[i]=='XOR':
893 910 y = y ^ y_temp
894 911 elif ops[i]=='AND':
895 912 y = y & y_temp
896 913 elif ops[i]=='NAND':
897 914 y = y & ~y_temp
898 915 else:
899 916 y = np.concatenate([y, Y])
900 917
901 918 total = len(y)
902 919 y = self.array_to_points(y)
903 920
904 921 else:
905 922 y = []
906 923
907 924 if self.rc_configuration.total_units != total:
908 925 self.rc_configuration.total_units = total
909 926 self.rc_configuration.save()
910 927
911 928 self.pulses = str(y)
912 929 self.save()
913 930
914 931 @staticmethod
915 932 def array_to_points(X):
916 933
917 934 d = X[1:]-X[:-1]
918 935
919 936 up = np.where(d==1)[0]
920 937 if X[0]==1:
921 938 up = np.concatenate((np.array([-1]), up))
922 939 up += 1
923 940
924 941 dw = np.where(d==-1)[0]
925 942 if X[-1]==1:
926 943 dw = np.concatenate((dw, np.array([len(X)-1])))
927 944 dw += 1
928 945
929 946 return [(tup[0], tup[1]) for tup in zip(up, dw)]
930 947
931 948 @staticmethod
932 949 def mask_ranges(Y, ranges):
933 950
934 951 y = [(0, 0) for __ in Y]
935 952
936 953 for index in ranges:
937 954 if '-' in index:
938 955 args = [int(a) for a in index.split('-')]
939 956 y[args[0]-1:args[1]] = Y[args[0]-1:args[1]]
940 957 else:
941 958 y[int(index-1)] = Y[int(index-1)]
942 959
943 960 return y
944 961
945 962 @staticmethod
946 963 def points(ntx, ipp, width, delay=[0], before=0, after=0, sync=0):
947 964
948 965 delays = len(delay)
949 966
950 967 Y = [(int(ipp*x+before+delay[x%delays]+sync), int(ipp*x+width+before+delay[x%delays]+after+sync)) for x in range(ntx)]
951 968
952 969 return Y
@@ -1,153 +1,153
1 1 '''
2 2 Created on Dec 2, 2014
3 3
4 4 @author: Miguel Urco
5 5
6 6 eth_device decorator is used to implement an api to ethernet devices.
7 7 When eth_device decorator is used it adds two parameters to any function (ip and port)
8 8
9 9 #Definition
10 10
11 11 @eth_device
12 12 def enable_rf()
13 13 cmd = "xxxxx"
14 14 payload = "xxxxxx"
15 15
16 16 return cmd, payload
17 17
18 18 #How to call this function:
19 19 answer = enable_rf(ip, port)
20 20
21 21 '''
22 22 from devices.dds import data
23 23
24 24 from devices.jro_device import eth_device, IdClass
25 25
26 26 ID_CLASS = IdClass["dds"]
27 27
28 28 CMD_RESET =0X01
29 29 CMD_ENABLE =0X02
30 30 CMD_CHANGEIP =0X03
31 31 CMD_STATUS =0X04
32 32 CMD_ECHO =0XFE
33 33
34 34 DDS_CMD_RESET =0X10
35 35 DDS_CMD_ENABLE_RF =0x11
36 36 # DDS_CMD_MULTIPLIER =0X12
37 37 # DDS_CMD_MODE =0x13
38 38 # DDS_CMD_FREQUENCY_A =0X14
39 39 # DDS_CMD_FREQUENCY_B =0x15
40 40 # DDS_CMD_PHASE_A =0X16
41 41 # DDS_CMD_PHASE_B =0x17
42 42 # DDS_CMD_AMPLITUDE_1 =0X19 #Se han invertido la posicion de los canales
43 43 # DDS_CMD_AMPLITUDE_2 =0x18 #en el PCB
44 44
45 45 DDS_CMD_WRITE =0x50
46 46 DDS_CMD_READ =0x8000
47 47
48 48 @eth_device(ID_CLASS)
49 49 def reset():
50 50
51 51 cmd = CMD_RESET
52 52 payload = ""
53 53
54 54 return cmd, payload
55 55
56 56 @eth_device(ID_CLASS)
57 def change_ip(ip, mask="255.255.255.0", gateway="0.0.0.0"):
57 def change_ip(new_ip, mask="255.255.255.0", gateway="0.0.0.0"):
58 58
59 59 cmd = CMD_CHANGEIP
60 payload = ip + '/' + mask + '/' + gateway
60 payload = new_ip + '/' + mask + '/' + gateway
61 61
62 62 return cmd, payload
63 63
64 64 @eth_device(ID_CLASS)
65 65 def status():
66 66
67 67 cmd = CMD_STATUS
68 68 payload = ""
69 69
70 70 return cmd, payload
71 71
72 72 @eth_device(ID_CLASS)
73 73 def echo():
74 74
75 75 cmd = CMD_ECHO
76 76 payload = ""
77 77
78 78 return cmd, payload
79 79
80 80 @eth_device(ID_CLASS)
81 81 def enable_rf():
82 82
83 83 cmd = DDS_CMD_ENABLE_RF
84 84 payload = chr(0x01)
85 85
86 86 return cmd, payload
87 87
88 88 @eth_device(ID_CLASS)
89 89 def disable_rf():
90 90
91 91 cmd = DDS_CMD_ENABLE_RF
92 92 payload = chr(0x00)
93 93
94 94 return cmd, payload
95 95
96 96 @eth_device(ID_CLASS)
97 97 def read_all_device():
98 98
99 99 payload = ""
100 100
101 101 return DDS_CMD_READ, payload
102 102
103 103 @eth_device(ID_CLASS)
104 104 def write_all_device(payload):
105 105
106 106 return DDS_CMD_WRITE, payload
107 107
108 108 def read_config(ip, port):
109 109 """
110 110 Output:
111 111 parms : Dictionary with keys
112 112 multiplier :
113 113 frequencyA :
114 114 frequencyB :
115 115 frequencyA_Mhz :
116 116 frequencyB_Mhz :
117 117 modulation :
118 118 phaseA_degrees :
119 119 phaseB_degrees :
120 120 amplitudeI :
121 121 amplitudeQ :
122 122
123 123 """
124 124 payload = read_all_device(ip, port)
125 125
126 126 return data.dds_str_to_dict(payload)
127 127
128 128 def write_config(ip, port, parms):
129 129 """
130 130 Input:
131 131 ip :
132 132 port :
133 133 parms : Dictionary with keys
134 134 multiplier : 4 to 20
135 135 frequencyA : 0 to (2**48-1) equivalent to: 0 - "Master clock"
136 136 frequencyB : 0 to (2**48-1) equivalent to: 0 - "Master clock"
137 137 modulation : 0 to 3
138 138 phaseA_degrees : 0 - 360 degrees
139 139 phaseB_degrees : 0 - 360 degrees
140 140 amplitudeI : 0 to (2**12-1) equivalent to: 0 - 100%
141 141 amplitudeQ : 0 to (2**12-1) equivalent to: 0 - 100%
142 142
143 143 """
144 144
145 145 payload = data.dict_to_dds_str(parms)
146 146
147 147 answer = write_all_device(ip, port, payload)
148 148
149 149 return answer
150 150
151 151 if __name__ == '__main__':
152 152
153 153 print(read_config("127.0.0.1", 2000))
General Comments 0
You need to be logged in to leave comments. Login now