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