##// END OF EJS Templates
Fix RC plots bug
Juan C. Espinoza -
r332:9bb45c0e1ac7
parent child
Show More
@@ -1,877 +1,877
1 1 from django.db import models
2 2 from apps.main.models import Configuration, User
3 3 from django.core.urlresolvers import reverse
4 4 from celery.execute import send_task
5 5 from datetime import datetime
6 6 import ast
7 7 import socket
8 8 import json
9 9 import requests
10 10 import struct
11 11 import os, sys, time
12 12
13 13 antenna_default = json.dumps({
14 14 "antenna_up": [[0.0,0.0,0.0,0.0,0.5,0.5,0.5,0.5],
15 15 [0.0,0.0,0.0,0.0,0.5,0.5,0.5,0.5],
16 16 [0.0,0.0,0.0,0.0,0.5,0.5,0.5,0.5],
17 17 [0.0,0.0,0.0,0.0,0.5,0.5,0.5,0.5],
18 18 [0.5,0.5,0.5,0.5,1.0,1.0,1.0,1.0],
19 19 [0.5,0.5,0.5,0.5,1.0,1.0,1.0,1.0],
20 20 [0.5,0.5,0.5,0.5,1.0,1.0,1.0,1.0],
21 21 [0.5,0.5,0.5,0.5,1.0,1.0,1.0,1.0]
22 22 ]
23 23 ,
24 24 "antenna_down": [[0.0,0.0,0.0,0.0,0.5,0.5,0.5,0.5],
25 25 [0.0,0.0,0.0,0.0,0.5,0.5,0.5,0.5],
26 26 [0.0,0.0,0.0,0.0,0.5,0.5,0.5,0.5],
27 27 [0.0,0.0,0.0,0.0,0.5,0.5,0.5,0.5],
28 28 [0.5,0.5,0.5,0.5,3.0,3.0,3.0,3.0],
29 29 [0.5,0.5,0.5,0.5,3.0,3.0,3.0,3.0],
30 30 [0.5,0.5,0.5,0.5,3.0,3.0,3.0,3.0],
31 31 [0.5,0.5,0.5,0.5,3.0,3.0,3.0,3.0]],
32 32 })
33 33
34 34
35 35 tx_default = json.dumps({
36 36 "up": [[1,1,1,1,0,0,0,0],
37 37 [1,1,1,1,0,0,0,0],
38 38 [1,1,1,1,0,0,0,0],
39 39 [1,1,1,1,0,0,0,0],
40 40 [0,0,0,0,1,1,1,1],
41 41 [0,0,0,0,1,1,1,1],
42 42 [0,0,0,0,1,1,1,1],
43 43 [0,0,0,0,1,1,1,1]],
44 44
45 45 "down": [[1,1,1,1,0,0,0,0],
46 46 [1,1,1,1,0,0,0,0],
47 47 [1,1,1,1,0,0,0,0],
48 48 [1,1,1,1,0,0,0,0],
49 49 [0,0,0,0,1,1,1,1],
50 50 [0,0,0,0,1,1,1,1],
51 51 [0,0,0,0,1,1,1,1],
52 52 [0,0,0,0,1,1,1,1]],
53 53 })
54 54
55 55 rx_default = json.dumps({
56 56 "up": [[1,1,1,1,0,0,0,0],
57 57 [1,1,1,1,0,0,0,0],
58 58 [1,1,1,1,0,0,0,0],
59 59 [1,1,1,1,0,0,0,0],
60 60 [0,0,0,0,1,1,1,1],
61 61 [0,0,0,0,1,1,1,1],
62 62 [0,0,0,0,1,1,1,1],
63 63 [0,0,0,0,1,1,1,1]],
64 64
65 65 "down": [[1,1,1,1,0,0,0,0],
66 66 [1,1,1,1,0,0,0,0],
67 67 [1,1,1,1,0,0,0,0],
68 68 [1,1,1,1,0,0,0,0],
69 69 [0,0,0,0,1,1,1,1],
70 70 [0,0,0,0,1,1,1,1],
71 71 [0,0,0,0,1,1,1,1],
72 72 [0,0,0,0,1,1,1,1]],
73 73 })
74 74
75 75 status_default = '0000000000000000000000000000000000000000000000000000000000000000'
76 76 default_messages = {}
77 77
78 78 for i in range(1,65):
79 79 default_messages[str(i)] = "Module "+str(i)
80 80
81 81
82 82 ues_default = json.dumps({
83 83 "up": [0.533333,0.00000,1.06667,0.00000],
84 84 "down": [0.533333,0.00000,1.06667,0.00000]
85 85 })
86 86
87 87 onlyrx_default = json.dumps({
88 88 "up": False,
89 89 "down": False
90 90 })
91 91
92 92 def up_convertion(cadena):
93 93 valores = []
94 94 for c in cadena:
95 95 if c == 1.0: valores=valores+['000']
96 96 if c == 2.0: valores=valores+['001']
97 97 if c == 3.0: valores=valores+['010']
98 98 if c == 0.0: valores=valores+['011']
99 99 if c == 0.5: valores=valores+['100']
100 100 if c == 1.5: valores=valores+['101']
101 101 if c == 2.5: valores=valores+['110']
102 102 if c == 3.5: valores=valores+['111']
103 103
104 104 return valores
105 105
106 106 def up_conv_bits(value):
107 107
108 108 if value == 1.0: bits="000"
109 109 if value == 2.0: bits="001"
110 110 if value == 3.0: bits="010"
111 111 if value == 0.0: bits="011"
112 112 if value == 0.5: bits="100"
113 113 if value == 1.5: bits="101"
114 114 if value == 2.5: bits="110"
115 115 if value == 3.5: bits="111"
116 116
117 117 return bits
118 118
119 119 def down_convertion(cadena):
120 120 valores = []
121 121 for c in cadena:
122 122 if c == 1.0: valores=valores+['000']
123 123 if c == 2.0: valores=valores+['001']
124 124 if c == 3.0: valores=valores+['010']
125 125 if c == 0.0: valores=valores+['011']
126 126 if c == 0.5: valores=valores+['100']
127 127 if c == 1.5: valores=valores+['101']
128 128 if c == 2.5: valores=valores+['110']
129 129 if c == 3.5: valores=valores+['111']
130 130
131 131 return valores
132 132
133 133 def down_conv_bits(value):
134 134
135 135 if value == 1.0: bits="000"
136 136 if value == 2.0: bits="001"
137 137 if value == 3.0: bits="010"
138 138 if value == 0.0: bits="011"
139 139 if value == 0.5: bits="100"
140 140 if value == 1.5: bits="101"
141 141 if value == 2.5: bits="110"
142 142 if value == 3.5: bits="111"
143 143
144 144 return bits
145 145
146 146 def up_conv_value(bits):
147 147
148 148 if bits == "000": value=1.0
149 149 if bits == "001": value=2.0
150 150 if bits == "010": value=3.0
151 151 if bits == "011": value=0.0
152 152 if bits == "100": value=0.5
153 153 if bits == "101": value=1.5
154 154 if bits == "110": value=2.5
155 155 if bits == "111": value=3.5
156 156
157 157 return value
158 158
159 159 def down_conv_value(bits):
160 160
161 161 if bits == "000": value=1.0
162 162 if bits == "001": value=2.0
163 163 if bits == "010": value=3.0
164 164 if bits == "011": value=0.0
165 165 if bits == "100": value=0.5
166 166 if bits == "101": value=1.5
167 167 if bits == "110": value=2.5
168 168 if bits == "111": value=3.5
169 169
170 170 return value
171 171
172 172 def ip2position(module_number):
173 173 j=0
174 174 i=0
175 175 for x in range(0,module_number-1):
176 176 j=j+1
177 177 if j==8:
178 178 i=i+1
179 179 j=0
180 180
181 181 pos = [i,j]
182 182 return pos
183 183
184 184
185 185 def fromBinary2Char(binary_string):
186 186 number = int(binary_string, 2)
187 187 #Plus 33 to avoid more than 1 characters values such as: '\x01'-'\x1f'
188 188 number = number + 33
189 189 char = chr(number)
190 190 return char
191 191
192 192 def fromChar2Binary(char):
193 193 number = ord(char) - 33
194 194 #Minus 33 to get the real value
195 195 bits = bin(number)[2:]
196 196 #To ensure we have a string with 6bits
197 197 if len(bits) < 6:
198 198 bits = bits.zfill(6)
199 199 return bits
200 200
201 201 OPERATION_MODES = (
202 202 (0, 'Manual'),
203 203 (1, 'Automatic'),
204 204 )
205 205
206 206
207 207 class ABSConfiguration(Configuration):
208 208 active_beam = models.PositiveSmallIntegerField(verbose_name='Active Beam', default=0)
209 209 module_status = models.CharField(verbose_name='Module Status', max_length=10000, default=status_default)
210 210 operation_mode = models.PositiveSmallIntegerField(verbose_name='Operation Mode', choices=OPERATION_MODES, default = 0)
211 211 operation_value = models.FloatField(verbose_name='Periodic (seconds)', default="10", null=True, blank=True)
212 212 module_messages = models.CharField(verbose_name='Modules Messages', max_length=10000, default=json.dumps(default_messages))
213 213
214 214 class Meta:
215 215 db_table = 'abs_configurations'
216 216
217 217 def get_absolute_url_plot(self):
218 218 return reverse('url_plot_abs_patterns', args=[str(self.id)])
219 219
220 220
221 221 def parms_to_dict(self):
222 222
223 223 parameters = {}
224 224
225 225 parameters['device_id'] = self.device.id
226 226 parameters['label'] = self.label
227 227 parameters['device_type'] = self.device.device_type.name
228 228 parameters['beams'] = {}
229 229
230 230 beams = ABSBeam.objects.filter(abs_conf=self)
231 231 b=1
232 232 for beam in beams:
233 233 #absbeam = ABSBeam.objects.get(pk=beams[beam])
234 234 parameters['beams']['beam'+str(b)] = beam.parms_to_dict()#absbeam.parms_to_dict()
235 235 b+=1
236 236
237 237 return parameters
238 238
239 239
240 240 def dict_to_parms(self, parameters):
241 241
242 242 self.label = parameters['label']
243 243
244 244 absbeams = ABSBeam.objects.filter(abs_conf=self)
245 245 beams = parameters['beams']
246 246
247 247 if absbeams:
248 248 beams_number = len(beams)
249 249 absbeams_number = len(absbeams)
250 250 if beams_number==absbeams_number:
251 251 i = 1
252 252 for absbeam in absbeams:
253 253 absbeam.dict_to_parms(beams['beam'+str(i)])
254 254 i = i+1
255 255 elif beams_number > absbeams_number:
256 256 i = 1
257 257 for absbeam in absbeams:
258 258 absbeam.dict_to_parms(beams['beam'+str(i)])
259 259 i=i+1
260 260 for x in range(i,beams_number+1):
261 261 new_beam = ABSBeam(
262 262 name =beams['beam'+str(i)]['name'],
263 263 antenna =json.dumps(beams['beam'+str(i)]['antenna']),
264 264 abs_conf = self,
265 265 tx =json.dumps(beams['beam'+str(i)]['tx']),
266 266 rx =json.dumps(beams['beam'+str(i)]['rx']),
267 267 ues =json.dumps(beams['beam'+str(i)]['ues']),
268 268 only_rx =json.dumps(beams['beam'+str(i)]['only_rx'])
269 269 )
270 270 new_beam.save()
271 271 i=i+1
272 272 else: #beams_number < absbeams_number:
273 273 i = 1
274 274 for absbeam in absbeams:
275 275 if i <= beams_number:
276 276 absbeam.dict_to_parms(beams['beam'+str(i)])
277 277 i=i+1
278 278 else:
279 279 absbeam.delete()
280 280 else:
281 281 for beam in beams:
282 282 new_beam = ABSBeam(
283 283 name =beams[beam]['name'],
284 284 antenna =json.dumps(beams[beam]['antenna']),
285 285 abs_conf = self,
286 286 tx =json.dumps(beams[beam]['tx']),
287 287 rx =json.dumps(beams[beam]['rx']),
288 288 ues =json.dumps(beams[beam]['ues']),
289 289 only_rx =json.dumps(beams[beam]['only_rx'])
290 290 )
291 291 new_beam.save()
292 292
293 293
294 294
295 295 def update_from_file(self, parameters):
296 296
297 297 self.dict_to_parms(parameters)
298 298 self.save()
299 299
300 300
301 301 def get_beams(self, **kwargs):
302 302 '''
303 303 This function returns ABS Configuration beams
304 304 '''
305 305 return ABSBeam.objects.filter(abs_conf=self.pk, **kwargs)
306 306
307 307 def clone(self, **kwargs):
308 308
309 309 beams = self.get_beams()
310 310 self.pk = None
311 311 self.id = None
312 312 for attr, value in kwargs.items():
313 313 setattr(self, attr, value)
314 314 self.save()
315 315
316 316 for beam in beams:
317 317 beam.clone(abs_conf=self)
318 318
319 319 #-----For Active Beam-----
320 320 new_beams = ABSBeam.objects.filter(abs_conf=self)
321 321 self.active_beam = new_beams[0].id
322 322 self.save()
323 323 #-----For Active Beam-----
324 324 #-----For Device Status---
325 325 self.device.status = 3
326 326 self.device.save()
327 327 #-----For Device Status---
328 328
329 329 return self
330 330
331 331
332 332 def start_device(self):
333 333
334 334 if self.device.status == 3:
335 335
336 336 try:
337 337 #self.write_device()
338 338 send_task('task_change_beam', [self.id],)
339 339 self.message = 'ABS running'
340 340
341 341 except Exception as e:
342 342 self.message = str(e)
343 343 return False
344 344
345 345 return True
346 346
347 347 else:
348 348 self.message = 'Please, select Write ABS Device first.'
349 349 return False
350 350
351 351
352 352 def stop_device(self):
353 353
354 354 self.device.status = 2
355 355 self.device.save()
356 356 self.message = 'ABS has been stopped.'
357 357 self.save()
358 358
359 359 return True
360 360
361 361
362 362 def write_device(self):
363 363
364 364 """
365 365 This function sends the beams list to every abs module.
366 366 It needs 'module_conf' function
367 367 """
368 368
369 369 beams = ABSBeam.objects.filter(abs_conf=self)
370 370 nbeams = len(beams)
371 371 if self.connected_modules() == 0 :
372 372 self.message = "No ABS Module detected."
373 373 return False
374 374
375 375 #-------------Write each abs module-----------
376 376
377 377 if beams:
378 378 block_id = 0
379 379 message = 'SNDF{:03d}{:02d}{:02d}'.format(nbeams, nbeams, block_id)
380 380 for i, status in enumerate(self.module_status):
381 381 message += ''.join([fromBinary2Char(beam.module_6bits(i)) for beam in beams])
382 382 status = ['0'] * 64
383 383 n = 0
384 384
385 385 sock = self.send_multicast(message)
386 386
387 387 for i in range(32):
388 388 try:
389 389 data, address = sock.recvfrom(1024)
390 390 print address, data
391 391 if data == '1':
392 392 status[int(address[0][10:])-1] = '3'
393 393 elif data == '0':
394 394 status[int(address[0][10:])-1] = '1'
395 395 except Exception as e:
396 396 print 'Error {}'.format(e)
397 397 n += 1
398 398 sock.close()
399 399 else:
400 400 self.message = "ABS Configuration does not have beams"
401 401 return False
402 402
403 403 if n == 64:
404 404 self.message = "Could not write ABS Modules"
405 405 self.device.status = 0
406 406 self.module_status = ''.join(status)
407 407 self.save()
408 408 return False
409 409 else:
410 410 self.message = "ABS Beams List have been sent to ABS Modules"
411 411 self.active_beam = beams[0].pk
412 412
413 413 self.device.status = 3
414 414 self.module_status = ''.join(status)
415 415 self.save()
416 416
417 417 return True
418 418
419 419
420 420 def read_module(self, module):
421 421
422 422 """
423 423 Read out-bits (up-down) of 1 abs module NOT for Configuration
424 424 """
425 425
426 426 ip_address = self.device.ip_address
427 427 ip_address = ip_address.split('.')
428 428 module_seq = (ip_address[0],ip_address[1],ip_address[2])
429 429 dot = '.'
430 430 module_ip = dot.join(module_seq)+'.'+str(module)
431 431 module_port = self.device.port_address
432 432 read_route = 'http://'+module_ip+':'+str(module_port)+'/read'
433 433
434 434 module_status = json.loads(self.module_status)
435 435 print(read_route)
436 436
437 437 module_bits = ''
438 438
439 439 try:
440 440 r_read = requests.get(read_route, timeout=0.5)
441 441 answer = r_read.json()
442 442 module_bits = answer['allbits']
443 443 except:
444 444 return {}
445 445
446 446 return module_bits
447 447
448 448 def read_device(self):
449 449
450 450 parms = {}
451 451 # Reads active modules.
452 452 module_status = json.loads(self.module_status)
453 453 total = 0
454 454 for status in module_status:
455 455 if module_status[status] != 0:
456 456 module_bits = self.read_module(int(status))
457 457 bits={}
458 458 if module_bits:
459 459 bits = (str(module_bits['um2']) + str(module_bits['um1']) + str(module_bits['um0']) +
460 460 str(module_bits['dm2']) + str(module_bits['dm1']) + str(module_bits['dm0']) )
461 461 parms[str(status)] = bits
462 462
463 463 total +=1
464 464
465 465 if total==0:
466 466 self.message = "No ABS Module detected. Please select 'Status'."
467 467 return False
468 468
469 469
470 470
471 471 self.message = "ABS Modules have been read"
472 472 #monitoreo_tx = JROABSClnt_01CeCnMod000000MNTR10
473 473 return parms
474 474
475 475
476 476 def connected_modules(self):
477 477 """
478 478 This function returns the number of connected abs-modules without updating.
479 479 """
480 480 num = 0
481 481 print(self.module_status)
482 482 for i, status in enumerate(self.module_status):
483 483 if status != '0':
484 484 num += 1
485 485 #print('status {}:{}'.format(i+1, status))
486 486 return num
487 487
488 488 def send_multicast(self, message):
489 489
490 490 multicast_group = ('224.3.29.71', 10000)
491 491 # Create the datagram socket
492 492 sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
493 493 sock.settimeout(1)
494 local_ip = os.environ.get('LOCAL_IP', '127.0.0.1')
494 local_ip = os.environ.get('LOCAL_IP', '192.168.1.128')
495 495 sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_IF, socket.inet_aton(local_ip))
496 496 sock.sendto(message, multicast_group)
497 497 print('Sending ' + message)
498 498 return sock
499 499
500 500 def status_device(self):
501 501 """
502 502 This function returns the status of all abs-modules as one.
503 503 If at least one module is connected, its answer is "1"
504 504 """
505 505
506 506 sock = self.send_multicast('MNTR')
507 507
508 508 n = 0
509 509 status = ['0'] * 64
510 510 for i in range(32):
511 511 #if True:
512 512 try:
513 513 address = None
514 514 data, address = sock.recvfrom(1024)
515 515 x = int(address[0][10:])-1
516 516 if data[0] == '1':
517 517 remote = fromChar2Binary(data[1])
518 518 local = ABSBeam.objects.get(pk=self.active_beam).module_6bits(x)
519 519 if local == remote:
520 520 status[x] = '3'
521 521 print('Module: {} connected...igual'.format(address))
522 522 else:
523 523 status[x] = '2'
524 524 print('Module: {} connected...diferente'.format(address))
525 525 elif data[0] == '0':
526 526 status[x] = '1'
527 527 n += 1
528 528 except:
529 529 print('Module: {} error'.format(address))
530 530 pass
531 531 sock.close()
532 532
533 533 if n > 0:
534 534 self.message = 'ABS modules Status have been updated.'
535 535 self.device.status = 1
536 536 else:
537 537 self.device.status = 0
538 538 self.message = 'No ABS module is connected.'
539 539 self.module_status = ''.join(status)
540 540 self.save()
541 541
542 542 return self.device.status
543 543
544 544
545 545 def send_beam(self, beam_pos):
546 546 """
547 547 This function connects to a multicast group and sends the beam number
548 548 to all abs modules.
549 549 """
550 550
551 551 # Se manda a cero RC para poder realizar cambio de beam
552 552 if self.experiment is None:
553 553 confs = []
554 554 else:
555 555 confs = Configuration.objects.filter(experiment = self.experiment).filter(type=0)
556 556 confdds = ''
557 557 confjars = ''
558 558 confrc = ''
559 559 #TO STOP DEVICES: DDS-JARS-RC
560 560 for i in range(0,len(confs)):
561 561 if i==0:
562 562 for conf in confs:
563 563 if conf.device.device_type.name == 'dds':
564 564 confdds = conf
565 565 confdds.stop_device()
566 566 break
567 567 if i==1:
568 568 for conf in confs:
569 569 if conf.device.device_type.name == 'jars':
570 570 confjars = conf
571 571 confjars.stop_device()
572 572 break
573 573 if i==2:
574 574 for conf in confs:
575 575 if conf.device.device_type.name == 'rc':
576 576 confrc = conf
577 577 confrc.stop_device()
578 578 break
579 579 if beam_pos > 0:
580 580 beam_pos = beam_pos - 1
581 581 else:
582 582 beam_pos = 0
583 583
584 584 #El indice del apunte debe ser menor que el numero total de apuntes
585 585 #El servidor tcp en el embebido comienza a contar desde 0
586 586 status = ['0'] * 64
587 587 message = 'CHGB{}'.format(beam_pos)
588 588 sock = self.send_multicast(message)
589 589 for i in range(32):
590 590 try:
591 591 data, address = sock.recvfrom(1024)
592 592 print address, data
593 593 if data == '1':
594 594 status[int(address[0][10:])-1] = '3'
595 595 elif data == '0':
596 596 status[int(address[0][10:])-1] = '1'
597 597 except Exception as e:
598 598 print 'Error {}'.format(e)
599 599 pass
600 600
601 601 sock.close()
602 602
603 603 #Start DDS-RC-JARS
604 604 if confdds:
605 605 confdds.start_device()
606 606 if confrc:
607 607 #print confrc
608 608 confrc.start_device()
609 609 if confjars:
610 610 confjars.start_device()
611 611
612 612 self.message = "ABS Beam has been changed"
613 613 self.module_status = ''.join(status)
614 614 self.save()
615 615 return True
616 616
617 617
618 618 def get_absolute_url_import(self):
619 619 return reverse('url_import_abs_conf', args=[str(self.id)])
620 620
621 621
622 622 class ABSBeam(models.Model):
623 623
624 624 name = models.CharField(max_length=60, default='Beam')
625 625 antenna = models.CharField(verbose_name='Antenna', max_length=1000, default=antenna_default)
626 626 abs_conf = models.ForeignKey(ABSConfiguration, null=True, verbose_name='ABS Configuration')
627 627 tx = models.CharField(verbose_name='Tx', max_length=1000, default=tx_default)
628 628 rx = models.CharField(verbose_name='Rx', max_length=1000, default=rx_default)
629 629 s_time = models.TimeField(verbose_name='Star Time', default='00:00:00')
630 630 e_time = models.TimeField(verbose_name='End Time', default='23:59:59')
631 631 ues = models.CharField(verbose_name='Ues', max_length=100, default=ues_default)
632 632 only_rx = models.CharField(verbose_name='Only RX', max_length=40, default=onlyrx_default)
633 633
634 634 class Meta:
635 635 db_table = 'abs_beams'
636 636
637 637 def __unicode__(self):
638 638 return u'%s' % (self.name)
639 639
640 640 def parms_to_dict(self):
641 641
642 642 parameters = {}
643 643 parameters['name'] = self.name
644 644 parameters['antenna'] = ast.literal_eval(self.antenna)
645 645 parameters['abs_conf'] = self.abs_conf.name
646 646 parameters['tx'] = ast.literal_eval(self.tx)
647 647 parameters['rx'] = ast.literal_eval(self.rx)
648 648 parameters['s_time'] = self.s_time.strftime("%H:%M:%S")
649 649 parameters['e_time'] = self.e_time.strftime("%H:%M:%S")
650 650 parameters['ues'] = ast.literal_eval(self.ues)
651 651 parameters['only_rx'] = json.loads(self.only_rx)
652 652
653 653 return parameters
654 654
655 655 def dict_to_parms(self, parameters):
656 656
657 657 self.name = parameters['name']
658 658 self.antenna = json.dumps(parameters['antenna'])
659 659 #self.abs_conf = parameters['abs_conf']
660 660 self.tx = json.dumps(parameters['tx'])
661 661 self.rx = json.dumps(parameters['rx'])
662 662 #self.s_time = parameters['s_time']
663 663 #self.e_time = parameters['e_time']
664 664 self.ues = json.dumps(parameters['ues'])
665 665 self.only_rx = json.dumps(parameters['only_rx'])
666 666 self.save()
667 667
668 668
669 669 def clone(self, **kwargs):
670 670
671 671 self.pk = None
672 672 self.id = None
673 673 for attr, value in kwargs.items():
674 674 setattr(self, attr, value)
675 675
676 676 self.save()
677 677
678 678 return self
679 679
680 680
681 681 def module_6bits(self, module):
682 682 """
683 683 This function reads antenna pattern and choose 6bits (upbits-downbits) for one abs module
684 684 """
685 685 module += 1
686 686 if module > 64:
687 687 beam_bits = ""
688 688 return beam_bits
689 689
690 690 data = ast.literal_eval(self.antenna)
691 691 up_data = data['antenna_up']
692 692 down_data = data['antenna_down']
693 693
694 694 pos = ip2position(module)
695 695 up_value = up_data[pos[0]][pos[1]]
696 696 down_value = down_data[pos[0]][pos[1]]
697 697
698 698 up_bits = up_conv_bits(up_value)
699 699 down_bits = down_conv_bits(down_value)
700 700 beam_bits = up_bits+down_bits
701 701
702 702 return beam_bits
703 703
704 704
705 705 @property
706 706 def get_upvalues(self):
707 707 """
708 708 This function reads antenna pattern and show the up-value of one abs module
709 709 """
710 710
711 711 data = ast.literal_eval(self.antenna)
712 712 up_data = data['antenna_up']
713 713
714 714 up_values = []
715 715 for data in up_data:
716 716 for i in range(0,8):
717 717 up_values.append(data[i])
718 718
719 719 return up_values
720 720
721 721 @property
722 722 def antenna_upvalues(self):
723 723 """
724 724 This function reads antenna pattern and show the up - values of one abs beam
725 725 in a particular order
726 726 """
727 727 data = ast.literal_eval(self.antenna)
728 728 up_data = data['antenna_up']
729 729
730 730 return up_data
731 731
732 732 @property
733 733 def antenna_downvalues(self):
734 734 """
735 735 This function reads antenna pattern and show the down - values of one abs beam
736 736 in a particular order
737 737 """
738 738 data = ast.literal_eval(self.antenna)
739 739 down_data = data['antenna_down']
740 740
741 741 return down_data
742 742
743 743 @property
744 744 def get_downvalues(self):
745 745 """
746 746 This function reads antenna pattern and show the down-value of one abs module
747 747 """
748 748
749 749 data = ast.literal_eval(self.antenna)
750 750 down_data = data['antenna_down']
751 751
752 752 down_values = []
753 753 for data in down_data:
754 754 for i in range(0,8):
755 755 down_values.append(data[i])
756 756
757 757 return down_values
758 758
759 759 @property
760 760 def get_up_ues(self):
761 761 """
762 762 This function shows the up-ues-value of one beam
763 763 """
764 764 data = ast.literal_eval(self.ues)
765 765 up_ues = data['up']
766 766
767 767 return up_ues
768 768
769 769 @property
770 770 def get_down_ues(self):
771 771 """
772 772 This function shows the down-ues-value of one beam
773 773 """
774 774 data = ast.literal_eval(self.ues)
775 775 down_ues = data['down']
776 776
777 777 return down_ues
778 778
779 779 @property
780 780 def get_up_onlyrx(self):
781 781 """
782 782 This function shows the up-onlyrx-value of one beam
783 783 """
784 784 data = json.loads(self.only_rx)
785 785 up_onlyrx = data['up']
786 786
787 787 return up_onlyrx
788 788
789 789 @property
790 790 def get_down_onlyrx(self):
791 791 """
792 792 This function shows the down-onlyrx-value of one beam
793 793 """
794 794 data = json.loads(self.only_rx)
795 795 down_onlyrx = data['down']
796 796
797 797 return down_onlyrx
798 798
799 799 @property
800 800 def get_tx(self):
801 801 """
802 802 This function shows the tx-values of one beam
803 803 """
804 804 data = json.loads(self.tx)
805 805
806 806 return data
807 807
808 808 @property
809 809 def get_uptx(self):
810 810 """
811 811 This function shows the up-tx-values of one beam
812 812 """
813 813 data = json.loads(self.tx)
814 814 up_data = data['up']
815 815
816 816 up_values = []
817 817 for data in up_data:
818 818 for i in range(0,8):
819 819 up_values.append(data[i])
820 820
821 821 return up_values
822 822
823 823 @property
824 824 def get_downtx(self):
825 825 """
826 826 This function shows the down-tx-values of one beam
827 827 """
828 828 data = json.loads(self.tx)
829 829 down_data = data['down']
830 830
831 831 down_values = []
832 832 for data in down_data:
833 833 for i in range(0,8):
834 834 down_values.append(data[i])
835 835
836 836 return down_values
837 837
838 838
839 839
840 840 @property
841 841 def get_rx(self):
842 842 """
843 843 This function shows the rx-values of one beam
844 844 """
845 845 data = json.loads(self.rx)
846 846
847 847 return data
848 848
849 849 @property
850 850 def get_uprx(self):
851 851 """
852 852 This function shows the up-rx-values of one beam
853 853 """
854 854 data = json.loads(self.rx)
855 855 up_data = data['up']
856 856
857 857 up_values = []
858 858 for data in up_data:
859 859 for i in range(0,8):
860 860 up_values.append(data[i])
861 861
862 862 return up_values
863 863
864 864 @property
865 865 def get_downrx(self):
866 866 """
867 867 This function shows the down-rx-values of one beam
868 868 """
869 869 data = json.loads(self.rx)
870 870 down_data = data['down']
871 871
872 872 down_values = []
873 873 for data in down_data:
874 874 for i in range(0,8):
875 875 down_values.append(data[i])
876 876
877 877 return down_values
@@ -1,806 +1,806
1 1
2 2 import os
3 3 import json
4 4 import requests
5 5 import time
6 6 from datetime import datetime
7 7
8 8 try:
9 9 from polymorphic.models import PolymorphicModel
10 10 except:
11 11 from polymorphic import PolymorphicModel
12 12
13 13 from django.template.base import kwarg_re
14 14 from django.db import models
15 15 from django.core.urlresolvers import reverse
16 16 from django.core.validators import MinValueValidator, MaxValueValidator
17 17 from django.shortcuts import get_object_or_404
18 18 from django.contrib.auth.models import User
19 19 from django.db.models.signals import post_save
20 20 from django.dispatch import receiver
21 21
22 22 from apps.main.utils import Params
23 23 from apps.rc.utils import RCFile
24 24 from apps.jars.utils import RacpFile
25 25 from devices.dds import api as dds_api
26 26 from devices.dds import data as dds_data
27 27
28 28
29 29 DEV_PORTS = {
30 30 'rc' : 2000,
31 31 'dds' : 2000,
32 32 'jars' : 2000,
33 33 'usrp' : 2000,
34 34 'cgs' : 8080,
35 35 'abs' : 8080
36 36 }
37 37
38 38 RADAR_STATES = (
39 39 (0, 'No connected'),
40 40 (1, 'Connected'),
41 41 (2, 'Configured'),
42 42 (3, 'Running'),
43 43 (4, 'Scheduled'),
44 44 )
45 45
46 46 EXPERIMENT_TYPE = (
47 47 (0, 'RAW_DATA'),
48 48 (1, 'PDATA'),
49 49 )
50 50
51 51 DECODE_TYPE = (
52 52 (0, 'None'),
53 53 (1, 'TimeDomain'),
54 54 (2, 'FreqDomain'),
55 55 (3, 'InvFreqDomain'),
56 56 )
57 57
58 58 DEV_STATES = (
59 59 (0, 'No connected'),
60 60 (1, 'Connected'),
61 61 (2, 'Configured'),
62 62 (3, 'Running'),
63 63 (4, 'Unknown'),
64 64 )
65 65
66 66 DEV_TYPES = (
67 67 ('', 'Select a device type'),
68 68 ('rc', 'Radar Controller'),
69 69 ('dds', 'Direct Digital Synthesizer'),
70 70 ('jars', 'Jicamarca Radar Acquisition System'),
71 71 ('usrp', 'Universal Software Radio Peripheral'),
72 72 ('cgs', 'Clock Generator System'),
73 73 ('abs', 'Automatic Beam Switching'),
74 74 )
75 75
76 76 EXP_STATES = (
77 77 (0,'Error'), #RED
78 78 (1,'Cancelled'), #YELLOW
79 79 (2,'Running'), #GREEN
80 80 (3,'Scheduled'), #BLUE
81 81 (4,'Unknown'), #WHITE
82 82 )
83 83
84 84 CONF_TYPES = (
85 85 (0, 'Active'),
86 86 (1, 'Historical'),
87 87 )
88 88
89 89 class Profile(models.Model):
90 90 user = models.OneToOneField(User, on_delete=models.CASCADE)
91 91 theme = models.CharField(max_length=30, default='spacelab')
92 92
93 93
94 94 @receiver(post_save, sender=User)
95 95 def create_user_profile(sender, instance, created, **kwargs):
96 96 if created:
97 97 Profile.objects.create(user=instance)
98 98
99 99 @receiver(post_save, sender=User)
100 100 def save_user_profile(sender, instance, **kwargs):
101 101 instance.profile.save()
102 102
103 103
104 104 class Location(models.Model):
105 105
106 106 name = models.CharField(max_length = 30)
107 107 description = models.TextField(blank=True, null=True)
108 108
109 109 class Meta:
110 110 db_table = 'db_location'
111 111
112 112 def __str__(self):
113 113 return u'%s' % self.name
114 114
115 115 def get_absolute_url(self):
116 116 return reverse('url_location', args=[str(self.id)])
117 117
118 118
119 119 class DeviceType(models.Model):
120 120
121 121 name = models.CharField(max_length = 10, choices = DEV_TYPES, default = 'rc')
122 122 sequence = models.PositiveSmallIntegerField(default=1000)
123 123 description = models.TextField(blank=True, null=True)
124 124
125 125 class Meta:
126 126 db_table = 'db_device_types'
127 127
128 128 def __str__(self):
129 129 return u'%s' % self.get_name_display()
130 130
131 131 class Device(models.Model):
132 132
133 133 device_type = models.ForeignKey(DeviceType, on_delete=models.CASCADE)
134 134 location = models.ForeignKey(Location, on_delete=models.CASCADE)
135 135 ip_address = models.GenericIPAddressField(protocol='IPv4', default='0.0.0.0')
136 136 port_address = models.PositiveSmallIntegerField(default=2000)
137 137 description = models.TextField(blank=True, null=True)
138 138 status = models.PositiveSmallIntegerField(default=0, choices=DEV_STATES)
139 139 conf_active = models.PositiveIntegerField(default=0, verbose_name='Current configuration')
140 140
141 141 class Meta:
142 142 db_table = 'db_devices'
143 143
144 144 def __str__(self):
145 145 ret = u'{} [{}]'.format(self.device_type.name.upper(), self.location.name)
146 146
147 147 return ret
148 148
149 149 @property
150 150 def name(self):
151 151 return str(self)
152 152
153 153 def get_status(self):
154 154 return self.status
155 155
156 156 @property
157 157 def status_color(self):
158 158 color = 'muted'
159 159 if self.status == 0:
160 160 color = "danger"
161 161 elif self.status == 1:
162 162 color = "warning"
163 163 elif self.status == 2:
164 164 color = "info"
165 165 elif self.status == 3:
166 166 color = "success"
167 167
168 168 return color
169 169
170 170 def url(self, path=None):
171 171
172 172 if path:
173 173 return 'http://{}:{}/{}/'.format(self.ip_address, self.port_address, path)
174 174 else:
175 175 return 'http://{}:{}/'.format(self.ip_address, self.port_address)
176 176
177 177 def get_absolute_url(self):
178 178 return reverse('url_device', args=[str(self.id)])
179 179
180 180 def get_absolute_url_edit(self):
181 181 return reverse('url_edit_device', args=[str(self.id)])
182 182
183 183 def get_absolute_url_delete(self):
184 184 return reverse('url_delete_device', args=[str(self.id)])
185 185
186 186 def change_ip(self, ip_address, mask, gateway, dns, **kwargs):
187 187
188 188 if self.device_type.name=='dds':
189 189 try:
190 190 answer = dds_api.change_ip(ip = self.ip_address,
191 191 port = self.port_address,
192 192 new_ip = ip_address,
193 193 mask = mask,
194 194 gateway = gateway)
195 195 if answer[0]=='1':
196 196 self.message = '25|DDS - {}'.format(answer)
197 197 self.ip_address = ip_address
198 198 self.save()
199 199 else:
200 200 self.message = '30|DDS - {}'.format(answer)
201 201 return False
202 202 except Exception as e:
203 203 self.message = '40|{}'.format(str(e))
204 204 return False
205 205
206 206 elif self.device_type.name=='rc':
207 207 headers = {'content-type': "application/json",
208 208 'cache-control': "no-cache"}
209 209
210 210 ip = [int(x) for x in ip_address.split('.')]
211 211 dns = [int(x) for x in dns.split('.')]
212 212 gateway = [int(x) for x in gateway.split('.')]
213 213 subnet = [int(x) for x in mask.split('.')]
214 214
215 215 payload = {
216 216 "ip": ip,
217 217 "dns": dns,
218 218 "gateway": gateway,
219 219 "subnet": subnet
220 220 }
221 221
222 222 req = requests.post(self.url('changeip'), data=json.dumps(payload), headers=headers)
223 223 try:
224 224 answer = req.json()
225 225 if answer['changeip']=='ok':
226 226 self.message = '25|IP succesfully changed'
227 227 self.ip_address = ip_address
228 228 self.save()
229 229 else:
230 230 self.message = '30|An error ocuur when changing IP'
231 231 except Exception as e:
232 232 self.message = '40|{}'.format(str(e))
233 233 else:
234 234 self.message = 'Not implemented'
235 235 return False
236 236
237 237 return True
238 238
239 239
240 240 class Campaign(models.Model):
241 241
242 242 template = models.BooleanField(default=False)
243 243 name = models.CharField(max_length=60, unique=True)
244 244 start_date = models.DateTimeField(blank=True, null=True)
245 245 end_date = models.DateTimeField(blank=True, null=True)
246 246 tags = models.CharField(max_length=40, blank=True, null=True)
247 247 description = models.TextField(blank=True, null=True)
248 248 experiments = models.ManyToManyField('Experiment', blank=True)
249 249 author = models.ForeignKey(User, null=True, blank=True)
250 250
251 251 class Meta:
252 252 db_table = 'db_campaigns'
253 253 ordering = ('name',)
254 254
255 255 def __str__(self):
256 256 if self.template:
257 257 return u'{} (template)'.format(self.name)
258 258 else:
259 259 return u'{}'.format(self.name)
260 260
261 261 def jsonify(self):
262 262
263 263 data = {}
264 264
265 265 ignored = ('template')
266 266
267 267 for field in self._meta.fields:
268 268 if field.name in ignored:
269 269 continue
270 270 data[field.name] = field.value_from_object(self)
271 271
272 272 data['start_date'] = data['start_date'].strftime('%Y-%m-%d')
273 273 data['end_date'] = data['end_date'].strftime('%Y-%m-%d')
274 274
275 275 return data
276 276
277 277 def parms_to_dict(self):
278 278
279 279 params = Params({})
280 280 params.add(self.jsonify(), 'campaigns')
281 281
282 282 for exp in Experiment.objects.filter(campaign = self):
283 283 params.add(exp.jsonify(), 'experiments')
284 284 configurations = Configuration.objects.filter(experiment=exp, type=0)
285 285
286 286 for conf in configurations:
287 287 params.add(conf.jsonify(), 'configurations')
288 288 if conf.device.device_type.name=='rc':
289 289 for line in conf.get_lines():
290 290 params.add(line.jsonify(), 'lines')
291 291
292 292 return params.data
293 293
294 294 def dict_to_parms(self, parms, CONF_MODELS):
295 295
296 296 experiments = Experiment.objects.filter(campaign = self)
297 297
298 298 if experiments:
299 299 for experiment in experiments:
300 300 experiment.delete()
301 301
302 302 for id_exp in parms['experiments']['allIds']:
303 303 exp_parms = parms['experiments']['byId'][id_exp]
304 304 dum = (datetime.now() - datetime(1970, 1, 1)).total_seconds()
305 305 exp = Experiment(name='{}'.format(dum))
306 306 exp.save()
307 307 exp.dict_to_parms(parms, CONF_MODELS, id_exp=id_exp)
308 308 self.experiments.add(exp)
309 309
310 310 camp_parms = parms['campaigns']['byId'][parms['campaigns']['allIds'][0]]
311 311
312 312 self.name = '{}-{}'.format(camp_parms['name'], datetime.now().strftime('%y%m%d'))
313 313 self.start_date = camp_parms['start_date']
314 314 self.end_date = camp_parms['end_date']
315 315 self.tags = camp_parms['tags']
316 316 self.save()
317 317
318 318 return self
319 319
320 320 def get_experiments_by_radar(self, radar=None):
321 321
322 322 ret = []
323 323 if radar:
324 324 locations = Location.objects.filter(pk=radar)
325 325 else:
326 326 locations = set([e.location for e in self.experiments.all()])
327 327
328 328 for loc in locations:
329 329 dum = {}
330 330 dum['name'] = loc.name
331 331 dum['id'] = loc.pk
332 332 dum['experiments'] = [e for e in self.experiments.all() if e.location==loc]
333 333 ret.append(dum)
334 334
335 335 return ret
336 336
337 337 def get_absolute_url(self):
338 338 return reverse('url_campaign', args=[str(self.id)])
339 339
340 340 def get_absolute_url_edit(self):
341 341 return reverse('url_edit_campaign', args=[str(self.id)])
342 342
343 343 def get_absolute_url_delete(self):
344 344 return reverse('url_delete_campaign', args=[str(self.id)])
345 345
346 346 def get_absolute_url_export(self):
347 347 return reverse('url_export_campaign', args=[str(self.id)])
348 348
349 349 def get_absolute_url_import(self):
350 350 return reverse('url_import_campaign', args=[str(self.id)])
351 351
352 352
353 353 class RunningExperiment(models.Model):
354 354 radar = models.OneToOneField('Location', on_delete=models.CASCADE)
355 355 running_experiment = models.ManyToManyField('Experiment', blank = True)
356 356 status = models.PositiveSmallIntegerField(default=0, choices=RADAR_STATES)
357 357
358 358
359 359 class Experiment(models.Model):
360 360
361 361 template = models.BooleanField(default=False)
362 362 name = models.CharField(max_length=40, default='', unique=True)
363 363 location = models.ForeignKey('Location', null=True, blank=True, on_delete=models.CASCADE)
364 364 freq = models.FloatField(verbose_name='Operating Freq. (MHz)', validators=[MinValueValidator(1), MaxValueValidator(10000)], default=49.9200)
365 365 start_time = models.TimeField(default='00:00:00')
366 366 end_time = models.TimeField(default='23:59:59')
367 367 task = models.CharField(max_length=36, default='', blank=True, null=True)
368 368 status = models.PositiveSmallIntegerField(default=4, choices=EXP_STATES)
369 369 author = models.ForeignKey(User, null=True, blank=True)
370 370 hash = models.CharField(default='', max_length=64, null=True, blank=True)
371 371
372 372 class Meta:
373 373 db_table = 'db_experiments'
374 374 ordering = ('template', 'name')
375 375
376 376 def __str__(self):
377 377 if self.template:
378 378 return u'%s (template)' % (self.name)
379 379 else:
380 380 return u'%s' % (self.name)
381 381
382 382 def jsonify(self):
383 383
384 384 data = {}
385 385
386 386 ignored = ('template')
387 387
388 388 for field in self._meta.fields:
389 389 if field.name in ignored:
390 390 continue
391 391 data[field.name] = field.value_from_object(self)
392 392
393 393 data['start_time'] = data['start_time'].strftime('%H:%M:%S')
394 394 data['end_time'] = data['end_time'].strftime('%H:%M:%S')
395 395 data['location'] = self.location.name
396 396 data['configurations'] = ['{}'.format(conf.pk) for
397 397 conf in Configuration.objects.filter(experiment=self, type=0)]
398 398
399 399 return data
400 400
401 401 @property
402 402 def radar_system(self):
403 403 return self.location
404 404
405 405 def clone(self, **kwargs):
406 406
407 407 confs = Configuration.objects.filter(experiment=self, type=0)
408 408 self.pk = None
409 409 self.name = '{}_{:%y%m%d}'.format(self.name, datetime.now())
410 410 for attr, value in kwargs.items():
411 411 setattr(self, attr, value)
412 412
413 413 self.save()
414 414
415 415 for conf in confs:
416 416 conf.clone(experiment=self, template=False)
417 417
418 418 return self
419 419
420 420 def start(self):
421 421 '''
422 422 Configure and start experiments's devices
423 423 ABS-CGS-DDS-RC-JARS
424 424 '''
425 425
426 426 confs = []
427 427 allconfs = Configuration.objects.filter(experiment=self, type = 0).order_by('-device__device_type__sequence')
428 428 rc_mix = [conf for conf in allconfs if conf.device.device_type.name=='rc' and conf.mix]
429 429 if rc_mix:
430 430 for conf in allconfs:
431 431 if conf.device.device_type.name == 'rc' and not conf.mix:
432 432 continue
433 433 confs.append(conf)
434 434 else:
435 435 confs = allconfs
436 436
437 437 try:
438 438 for conf in confs:
439 439 conf.stop_device()
440 440 conf.write_device()
441 441 conf.device.conf_active = conf.pk
442 442 conf.device.save()
443 443 conf.start_device()
444 444 time.sleep(1)
445 445 except:
446 446 return 0
447 447 return 2
448 448
449 449
450 450 def stop(self):
451 451 '''
452 452 Stop experiments's devices
453 453 DDS-JARS-RC-CGS-ABS
454 454 '''
455 455
456 456 confs = Configuration.objects.filter(experiment=self, type = 0).order_by('device__device_type__sequence')
457 457 confs=confs.exclude(device__device_type__name='cgs')
458 458 try:
459 459 for conf in confs:
460 460 conf.stop_device()
461 461 except:
462 462 return 0
463 463 return 1
464 464
465 465 def get_status(self):
466 466
467 467 if self.status == 3:
468 468 return
469 469
470 470 confs = Configuration.objects.filter(experiment=self, type=0)
471 471
472 472 for conf in confs:
473 473 conf.status_device()
474 474
475 475 total = confs.aggregate(models.Sum('device__status'))['device__status__sum']
476 476
477 477 if total==2*confs.count():
478 478 status = 1
479 479 elif total == 3*confs.count():
480 480 status = 2
481 481 else:
482 482 status = 0
483 483
484 484 self.status = status
485 485 self.save()
486 486
487 487 def status_color(self):
488 488 color = 'muted'
489 489 if self.status == 0:
490 490 color = "danger"
491 491 elif self.status == 1:
492 492 color = "warning"
493 493 elif self.status == 2:
494 494 color = "success"
495 495 elif self.status == 3:
496 496 color = "info"
497 497
498 498 return color
499 499
500 500 def parms_to_dict(self):
501 501
502 502 params = Params({})
503 503 params.add(self.jsonify(), 'experiments')
504 504
505 505 configurations = Configuration.objects.filter(experiment=self, type=0)
506 506
507 507 for conf in configurations:
508 508 params.add(conf.jsonify(), 'configurations')
509 509 if conf.device.device_type.name=='rc':
510 510 for line in conf.get_lines():
511 511 params.add(line.jsonify(), 'lines')
512 512
513 513 return params.data
514 514
515 515 def dict_to_parms(self, parms, CONF_MODELS, id_exp=None):
516 516
517 517 configurations = Configuration.objects.filter(experiment=self)
518 518
519 519 if id_exp is not None:
520 520 exp_parms = parms['experiments']['byId'][id_exp]
521 521 else:
522 522 exp_parms = parms['experiments']['byId'][parms['experiments']['allIds'][0]]
523 523
524 524 if configurations:
525 525 for configuration in configurations:
526 526 configuration.delete()
527 527
528 528 for id_conf in exp_parms['configurations']:
529 529 conf_parms = parms['configurations']['byId'][id_conf]
530 530 device = Device.objects.filter(device_type__name=conf_parms['device_type'])[0]
531 531 model = CONF_MODELS[conf_parms['device_type']]
532 532 conf = model(
533 533 experiment = self,
534 534 device = device,
535 535 )
536 536 conf.dict_to_parms(parms, id=id_conf)
537 537
538 538
539 539 location, created = Location.objects.get_or_create(name=exp_parms['location'])
540 540 self.name = '{}-{}'.format(exp_parms['name'], datetime.now().strftime('%y%m%d'))
541 541 self.location = location
542 542 self.start_time = exp_parms['start_time']
543 543 self.end_time = exp_parms['end_time']
544 544 self.save()
545 545
546 546 return self
547 547
548 548 def get_absolute_url(self):
549 549 return reverse('url_experiment', args=[str(self.id)])
550 550
551 551 def get_absolute_url_edit(self):
552 552 return reverse('url_edit_experiment', args=[str(self.id)])
553 553
554 554 def get_absolute_url_delete(self):
555 555 return reverse('url_delete_experiment', args=[str(self.id)])
556 556
557 557 def get_absolute_url_import(self):
558 558 return reverse('url_import_experiment', args=[str(self.id)])
559 559
560 560 def get_absolute_url_export(self):
561 561 return reverse('url_export_experiment', args=[str(self.id)])
562 562
563 563 def get_absolute_url_start(self):
564 564 return reverse('url_start_experiment', args=[str(self.id)])
565 565
566 566 def get_absolute_url_stop(self):
567 567 return reverse('url_stop_experiment', args=[str(self.id)])
568 568
569 569
570 570 class Configuration(PolymorphicModel):
571 571
572 572 template = models.BooleanField(default=False)
573 573 # name = models.CharField(verbose_name="Configuration Name", max_length=40, default='')
574 label = models.CharField(verbose_name="Label", max_length=40, default='', blank=True, null=True)
575 experiment = models.ForeignKey('Experiment', verbose_name='Experiment', null=True, blank=True, on_delete=models.CASCADE)
576 574 device = models.ForeignKey('Device', verbose_name='Device', null=True, on_delete=models.CASCADE)
575 label = models.CharField(verbose_name="Label", max_length=40, default='', blank=True, null=True)
576 experiment = models.ForeignKey('Experiment', verbose_name='Experiment', null=True, blank=True, on_delete=models.CASCADE)
577 577 type = models.PositiveSmallIntegerField(default=0, choices=CONF_TYPES)
578 578 created_date = models.DateTimeField(auto_now_add=True)
579 579 programmed_date = models.DateTimeField(auto_now=True)
580 580 parameters = models.TextField(default='{}')
581 581 author = models.ForeignKey(User, null=True, blank=True)
582 582 hash = models.CharField(default='', max_length=64, null=True, blank=True)
583 583 message = ""
584 584
585 585 class Meta:
586 586 db_table = 'db_configurations'
587 587 ordering = ('device__device_type__name',)
588 588
589 589 def __str__(self):
590 590
591 591 ret = u'{} '.format(self.device.device_type.name.upper())
592 592
593 593 if 'mix' in [f.name for f in self._meta.get_fields()]:
594 594 if self.mix:
595 595 ret = '{} MIX '.format(self.device.device_type.name.upper())
596 596
597 597 if 'label' in [f.name for f in self._meta.get_fields()]:
598 598 ret += '{}'.format(self.label)
599 599
600 600 if self.template:
601 601 ret += ' (template)'
602 602
603 603 return ret
604 604
605 605 @property
606 606 def name(self):
607 607
608 608 return str(self)
609 609
610 610 def jsonify(self):
611 611
612 612 data = {}
613 613
614 614 ignored = ('type', 'polymorphic_ctype', 'configuration_ptr',
615 615 'created_date', 'programmed_date', 'template', 'device',
616 616 'experiment')
617 617
618 618 for field in self._meta.fields:
619 619 if field.name in ignored:
620 620 continue
621 621 data[field.name] = field.value_from_object(self)
622 622
623 623 data['device_type'] = self.device.device_type.name
624 624
625 625 if self.device.device_type.name == 'rc':
626 626 data['lines'] = ['{}'.format(line.pk) for line in self.get_lines()]
627 627 data['delays'] = self.get_delays()
628 628 data['pulses'] = self.get_pulses()
629 629
630 630 elif self.device.device_type.name == 'jars':
631 631 data['decode_type'] = DECODE_TYPE[self.decode_data][1]
632 632
633 633 elif self.device.device_type.name == 'dds':
634 634 data['frequencyA_Mhz'] = float(data['frequencyA_Mhz'])
635 635 data['frequencyB_Mhz'] = float(data['frequencyB_Mhz'])
636 636 data['phaseA'] = dds_data.phase_to_binary(data['phaseA_degrees'])
637 637 data['phaseB'] = dds_data.phase_to_binary(data['phaseB_degrees'])
638 638
639 639 return data
640 640
641 641 def clone(self, **kwargs):
642 642
643 643 self.pk = None
644 644 self.id = None
645 645 for attr, value in kwargs.items():
646 646 setattr(self, attr, value)
647 647
648 648 self.save()
649 649
650 650 return self
651 651
652 652 def parms_to_dict(self):
653 653
654 654 params = Params({})
655 655 params.add(self.jsonify(), 'configurations')
656 656
657 657 if self.device.device_type.name=='rc':
658 658 for line in self.get_lines():
659 659 params.add(line.jsonify(), 'lines')
660 660
661 661 return params.data
662 662
663 663 def parms_to_text(self):
664 664
665 665 raise NotImplementedError("This method should be implemented in %s Configuration model" %str(self.device.device_type.name).upper())
666 666
667 667
668 668 def parms_to_binary(self):
669 669
670 670 raise NotImplementedError("This method should be implemented in %s Configuration model" %str(self.device.device_type.name).upper())
671 671
672 672
673 673 def dict_to_parms(self, parameters, id=None):
674 674
675 675 params = Params(parameters)
676 676
677 677 if id:
678 678 data = params.get_conf(id_conf=id)
679 679 else:
680 680 data = params.get_conf(dtype=self.device.device_type.name)
681 681
682 682 if data['device_type']=='rc':
683 683 self.clean_lines()
684 684 lines = data.pop('lines', None)
685 685 for line_id in lines:
686 686 pass
687 687
688 688 for key, value in data.items():
689 689 if key not in ('id', 'device_type'):
690 690 setattr(self, key, value)
691 691
692 692 self.save()
693 693
694 694
695 695 def export_to_file(self, format="json"):
696 696
697 697 content_type = ''
698 698
699 699 if format == 'racp':
700 700 content_type = 'text/plain'
701 701 filename = '%s_%s.%s' %(self.device.device_type.name, self.name, 'racp')
702 702 content = self.parms_to_text(file_format = 'racp')
703 703
704 704 if format == 'text':
705 705 content_type = 'text/plain'
706 706 filename = '%s_%s.%s' %(self.device.device_type.name, self.name, self.device.device_type.name)
707 707 content = self.parms_to_text()
708 708
709 709 if format == 'binary':
710 710 content_type = 'application/octet-stream'
711 711 filename = '%s_%s.bin' %(self.device.device_type.name, self.name)
712 712 content = self.parms_to_binary()
713 713
714 714 if not content_type:
715 715 content_type = 'application/json'
716 716 filename = '%s_%s.json' %(self.device.device_type.name, self.name)
717 717 content = json.dumps(self.parms_to_dict(), indent=2)
718 718
719 719 fields = {'content_type':content_type,
720 720 'filename':filename,
721 721 'content':content
722 722 }
723 723
724 724 return fields
725 725
726 726 def import_from_file(self, fp):
727 727
728 728 parms = {}
729 729
730 730 path, ext = os.path.splitext(fp.name)
731 731
732 732 if ext == '.json':
733 733 parms = json.load(fp)
734 734
735 735 if ext == '.dds':
736 736 lines = fp.readlines()
737 737 parms = dds_data.text_to_dict(lines)
738 738
739 739 if ext == '.racp':
740 740 if self.device.device_type.name == 'jars':
741 741 parms = RacpFile(fp).to_dict()
742 742 parms['filter_parms'] = json.loads(self.filter_parms)
743 743 return parms
744 744 parms = RCFile(fp).to_dict()
745 745
746 746 return parms
747 747
748 748 def status_device(self):
749 749
750 750 self.message = 'Function not implemented'
751 751 return False
752 752
753 753
754 754 def stop_device(self):
755 755
756 756 self.message = 'Function not implemented'
757 757 return False
758 758
759 759
760 760 def start_device(self):
761 761
762 762 self.message = 'Function not implemented'
763 763 return False
764 764
765 765
766 766 def write_device(self, parms):
767 767
768 768 self.message = 'Function not implemented'
769 769 return False
770 770
771 771
772 772 def read_device(self):
773 773
774 774 self.message = 'Function not implemented'
775 775 return False
776 776
777 777
778 778 def get_absolute_url(self):
779 779 return reverse('url_%s_conf' % self.device.device_type.name, args=[str(self.id)])
780 780
781 781 def get_absolute_url_edit(self):
782 782 return reverse('url_edit_%s_conf' % self.device.device_type.name, args=[str(self.id)])
783 783
784 784 def get_absolute_url_delete(self):
785 785 return reverse('url_delete_dev_conf', args=[str(self.id)])
786 786
787 787 def get_absolute_url_import(self):
788 788 return reverse('url_import_dev_conf', args=[str(self.id)])
789 789
790 790 def get_absolute_url_export(self):
791 791 return reverse('url_export_dev_conf', args=[str(self.id)])
792 792
793 793 def get_absolute_url_write(self):
794 794 return reverse('url_write_dev_conf', args=[str(self.id)])
795 795
796 796 def get_absolute_url_read(self):
797 797 return reverse('url_read_dev_conf', args=[str(self.id)])
798 798
799 799 def get_absolute_url_start(self):
800 800 return reverse('url_start_dev_conf', args=[str(self.id)])
801 801
802 802 def get_absolute_url_stop(self):
803 803 return reverse('url_stop_dev_conf', args=[str(self.id)])
804 804
805 805 def get_absolute_url_status(self):
806 806 return reverse('url_status_dev_conf', args=[str(self.id)])
@@ -1,415 +1,418
1 1 import os
2 2 import json
3 3
4 4 from django import forms
5 5 from django.utils.safestring import mark_safe
6 6 from apps.main.models import Device
7 7 from apps.main.forms import add_empty_choice
8 8 from .models import RCConfiguration, RCLine, RCLineType, RCLineCode, RCClock
9 9 from .widgets import KmUnitWidget, KmUnitHzWidget, KmUnitDcWidget, UnitKmWidget, DefaultWidget, CodesWidget, HiddenWidget, HCheckboxSelectMultiple
10 10
11 11 def create_choices_from_model(model, conf_id, all_choice=False):
12 12
13 13 if model=='RCLine':
14 14 instance = RCConfiguration.objects.get(pk=conf_id)
15 15 choices = [(line.pk, line.get_name()) for line in instance.get_lines(line_type__name='tx')]
16 16 if all_choice:
17 17 choices = add_empty_choice(choices, label='All')
18 18 else:
19 19 instance = globals()[model]
20 20 choices = instance.objects.all().values_list('pk', 'name')
21 21
22 22 return choices
23 23
24 24
25 25 class ExtFileField(forms.FileField):
26 26 """
27 27 Same as forms.FileField, but you can specify a file extension whitelist.
28 28
29 29 >>> from django.core.files.uploadedfile import SimpleUploadedFile
30 30 >>>
31 31 >>> t = ExtFileField(ext_whitelist=(".pdf", ".txt"))
32 32 >>>
33 33 >>> t.clean(SimpleUploadedFile('filename.pdf', 'Some File Content'))
34 34 >>> t.clean(SimpleUploadedFile('filename.txt', 'Some File Content'))
35 35 >>>
36 36 >>> t.clean(SimpleUploadedFile('filename.exe', 'Some File Content'))
37 37 Traceback (most recent call last):
38 38 ...
39 39 ValidationError: [u'Not allowed filetype!']
40 40 """
41 41 def __init__(self, *args, **kwargs):
42 42 extensions = kwargs.pop("extensions")
43 43 self.extensions = [i.lower() for i in extensions]
44 44
45 45 super(ExtFileField, self).__init__(*args, **kwargs)
46 46
47 47 def clean(self, *args, **kwargs):
48 48 data = super(ExtFileField, self).clean(*args, **kwargs)
49 49 filename = data.name
50 50 ext = os.path.splitext(filename)[1]
51 51 ext = ext.lower()
52 52 if ext not in self.extensions:
53 53 raise forms.ValidationError('Not allowed file type: %s' % ext)
54 54
55 55
56 56 class RCConfigurationForm(forms.ModelForm):
57 57
58 58 def __init__(self, *args, **kwargs):
59 59 super(RCConfigurationForm, self).__init__(*args, **kwargs)
60 60
61 61 instance = getattr(self, 'instance', None)
62 62
63 63 if instance and instance.pk:
64 64
65 65 devices = Device.objects.filter(device_type__name='rc')
66 66 if instance.experiment:
67 67 self.fields['experiment'].widget.attrs['read_only'] = True
68 68 #self.fields['experiment'].widget.choices = [(instance.experiment.id, instance.experiment)]
69 69 self.fields['device'].widget.choices = [(device.id, device) for device in devices]
70 70 self.fields['ipp'].widget = KmUnitHzWidget(attrs={'km2unit':instance.km2unit})
71 71 self.fields['clock'].widget.attrs['readonly'] = True
72 72
73 73 self.fields['time_before'].label = mark_safe(self.fields['time_before'].label)
74 74 self.fields['time_after'].label = mark_safe(self.fields['time_after'].label)
75 75
76 76 if 'initial' in kwargs and 'experiment' in kwargs['initial'] and kwargs['initial']['experiment'] not in (0, '0'):
77 77 self.fields['experiment'].widget.attrs['readonly'] = True
78 78
79 79 class Meta:
80 80 model = RCConfiguration
81 81 exclude = ('type', 'parameters', 'status', 'total_units', 'mix', 'author', 'hash', 'clock_in')
82 82
83 83 def clean(self):
84 84 form_data = super(RCConfigurationForm, self).clean()
85 85
86 86 if 'clock_divider' in form_data:
87 87 if form_data['clock_divider']<1:
88 88 self.add_error('clock_divider', 'Invalid Value')
89 89 #else:
90 90 # if form_data['ipp']*(20./3*(form_data['clock_in']/form_data['clock_divider']))%10!=0:
91 91 # self.add_error('ipp', 'Invalid IPP units={}'.format(form_data['ipp']*(20./3*(form_data['clock_in']/form_data['clock_divider']))))
92 92
93 93 return form_data
94 94
95 95 def save(self, *args, **kwargs):
96 96 conf = super(RCConfigurationForm, self).save(*args, **kwargs)
97 clk = RCClock.objects.filter(rc_configuration=conf).first()
98 if clk:
99 conf.clock_in = clk.frequency
97 100 conf.total_units = conf.ipp*conf.ntx*conf.km2unit
98 101 conf.save()
99 102 return conf
100 103
101 104
102 105 class RCMixConfigurationForm(forms.Form):
103 106
104 107 clock_in = forms.CharField(widget=forms.HiddenInput())
105 108 clock_divider = forms.CharField(widget=forms.HiddenInput())
106 109 name = forms.CharField()
107 110 experiment = forms.ChoiceField()
108 111 mode = forms.ChoiceField(widget=forms.RadioSelect(),
109 112 choices=[(0, 'Parallel'), (1, 'Sequence')],
110 113 initial=0)
111 114 operation = forms.ChoiceField(widget=forms.RadioSelect(),
112 115 choices=[(0, 'OR'), (1, 'XOR'), (2, 'AND'), (3, 'NAND')],
113 116 initial=1)
114 117 delay = forms.CharField()
115 118 mask = forms.MultipleChoiceField(
116 119 choices=[(0, 'L1'),(1, 'L2'),(2, 'L3'),(3, 'L4'),(4, 'L5'),(5, 'L6'),(6, 'L7'),(7, 'L8'),
117 120 (8, 'L9'),(9, 'L10'),(10, 'L11'),(11, 'L12'),(12, 'L13'),(13, 'L14'),(14, 'L15'),(15, 'L16')],
118 121 widget=HCheckboxSelectMultiple())
119 122 result = forms.CharField(required=False,
120 123 widget=forms.Textarea(attrs={'readonly':True, 'rows':5, 'class':'tabuled'}))
121 124
122 125 def __init__(self, *args, **kwargs):
123 126 confs = kwargs.pop('confs', [])
124 127 if confs:
125 128 km2unit = confs[0].km2unit
126 129 clock_in = confs[0].clock_in
127 130 clock_divider = confs[0].clock_divider
128 131 else:
129 132 km2unit = clock_in = clock_divider = 0
130 133 super(RCMixConfigurationForm, self).__init__(*args, **kwargs)
131 134 self.fields['experiment'].choices = [(conf.pk, '{} | {}'.format(conf.pk, conf.name)) for conf in confs]
132 135 self.fields['delay'].widget = KmUnitWidget(attrs = {'km2unit':km2unit})
133 136 self.fields['clock_in'].initial = clock_in
134 137 self.fields['clock_divider'].initial = clock_divider
135 138
136 139
137 140 class RCLineForm(forms.ModelForm):
138 141
139 142 def __init__(self, *args, **kwargs):
140 143 self.extra_fields = kwargs.pop('extra_fields', [])
141 144 super(RCLineForm, self).__init__(*args, **kwargs)
142 145
143 146 if 'initial' in kwargs and 'line_type' in kwargs['initial']:
144 147 line_type = RCLineType.objects.get(pk=kwargs['initial']['line_type'])
145 148
146 149 if 'code_id' in kwargs['initial']:
147 150 model_initial = kwargs['initial']['code_id']
148 151 else:
149 152 model_initial = 0
150 153
151 154 params = json.loads(line_type.params)
152 155
153 156 for label, value in self.extra_fields.items():
154 157 if label=='params':
155 158 continue
156 159
157 160 if 'model' in params[label]:
158 161 self.fields[label] = forms.ChoiceField(choices=create_choices_from_model(params[label]['model'],
159 162 kwargs['initial']['rc_configuration']),
160 163 initial=model_initial)
161 164
162 165
163 166 else:
164 167 if label=='codes' and 'code_id' in kwargs['initial']:
165 168 self.fields[label] = forms.CharField(initial=RCLineCode.objects.get(pk=kwargs['initial']['code_id']).codes)
166 169 else:
167 170 self.fields[label] = forms.CharField(initial=value['value'])
168 171
169 172 if label=='codes':
170 173 self.fields[label].widget = CodesWidget()
171 174
172 175 if self.data:
173 176 line_type = RCLineType.objects.get(pk=self.data['line_type'])
174 177
175 178 if 'code_id' in self.data:
176 179 model_initial = self.data['code_id']
177 180 else:
178 181 model_initial = 0
179 182
180 183 params = json.loads(line_type.params)
181 184
182 185 for label, value in self.extra_fields.items():
183 186 if label=='params':
184 187 continue
185 188
186 189 if 'model' in params[label]:
187 190 self.fields[label] = forms.ChoiceField(choices=create_choices_from_model(params[label]['model'],
188 191 self.data['rc_configuration']),
189 192 initial=model_initial)
190 193
191 194
192 195 else:
193 196 if label=='codes' and 'code' in self.data:
194 197 self.fields[label] = forms.CharField(initial=self.data['codes'])
195 198 else:
196 199 self.fields[label] = forms.CharField(initial=self.data[label])
197 200
198 201 if label=='codes':
199 202 self.fields[label].widget = CodesWidget()
200 203
201 204
202 205 class Meta:
203 206 model = RCLine
204 207 fields = ('rc_configuration', 'line_type', 'channel')
205 208 widgets = {
206 209 'channel': forms.HiddenInput(),
207 210 }
208 211
209 212
210 213 def clean(self):
211 214
212 215 form_data = self.cleaned_data
213 216 if 'code' in self.data and self.data['TX_ref']=="0":
214 217 self.add_error('TX_ref', 'Choose a valid TX reference')
215 218
216 219 if RCLineType.objects.get(pk=self.data['line_type']).name=='mix':
217 220 self.add_error('line_type', 'Invalid Line type')
218 221
219 222 return form_data
220 223
221 224
222 225 def save(self):
223 226 line = super(RCLineForm, self).save()
224 227
225 228 #auto add channel
226 229 line.channel = RCLine.objects.filter(rc_configuration=line.rc_configuration).count()-1
227 230
228 231 #auto add position for TX, TR & CODE
229 232 if line.line_type.name in ('tx', ):
230 233 line.position = RCLine.objects.filter(rc_configuration=line.rc_configuration, line_type=line.line_type).count()-1
231 234
232 235 #save extra fields in params
233 236 params = {}
234 237 for label, value in self.extra_fields.items():
235 238 if label=='params':
236 239 params['params'] = []
237 240 elif label=='codes':
238 241 params[label] = [s for s in self.data[label].split('\r\n') if s]
239 242 else:
240 243 params[label] = self.data[label]
241 244 line.params = json.dumps(params)
242 245 line.save()
243 246 return
244 247
245 248
246 249 class RCLineViewForm(forms.Form):
247 250
248 251 def __init__(self, *args, **kwargs):
249 252
250 253 extra_fields = kwargs.pop('extra_fields')
251 254 line = kwargs.pop('line')
252 255 subform = kwargs.pop('subform', False)
253 256 super(RCLineViewForm, self).__init__(*args, **kwargs)
254 257
255 258 if subform:
256 259 params = json.loads(line.line_type.params)['params']
257 260 else:
258 261 params = json.loads(line.line_type.params)
259 262
260 263 for label, value in extra_fields.items():
261 264
262 265 if label=='params':
263 266 continue
264 267 if 'ref' in label:
265 268 if value in (0, '0'):
266 269 value = 'All'
267 270 else:
268 271 value = RCLine.objects.get(pk=value).get_name()
269 272 elif label=='code':
270 273 value = RCLineCode.objects.get(pk=value).name
271 274
272 275 self.fields[label] = forms.CharField(initial=value)
273 276
274 277 if 'widget' in params[label]:
275 278 km2unit = line.rc_configuration.km2unit
276 279 if params[label]['widget']=='km':
277 280 self.fields[label].widget = KmUnitWidget(attrs={'line':line, 'km2unit':km2unit, 'disabled':True})
278 281 elif params[label]['widget']=='unit':
279 282 self.fields[label].widget = UnitKmWidget(attrs={'line':line, 'km2unit':km2unit, 'disabled':True})
280 283 elif params[label]['widget']=='dc':
281 284 self.fields[label].widget = KmUnitDcWidget(attrs={'line':line, 'km2unit':km2unit, 'disabled':True})
282 285 elif params[label]['widget']=='codes':
283 286 self.fields[label].widget = CodesWidget(attrs={'line':line, 'km2unit':km2unit, 'disabled':True})
284 287 else:
285 288 self.fields[label].widget = DefaultWidget(attrs={'disabled':True})
286 289
287 290
288 291 class RCLineEditForm(forms.ModelForm):
289 292
290 293 def __init__(self, *args, **kwargs):
291 294
292 295 extra_fields = kwargs.pop('extra_fields', [])
293 296 conf = kwargs.pop('conf', False)
294 297 line = kwargs.pop('line')
295 298 subform = kwargs.pop('subform', False)
296 299
297 300 super(RCLineEditForm, self).__init__(*args, **kwargs)
298 301
299 302 if subform is not False:
300 303 params = json.loads(line.line_type.params)['params']
301 304 count = subform
302 305 else:
303 306 params = json.loads(line.line_type.params)
304 307 count = -1
305 308
306 309 for label, value in extra_fields.items():
307 310
308 311 if label in ('params',):
309 312 continue
310 313 if 'help' in params[label]:
311 314 help_text = params[label]['help']
312 315 else:
313 316 help_text = ''
314 317
315 318 if 'model' in params[label]:
316 319 if line.line_type.name=='tr':
317 320 all_choice = True
318 321 else:
319 322 all_choice = False
320 323 self.fields[label] = forms.ChoiceField(choices=create_choices_from_model(params[label]['model'], conf.id, all_choice=all_choice),
321 324 initial=value,
322 325 widget=forms.Select(attrs={'name':'%s|%s|%s' % (count, line.id, label)}),
323 326 help_text=help_text)
324 327
325 328 else:
326 329 self.fields[label] = forms.CharField(initial=value, help_text=help_text)
327 330
328 331 if label in ('code', ):
329 332 self.fields[label].widget = HiddenWidget(attrs={'name':'%s|%s|%s' % (count, line.id, label)})
330 333
331 334 elif 'widget' in params[label]:
332 335 km2unit = line.rc_configuration.km2unit
333 336 if params[label]['widget']=='km':
334 337 self.fields[label].widget = KmUnitWidget(attrs={'line':line, 'km2unit':km2unit, 'name':'%s|%s|%s' % (count, line.id, label)})
335 338 elif params[label]['widget']=='unit':
336 339 self.fields[label].widget = UnitKmWidget(attrs={'line':line, 'km2unit':km2unit, 'name':'%s|%s|%s' % (count, line.id, label)})
337 340 elif params[label]['widget']=='dc':
338 341 self.fields[label].widget = KmUnitDcWidget(attrs={'line':line, 'km2unit':km2unit, 'name':'%s|%s|%s' % (count, line.id, label)})
339 342 elif params[label]['widget']=='codes':
340 343 self.fields[label].widget = CodesWidget(attrs={'line':line, 'km2unit':km2unit, 'name':'%s|%s|%s' % (count, line.id, label)})
341 344 else:
342 345 self.fields[label].widget = DefaultWidget(attrs={'line':line, 'name':'%s|%s|%s' % (count, line.id, label)})
343 346
344 347
345 348 class Meta:
346 349 model = RCLine
347 350 exclude = ('rc_configuration', 'line_type', 'channel', 'position', 'params', 'pulses')
348 351
349 352
350 353 class RCSubLineEditForm(forms.Form):
351 354
352 355 def __init__(self, *args, **kwargs):
353 356 extra_fields = kwargs.pop('extra_fields')
354 357 count = kwargs.pop('count')
355 358 line = kwargs.pop('line')
356 359 super(RCSubLineEditForm, self).__init__(*args, **kwargs)
357 360 for label, value in extra_fields.items():
358 361 self.fields[label] = forms.CharField(initial=value,
359 362 widget=forms.TextInput(attrs={'name':'%s|%s|%s' % (count, line, label)}))
360 363
361 364
362 365 class RCImportForm(forms.Form):
363 366
364 367 file_name = ExtFileField(extensions=['.racp', '.json', '.dat'])
365 368
366 369
367 370 class RCLineCodesForm(forms.ModelForm):
368 371
369 372 def __init__(self, *args, **kwargs):
370 373 super(RCLineCodesForm, self).__init__(*args, **kwargs)
371 374
372 375 if 'initial' in kwargs:
373 376 self.fields['code'] = forms.ChoiceField(choices=RCLineCode.objects.all().values_list('pk', 'name'),
374 377 initial=kwargs['initial']['code'])
375 378 if 'instance' in kwargs:
376 379 self.fields['code'] = forms.ChoiceField(choices=RCLineCode.objects.all().values_list('pk', 'name'),
377 380 initial=kwargs['instance'].pk)
378 381
379 382 self.fields['codes'].widget = CodesWidget()
380 383
381 384
382 385 class Meta:
383 386 model = RCLineCode
384 387 exclude = ('name',)
385 388
386 389 class RCClockForm(forms.ModelForm):
387 390
388 391 def __init__(self, *args, **kwargs):
389 392 super(RCClockForm, self).__init__(*args, **kwargs)
390 393
391 394 instance = getattr(self, 'instance', None)
392 395
393 396 if instance is not None and instance.mode:
394 397 self.fields['multiplier'].widget.attrs['readonly'] = True
395 398 self.fields['divisor'].widget.attrs['readonly'] = True
396 399 self.fields['reference'].widget.attrs['readonly'] = True
397 400
398 401
399 402 class Meta:
400 403 model = RCClock
401 404 exclude = ('rc_configuration',)
402 405
403 406 def clean(self):
404 407
405 408 form_data = self.cleaned_data
406 409
407 410 if form_data['mode'] is True and float(form_data['frequency']) not in (60., 55.):
408 411 self.add_error('frequency', 'Only 60 and 55 are valid values in auto mode')
409 412 elif form_data['mode'] is False:
410 413 if form_data['reference']==0 and not 24<=form_data['multiplier']<=36:
411 414 self.add_error('multiplier', 'For 25MHz, valid values are between 24 and 36')
412 415 elif form_data['reference']==1 and not 60<=form_data['multiplier']<=90:
413 416 self.add_error('multiplier', 'For 10MHz, valid values are between 60 and 90')
414 417
415 418 return form_data No newline at end of file
General Comments 0
You need to be logged in to leave comments. Login now