##// END OF EJS Templates
Funciona el cambio de dev_conf.status y beam.status para Write MQTT
Renato Huallpa -
r393:9bd6b0a0e546
parent child
Show More
@@ -1,35 +1,35
1 1
2 2 REDIS_HOST=radarsys-redis
3 3 REDIS_PORT=6300
4 4 POSTGRES_PORT_5432_TCP_ADDR=radarsys-postgres
5 5 POSTGRES_PORT_5432_TCP_PORT=5432
6 6 #POSTGRES_HOST=postgres
7 7 POSTGRES_HOST=localhost
8 8 POSTGRES_USER=docker
9 9 POSTGRES_PASSWORD=docker
10 10 POSTGRES_DB=radarsys
11 11
12 12 # DB_NAME=radarsys
13 13 # DB_USER=docker
14 14 # DB_PASSWORD=docker
15 15 PGDATA=/var/lib/postgresql/data
16 16 LC_ALL=C.UTF-8
17 17 TZ=America/Lima
18 18 DOCKER_DATA=/data/dockers/radarsys/
19 19 LOCAL_IP=192.168.1.128
20 20
21 MQTT_SERVER=10.10.10.200
22 # MQTT_SERVER = 192.168.100.5
21 # MQTT_SERVER=10.10.10.200
22 MQTT_SERVER = 192.168.100.5
23 23 MQTT_PORT = 1883
24 24 MQTT_KEEPALIVE = 3660
25 25
26 26 MQTT_USER_ATRAD=''
27 27 MQTT_PASSWORD_ATRAD = ''
28 28 MQTT_TOPIC_ATRAD_RECIEVE = "atrad/test4"
29 29
30 30 MQTT_USER = abs
31 31 MQTT_PASSWORD = abs
32 32
33 33 TOPIC_ABS=abs/beams
34 34 TOPIC_ABS_ACK=abs/beams_ack
35 35 TOPIC_ABS_CHANGE=abs/change_beam
@@ -1,1079 +1,1190
1 1 from django.db import models
2 2 from apps.main.models import Configuration , User
3 3 from django.urls 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 from .mqtt import client as mqtt_client
14 14 from radarsys.socketconfig import sio as sio
15 15 import json
16 16
17 17 antenna_default = json.dumps({
18 18 "antenna_up": [[0.0,0.0,0.0,0.0,0.5,0.5,0.5,0.5],
19 19 [0.0,0.0,0.0,0.0,0.5,0.5,0.5,0.5],
20 20 [0.0,0.0,0.0,0.0,0.5,0.5,0.5,0.5],
21 21 [0.0,0.0,0.0,0.0,0.5,0.5,0.5,0.5],
22 22 [0.5,0.5,0.5,0.5,1.0,1.0,1.0,1.0],
23 23 [0.5,0.5,0.5,0.5,1.0,1.0,1.0,1.0],
24 24 [0.5,0.5,0.5,0.5,1.0,1.0,1.0,1.0],
25 25 [0.5,0.5,0.5,0.5,1.0,1.0,1.0,1.0]
26 26 ]
27 27 ,
28 28 "antenna_down": [[0.0,0.0,0.0,0.0,0.5,0.5,0.5,0.5],
29 29 [0.0,0.0,0.0,0.0,0.5,0.5,0.5,0.5],
30 30 [0.0,0.0,0.0,0.0,0.5,0.5,0.5,0.5],
31 31 [0.0,0.0,0.0,0.0,0.5,0.5,0.5,0.5],
32 32 [0.5,0.5,0.5,0.5,3.0,3.0,3.0,3.0],
33 33 [0.5,0.5,0.5,0.5,3.0,3.0,3.0,3.0],
34 34 [0.5,0.5,0.5,0.5,3.0,3.0,3.0,3.0],
35 35 [0.5,0.5,0.5,0.5,3.0,3.0,3.0,3.0]],
36 36 })
37 37
38 38
39 39 tx_default = json.dumps({
40 40 "up": [[1,1,1,1,0,0,0,0],
41 41 [1,1,1,1,0,0,0,0],
42 42 [1,1,1,1,0,0,0,0],
43 43 [1,1,1,1,0,0,0,0],
44 44 [0,0,0,0,1,1,1,1],
45 45 [0,0,0,0,1,1,1,1],
46 46 [0,0,0,0,1,1,1,1],
47 47 [0,0,0,0,1,1,1,1]],
48 48
49 49 "down": [[1,1,1,1,0,0,0,0],
50 50 [1,1,1,1,0,0,0,0],
51 51 [1,1,1,1,0,0,0,0],
52 52 [1,1,1,1,0,0,0,0],
53 53 [0,0,0,0,1,1,1,1],
54 54 [0,0,0,0,1,1,1,1],
55 55 [0,0,0,0,1,1,1,1],
56 56 [0,0,0,0,1,1,1,1]],
57 57 })
58 58
59 59 rx_default = json.dumps({
60 60 "up": [[1,1,1,1,0,0,0,0],
61 61 [1,1,1,1,0,0,0,0],
62 62 [1,1,1,1,0,0,0,0],
63 63 [1,1,1,1,0,0,0,0],
64 64 [0,0,0,0,1,1,1,1],
65 65 [0,0,0,0,1,1,1,1],
66 66 [0,0,0,0,1,1,1,1],
67 67 [0,0,0,0,1,1,1,1]],
68 68
69 69 "down": [[1,1,1,1,0,0,0,0],
70 70 [1,1,1,1,0,0,0,0],
71 71 [1,1,1,1,0,0,0,0],
72 72 [1,1,1,1,0,0,0,0],
73 73 [0,0,0,0,1,1,1,1],
74 74 [0,0,0,0,1,1,1,1],
75 75 [0,0,0,0,1,1,1,1],
76 76 [0,0,0,0,1,1,1,1]],
77 77 })
78 78
79 79 status_default = '0000000000000000000000000000000000000000000000000000000000000000'
80 80 default_messages = {}
81 81
82 82 for i in range(1,65):
83 83 default_messages[str(i)] = "Module "+str(i)
84 84
85 85
86 86 ues_default = json.dumps({
87 87 "up": [0.533333,0.00000,1.06667,0.00000],
88 88 "down": [0.533333,0.00000,1.06667,0.00000]
89 89 })
90 90
91 91 onlyrx_default = json.dumps({
92 92 "up": False,
93 93 "down": False
94 94 })
95 95
96 96 def up_convertion(cadena):
97 97 valores = []
98 98 for c in cadena:
99 99 if c == 1.0: valores=valores+['000']
100 100 if c == 2.0: valores=valores+['001']
101 101 if c == 3.0: valores=valores+['010']
102 102 if c == 0.0: valores=valores+['011']
103 103 if c == 0.5: valores=valores+['100']
104 104 if c == 1.5: valores=valores+['101']
105 105 if c == 2.5: valores=valores+['110']
106 106 if c == 3.5: valores=valores+['111']
107 107
108 108 return valores
109 109
110 110 def up_conv_bits(value):
111 111
112 112 if value == 1.0: bits="000"
113 113 if value == 2.0: bits="001"
114 114 if value == 3.0: bits="010"
115 115 if value == 0.0: bits="011"
116 116 if value == 0.5: bits="100"
117 117 if value == 1.5: bits="101"
118 118 if value == 2.5: bits="110"
119 119 if value == 3.5: bits="111"
120 120
121 121 return bits
122 122
123 123 def down_convertion(cadena):
124 124 valores = []
125 125 for c in cadena:
126 126 if c == 1.0: valores=valores+['000']
127 127 if c == 2.0: valores=valores+['001']
128 128 if c == 3.0: valores=valores+['010']
129 129 if c == 0.0: valores=valores+['011']
130 130 if c == 0.5: valores=valores+['100']
131 131 if c == 1.5: valores=valores+['101']
132 132 if c == 2.5: valores=valores+['110']
133 133 if c == 3.5: valores=valores+['111']
134 134
135 135 return valores
136 136
137 137 def down_conv_bits(value):
138 138
139 139 if value == 1.0: bits="000"
140 140 if value == 2.0: bits="001"
141 141 if value == 3.0: bits="010"
142 142 if value == 0.0: bits="011"
143 143 if value == 0.5: bits="100"
144 144 if value == 1.5: bits="101"
145 145 if value == 2.5: bits="110"
146 146 if value == 3.5: bits="111"
147 147
148 148 return bits
149 149
150 150 def up_conv_value(bits):
151 151
152 152 if bits == "000": value=1.0
153 153 if bits == "001": value=2.0
154 154 if bits == "010": value=3.0
155 155 if bits == "011": value=0.0
156 156 if bits == "100": value=0.5
157 157 if bits == "101": value=1.5
158 158 if bits == "110": value=2.5
159 159 if bits == "111": value=3.5
160 160
161 161 return value
162 162
163 163 def down_conv_value(bits):
164 164
165 165 if bits == "000": value=1.0
166 166 if bits == "001": value=2.0
167 167 if bits == "010": value=3.0
168 168 if bits == "011": value=0.0
169 169 if bits == "100": value=0.5
170 170 if bits == "101": value=1.5
171 171 if bits == "110": value=2.5
172 172 if bits == "111": value=3.5
173 173
174 174 return value
175 175
176 176 def ip2position(module_number):
177 177 j=0
178 178 i=0
179 179 for x in range(0,module_number-1):
180 180 j=j+1
181 181 if j==8:
182 182 i=i+1
183 183 j=0
184 184
185 185 pos = [i,j]
186 186 return pos
187 187
188 188
189 189 def fromBinary2Char(binary_string):
190 190 number = int(binary_string, 2)
191 191 #Plus 33 to avoid more than 1 characters values such as: '\x01'-'\x1f'
192 192 number = number + 33
193 193 char = chr(number)
194 194 return char
195 195
196 196 def fromChar2Binary(char):
197 197 number = ord(char) - 33
198 198 #Minus 33 to get the real value
199 199 bits = bin(number)[2:]
200 200 #To ensure we have a string with 6bits
201 201 if len(bits) < 6:
202 202 bits = bits.zfill(6)
203 203 return bits
204 204
205 205 OPERATION_MODES = (
206 206 (0, 'Manual'),
207 207 (1, 'Automatic'),
208 208 )
209 209
210 210 class ABSConfiguration(Configuration):
211 211 active_beam = models.PositiveSmallIntegerField(verbose_name='Active Beam', default=0)
212 212 module_status = models.CharField(verbose_name='Module Status', max_length=10000, default=status_default)
213 213 operation_mode = models.PositiveSmallIntegerField(verbose_name='Operation Mode', choices=OPERATION_MODES, default = 0)
214 214 operation_value = models.FloatField(verbose_name='Periodic (seconds)', default="10", null=True, blank=True)
215 215 module_messages = models.CharField(verbose_name='Modules Messages', max_length=10000, default=json.dumps(default_messages))
216 216
217 217 class Meta:
218 218 db_table = 'abs_configurations'
219 219
220 220 def get_absolute_url_plot(self):
221 221 return reverse('url_plot_abs_patterns', args=[str(self.id)])
222 222
223 223
224 224 def parms_to_dict(self):
225 225
226 226 parameters = {}
227 227
228 228 parameters['device_id'] = self.device.id
229 229 parameters['label'] = self.label
230 230 parameters['device_type'] = self.device.device_type.name
231 231 parameters['beams'] = {}
232 232
233 233 beams = ABSBeam.objects.filter(abs_conf=self)
234 234 b=1
235 235 for beam in beams:
236 236 #absbeam = ABSBeam.objects.get(pk=beams[beam])
237 237 parameters['beams']['beam'+str(b)] = beam.parms_to_dict()#absbeam.parms_to_dict()
238 238 b+=1
239 239
240 240 return parameters
241 241
242 242
243 243 def dict_to_parms(self, parameters):
244 244
245 245 self.label = parameters['label']
246 246
247 247 absbeams = ABSBeam.objects.filter(abs_conf=self)
248 248 beams = parameters['beams']
249 249
250 250 if absbeams:
251 251 beams_number = len(beams)
252 252 absbeams_number = len(absbeams)
253 253 if beams_number==absbeams_number:
254 254 i = 1
255 255 for absbeam in absbeams:
256 256 absbeam.dict_to_parms(beams['beam'+str(i)])
257 257 i = i+1
258 258 elif beams_number > absbeams_number:
259 259 i = 1
260 260 for absbeam in absbeams:
261 261 absbeam.dict_to_parms(beams['beam'+str(i)])
262 262 i=i+1
263 263 for x in range(i,beams_number+1):
264 264 new_beam = ABSBeam(
265 265 name =beams['beam'+str(i)]['name'],
266 266 antenna =json.dumps(beams['beam'+str(i)]['antenna']),
267 267 abs_conf = self,
268 268 tx =json.dumps(beams['beam'+str(i)]['tx']),
269 269 rx =json.dumps(beams['beam'+str(i)]['rx']),
270 270 ues =json.dumps(beams['beam'+str(i)]['ues']),
271 271 only_rx =json.dumps(beams['beam'+str(i)]['only_rx'])
272 272 )
273 273 new_beam.save()
274 274 i=i+1
275 275 else: #beams_number < absbeams_number:
276 276 i = 1
277 277 for absbeam in absbeams:
278 278 if i <= beams_number:
279 279 absbeam.dict_to_parms(beams['beam'+str(i)])
280 280 i=i+1
281 281 else:
282 282 absbeam.delete()
283 283 else:
284 284 for beam in beams:
285 285 new_beam = ABSBeam(
286 286 name =beams[beam]['name'],
287 287 antenna =json.dumps(beams[beam]['antenna']),
288 288 abs_conf = self,
289 289 tx =json.dumps(beams[beam]['tx']),
290 290 rx =json.dumps(beams[beam]['rx']),
291 291 ues =json.dumps(beams[beam]['ues']),
292 292 only_rx =json.dumps(beams[beam]['only_rx'])
293 293 )
294 294 new_beam.save()
295 295
296 296
297 297
298 298 def update_from_file(self, parameters):
299 299
300 300 self.dict_to_parms(parameters)
301 301 self.save()
302 302
303 303
304 304 def get_beams(self, **kwargs):
305 305 '''
306 306 This function returns ABS Configuration beams
307 307 '''
308 308 return ABSBeam.objects.filter(abs_conf=self.pk, **kwargs)
309 309
310 310 def clone(self, **kwargs):
311 311
312 312 beams = self.get_beams()
313 313 self.pk = None
314 314 self.id = None
315 315 for attr, value in kwargs.items():
316 316 setattr(self, attr, value)
317 317 self.save()
318 318
319 319 for beam in beams:
320 320 beam.clone(abs_conf=self)
321 321
322 322 #-----For Active Beam-----
323 323 new_beams = ABSBeam.objects.filter(abs_conf=self)
324 324 self.active_beam = new_beams[0].id
325 325 self.save()
326 326 #-----For Active Beam-----
327 327 #-----For Device Status---
328 328 self.device.status = 3
329 329 self.device.save()
330 330 #-----For Device Status---
331 331
332 332 return self
333 333
334 334
335 335 def start_device(self):
336 336
337 337 if self.device.status == 3:
338 338
339 339 try:
340 340 #self.write_device()
341 341 send_task('task_change_beam', [self.id],)
342 342 # print("*************************RUNNING ABS**************************",flush=True)
343 343 self.message = 'ABS running'
344 344
345 345 except Exception as e:
346 346 self.message = str(e)
347 347 return False
348 348
349 349 return True
350 350
351 351 else:
352 352 self.message = 'Please, select Write ABS Device first.'
353 353 return False
354 354
355 355
356 356 def stop_device(self):
357 357 self.device.status = 2
358 self.active_beam = 0
358 359 self.device.save()
359 360 self.message = 'ABS has been stopped.'
360 361 self.save()
361 362
362 363 return True
363 364
364 365 def stop_device_mqtt(self):
365 366
366 367 self.device.status = 2
368 self.active_beam = 0
369 # conf_active = None
370 # conf_active.save()
367 371 self.device.save()
368 372 self.message = 'ABS has been stopped.'
369 373 self.save()
370 374
371 375 mqtt_client.publish(os.environ.get('TOPIC_ABS', 'abs/beams'),"STOP")
372 376
373 377 return True
374 378
375 379 def write_device(self):
376 380
377 381 """
378 382 This function sends the beams list to every abs module.
379 383 It needs 'module_conf' function
380 384 """
381 385
382 386 beams = ABSBeam.objects.filter(abs_conf=self)
383 387 nbeams = len(beams)
384 388
385 389 # Se manda a cero RC para poder realizar cambio de beam
386 390 if self.experiment is None:
387 391 confs = []
388 392 else:
389 393 confs = Configuration.objects.filter(experiment = self.experiment).filter(type=0)
390 394 confdds = ''
391 395 confjars = ''
392 396 confrc = ''
393 397 #TO STOP DEVICES: DDS-JARS-RC
394 398 for i in range(0,len(confs)):
395 399 if i==0:
396 400 for conf in confs:
397 401 if conf.device.device_type.name == 'dds':
398 402 confdds = conf
399 403 confdds.stop_device()
400 404 break
401 405 if i==1:
402 406 for conf in confs:
403 407 if conf.device.device_type.name == 'jars':
404 408 confjars = conf
405 409 confjars.stop_device()
406 410 break
407 411 if i==2:
408 412 for conf in confs:
409 413 if conf.device.device_type.name == 'rc':
410 414 confrc = conf
411 415 confrc.stop_device()
412 416 break
413 417
414 418 '''
415 419 if self.connected_modules() == 0 :
416 420 print("No encuentra modulos")
417 421 self.message = "No ABS Module detected."
418 422 return False
419 423 '''
420 424 #-------------Write each abs module-----------
421 425
422 426 if beams:
423 427 block_id = 0
424 428 message = 'SNDF{:03d}{:02d}{:02d}'.format(nbeams, nbeams, block_id)
425 429 for i, status in enumerate(self.module_status):
426 430 message += ''.join([fromBinary2Char(beam.module_6bits(i)) for beam in beams])
427 431 status = ['0'] * 64
428 432 n = 0
429
433 print("Estoy en write_device normal",flush=True)
430 434 sock = self.send_multicast(message)
431 435
432 436 while True:
433 437 #for i in range(32):
434 438 try:
435 439 data, address = sock.recvfrom(1024)
436 440 print (address, data)
437 441 data = data.decode("utf-8")
438 442 if data == '1':
439 443 status[int(address[0][10:])-1] = '3'
440 444 #print (int(address[0][10:])-1)
441 445 elif data == '0':
442 446 status[int(address[0][10:])-1] = '1'
443 447 except socket.timeout:
444 448 print('Timeout')
445 449 break
446 450 except Exception as e:
447 451 print ('Error {}'.format(e))
448 452 n += 1
449 453 sock.close()
450 454 else:
451 455 self.message = "ABS Configuration does not have beams"
452 456 # print('No beams')
453 457 #Start DDS-RC-JARS
454 458 if confdds:
455 459 confdds.start_device()
456 460 if confrc:
457 461 #print confrc
458 462 confrc.start_device()
459 463 if confjars:
460 464 confjars.start_device()
461 465 return False
462 466
463 467 if n == 64:
464 468 self.message = "Could not write ABS Modules"
465 469 self.device.status = 0
466 470 self.module_status = ''.join(status)
467 471 self.save()
468 472 # print('Could not write ABS')
469 473 #Start DDS-RC-JARS
470 474 if confdds:
471 475 confdds.start_device()
472 476 if confrc:
473 477 #print confrc
474 478 confrc.start_device()
475 479 if confjars:
476 480 confjars.start_device()
477 481 return False
478 482 else:
479 483 self.message = "ABS Beams List have been sent to ABS Modules"
480 484 print('ABS beams list sent')
481 485 self.active_beam = beams[0].pk
482 486
483 487 #Start DDS-RC-JARS
484 488 if confdds:
485 489 confdds.start_device()
486 490 if confrc:
487 491 #print confrc
488 492 confrc.start_device()
489 493 if confjars:
490 494 confjars.start_device()
491 495
492 496 # print('Inicia intento de salvar device.status')
493 497 self.device.status = 3
494 498 self.module_status = ''.join(status)
495 499 #print(status)
496 500 self.save()
497 501 # print('Estatus salvado')
498 502 conf_active, __ = ABSActive.objects.get_or_create(pk=1)
499 503 conf_active.conf = self
500 504 conf_active.save()
501 505 return True
502 506
507
508 # DEV_STATES = (
509 # (0, 'No connected'),
510 # (1, 'Connected'),
511 # (2, 'Configured'),
512 # (3, 'Running'),
513 # (4, 'Unknown'),
514 # (5, 'Busy')
515 # )
516
503 517 def write_device_mqtt(self):
504 518
505 519 if self.experiment is None:
506 520 confs = []
507 521 else:
508 522 confs = Configuration.objects.filter(experiment = self.experiment).filter(type=0)
509 523 confdds = ''
510 524 confjars = ''
511 525 confrc = ''
512 526 #TO STOP DEVICES: DDS-JARS-RC
513 527 for i in range(0,len(confs)):
514 528 if i==0:
515 529 for conf in confs:
516 530 if conf.device.device_type.name == 'dds':
517 531 confdds = conf
518 532 confdds.stop_device()
519 533 break
520 534 if i==1:
521 535 for conf in confs:
522 536 if conf.device.device_type.name == 'jars':
523 537 confjars = conf
524 538 confjars.stop_device()
525 539 break
526 540 if i==2:
527 541 for conf in confs:
528 542 if conf.device.device_type.name == 'rc':
529 543 confrc = conf
530 544 confrc.stop_device()
531 545 break
532 546
533 547 apuntes_up_down=''
534 548 beams = ABSBeam.objects.filter(abs_conf=self)
535 549
536 550 inicializacion="{\"beams\":["
537 551 finalizacion="]}"
538 552
539 553 for beam in beams:
540 554 beam.antenna=beam.antenna[1:]
541 555 info="{\"id\":"+str(beam.id)+","+beam.antenna + ","
542 556 apuntes_up_down=apuntes_up_down+info
543 557
544 558 apuntes_up_down=apuntes_up_down[:len(apuntes_up_down)-1]
545 559 apuntes_up_down=inicializacion+ apuntes_up_down+finalizacion
546 560 mqtt_client.publish(os.environ.get('TOPIC_ABS', 'abs/beams'),apuntes_up_down)
547 561
562 self.active_beam = beams[0].pk
563
548 564 #Start DDS-RC-JARS
549 565 if confdds:
550 566 confdds.start_device()
551 567 if confrc:
552 568 #print confrc
553 569 confrc.start_device()
554 570 if confjars:
555 571 confjars.start_device()
556 572
573 self.device.status = 3
574 self.save()
575
576 conf_active, __ = ABSActive.objects.get_or_create(pk=1)
577 conf_active.conf = self
578 conf_active.save()
557 579 return True
558 580
559 581 def read_module(self, module):
560 582
561 583 """
562 584 Read out-bits (up-down) of 1 abs module NOT for Configuration
563 585 """
564 586
565 587 ip_address = self.device.ip_address
566 588 ip_address = ip_address.split('.')
567 589 module_seq = (ip_address[0],ip_address[1],ip_address[2])
568 590 dot = '.'
569 591 module_ip = dot.join(module_seq)+'.'+str(module)
570 592 module_port = self.device.port_address
571 593 read_route = 'http://'+module_ip+':'+str(module_port)+'/read'
572 594
573 595 module_status = json.loads(self.module_status)
574 596 print(read_route)
575 597
576 598 module_bits = ''
577 599
578 600 try:
579 601 r_read = requests.get(read_route, timeout=0.5)
580 602 answer = r_read.json()
581 603 module_bits = answer['allbits']
582 604 except:
583 605 return {}
584 606
585 607 return module_bits
586 608
587 609 def read_device(self):
588 610
589 611 parms = {}
590 612 # Reads active modules.
591 613 module_status = json.loads(self.module_status)
592 614 total = 0
593 615 for status in module_status:
594 616 if module_status[status] != 0:
595 617 module_bits = self.read_module(int(status))
596 618 bits={}
597 619 if module_bits:
598 620 bits = (str(module_bits['um2']) + str(module_bits['um1']) + str(module_bits['um0']) +
599 621 str(module_bits['dm2']) + str(module_bits['dm1']) + str(module_bits['dm0']) )
600 622 parms[str(status)] = bits
601 623
602 624 total +=1
603 625
604 626 if total==0:
605 627 self.message = "No ABS Module detected. Please select 'Status'."
606 628 return False
607 629
608 630
609 631
610 632 self.message = "ABS Modules have been read"
611 633 #monitoreo_tx = JROABSClnt_01CeCnMod000000MNTR10
612 634 return parms
613 635
614 636
615 637 def connected_modules(self):
616 638 """
617 639 This function returns the number of connected abs-modules without updating.
618 640 """
619 641 num = 0
620 642 print(self.module_status)
621 643 for i, status in enumerate(self.module_status):
622 644 if status != '0':
623 645 num += 1
624 646 #print('status {}:{}'.format(i+1, status))
625 647 return num
626 648
627 649 def send_multicast(self, message):
628 650 #print("Send multicast")
629 651 multicast_group = ('224.3.29.71', 10000)
630 652 # Create the datagram socket
631 653 sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
632 654 sock.settimeout(1)
633 655 local_ip = os.environ.get('LOCAL_IP', '0.0.0.0')
634 656 local_ip = '0.0.0.0'
635 657 print("He llegado a IP local")
636 658
637 659 sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_IF, socket.inet_aton(local_ip))
638 660 sock.sendto(message.encode(), multicast_group)
639 661 print('Sending ' + message)
640 662 return sock
641 663
642 664 def status_device(self):
643 665 """
644 666 This function returns the status of all abs-modules as one.
645 667 If at least one module is connected, its answer is "1"
646 668 """
647 669 print ('Status device')
648 670 print (self.active_beam)
649 671 beams = ABSBeam.objects.filter(abs_conf=self)
650 672 #print beams[self.active_beam-1].module_6bits(0)
651 673 active = ABSActive.objects.get(pk=1)
652 674 if active.conf != self:
653 675 self.message = 'La configuracion actual es la del siguiente enlace %s.' % active.conf.get_absolute_url()
654 676 self.message += "\n"
655 677 self.message += 'Se debe realizar un write en esta configuracion para luego obtener un status valido.'
656 678
657 679 return False
658 680
659 681 sock = self.send_multicast('MNTR')
682 print("Estoy en status_deice",flush=True)
660 683
661 684 n = 0
662 685 status = ['0'] * 64
663 686
664 687 while True:
665 688 #for i in range(32):
666 689 #if True:
667 690 try:
668 691 print("Recibiendo")
669 692 address = None
670 693 data, address = sock.recvfrom(2)
671 694 print (address, data)
672 695 print("!!!!")
673 696 data = data.decode()
674 697 aux_mon = "1"
675 698 aux_expected = aux_mon
676 699 if(len(data)==2):
677 700 print ("data[1]: ")
678 701 print (data[1])
679 702 aux_mon = fromChar2Binary(data[1])
680 703 print (aux_mon)
681 704 aux_i = (str(address[0]).split('.'))[3]
682 705 print (aux_i)
683 706 print ('Active beam')
684 707 beam_active = ABSBeam.objects.get(pk=self.active_beam)
685 708 print (beam_active)
686 709 aux_expected = beam_active.module_6bits(int(aux_i)-1)
687 710 print (aux_expected)
688 711
689 712 print ("data[0]: ")
690 713 print (data[0])
691 714
692 715 if data[0] == '1':
693 716 status[int(address[0][10:])-1] = '3'
694 717 if aux_mon == aux_expected:
695 718 print ('Es igual')
696 719 else:
697 720 print ('Es diferente')
698 721 status[int(address[0][10:])-1] = '2'
699 722
700 723 elif data[0] == '0':
701 724 status[int(address[0][10:])-1] = '1'
702 725 n += 1
703 726 print('Module: {} connected'.format(address))
704 727 except socket.timeout:
705 728 print('Timeout')
706 729 break
707 730 except:
708 731 print('Module: {} error'.format(address))
709 732 pass
710 733
711 734 sock.close()
712 735
713 736 if n > 0:
714 737 self.message = 'ABS modules Status have been updated.'
715 738 self.device.status = 1
716 739 else:
717 740 self.device.status = 0
718 741 self.message = 'No ABS module is connected.'
719 742 self.module_status = ''.join(status)
720 743 self.save()
721 744
722 745 return self.device.status
723 746
724 747
725 748 def send_beam(self, beam_pos):
726 749 """
727 750 This function connects to a multicast group and sends the beam number
728 751 to all abs modules.
729 752 """
730 753 print ('Send beam')
731 754 print (self.active_beam)
732 755 beams = ABSBeam.objects.filter(abs_conf=self)
733 756 #print beams[self.active_beam-1].module_6bits(0)
734 757 active = ABSActive.objects.get(pk=1)
735 758 if active.conf != self:
736 759 self.message = 'La configuracion actual es la del siguiente enlace %s.' % active.conf.get_absolute_url()
737 760 self.message += "\n"
738 761 self.message += 'Se debe realizar un write en esta configuracion para luego obtener un status valido.'
739 762
740 763 return False
741 764
742 765 # Se manda a cero RC para poder realizar cambio de beam
743 766 if self.experiment is None:
744 767 confs = []
745 768 else:
746 769 confs = Configuration.objects.filter(experiment = self.experiment).filter(type=0)
747 770 confdds = ''
748 771 confjars = ''
749 772 confrc = ''
750 773 #TO STOP DEVICES: DDS-JARS-RC
751 774 for i in range(0,len(confs)):
752 775 if i==0:
753 776 for conf in confs:
754 777 if conf.device.device_type.name == 'dds':
755 778 confdds = conf
756 779 confdds.stop_device()
757 780 break
758 781 if i==1:
759 782 for conf in confs:
760 783 if conf.device.device_type.name == 'jars':
761 784 confjars = conf
762 785 confjars.stop_device()
763 786 break
764 787 if i==2:
765 788 for conf in confs:
766 789 if conf.device.device_type.name == 'rc':
767 790 confrc = conf
768 791 confrc.stop_device()
769 792 break
770 793 if beam_pos > 0:
771 794 beam_pos = beam_pos - 1
772 795 else:
773 796 beam_pos = 0
774 797
775 798 #El indice del apunte debe ser menor que el numero total de apuntes
776 799 #El servidor tcp en el embebido comienza a contar desde 0
777 800 status = ['0'] * 64
778 801 message = 'CHGB{}'.format(beam_pos)
779 802 sock = self.send_multicast(message)
803 print("Estoy en send_beam ",flush=True)
780 804 while True:
781 805 #for i in range(32):
782 806 try:
783 807 data, address = sock.recvfrom(1024)
784 808 print (address, data)
785 809 data = data.decode()
786 810 if data == '1':
787 811 status[int(address[0][10:])-1] = '3'
788 812 elif data == '0':
789 813 status[int(address[0][10:])-1] = '1'
790 814 except socket.timeout:
791 815 print('Timeout')
792 816 break
793 817 except Exception as e:
794 818 print ('Error {}'.format(e))
795 819 pass
796 820
797 821 sock.close()
798 822
799 823 #Start DDS-RC-JARS
800 824 if confdds:
801 825 confdds.start_device()
802 826 if confrc:
803 827 #print confrc
804 828 confrc.start_device()
805 829 if confjars:
806 830 confjars.start_device()
807 831
808 832 self.message = "ABS Beam has been changed"
809 833 self.module_status = ''.join(status)
810 834 self.save()
811 835 return True
812 836
837 def change_beam_mqtt(self, beam_pos):
838 """
839 This function connects to a multicast group and sends the beam number
840 to all abs modules.
841 """
842 print ('Send beam')
843 print (self.active_beam)
844 beams = ABSBeam.objects.filter(abs_conf=self)
845 #print beams[self.active_beam-1].module_6bits(0)
846 active = ABSActive.objects.get(pk=1)
847 if active.conf != self:
848 self.message = 'La configuracion actual es la del siguiente enlace %s.' % active.conf.get_absolute_url()
849 self.message += "\n"
850 self.message += 'Se debe realizar un write en esta configuracion para luego obtener un status valido.'
851
852 return False
853
854 # Se manda a cero RC para poder realizar cambio de beam
855 if self.experiment is None:
856 confs = []
857 else:
858 confs = Configuration.objects.filter(experiment = self.experiment).filter(type=0)
859 confdds = ''
860 confjars = ''
861 confrc = ''
862 #TO STOP DEVICES: DDS-JARS-RC
863 for i in range(0,len(confs)):
864 if i==0:
865 for conf in confs:
866 if conf.device.device_type.name == 'dds':
867 confdds = conf
868 confdds.stop_device()
869 break
870 if i==1:
871 for conf in confs:
872 if conf.device.device_type.name == 'jars':
873 confjars = conf
874 confjars.stop_device()
875 break
876 if i==2:
877 for conf in confs:
878 if conf.device.device_type.name == 'rc':
879 confrc = conf
880 confrc.stop_device()
881 break
882 if beam_pos > 0:
883 beam_pos = beam_pos - 1
884 else:
885 beam_pos = 0
886
887 #El indice del apunte debe ser menor que el numero total de apuntes
888 #El servidor tcp en el embebido comienza a contar desde 0
889 # status = ['0'] * 64
890 # message = 'CHGB{}'.format(beam_pos)
891 # sock = self.send_multicast(message)
892 # while True:
893 # #for i in range(32):
894 # try:
895 # data, address = sock.recvfrom(1024)
896 # print (address, data)
897 # data = data.decode()
898 # if data == '1':
899 # status[int(address[0][10:])-1] = '3'
900 # elif data == '0':
901 # status[int(address[0][10:])-1] = '1'
902 # except socket.timeout:
903 # print('Timeout')
904 # break
905 # except Exception as e:
906 # print ('Error {}'.format(e))
907 # pass
908
909 # sock.close()
910
911 #Start DDS-RC-JARS
912 if confdds:
913 confdds.start_device()
914 if confrc:
915 #print confrc
916 confrc.start_device()
917 if confjars:
918 confjars.start_device()
919
920 self.message = "ABS Beam has been changed"
921 self.module_status = ''.join(status)
922 self.save()
923 return True
813 924
814 925 def get_absolute_url_import(self):
815 926 return reverse('url_import_abs_conf', args=[str(self.id)])
816 927
817 928 class ABSActive(models.Model):
818 929 conf = models.ForeignKey(ABSConfiguration, null=True, verbose_name='ABS Configuration', on_delete=models.CASCADE)
819 930
820 931 class Meta:
821 932 db_table = 'abs_absactive'
822 933
823 934 class ABSBeam(models.Model):
824 935
825 936 name = models.CharField(max_length=60, default='Beam')
826 937 antenna = models.CharField(verbose_name='Antenna', max_length=1000, default=antenna_default)
827 938 abs_conf = models.ForeignKey('ABSConfiguration', null=True,
828 939 verbose_name='ABS Configuration', on_delete=models.CASCADE)
829 940 tx = models.CharField(verbose_name='Tx', max_length=1000, default=tx_default)
830 941 rx = models.CharField(verbose_name='Rx', max_length=1000, default=rx_default)
831 942 s_time = models.TimeField(verbose_name='Star Time', default='00:00:00')
832 943 e_time = models.TimeField(verbose_name='End Time', default='23:59:59')
833 944 ues = models.CharField(verbose_name='Ues', max_length=100, default=ues_default)
834 945 only_rx = models.CharField(verbose_name='Only RX', max_length=40, default=onlyrx_default)
835 946
836 947 class Meta:
837 948 db_table = 'abs_beams'
838 949
839 950 def __unicode__(self):
840 951 return u'%s' % (self.name)
841 952
842 953 def parms_to_dict(self):
843 954
844 955 parameters = {}
845 956 parameters['name'] = self.name
846 957 parameters['antenna'] = ast.literal_eval(self.antenna)
847 958 parameters['abs_conf'] = self.abs_conf.name
848 959 parameters['tx'] = ast.literal_eval(self.tx)
849 960 parameters['rx'] = ast.literal_eval(self.rx)
850 961 parameters['s_time'] = self.s_time.strftime("%H:%M:%S")
851 962 parameters['e_time'] = self.e_time.strftime("%H:%M:%S")
852 963 parameters['ues'] = ast.literal_eval(self.ues)
853 964 parameters['only_rx'] = json.loads(self.only_rx)
854 965
855 966 return parameters
856 967
857 968 def dict_to_parms(self, parameters):
858 969
859 970 self.name = parameters['name']
860 971 self.antenna = json.dumps(parameters['antenna'])
861 972 #self.abs_conf = parameters['abs_conf']
862 973 self.tx = json.dumps(parameters['tx'])
863 974 self.rx = json.dumps(parameters['rx'])
864 975 #self.s_time = parameters['s_time']
865 976 #self.e_time = parameters['e_time']
866 977 self.ues = json.dumps(parameters['ues'])
867 978 self.only_rx = json.dumps(parameters['only_rx'])
868 979 self.save()
869 980
870 981
871 982 def clone(self, **kwargs):
872 983
873 984 self.pk = None
874 985 self.id = None
875 986 for attr, value in kwargs.items():
876 987 setattr(self, attr, value)
877 988
878 989 self.save()
879 990
880 991 return self
881 992
882 993
883 994 def module_6bits(self, module):
884 995 """
885 996 This function reads antenna pattern and choose 6bits (upbits-downbits) for one abs module
886 997 """
887 998 module += 1
888 999 if module > 64:
889 1000 beam_bits = ""
890 1001 return beam_bits
891 1002
892 1003 data = ast.literal_eval(self.antenna)
893 1004 up_data = data['antenna_up']
894 1005 down_data = data['antenna_down']
895 1006
896 1007 pos = ip2position(module)
897 1008 up_value = up_data[pos[0]][pos[1]]
898 1009 down_value = down_data[pos[0]][pos[1]]
899 1010
900 1011 up_bits = up_conv_bits(up_value)
901 1012 down_bits = down_conv_bits(down_value)
902 1013 beam_bits = up_bits+down_bits
903 1014
904 1015 return beam_bits
905 1016
906 1017
907 1018 @property
908 1019 def get_upvalues(self):
909 1020 """
910 1021 This function reads antenna pattern and show the up-value of one abs module
911 1022 """
912 1023
913 1024 data = ast.literal_eval(self.antenna)
914 1025 up_data = data['antenna_up']
915 1026
916 1027 up_values = []
917 1028 for data in up_data:
918 1029 for i in range(0,8):
919 1030 up_values.append(data[i])
920 1031
921 1032 return up_values
922 1033
923 1034 @property
924 1035 def antenna_upvalues(self):
925 1036 """
926 1037 This function reads antenna pattern and show the up - values of one abs beam
927 1038 in a particular order
928 1039 """
929 1040 data = ast.literal_eval(self.antenna)
930 1041 up_data = data['antenna_up']
931 1042
932 1043 return up_data
933 1044
934 1045 @property
935 1046 def antenna_downvalues(self):
936 1047 """
937 1048 This function reads antenna pattern and show the down - values of one abs beam
938 1049 in a particular order
939 1050 """
940 1051 data = ast.literal_eval(self.antenna)
941 1052 down_data = data['antenna_down']
942 1053
943 1054 return down_data
944 1055
945 1056 @property
946 1057 def get_downvalues(self):
947 1058 """
948 1059 This function reads antenna pattern and show the down-value of one abs module
949 1060 """
950 1061
951 1062 data = ast.literal_eval(self.antenna)
952 1063 down_data = data['antenna_down']
953 1064
954 1065 down_values = []
955 1066 for data in down_data:
956 1067 for i in range(0,8):
957 1068 down_values.append(data[i])
958 1069
959 1070 return down_values
960 1071
961 1072 @property
962 1073 def get_up_ues(self):
963 1074 """
964 1075 This function shows the up-ues-value of one beam
965 1076 """
966 1077 data = ast.literal_eval(self.ues)
967 1078 up_ues = data['up']
968 1079
969 1080 return up_ues
970 1081
971 1082 @property
972 1083 def get_down_ues(self):
973 1084 """
974 1085 This function shows the down-ues-value of one beam
975 1086 """
976 1087 data = ast.literal_eval(self.ues)
977 1088 down_ues = data['down']
978 1089
979 1090 return down_ues
980 1091
981 1092 @property
982 1093 def get_up_onlyrx(self):
983 1094 """
984 1095 This function shows the up-onlyrx-value of one beam
985 1096 """
986 1097 data = json.loads(self.only_rx)
987 1098 up_onlyrx = data['up']
988 1099
989 1100 return up_onlyrx
990 1101
991 1102 @property
992 1103 def get_down_onlyrx(self):
993 1104 """
994 1105 This function shows the down-onlyrx-value of one beam
995 1106 """
996 1107 data = json.loads(self.only_rx)
997 1108 down_onlyrx = data['down']
998 1109
999 1110 return down_onlyrx
1000 1111
1001 1112 @property
1002 1113 def get_tx(self):
1003 1114 """
1004 1115 This function shows the tx-values of one beam
1005 1116 """
1006 1117 data = json.loads(self.tx)
1007 1118
1008 1119 return data
1009 1120
1010 1121 @property
1011 1122 def get_uptx(self):
1012 1123 """
1013 1124 This function shows the up-tx-values of one beam
1014 1125 """
1015 1126 data = json.loads(self.tx)
1016 1127 up_data = data['up']
1017 1128
1018 1129 up_values = []
1019 1130 for data in up_data:
1020 1131 for i in range(0,8):
1021 1132 up_values.append(data[i])
1022 1133
1023 1134 return up_values
1024 1135
1025 1136 @property
1026 1137 def get_downtx(self):
1027 1138 """
1028 1139 This function shows the down-tx-values of one beam
1029 1140 """
1030 1141 data = json.loads(self.tx)
1031 1142 down_data = data['down']
1032 1143
1033 1144 down_values = []
1034 1145 for data in down_data:
1035 1146 for i in range(0,8):
1036 1147 down_values.append(data[i])
1037 1148
1038 1149 return down_values
1039 1150
1040 1151
1041 1152
1042 1153 @property
1043 1154 def get_rx(self):
1044 1155 """
1045 1156 This function shows the rx-values of one beam
1046 1157 """
1047 1158 data = json.loads(self.rx)
1048 1159
1049 1160 return data
1050 1161
1051 1162 @property
1052 1163 def get_uprx(self):
1053 1164 """
1054 1165 This function shows the up-rx-values of one beam
1055 1166 """
1056 1167 data = json.loads(self.rx)
1057 1168 up_data = data['up']
1058 1169
1059 1170 up_values = []
1060 1171 for data in up_data:
1061 1172 for i in range(0,8):
1062 1173 up_values.append(data[i])
1063 1174
1064 1175 return up_values
1065 1176
1066 1177 @property
1067 1178 def get_downrx(self):
1068 1179 """
1069 1180 This function shows the down-rx-values of one beam
1070 1181 """
1071 1182 data = json.loads(self.rx)
1072 1183 down_data = data['down']
1073 1184
1074 1185 down_values = []
1075 1186 for data in down_data:
1076 1187 for i in range(0,8):
1077 1188 down_values.append(data[i])
1078 1189
1079 1190 return down_values
@@ -1,425 +1,426
1 1 {% extends "dev_conf.html" %} {% load static %} {% load django_bootstrap5 %} {% load main_tags %}
2 2 {% block extra-head %}
3 3 <style>
4 4 .abs {
5 5 width: auto;
6 6 display: inline-block;
7 7 text-align: center;
8 8 }
9 9
10 10 .abs td {
11 11 padding: 4px;
12 12 }
13 13
14 14 .module td {
15 15 padding: 4px 15px 4px 15px;
16 16 font-weight: bold;
17 17 border: 1px solid
18 18 }
19 19
20 20 .legend {
21 21 margin-left: 15px;
22 22 display: inline-block;
23 23 border: 2px solid;
24 24 vertical-align: top;
25 25 }
26 26
27 27 .legend th {
28 28 border-bottom: 1px dashed;
29 29 font-weight: bold;
30 30 vertical-align: center;
31 31 text-align: center;
32 32 }
33 33
34 34 .legend td {
35 35 padding: 2px;
36 36 text-align: center;
37 37 font-weight: bold;
38 38 }
39 39
40 40 </style>
41 41 {% endblock %}
42 42
43 43
44 44 {% block extra-menu-actions %}
45 45 <li>
46 46 <a href="{{ dev_conf.get_absolute_url_plot }}" target="_blank">
47 47 <span class="far fa-image" aria-hidden="true"></span> View Patterns </a>
48 48 </li>
49 49 {% endblock %}
50 50
51 51
52 52 {% block extra-content %}
53 53 <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.3/jquery.min.js"></script>
54 54 <script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/socket.io/4.4.1/socket.io.min.js">
55 55 </script>
56 56
57 57
58 58 {% if beams %}
59 59 <h4>Beams:</h4>
60 60 <div class="container">
61 61 <ul class="nav nav-pills">
62 62 {% for beam in beams %}
63 63 <li class="nav-item">
64 64 <a {%if beam.pk == active_beam %} class="nav-link active" {% else %} class="nav-link" {% endif %} data-toggle="pill" href="#menu{{forloop.counter}}">{{forloop.counter}}</a>
65 65 </li>
66 66 {% endfor %}
67 67 </ul>
68 68
69 69 <div class="tab-content">
70 70 {% for beam in beams %}
71 71 <div id="menu{{forloop.counter}}" class="tab-pane fade {%if beam.pk == active_beam %}in active show{% endif %}">
72 72 <h3>{%if beam.pk == active_beam %}Active Beam: {%endif%}{{beam.name}}</h3>
73 73 <table id="abs_pattern{{forloop.counter}}" class="abs">
74 74 <tr>
75 75 <td>
76 76 <b>North Quarter</b>
77 77 <table class="module">
78 78 <tr>
79 79 <td title='{{module_messages.1}}'><span id="1" {%if beam.pk == active_beam %} {{color_status.1}} {%endif%}>{{beam.get_upvalues.0}}</span></td>
80 80 <td title='{{module_messages.2}}'><span id="2" {%if beam.pk == active_beam %} {{color_status.2}} {%endif%}>{{beam.get_upvalues.1}}</span></td>
81 81 <td title='{{module_messages.3}}'><span id="3" {%if beam.pk == active_beam %} {{color_status.3}} {%endif%}>{{beam.get_upvalues.2}}</span></td>
82 82 <td title='{{module_messages.4}}'><span id="4" {%if beam.pk == active_beam %} {{color_status.4}} {%endif%}>{{beam.get_upvalues.3}}</span></td>
83 83 </tr>
84 84 <tr>
85 85 <td title='{{module_messages.1}}'><span id="101" {%if beam.pk == active_beam %} {{color_status.1}} {%endif%}>{{beam.get_downvalues.0}}</span></td>
86 86 <td title='{{module_messages.2}}'><span id="102" {%if beam.pk == active_beam %} {{color_status.2}} {%endif%}>{{beam.get_downvalues.1}}</span></td>
87 87 <td title='{{module_messages.3}}'> <span id="103" {%if beam.pk == active_beam %} {{color_status.3}} {%endif%}>{{beam.get_downvalues.2}}</span></td>
88 88 <td title='{{module_messages.4}}'> <span id="104" {%if beam.pk == active_beam %} {{color_status.4}} {%endif%}>{{beam.get_downvalues.3}}</span></td>
89 89 </tr>
90 90 <tr>
91 91 <td title='{{module_messages.9}}'> <span id="9" {%if beam.pk == active_beam %} {{color_status.9}} {%endif%}>{{beam.get_upvalues.8}}</span></td>
92 92 <td title='{{module_messages.10}}'><span id="10" {%if beam.pk == active_beam %} {{color_status.10}} {%endif%}>{{beam.get_upvalues.9}}</span></td>
93 93 <td title='{{module_messages.11}}'><span id="11" {%if beam.pk == active_beam %} {{color_status.11}} {%endif%}>{{beam.get_upvalues.10}}</span></td>
94 94 <td title='{{module_messages.12}}'><span id="12" {%if beam.pk == active_beam %} {{color_status.12}} {%endif%}>{{beam.get_upvalues.11}}</span></td>
95 95 </tr>
96 96 <tr>
97 97 <td title='{{module_messages.9}}'> <span id="109" {%if beam.pk == active_beam %} {{color_status.9}} {%endif%}>{{beam.get_downvalues.8}}</span></td>
98 98 <td title='{{module_messages.10}}'><span id="110" {%if beam.pk == active_beam %} {{color_status.10}} {%endif%}>{{beam.get_downvalues.9}}</span></td>
99 99 <td title='{{module_messages.11}}'><span id="111" {%if beam.pk == active_beam %} {{color_status.11}} {%endif%}>{{beam.get_downvalues.10}}</span></td>
100 100 <td title='{{module_messages.12}}'><span id="112" {%if beam.pk == active_beam %} {{color_status.12}} {%endif%}>{{beam.get_downvalues.11}}</span></td>
101 101 </tr>
102 102 <tr>
103 103 <td title='{{module_messages.17}}'><span id="17" {%if beam.pk == active_beam %} {{color_status.17}} {%endif%}>{{beam.get_upvalues.16}}</span></td>
104 104 <td title='{{module_messages.18}}'><span id="18" {%if beam.pk == active_beam %} {{color_status.18}} {%endif%}>{{beam.get_upvalues.17}}</span></td>
105 105 <td title='{{module_messages.19}}'><span id="19" {%if beam.pk == active_beam %} {{color_status.19}} {%endif%}>{{beam.get_upvalues.18}}</span></td>
106 106 <td title='{{module_messages.20}}'><span id="20" {%if beam.pk == active_beam %} {{color_status.20}} {%endif%}>{{beam.get_upvalues.19}}</span></td>
107 107 </tr>
108 108 <tr>
109 109 <td title='{{module_messages.17}}'><span id="117" {%if beam.pk == active_beam %} {{color_status.17}} {%endif%}>{{beam.get_downvalues.16}}</span></td>
110 110 <td title='{{module_messages.18}}'><span id="118" {%if beam.pk == active_beam %} {{color_status.18}} {%endif%}>{{beam.get_downvalues.17}}</span></td>
111 111 <td title='{{module_messages.19}}'><span id="119" {%if beam.pk == active_beam %} {{color_status.19}} {%endif%}>{{beam.get_downvalues.18}}</span></td>
112 112 <td title='{{module_messages.20}}'><span id="120" {%if beam.pk == active_beam %} {{color_status.20}} {%endif%}>{{beam.get_downvalues.19}}</span></td>
113 113 </tr>
114 114 <tr>
115 115 <td title='{{module_messages.25}}'><span id="25" {%if beam.pk == active_beam %} {{color_status.25}} {%endif%}>{{beam.get_upvalues.24}}</span></td>
116 116 <td title='{{module_messages.26}}'><span id="26" {%if beam.pk == active_beam %} {{color_status.26}} {%endif%}>{{beam.get_upvalues.25}}</span></td>
117 117 <td title='{{module_messages.27}}'><span id="27" {%if beam.pk == active_beam %} {{color_status.27}} {%endif%}>{{beam.get_upvalues.26}}</span></td>
118 118 <td title='{{module_messages.28}}'><span id="28" {%if beam.pk == active_beam %} {{color_status.28}} {%endif%}>{{beam.get_upvalues.27}}</span></td>
119 119 </tr>
120 120 <tr>
121 121 <td title='{{module_messages.25}}'><span id="125" {%if beam.pk == active_beam %} {{color_status.25}} {%endif%}>{{beam.get_downvalues.24}}</span></td>
122 122 <td title='{{module_messages.26}}'><span id="126" {%if beam.pk == active_beam %} {{color_status.26}} {%endif%}>{{beam.get_downvalues.25}}</span></td>
123 123 <td title='{{module_messages.27}}'><span id="127" {%if beam.pk == active_beam %} {{color_status.27}} {%endif%}>{{beam.get_downvalues.26}}</span></td>
124 124 <td title='{{module_messages.28}}'><span id="128" {%if beam.pk == active_beam %} {{color_status.28}} {%endif%}>{{beam.get_downvalues.27}}</span></td>
125 125 </tr>
126 126 </table>
127 127 </td>
128 128 <td>
129 129 <b>East Quarter</b>
130 130 <table class="module">
131 131 <tr>
132 132 <td title='{{module_messages.5}}'> <span id="5" {%if beam.pk == active_beam %} {{color_status.5}} {%endif%}>{{beam.get_upvalues.4}}</span></td>
133 133 <td title='{{module_messages.6}}'> <span id="6" {%if beam.pk == active_beam %} {{color_status.6}} {%endif%}>{{beam.get_upvalues.5}}</span></td>
134 134 <td title='{{module_messages.7}}'> <span id="7" {%if beam.pk == active_beam %} {{color_status.7}} {%endif%}>{{beam.get_upvalues.6}}</span></td>
135 135 <td title='{{module_messages.8}}'> <span id="8" {%if beam.pk == active_beam %} {{color_status.8}} {%endif%}>{{beam.get_upvalues.7}}</span></td>
136 136 </tr>
137 137 <tr>
138 138 <td title='{{module_messages.5}}'> <span id="105" {%if beam.pk == active_beam %} {{color_status.5}} {%endif%}>{{beam.get_downvalues.4}}</span></td>
139 139 <td title='{{module_messages.6}}'> <span id="106" {%if beam.pk == active_beam %} {{color_status.6}} {%endif%}>{{beam.get_downvalues.5}}</span></td>
140 140 <td title='{{module_messages.7}}'> <span id="107" {%if beam.pk == active_beam %} {{color_status.7}} {%endif%}>{{beam.get_downvalues.6}}</span></td>
141 141 <td title='{{module_messages.8}}'> <span id="108" {%if beam.pk == active_beam %} {{color_status.8}} {%endif%}>{{beam.get_downvalues.7}}</span></td>
142 142 </tr>
143 143 <tr>
144 144 <td title='{{module_messages.13}}'><span id="13" {%if beam.pk == active_beam %} {{color_status.13}} {%endif%}>{{beam.get_upvalues.12}}</span></td>
145 145 <td title='{{module_messages.14}}'><span id="14" {%if beam.pk == active_beam %} {{color_status.14}} {%endif%}>{{beam.get_upvalues.13}}</span></td>
146 146 <td title='{{module_messages.15}}'><span id="15" {%if beam.pk == active_beam %} {{color_status.15}} {%endif%}>{{beam.get_upvalues.14}}</span></td>
147 147 <td title='{{module_messages.16}}'><span id="16" {%if beam.pk == active_beam %} {{color_status.16}} {%endif%}>{{beam.get_upvalues.15}}</span></td>
148 148 </tr>
149 149 <tr>
150 150 <td title='{{module_messages.13}}'><span id="113" {%if beam.pk == active_beam %} {{color_status.13}} {%endif%}>{{beam.get_downvalues.12}}</span></td>
151 151 <td title='{{module_messages.14}}'><span id="114" {%if beam.pk == active_beam %} {{color_status.14}} {%endif%}>{{beam.get_downvalues.13}}</span></td>
152 152 <td title='{{module_messages.15}}'><span id="115" {%if beam.pk == active_beam %} {{color_status.15}} {%endif%}>{{beam.get_downvalues.14}}</span></td>
153 153 <td title='{{module_messages.16}}'><span id="116" {%if beam.pk == active_beam %} {{color_status.16}} {%endif%}>{{beam.get_downvalues.15}}</span></td>
154 154 </tr>
155 155 <tr>
156 156 <td title='{{module_messages.21}}'><span id="21" {%if beam.pk == active_beam %} {{color_status.21}} {%endif%}>{{beam.get_upvalues.20}}</span></td>
157 157 <td title='{{module_messages.22}}'><span id="22" {%if beam.pk == active_beam %} {{color_status.22}} {%endif%}>{{beam.get_upvalues.21}}</span></td>
158 158 <td title='{{module_messages.23}}'><span id="23" {%if beam.pk == active_beam %} {{color_status.23}} {%endif%}>{{beam.get_upvalues.22}}</span></td>
159 159 <td title='{{module_messages.24}}'><span id="24" {%if beam.pk == active_beam %} {{color_status.24}} {%endif%}>{{beam.get_upvalues.23}}</span></td>
160 160 </tr>
161 161 <tr>
162 162 <td title='{{module_messages.21}}'><span id="121" {%if beam.pk == active_beam %} {{color_status.21}} {%endif%}>{{beam.get_downvalues.20}}</span></td>
163 163 <td title='{{module_messages.22}}'><span id="122" {%if beam.pk == active_beam %} {{color_status.22}} {%endif%}>{{beam.get_downvalues.21}}</span></td>
164 164 <td title='{{module_messages.23}}'><span id="123" {%if beam.pk == active_beam %} {{color_status.23}} {%endif%}>{{beam.get_downvalues.22}}</span></td>
165 165 <td title='{{module_messages.24}}'><span id="124" {%if beam.pk == active_beam %} {{color_status.24}} {%endif%}>{{beam.get_downvalues.23}}</span></td>
166 166 </tr>
167 167 <tr>
168 168 <td title='{{module_messages.29}}'><span id="29" {%if beam.pk == active_beam %} {{color_status.29}} {%endif%}>{{beam.get_upvalues.28}}</span></td>
169 169 <td title='{{module_messages.30}}'><span id="30" {%if beam.pk == active_beam %} {{color_status.30}} {%endif%}>{{beam.get_upvalues.29}}</span></td>
170 170 <td title='{{module_messages.31}}'><span id="31" {%if beam.pk == active_beam %} {{color_status.31}} {%endif%}>{{beam.get_upvalues.30}}</span></td>
171 171 <td title='{{module_messages.32}}'><span id="32" {%if beam.pk == active_beam %} {{color_status.32}} {%endif%}>{{beam.get_upvalues.31}}</span></td>
172 172 </tr>
173 173 <tr>
174 174 <td title='{{module_messages.29}}'><span id="129" {%if beam.pk == active_beam %} {{color_status.29}} {%endif%}>{{beam.get_downvalues.28}}</span></td>
175 175 <td title='{{module_messages.30}}'><span id="130" {%if beam.pk == active_beam %} {{color_status.30}} {%endif%}>{{beam.get_downvalues.29}}</span></td>
176 176 <td title='{{module_messages.31}}'><span id="131" {%if beam.pk == active_beam %} {{color_status.31}} {%endif%}>{{beam.get_downvalues.30}}</span></td>
177 177 <td title='{{module_messages.32}}'><span id="132" {%if beam.pk == active_beam %} {{color_status.32}} {%endif%}>{{beam.get_downvalues.31}}</span></td>
178 178 </tr>
179 179 </table>
180 180 </td>
181 181 </tr>
182 182 <tr>
183 183 <td>
184 184 <b>West Quarter</b>
185 185 <table class="module">
186 186 <tr>
187 187 <td title='{{module_messages.33}}'><span id="33" {%if beam.pk == active_beam %} {{color_status.33}} {%endif%}>{{beam.get_upvalues.32}}</span></td>
188 188 <td title='{{module_messages.34}}'><span id="34" {%if beam.pk == active_beam %} {{color_status.34}} {%endif%}>{{beam.get_upvalues.33}}</span></td>
189 189 <td title='{{module_messages.35}}'><span id="35" {%if beam.pk == active_beam %} {{color_status.35}} {%endif%}>{{beam.get_upvalues.34}}</span></td>
190 190 <td title='{{module_messages.36}}'><span id="36" {%if beam.pk == active_beam %} {{color_status.36}} {%endif%}>{{beam.get_upvalues.35}}</span></td>
191 191 </tr>
192 192 <tr>
193 193 <td title='{{module_messages.33}}'><span id="133" {%if beam.pk == active_beam %} {{color_status.33}} {%endif%}>{{beam.get_downvalues.32}}</span></td>
194 194 <td title='{{module_messages.34}}'><span id="134" {%if beam.pk == active_beam %} {{color_status.34}} {%endif%}>{{beam.get_downvalues.33}}</span></td>
195 195 <td title='{{module_messages.35}}'><span id="135" {%if beam.pk == active_beam %} {{color_status.35}} {%endif%}>{{beam.get_downvalues.34}}</span></td>
196 196 <td title='{{module_messages.36}}'><span id="136" {%if beam.pk == active_beam %} {{color_status.36}} {%endif%}>{{beam.get_downvalues.35}}</span></td>
197 197 </tr>
198 198 <tr>
199 199 <td title='{{module_messages.41}}'><span id="41" {%if beam.pk == active_beam %} {{color_status.41}} {%endif%}>{{beam.get_upvalues.40}}</span></td>
200 200 <td title='{{module_messages.42}}'><span id="42" {%if beam.pk == active_beam %} {{color_status.42}} {%endif%}>{{beam.get_upvalues.41}}</span></td>
201 201 <td title='{{module_messages.43}}'><span id="43" {%if beam.pk == active_beam %} {{color_status.43}} {%endif%}>{{beam.get_upvalues.42}}</span></td>
202 202 <td title='{{module_messages.44}}'><span id="44" {%if beam.pk == active_beam %} {{color_status.44}} {%endif%}>{{beam.get_upvalues.43}}</span></td>
203 203 </tr>
204 204 <tr>
205 205 <td title='{{module_messages.41}}'><span id="141" {%if beam.pk == active_beam %} {{color_status.41}} {%endif%}>{{beam.get_downvalues.40}}</span></td>
206 206 <td title='{{module_messages.42}}'><span id="142" {%if beam.pk == active_beam %} {{color_status.42}} {%endif%}>{{beam.get_downvalues.41}}</span></td>
207 207 <td title='{{module_messages.43}}'><span id="143" {%if beam.pk == active_beam %} {{color_status.43}} {%endif%}>{{beam.get_downvalues.42}}</span></td>
208 208 <td title='{{module_messages.44}}'><span id="144" {%if beam.pk == active_beam %} {{color_status.44}} {%endif%}>{{beam.get_downvalues.43}}</span></td>
209 209 </tr>
210 210 <tr>
211 211 <td title='{{module_messages.49}}'><span id="49" {%if beam.pk == active_beam %} {{color_status.49}} {%endif%}>{{beam.get_upvalues.48}}</span></td>
212 212 <td title='{{module_messages.51}}'><span id="50" {%if beam.pk == active_beam %} {{color_status.50}} {%endif%}>{{beam.get_upvalues.49}}</span></td>
213 213 <td title='{{module_messages.52}}'><span id="51" {%if beam.pk == active_beam %} {{color_status.51}} {%endif%}>{{beam.get_upvalues.50}}</span></td>
214 214 <td title='{{module_messages.53}}'><span id="52" {%if beam.pk == active_beam %} {{color_status.52}} {%endif%}>{{beam.get_upvalues.51}}</span></td>
215 215 </tr>
216 216 <tr>
217 217 <td title='{{module_messages.49}}'><span id="149" {%if beam.pk == active_beam %} {{color_status.49}} {%endif%}>{{beam.get_downvalues.48}}</span></td>
218 218 <td title='{{module_messages.50}}'><span id="150" {%if beam.pk == active_beam %} {{color_status.50}} {%endif%}>{{beam.get_downvalues.49}}</span></td>
219 219 <td title='{{module_messages.51}}'><span id="151" {%if beam.pk == active_beam %} {{color_status.51}} {%endif%}>{{beam.get_downvalues.50}}</span></td>
220 220 <td title='{{module_messages.52}}'><span id="152" {%if beam.pk == active_beam %} {{color_status.52}} {%endif%}>{{beam.get_downvalues.51}}</span></td>
221 221 </tr>
222 222 <tr>
223 223 <td title='{{module_messages.57}}'><span id="57" {%if beam.pk == active_beam %} {{color_status.57}} {%endif%}>{{beam.get_upvalues.56}}</span></td>
224 224 <td title='{{module_messages.58}}'><span id="58" {%if beam.pk == active_beam %} {{color_status.58}} {%endif%}>{{beam.get_upvalues.57}}</span></td>
225 225 <td title='{{module_messages.59}}'><span id="59" {%if beam.pk == active_beam %} {{color_status.59}} {%endif%}>{{beam.get_upvalues.58}}</span></td>
226 226 <td title='{{module_messages.60}}'><span id="60" {%if beam.pk == active_beam %} {{color_status.60}} {%endif%}>{{beam.get_upvalues.59}}</span></td>
227 227 </tr>
228 228 <tr>
229 229 <td title='{{module_messages.57}}'><span id="157" {%if beam.pk == active_beam %} {{color_status.57}} {%endif%}>{{beam.get_downvalues.56}}</span></td>
230 230 <td title='{{module_messages.58}}'><span id="158" {%if beam.pk == active_beam %} {{color_status.58}} {%endif%}>{{beam.get_downvalues.57}}</span></td>
231 231 <td title='{{module_messages.59}}'><span id="159" {%if beam.pk == active_beam %} {{color_status.59}} {%endif%}>{{beam.get_downvalues.58}}</span></td>
232 232 <td title='{{module_messages.60}}'><span id="160" {%if beam.pk == active_beam %} {{color_status.60}} {%endif%}>{{beam.get_downvalues.59}}</span></td>
233 233 </tr>
234 234 </table>
235 235 </td>
236 236 <td>
237 237 <b>South Quarter</b>
238 238 <table class="module">
239 239 <tr>
240 240 <td title='{{module_messages.37}}'><span id="37" {%if beam.pk == active_beam %} {{color_status.37}} {%endif%}>{{beam.get_upvalues.36}}</span></td>
241 241 <td title='{{module_messages.38}}'><span id="38" {%if beam.pk == active_beam %} {{color_status.38}} {%endif%}>{{beam.get_upvalues.37}}</span></td>
242 242 <td title='{{module_messages.39}}'><span id="39" {%if beam.pk == active_beam %} {{color_status.39}} {%endif%}>{{beam.get_upvalues.38}}</span></td>
243 243 <td title='{{module_messages.40}}'><span id="40" {%if beam.pk == active_beam %} {{color_status.40}} {%endif%}>{{beam.get_upvalues.39}}</span></td>
244 244 </tr>
245 245 <tr>
246 246 <td title='{{module_messages.37}}'><span id="137" {%if beam.pk == active_beam %} {{color_status.37}} {%endif%}>{{beam.get_downvalues.36}}</span></td>
247 247 <td title='{{module_messages.38}}'><span id="138" {%if beam.pk == active_beam %} {{color_status.38}} {%endif%}>{{beam.get_downvalues.37}}</span></td>
248 248 <td title='{{module_messages.39}}'><span id="139" {%if beam.pk == active_beam %} {{color_status.39}} {%endif%}>{{beam.get_downvalues.38}}</span></td>
249 249 <td title='{{module_messages.40}}'><span id="140" {%if beam.pk == active_beam %} {{color_status.40}} {%endif%}>{{beam.get_downvalues.39}}</span></td>
250 250 </tr>
251 251 <tr>
252 252 <td title='{{module_messages.45}}'><span id="45" {%if beam.pk == active_beam %} {{color_status.45}} {%endif%}>{{beam.get_upvalues.44}}</span></td>
253 253 <td title='{{module_messages.46}}'><span id="46" {%if beam.pk == active_beam %} {{color_status.46}} {%endif%}>{{beam.get_upvalues.45}}</span></td>
254 254 <td title='{{module_messages.47}}'><span id="47" {%if beam.pk == active_beam %} {{color_status.47}} {%endif%}>{{beam.get_upvalues.46}}</span></td>
255 255 <td title='{{module_messages.48}}'><span id="48" {%if beam.pk == active_beam %} {{color_status.48}} {%endif%}>{{beam.get_upvalues.47}}</span></td>
256 256 </tr>
257 257 <tr>
258 258 <td title='{{module_messages.45}}'><span id="145" {%if beam.pk == active_beam %} {{color_status.45}} {%endif%}>{{beam.get_downvalues.44}}</span></td>
259 259 <td title='{{module_messages.46}}'><span id="146" {%if beam.pk == active_beam %} {{color_status.46}} {%endif%}>{{beam.get_downvalues.45}}</span></td>
260 260 <td title='{{module_messages.47}}'><span id="147" {%if beam.pk == active_beam %} {{color_status.47}} {%endif%}>{{beam.get_downvalues.46}}</span></td>
261 261 <td title='{{module_messages.48}}'><span id="148" {%if beam.pk == active_beam %} {{color_status.48}} {%endif%}>{{beam.get_downvalues.47}}</span></td>
262 262 </tr>
263 263 <tr>
264 264 <td title='{{module_messages.53}}'><span id="53" {%if beam.pk == active_beam %} {{color_status.53}} {%endif%}>{{beam.get_upvalues.52}}</span></td>
265 265 <td title='{{module_messages.54}}'><span id="54" {%if beam.pk == active_beam %} {{color_status.54}} {%endif%}>{{beam.get_upvalues.53}}</span></td>
266 266 <td title='{{module_messages.55}}'><span id="55" {%if beam.pk == active_beam %} {{color_status.55}} {%endif%}>{{beam.get_upvalues.54}}</span></td>
267 267 <td title='{{module_messages.56}}'><span id="56" {%if beam.pk == active_beam %} {{color_status.56}} {%endif%}>{{beam.get_upvalues.55}}</span></td>
268 268 </tr>
269 269 <tr>
270 270 <td title='{{module_messages.53}}'><span id="153" {%if beam.pk == active_beam %} {{color_status.53}} {%endif%}>{{beam.get_downvalues.52}}</span></td>
271 271 <td title='{{module_messages.54}}'><span id="154" {%if beam.pk == active_beam %} {{color_status.54}} {%endif%}>{{beam.get_downvalues.53}}</span></td>
272 272 <td title='{{module_messages.55}}'><span id="155" {%if beam.pk == active_beam %} {{color_status.55}} {%endif%}>{{beam.get_downvalues.54}}</span></td>
273 273 <td title='{{module_messages.56}}'><span id="156" {%if beam.pk == active_beam %} {{color_status.56}} {%endif%}>{{beam.get_downvalues.55}}</span></td>
274 274 </tr>
275 275 <tr>
276 276 <td title='{{module_messages.61}}'><span id="61" {%if beam.pk == active_beam %} {{color_status.61}} {%endif%}>{{beam.get_upvalues.60}}</span></td>
277 277 <td title='{{module_messages.62}}'><span id="62" {%if beam.pk == active_beam %} {{color_status.62}} {%endif%}>{{beam.get_upvalues.61}}</span></td>
278 278 <td title='{{module_messages.63}}'><span id="63" {%if beam.pk == active_beam %} {{color_status.63}} {%endif%}>{{beam.get_upvalues.62}}</span></td>
279 279 <td title='{{module_messages.64}}'><span id="64" {%if beam.pk == active_beam %} {{color_status.64}} {%endif%}>{{beam.get_upvalues.63}}</span></td>
280 280 </tr>
281 281 <tr>
282 282 <td title='{{module_messages.61}}'><span id="161" {%if beam.pk == active_beam %} {{color_status.61}} {%endif%}>{{beam.get_downvalues.60}}</span></td>
283 283 <td title='{{module_messages.62}}'><span id="162" {%if beam.pk == active_beam %} {{color_status.62}} {%endif%}>{{beam.get_downvalues.61}}</span></td>
284 284 <td title='{{module_messages.63}}'><span id="163" {%if beam.pk == active_beam %} {{color_status.63}} {%endif%}>{{beam.get_downvalues.62}}</span></td>
285 285 <td title='{{module_messages.64}}'><span id="164" {%if beam.pk == active_beam %} {{color_status.64}} {%endif%}>{{beam.get_downvalues.63}}</span></td>
286 286 </tr>
287 287 </table>
288 288 </td>
289 289 </tr>
290 290 </table>
291 291
292 292 <!-- <meta id="configuraciones_down" data-playlist="{{ beam.get_downvalues }}">
293 293 <meta id="configuraciones_up" data-playlist="{{ beam.get_upvalues }}">
294 294 <meta id="sda" data-toggle="" -->
295 295
296 296 {% if beam.id == active_beam %}
297 297 <table class="legend">
298 298 <tr>
299 299 <th>Legend</th>
300 300 </tr>
301 301 <tr>
302 302 <td class="text-warning">Connected</td>
303 303 </tr>
304 304 <tr>
305 305 <td class="text-success">Running</td>
306 306 </tr>
307 307 <tr>
308 308 <td class="text-info">Mismath</td>
309 309 </tr>
310 310 <tr>
311 311 <td class="text-danger">Disconnected</td>
312 312 </tr>
313 313 </table>
314 314 {% else %}
315 315 <div style="vertical-align: top; display:inline-block;">
316 316 <button id="send_beam{{forloop.counter}}" type="button" class="btn btn-default">
317 317 <span class="fas fa-external-link-square-alt" aria-hidden="true"></span>
318 318 Change Beam</button>
319 319 <br><br><br>
320 320 <button id="change_beam_mqtt{{forloop.counter}}" type="button" class="btn btn-default">
321 321 <span class="fas fa-external-link-square-alt" aria-hidden="true"></span>
322 322 Change Beam MQTT</button>
323 323 </div>
324 324 {% endif %}
325 325 </div>
326 326 {% endfor %}
327 327 </div>
328 328 </div>
329 329
330 330
331 331 {% else %}
332 332 <p style="color:#b4bcc2; margin-left: 5%;">
333 333 <i>No Beams...</i>
334 334 </p>
335 335 {% endif %}
336 336 {% endblock extra-content %}
337 337
338 338 {% block extra-js%}
339 339 <script>
340 340 $(document).ready(function () {
341 341
342 342 // var elemento = document.getElementById("4");
343 343
344 344 var socket = io.connect('http://' + document.domain + ':' + location.port);
345 345
346 346 socket.on('connect', function(data) {
347 347 console.log('Connecting... OK');
348 348 })
349 349
350 350 socket.on('abs_ws', function(data) {
351 351 console.log('ingresamos');
352 352 console.log(data.msg);
353 353 var text = data['msg'];
354 354 // $('#chatLog').val(text);
355 355
356 356 if(data.msg=="b\'Hola\'"){console.log('Hola_amigo')};
357 357 })
358 358
359 359 socket.on('beams_ack', function(data) {
360 360 console.log('beams_ack');
361 361 var text = data['msg'];
362 362
363 363 for (let i=1; i<=64;i++){
364 364
365 365 var elemento = document.getElementById(text[i-1]);
366 366 var elemento2 = document.getElementById(text[i-1]+100);
367 367 if (text[i-1]<=64){
368 368 console.log("1")
369 369 // elemento=document.getElementById(text[i-1]);
370 370 elemento.style.color="green";
371 371 elemento.style.fontWeight = "bold";
372 372 elemento2.style.color="green";
373 373 elemento2.style.fontWeight = "bold";}
374 374 else if (text[i-1]>64){
375 375 elemento=document.getElementById(text[i-1]-64);
376 376 elemento2=document.getElementById(text[i-1]-64+100);
377 377 elemento.style.color="yellow";
378 378 elemento.style.fontWeight = "bold";
379 379 elemento2.style.color="yellow";
380 380 elemento2.style.fontWeight = "bold"}
381 381 else {
382 382 elemento.style.color="red";
383 383 elemento.style.fontWeight = "bold";
384 384 elemento2.style.color="red";
385 385 elemento2.style.fontWeight = "bold"}
386 386 }
387 387
388 388
389 389
390 390 console.log(text[0])
391 391
392 392
393 393 // $('#chatLog').val(text);
394 394
395 395 if(data.msg=="b\'Hola\'"){console.log('Hola_amigo')};
396 396 })
397 397
398 398
399 399 {% for beam in beams %}
400 400
401 401 {% if dev_conf.operation_mode == 1 %}
402 402 $("#send_beam{{forloop.counter}}").prop('disabled', true)
403 403 $("#change_beam_mqtt{{forloop.counter}}").prop('disabled', true)
404 404 {% else %}
405 405 $("#send_beam{{forloop.counter}}").click(function () {
406 406 document.location = "{% url 'url_send_beam' dev_conf.id beam.id %}";
407 407 });
408 408
409 a=$("#change_beam_mqtt{{forloop.counter}}")
410 a.click(function () {
409 change_beam_mqtt_btn=$("#change_beam_mqtt{{forloop.counter}}")
410 change_beam_mqtt_btn.click(function () {
411 411 info="change_beam_mqtt{{forloop.counter}}"
412 socket.emit('change_beam',{data:info})
412 socket.emit('change_beam',{data:info});
413 document.location = "{% url 'url_send_beam_mqtt' dev_conf.id beam.id %}";
413 414 });
414 415
415 416 {% endif %}
416 417
417 418 {% endfor %}
418 419
419 420
420 421 });
421 422
422 423 </script>
423 424
424 425
425 426 {% endblock %}
@@ -1,18 +1,19
1 1 from django.urls import path
2 2
3 3 from apps.abs import views
4 4
5 5 urlpatterns = (
6 6 path('<int:id_conf>/', views.abs_conf, name='url_abs_conf'),
7 7 path('<int:id_conf>/edit/', views.abs_conf_edit, name='url_edit_abs_conf'),
8 8 path('alert/', views.abs_conf_alert, name='url_alert_abs_conf'),
9 9 path('<int:id_conf>/import/', views.import_file, name='url_import_abs_conf'),
10 10 #url(r'^(?P<id_conf>-?\d+)/status/', views.abs_conf, {'status_request':True},name='url_status_abs_conf'),
11 11 path('<int:id_conf>/change_beam/<int:id_beam>/', views.send_beam, name='url_send_beam'),
12 path('<int:id_conf>/change_beam/<int:id_beam>/', views.change_beam_mqtt, name='url_send_beam_mqtt'),
12 13 path('<int:id_conf>/plot/', views.plot_patterns, name='url_plot_abs_patterns'),
13 14 path('<int:id_conf>/plot/<int:id_beam>/', views.plot_patterns, name='url_plot_abs_patterns2'),
14 15 path('<int:id_conf>/plot/<int:id_beam>/<slug:antenna>/pattern.png/', views.plot_pattern, name='url_plot_beam'),
15 16 path('<int:id_conf>/add_beam/', views.add_beam, name='url_add_abs_beam'),
16 17 path('<int:id_conf>/beam/<int:id_beam>/delete/', views.remove_beam, name='url_remove_abs_beam'),
17 18 path('<int:id_conf>/beam/<int:id_beam>/edit/', views.edit_beam, name='url_edit_abs_beam'),
18 19 )
@@ -1,485 +1,560
1 1 from django.shortcuts import render
2 2 from django.template import RequestContext
3 3 from django.shortcuts import redirect, render, get_object_or_404
4 4 from django.contrib import messages
5 5 from django.conf import settings
6 6 from django.http import HttpResponse
7 7 from django.urls import reverse
8 8 from django.views.decorators.csrf import csrf_exempt
9 9 from django.utils.safestring import mark_safe
10 10
11 11 from datetime import datetime
12 12 from time import sleep
13 13 import os
14 14 import io
15 15
16 16 from apps.main.models import Device, Configuration, Experiment
17 17 from apps.main.views import sidebar
18 18
19 19 from .models import ABSConfiguration, ABSBeam
20 20 from .forms import ABSConfigurationForm, ABSBeamEditForm, ABSBeamAddForm, ABSImportForm
21 21
22 22 from .utils.overJroShow import overJroShow
23 23 #from .utils.OverJRO import OverJRO
24 24 #Create your views here.
25 25 import json, ast
26 26
27 27 from .mqtt import client as mqtt_client
28 28 from radarsys.socketconfig import sio as sio
29 29
30 30 def get_values_from_form(form_data):
31 31
32 32 sublistup = []
33 33 sublistdown = []
34 34 subtxlistup = []
35 35 subtxlistdown = []
36 36 subrxlistup = []
37 37 subrxlistdown = []
38 38
39 39 up_values_list = []
40 40 down_values_list = []
41 41 up_txvalues_list = []
42 42 down_txvalues_list = []
43 43 up_rxvalues_list = []
44 44 down_rxvalues_list = []
45 45
46 46 values_list = {}
47 47 cont = 1
48 48
49 49 for i in range(1,65):
50 50 x = float(form_data['abs_up'+str(i)])
51 51 y = float(form_data['abs_down'+str(i)])
52 52 sublistup.append(x)
53 53 sublistdown.append(y)
54 54
55 55 if str(i) in form_data.getlist('uptx_checks'):
56 56 subtxlistup.append(1)
57 57 else:
58 58 subtxlistup.append(0)
59 59 if str(i) in form_data.getlist('downtx_checks'):
60 60 subtxlistdown.append(1)
61 61 else:
62 62 subtxlistdown.append(0)
63 63
64 64 if str(i) in form_data.getlist('uprx_checks'):
65 65 subrxlistup.append(1)
66 66 else:
67 67 subrxlistup.append(0)
68 68 if str(i) in form_data.getlist('downrx_checks'):
69 69 subrxlistdown.append(1)
70 70 else:
71 71 subrxlistdown.append(0)
72 72
73 73 cont = cont+1
74 74
75 75 if cont == 9:
76 76 up_values_list.append(sublistup)
77 77 down_values_list.append(sublistdown)
78 78 sublistup = []
79 79 sublistdown = []
80 80
81 81 up_txvalues_list.append(subtxlistup)
82 82 down_txvalues_list.append(subtxlistdown)
83 83 subtxlistup = []
84 84 subtxlistdown = []
85 85 up_rxvalues_list.append(subrxlistup)
86 86 down_rxvalues_list.append(subrxlistdown)
87 87 subrxlistup = []
88 88 subrxlistdown = []
89 89 cont = 1
90 90
91 91
92 92 list_uesup = []
93 93 list_uesdown = []
94 94 for i in range(1,5):
95 95 if form_data['ues_up'+str(i)] == '':
96 96 list_uesup.append(0.0)
97 97 else:
98 98 list_uesup.append(float(form_data['ues_up'+str(i)]))
99 99
100 100 if form_data['ues_down'+str(i)] == '':
101 101 list_uesdown.append(0.0)
102 102 else:
103 103 list_uesdown.append(float(form_data['ues_down'+str(i)]))
104 104
105 105 onlyrx_list = form_data.getlist('onlyrx')
106 106 only_rx = {}
107 107 if '1' in onlyrx_list:
108 108 only_rx['up'] = True
109 109 else:
110 110 only_rx['up'] = False
111 111 if '2' in onlyrx_list:
112 112 only_rx['down'] = True
113 113 else:
114 114 only_rx['down'] = False
115 115
116 116 antenna = {'antenna_up': up_values_list, 'antenna_down': down_values_list}
117 117 tx = {'up': up_txvalues_list, 'down': down_txvalues_list}
118 118 rx = {'up': up_rxvalues_list, 'down': down_rxvalues_list}
119 119 ues = {'up': list_uesup, 'down': list_uesdown}
120 120 name = str(form_data['beam_name'])
121 121
122 122 beam_data = {'name': name, 'antenna': antenna, 'tx': tx, 'rx': rx, 'ues': ues, 'only_rx': only_rx}
123 123
124 124 return beam_data
125 125
126 126
127 127 def abs_conf(request, id_conf):
128 128
129 129 conf = get_object_or_404(ABSConfiguration, pk=id_conf)
130 130 beams = ABSBeam.objects.filter(abs_conf=conf)
131 131 #------------Colors for Active Beam:-------------
132 132 all_status = {}
133 133 module_messages = json.loads(conf.module_messages)
134 134
135 135 color_status = {}
136 136 for i, status in enumerate(conf.module_status):
137 137 if status == '3': #Running background-color: #00cc00;
138 138 all_status['{}'.format(i+1)] = 2
139 139 color_status['{}'.format(i+1)] = 'class=text-success'#'bgcolor=#00cc00'
140 140 elif status == '2':
141 141 all_status['{}'.format(i+1)] = 1
142 142 color_status['{}'.format(i+1)] = 'class=text-info'
143 143 elif status == '1': #Connected background-color: #ee902c;
144 144 all_status['{}'.format(i+1)] = 1
145 145 color_status['{}'.format(i+1)] = 'class=text-warning'#'bgcolor=#ee902c'
146 146 else: #Disconnected background-color: #ff0000;
147 147 all_status['{}'.format(i+1)] = 0
148 148 color_status['{}'.format(i+1)] = 'class=text-danger'#'bgcolor=#FF0000'
149 149 #------------------------------------------------
150 150
151 151 kwargs = {}
152 152 kwargs['connected_modules'] = str(conf.connected_modules())+'/64'
153 153 kwargs['dev_conf'] = conf
154 154
155 155 if conf.operation_mode == 0:
156 156 kwargs['dev_conf_keys'] = ['label', 'operation_mode']
157 157 else:
158 158 kwargs['dev_conf_keys'] = ['label', 'operation_mode', 'operation_value']
159 159
160 160 kwargs['title'] = 'ABS Configuration'
161 161 kwargs['suptitle'] = 'Details'
162 162 kwargs['button'] = 'Edit Configuration'
163 163
164 164 if conf.active_beam != 0:
165 165 kwargs['active_beam'] = int(conf.active_beam)
166 166
167 167 kwargs['beams'] = beams
168 168 kwargs['modules_status'] = all_status
169 169 kwargs['color_status'] = color_status
170 170 kwargs['module_messages'] = module_messages
171 171 ###### SIDEBAR ######
172 172 kwargs.update(sidebar(conf=conf))
173 173
174 174 return render(request, 'abs_conf.html', kwargs)
175 175
176 176
177 177 # def abs_conf_mqtt(request, id_conf):
178 178 # # socket.on('beams_ack',function(data){
179 179 # ack=data;
180 180 # console.log("ack")
181 181 # console.log(ack)
182 182 # })
183 183
184 184
185 185 def abs_conf_edit(request, id_conf):
186 186
187 187 conf = get_object_or_404(ABSConfiguration, pk=id_conf)
188 188
189 189 beams = ABSBeam.objects.filter(abs_conf=conf)
190 190
191 191 if request.method=='GET':
192 192 form = ABSConfigurationForm(instance=conf)
193 193
194 194 if request.method=='POST':
195 195 form = ABSConfigurationForm(request.POST, instance=conf)
196 196
197 197 if form.is_valid():
198 198 conf = form.save(commit=False)
199 199 conf.save()
200 200 return redirect('url_abs_conf', id_conf=conf.id)
201 201
202 202 ###### SIDEBAR ######
203 203 kwargs = {}
204 204
205 205 kwargs['dev_conf'] = conf
206 206 #kwargs['id_dev'] = conf.id
207 207 kwargs['id_conf'] = conf.id
208 208 kwargs['form'] = form
209 209 kwargs['abs_beams'] = beams
210 210 kwargs['title'] = 'Device Configuration'
211 211 kwargs['suptitle'] = 'Edit'
212 212 kwargs['button'] = 'Save'
213 213
214 214 kwargs['edit'] = True
215 215
216 216 return render(request, 'abs_conf_edit.html', kwargs)
217 217
218 218 @csrf_exempt
219 219 def abs_conf_alert(request):
220 220
221 221 if request.method == 'POST':
222 222 print (request.POST)
223 223 return HttpResponse(json.dumps({'result':1}), content_type='application/json')
224 224 else:
225 225 return redirect('index')
226 226
227 227
228 228 def import_file(request, id_conf):
229 229
230 230 conf = get_object_or_404(ABSConfiguration, pk=id_conf)
231 231 if request.method=='POST':
232 232 form = ABSImportForm(request.POST, request.FILES)
233 233 if form.is_valid():
234 234 try:
235 235 parms = conf.import_from_file(request.FILES['file_name'])
236 236
237 237 if parms:
238 238 conf.update_from_file(parms)
239 239 messages.success(request, 'Configuration "%s" loaded succesfully' % request.FILES['file_name'])
240 240 return redirect(conf.get_absolute_url_edit())
241 241
242 242 except Exception as e:
243 243 messages.error(request, 'Error parsing file: "%s" - %s' % (request.FILES['file_name'], e))
244 244
245 245 else:
246 246 messages.warning(request, 'Your current configuration will be replaced')
247 247 form = ABSImportForm()
248 248
249 249 kwargs = {}
250 250 kwargs['form'] = form
251 251 kwargs['title'] = 'ABS Configuration'
252 252 kwargs['suptitle'] = 'Import file'
253 253 kwargs['button'] = 'Upload'
254 254 kwargs['previous'] = conf.get_absolute_url()
255 255
256 256 return render(request, 'abs_import.html', kwargs)
257 257
258 258
259 259 def send_beam(request, id_conf, id_beam):
260 260
261 261 conf = get_object_or_404(ABSConfiguration, pk=id_conf)
262 262
263 263 abs = Configuration.objects.filter(pk=conf.device.conf_active).first()
264 264 if abs!=conf:
265 265 url = '#' if abs is None else abs.get_absolute_url()
266 266 label = 'None' if abs is None else abs.label
267 267 messages.warning(
268 268 request,
269 269 mark_safe('The current configuration has not been written in the modules, the active configuration is <a href="{}">{}</a>'.format(
270 270 url,
271 271 label
272 272 ))
273 273 )
274 274 return redirect(conf.get_absolute_url())
275 275
276 276 beam = get_object_or_404(ABSBeam, pk=id_beam)
277 277
278 278 if request.method == 'POST':
279 279
280 280 beams_list = ABSBeam.objects.filter(abs_conf=conf)
281 281 conf.active_beam = id_beam
282 282
283 283 i = 0
284 284 for b in beams_list:
285 285 if b.id == int(id_beam):
286 286 break
287 287 else:
288 288 i += 1
289 289 beam_pos = i + 1 #Estandarizar
290 print ('%s Position: %s') % (beam.name, str(beam_pos))
290 print('{} Position {}'.format(beam.name,str(beam_pos)))
291 291 conf.send_beam(beam_pos)
292 292
293 293 return redirect('url_abs_conf', conf.id)
294 294
295 295 kwargs = {
296 296 'title': 'ABS',
297 297 'suptitle': conf.label,
298 298 'message': 'Are you sure you want to change ABS Beam to: {}?'.format(beam.name),
299 299 'delete': False
300 300 }
301 301 kwargs['menu_configurations'] = 'active'
302 302
303 303 return render(request, 'confirm.html', kwargs)
304 304
305 def change_beam_mqtt(request, id_conf, id_beam):
306
307 conf = get_object_or_404(ABSConfiguration, pk=id_conf)
308
309 abs = Configuration.objects.filter(pk=conf.device.conf_active).first()
310 if abs!=conf:
311 url = '#' if abs is None else abs.get_absolute_url()
312 label = 'None' if abs is None else abs.label
313 messages.warning(
314 request,
315 mark_safe('The current configuration has not been written in the modules, the active configuration is <a href="{}">{}</a>'.format(
316 url,
317 label
318 ))
319 )
320 return redirect(conf.get_absolute_url())
321
322 beams = ABSBeam.objects.filter(abs_conf=conf)
323 beam = get_object_or_404(ABSBeam, pk=id_beam)
324
325 if request.method == 'POST':
326
327 beams_list = ABSBeam.objects.filter(abs_conf=conf)
328 conf.active_beam = id_beam
329
330 i = 0
331 for b in beams_list:
332 if b.id == int(id_beam):
333 break
334 else:
335 i += 1
336 beam_pos = i + 1 #Estandarizar
337
338 print('{} Position {}'.format(beam.name,str(beam_pos)))
339 conf.change_beam_mqtt(beam_pos)
340
341 module_messages = json.loads(conf.module_messages)
342 kwargs = {}
343 kwargs['connected_modules'] = str(conf.connected_modules())+'/64'
344 kwargs['dev_conf'] = conf
345
346 if conf.operation_mode == 0:
347 kwargs['dev_conf_keys'] = ['label', 'operation_mode']
348 else:
349 kwargs['dev_conf_keys'] = ['label', 'operation_mode', 'operation_value']
350
351 kwargs['title'] = 'ABS Configuration'
352 kwargs['suptitle'] = 'Details'
353 kwargs['button'] = 'Edit Configuration'
354 if conf.active_beam != 0:
355 kwargs['active_beam'] = int(conf.active_beam)
356
357
358 kwargs['beams'] = beams
359 # kwargs['modules_status'] = all_status
360 # kwargs['color_status'] = color_status
361
362
363 kwargs['module_messages'] = module_messages
364
365 ###### SIDEBAR ######
366 kwargs.update(sidebar(conf=conf))
367
368 # return redirect('url_abs_conf', conf.id)
369 return render(request, 'abs_conf_mqtt.html',kwargs)
370
371 kwargs = {
372 'title': 'ABS',
373 'suptitle': conf.label,
374 'message': 'Are you sure you want to change ABS Beam through MQTT to: {}?'.format(beam.name),
375 'delete': False
376 }
377 kwargs['menu_configurations'] = 'active'
378
379 return render(request, 'confirm.html', kwargs)
305 380
306 381 def add_beam(request, id_conf):
307 382
308 383 conf = get_object_or_404(ABSConfiguration, pk=id_conf)
309 384 confs = Configuration.objects.all()
310 385
311 386 if request.method=='GET':
312 387 form = ABSBeamAddForm()
313 388
314 389 if request.method=='POST':
315 390 form = ABSBeamAddForm(request.POST)
316 391
317 392 beam_data = get_values_from_form(request.POST)
318 393
319 394 new_beam = ABSBeam(
320 395 name = beam_data['name'],
321 396 antenna = json.dumps(beam_data['antenna']),
322 397 abs_conf = conf,
323 398 tx = json.dumps(beam_data['tx']),
324 399 rx = json.dumps(beam_data['rx']),
325 400 ues = json.dumps(beam_data['ues']),
326 401 only_rx = json.dumps(beam_data['only_rx'])
327 402 )
328 403 new_beam.save()
329 404 messages.success(request, 'Beam: "%s" has been added.' % new_beam.name)
330 405
331 406 return redirect('url_edit_abs_conf', conf.id)
332 407
333 408 ###### SIDEBAR ######
334 409 kwargs = {}
335 410
336 411 #kwargs['dev_conf'] = conf.device
337 412 #kwargs['id_dev'] = conf.device
338 413 #kwargs['previous'] = conf.get_absolute_url_edit()
339 414 kwargs['id_conf'] = conf.id
340 415 kwargs['form'] = form
341 416 kwargs['title'] = 'ABS Beams'
342 417 kwargs['suptitle'] = 'Add Beam'
343 418 kwargs['button'] = 'Add'
344 419 kwargs['no_sidebar'] = True
345 420 kwargs['edit'] = True
346 421
347 422 return render(request, 'abs_add_beam.html', kwargs)
348 423
349 424
350 425 def edit_beam(request, id_conf, id_beam):
351 426
352 427 conf = get_object_or_404(ABSConfiguration, pk=id_conf)
353 428 beam = get_object_or_404(ABSBeam, pk=id_beam)
354 429
355 430 if request.method=='GET':
356 431 form = ABSBeamEditForm(initial={'beam': beam})
357 432
358 433 if request.method=='POST':
359 434 form = ABSBeamEditForm(request.POST)
360 435
361 436 beam_data = get_values_from_form(request.POST)
362 437
363 438 beam.dict_to_parms(beam_data)
364 439 beam.save()
365 440
366 441 messages.success(request, 'Beam: "%s" has been updated.' % beam.name)
367 442
368 443 return redirect('url_edit_abs_conf', conf.id)
369 444
370 445 ###### SIDEBAR ######
371 446 kwargs = {}
372 447
373 448 kwargs['id_conf'] = conf.id
374 449 kwargs['form'] = form
375 450 kwargs['title'] = 'ABS Beams'
376 451 kwargs['suptitle'] = 'Edit Beam'
377 452 kwargs['button'] = 'Save'
378 453 kwargs['no_sidebar'] = True
379 454
380 455 #kwargs['previous'] = conf.get_absolute_url_edit()
381 456 kwargs['edit'] = True
382 457
383 458 return render(request, 'abs_edit_beam.html', kwargs)
384 459
385 460
386 461
387 462 def remove_beam(request, id_conf, id_beam):
388 463
389 464 conf = get_object_or_404(ABSConfiguration, pk=id_conf)
390 465 beam = get_object_or_404(ABSBeam, pk=id_beam)
391 466
392 467 if request.method=='POST':
393 468 if beam:
394 469 try:
395 470 beam.delete()
396 471 messages.success(request, 'Beam: "%s" has been deleted.' % beam)
397 472 except:
398 473 messages.error(request, 'Unable to delete beam: "%s".' % beam)
399 474
400 475 return redirect('url_edit_abs_conf', conf.id)
401 476
402 477 ###### SIDEBAR ######
403 478 kwargs = {}
404 479
405 480 kwargs['object'] = beam
406 481 kwargs['delete'] = True
407 482 kwargs['title'] = 'Delete'
408 483 kwargs['suptitle'] = 'Beam'
409 484 kwargs['previous'] = conf.get_absolute_url_edit()
410 485 return render(request, 'confirm.html', kwargs)
411 486
412 487
413 488
414 489 def plot_patterns(request, id_conf, id_beam=None):
415 490
416 491 kwargs = {}
417 492 conf = get_object_or_404(ABSConfiguration, pk=id_conf)
418 493 beams = ABSBeam.objects.filter(abs_conf=conf)
419 494
420 495 if id_beam:
421 496 beam = get_object_or_404(ABSBeam, pk=id_beam)
422 497 kwargs['beam'] = beam
423 498
424 499 ###### SIDEBAR ######
425 500
426 501 kwargs['dev_conf'] = conf.device
427 502 kwargs['id_dev'] = conf.device
428 503 kwargs['id_conf'] = conf.id
429 504 kwargs['abs_beams'] = beams
430 505 kwargs['title'] = 'ABS Patterns'
431 506 kwargs['suptitle'] = conf.name
432 507 kwargs['no_sidebar'] = True
433 508
434 509 return render(request, 'abs_patterns.html', kwargs)
435 510
436 511
437 512 def plot_pattern(request, id_conf, id_beam, antenna):
438 513
439 514 if antenna=='down':
440 515 sleep(3)
441 516
442 517 conf = get_object_or_404(ABSConfiguration, pk=id_conf)
443 518 beam = get_object_or_404(ABSBeam, pk=id_beam)
444 519 just_rx = 1 if json.loads(beam.only_rx)[antenna] else 0
445 520 phases = json.loads(beam.antenna)['antenna_{}'.format(antenna)]
446 521 gain_tx = json.loads(beam.tx)[antenna]
447 522 gain_rx = json.loads(beam.rx)[antenna]
448 523 ues = json.loads(beam.ues)[antenna]
449 524 newOverJro = overJroShow(beam.name)
450 525 fig = newOverJro.plotPattern2(datetime.today(), phases, gain_tx, gain_rx, ues, just_rx)
451 526 buf = io.BytesIO()
452 527 fig.savefig(buf, format='png')
453 528 response = HttpResponse(buf.getvalue(), content_type='image/png')
454 529 return response
455 530
456 531 import os
457 532 from django.http import HttpResponse
458 533
459 534 @sio.on('connection-bind')
460 535 def abs_connection_bind(sid, data):
461 536 print("sid:",sid,"data",data)
462 537
463 538 @sio.on('disconnect')
464 539 def abs_test_disconnect(sid):
465 540 print("Disconnected")
466 541
467 542 @sio.event
468 543 def abs_send_beam_up(sid, message):
469 544 mqtt_client.publish('abs/beams_up', message['data'])
470 545
471 546 @sio.event
472 547 def abs_send_beam_down(sid, message):
473 548 mqtt_client.publish('abs/beams_down', message['data'])
474 549
475 550 @sio.event
476 551 def change_beam(sid,message):
477 552 data=str(message['data'])
478 553 data=data[16]
479 554 mqtt_client.publish('abs/change_beam',data)
480 555
481 556
482 557
483 558
484 559
485 560
@@ -1,105 +1,104
1 1 import paho.mqtt.client as mqtt
2 2 from radarsys import settings
3 3 from radarsys.socketconfig import sio as sio
4 4 import numpy as np
5 5 import psycopg2
6 6 import os
7 7
8 8 def insert(time,data):
9 9 sql = """INSERT INTO atrad_datas(
10 10 datetime,nstx,status,temp_cll,nboards,tempdvr,potincdvr,potretdvr,
11 11 temp1,potinc1,potret1,temp2,potinc2,potret2,temp3,potinc3,potret3,
12 12 temp4,potinc4,potret4,temp5,potinc5,potret5,temp6,potinc6,potret6)
13 13 VALUES(%s,%s,%s,%s,%s,%s,%s,%s,
14 14 %s,%s,%s,%s,%s,%s,%s,%s,%s,
15 15 %s,%s,%s,%s,%s,%s,%s,%s,%s);"""
16 16 try:
17 17 # connect to the PostgreSQL database
18 18 conn = psycopg2.connect(database="radarsys", user='docker', password='docker', host='radarsys-postgres', port= '5432')
19 19 # create a new cursor
20 20 cur = conn.cursor()
21 21 # execute the INSERT statement
22 22 #data_tuple = [tuple(i[:]) for i in a]
23 23 values = (time,) + tuple(data[0][:25])
24 24 cur.execute(sql, values)
25 25
26 26 # get the generated id back
27 27 #vendor_id = cur.fetchone()[0]
28 28
29 29 # commit the changes to the database
30 30 conn.commit()
31 31 # close communication with the database
32 32 cur.close()
33 33 except (Exception, psycopg2.DatabaseError) as error:
34 34 print(error)
35 35 finally:
36 36 if conn is not None:
37 37 conn.close()
38 38
39 39 def maxTemperature(trs):
40 40 temps = GetTemperatures(trs)
41 41 maxT_STX = [max(i) for i in temps]
42 42 maxT = max(maxT_STX)
43 43 STXnum = maxT_STX.index(maxT)
44 44 STXloc = temps[STXnum].index(maxT)
45 45 maxT_loc = 'Amp ' + str(STXnum+1)
46 46
47 47 if STXloc == 0:
48 48 maxT_loc = maxT_loc + " Controller"
49 49 elif STXloc<7:
50 50 maxT_loc = maxT_loc + " PA " + str(STXloc+1)
51 51 else:
52 52 maxT_loc = maxT_loc + " Combiners"
53 53
54 54 return maxT,maxT_loc,temps
55 55
56 56 def dataConvert(msg):
57 57 msgStr = str(msg.payload)
58 58 msgClean = [i for i in msgStr[21:-1].split("*")]
59 59 dataSTX = [[],[],[],[]]
60 60 for trs,i in zip(msgClean,[0,1,2,3]) :
61 61 dataSTX[i]= [int(i) for i in trs[1:-1].split(",")]
62 62 # Data to database
63 63 insert(msgStr[2:21],dataSTX)
64 64 # Data to send by socket
65 65 id_STX = dataSTX[0][0] // 4
66 66 status = ''.join([msgClean[i][3] for i in [0,1,2,3]])
67 67 powers = [dataSTX[0][34],dataSTX[0][36],dataSTX[2][32],dataSTX[2][34]]
68 68 tmax,index,tempData = maxTemperature(dataSTX)
69 69 #Json to send
70 70 data = {'time':msgStr[2:21],'num':id_STX,'pow':powers,'tmax':[str(tmax),index],'status':status}
71 71 data_temp = {'time':msgStr[2:21],'temp':tempData}
72 72 return data, data_temp
73 73
74 74 def GetTemperatures(data):
75 75 np_data = [np.array(i) for i in data]
76 76 temps = [i[i<40] for i in np_data]
77 77 return [i[i>15].tolist() for i in temps]
78 78
79 79 def on_connect(mqtt_client, userdata, flags, rc):
80 80 if rc == 0:
81 print('Connected successfullyasdss')
81 # print('Connected successfullyasdss')
82 82 mqtt_client.subscribe("atrad/test4")
83 print("Exito")
84 83 else:
85 84 print('Bad connection. Code:', rc)
86 85
87 86 def on_message(mqtt_client, userdata, msg):
88 87 print('Received message on topic: {} with payload: {}'.format(msg.topic,msg.payload), flush=True)
89 88 mainData, tempData = dataConvert(msg)
90 89 # print("Recibi : {}".format(msg.payload),flush=True)
91 90 #socket fot general data
92 91 sio.emit('test',data = mainData)
93 92 print(mainData)
94 93 #socket for temperature details
95 94 sio.emit('temptx'+str(mainData['num'] + 1),data = tempData)
96 95
97 96 client = mqtt.Client()
98 97 client.on_connect = on_connect
99 98 client.on_message = on_message
100 99 client.username_pw_set( '','')
101 100 client.connect(
102 101 host=os.environ.get('MQTT_SERVER', '10.10.10.200'),
103 102 port=int(settings.os.environ.get('MQTT_PORT', 1883)),
104 103 keepalive=int(os.environ.get('MQTT_KEEPALIVE', 60))
105 104 ) No newline at end of file
@@ -1,849 +1,850
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.urls 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 'dds_rest': 80
37 37 }
38 38
39 39 RADAR_STATES = (
40 40 (0, 'No connected'),
41 41 (1, 'Connected'),
42 42 (2, 'Configured'),
43 43 (3, 'Running'),
44 44 (4, 'Scheduled'),
45 45 )
46 46
47 47 EXPERIMENT_TYPE = (
48 48 (0, 'RAW_DATA'),
49 49 (1, 'PDATA'),
50 50 )
51 51
52 52 DECODE_TYPE = (
53 53 (0, 'None'),
54 54 (1, 'TimeDomain'),
55 55 (2, 'FreqDomain'),
56 56 (3, 'InvFreqDomain'),
57 57 )
58 58
59 59 DEV_STATES = (
60 60 (0, 'No connected'),
61 61 (1, 'Connected'),
62 62 (2, 'Configured'),
63 63 (3, 'Running'),
64 64 (4, 'Unknown'),
65 65 (5, 'Busy')
66 66 )
67 67
68 68 DEV_TYPES = (
69 69 ('', 'Select a device type'),
70 70 ('rc', 'Radar Controller'),
71 71 ('dds', 'Direct Digital Synthesizer'),
72 72 ('jars', 'Jicamarca Radar Acquisition System'),
73 73 ('usrp', 'Universal Software Radio Peripheral'),
74 74 ('cgs', 'Clock Generator System'),
75 75 ('abs', 'Automatic Beam Switching'),
76 76 ('dds_rest', 'Direct Digital Synthesizer_REST'),
77 77 ('atrad', 'Transmitter ATRAD'),
78 78 )
79 79
80 80 EXP_STATES = (
81 81 (0,'Error'), #RED
82 82 (1,'Cancelled'), #YELLOW
83 83 (2,'Running'), #GREEN
84 84 (3,'Scheduled'), #BLUE
85 85 (4,'Unknown'), #WHITE
86 86 )
87 87
88 88 CONF_TYPES = (
89 89 (0, 'Active'),
90 90 (1, 'Historical'),
91 91 )
92 92
93 93 class Profile(models.Model):
94 94 user = models.OneToOneField(User, on_delete=models.CASCADE)
95 95 theme = models.CharField(max_length=30, default='spacelab')
96 96
97 97
98 98 @receiver(post_save, sender=User)
99 99 def create_user_profile(sender, instance, created, **kwargs):
100 100 if created:
101 101 Profile.objects.create(user=instance)
102 102
103 103 @receiver(post_save, sender=User)
104 104 def save_user_profile(sender, instance, **kwargs):
105 105 instance.profile.save()
106 106
107 107
108 108 class Location(models.Model):
109 109
110 110 name = models.CharField(max_length = 30)
111 111 description = models.TextField(blank=True, null=True)
112 112
113 113 class Meta:
114 114 db_table = 'db_location'
115 115
116 116 def __str__(self):
117 117 return u'%s' % self.name
118 118
119 119 def get_absolute_url(self):
120 120 return reverse('url_location', args=[str(self.id)])
121 121
122 122
123 123 class DeviceType(models.Model):
124 124
125 125 name = models.CharField(max_length = 10, choices = DEV_TYPES, default = 'dds_rest')
126 126 sequence = models.PositiveSmallIntegerField(default=55)
127 127 description = models.TextField(blank=True, null=True)
128 128
129 129 class Meta:
130 130 db_table = 'db_device_types'
131 131
132 132 def __str__(self):
133 133 return u'%s' % self.get_name_display()
134 134
135 135 class Device(models.Model):
136 136
137 137 device_type = models.ForeignKey('DeviceType', on_delete=models.CASCADE)
138 138 location = models.ForeignKey('Location', on_delete=models.CASCADE)
139 139 ip_address = models.GenericIPAddressField(protocol='IPv4', default='0.0.0.0')
140 140 port_address = models.PositiveSmallIntegerField(default=2000)
141 141 description = models.TextField(blank=True, null=True)
142 142 status = models.PositiveSmallIntegerField(default=4, choices=DEV_STATES)
143 143 conf_active = models.PositiveIntegerField(default=0, verbose_name='Current configuration')
144 144
145 145 class Meta:
146 146 db_table = 'db_devices'
147 147
148 148 def __str__(self):
149 149 ret = u'{} [{}]'.format(self.device_type.name.upper(), self.location.name)
150 150
151 151 return ret
152 152
153 153 @property
154 154 def name(self):
155 155 return str(self)
156 156
157 157 def get_status(self):
158 158 return self.status
159 159
160 160 @property
161 161 def status_color(self):
162 162 color = 'muted'
163 163 if self.status == 0:
164 164 color = "danger"
165 165 elif self.status == 1:
166 166 color = "warning"
167 167 elif self.status == 2:
168 168 color = "info"
169 169 elif self.status == 3:
170 170 color = "success"
171 171
172 172 return color
173 173
174 174 def url(self, path=None):
175 175
176 176 if path:
177 177 return 'http://{}:{}/{}/'.format(self.ip_address, self.port_address, path)
178 178 else:
179 179 return 'http://{}:{}/'.format(self.ip_address, self.port_address)
180 180
181 181 def get_absolute_url(self):
182 182 return reverse('url_device', args=[str(self.id)])
183 183
184 184 def get_absolute_url_edit(self):
185 185 return reverse('url_edit_device', args=[str(self.id)])
186 186
187 187 def get_absolute_url_delete(self):
188 188 return reverse('url_delete_device', args=[str(self.id)])
189 189
190 190 def change_ip(self, ip_address, mask, gateway, dns, **kwargs):
191 191
192 192 if self.device_type.name=='dds':
193 193 try:
194 194 answer = dds_api.change_ip(ip = self.ip_address,
195 195 port = self.port_address,
196 196 new_ip = ip_address,
197 197 mask = mask,
198 198 gateway = gateway)
199 199 if answer[0]=='1':
200 200 self.message = '25|DDS - {}'.format(answer)
201 201 self.ip_address = ip_address
202 202 self.save()
203 203 else:
204 204 self.message = '30|DDS - {}'.format(answer)
205 205 return False
206 206 except Exception as e:
207 207 self.message = '40|{}'.format(str(e))
208 208 return False
209 209
210 210 elif self.device_type.name=='rc':
211 211 headers = {'content-type': "application/json",
212 212 'cache-control': "no-cache"}
213 213
214 214 ip = [int(x) for x in ip_address.split('.')]
215 215 dns = [int(x) for x in dns.split('.')]
216 216 gateway = [int(x) for x in gateway.split('.')]
217 217 subnet = [int(x) for x in mask.split('.')]
218 218
219 219 payload = {
220 220 "ip": ip,
221 221 "dns": dns,
222 222 "gateway": gateway,
223 223 "subnet": subnet
224 224 }
225 225
226 226 req = requests.post(self.url('changeip'), data=json.dumps(payload), headers=headers)
227 227 try:
228 228 answer = req.json()
229 229 if answer['changeip']=='ok':
230 230 self.message = '25|IP succesfully changed'
231 231 self.ip_address = ip_address
232 232 self.save()
233 233 else:
234 234 self.message = '30|An error ocuur when changing IP'
235 235 except Exception as e:
236 236 self.message = '40|{}'.format(str(e))
237 237 else:
238 238 self.message = 'Not implemented'
239 239 return False
240 240
241 241 return True
242 242
243 243
244 244 class Campaign(models.Model):
245 245
246 246 template = models.BooleanField(default=False)
247 247 name = models.CharField(max_length=60, unique=True)
248 248 start_date = models.DateTimeField(blank=True, null=True)
249 249 end_date = models.DateTimeField(blank=True, null=True)
250 250 tags = models.CharField(max_length=40, blank=True, null=True)
251 251 description = models.TextField(blank=True, null=True)
252 252 experiments = models.ManyToManyField('Experiment', blank=True)
253 253 author = models.ForeignKey(User, null=True, blank=True,on_delete=models.CASCADE)
254 254
255 255 class Meta:
256 256 db_table = 'db_campaigns'
257 257 ordering = ('name',)
258 258
259 259 def __str__(self):
260 260 if self.template:
261 261 return u'{} (template)'.format(self.name)
262 262 else:
263 263 return u'{}'.format(self.name)
264 264
265 265 def jsonify(self):
266 266
267 267 data = {}
268 268
269 269 ignored = ('template')
270 270
271 271 for field in self._meta.fields:
272 272 if field.name in ignored:
273 273 continue
274 274 data[field.name] = field.value_from_object(self)
275 275
276 276 data['start_date'] = data['start_date'].strftime('%Y-%m-%d')
277 277 data['end_date'] = data['end_date'].strftime('%Y-%m-%d')
278 278
279 279 return data
280 280
281 281 def parms_to_dict(self):
282 282
283 283 params = Params({})
284 284 params.add(self.jsonify(), 'campaigns')
285 285
286 286 for exp in Experiment.objects.filter(campaign = self):
287 287 params.add(exp.jsonify(), 'experiments')
288 288 configurations = Configuration.objects.filter(experiment=exp, type=0)
289 289
290 290 for conf in configurations:
291 291 params.add(conf.jsonify(), 'configurations')
292 292 if conf.device.device_type.name=='rc':
293 293 for line in conf.get_lines():
294 294 params.add(line.jsonify(), 'lines')
295 295
296 296 return params.data
297 297
298 298 def dict_to_parms(self, parms, CONF_MODELS):
299 299
300 300 experiments = Experiment.objects.filter(campaign = self)
301 301
302 302 if experiments:
303 303 for experiment in experiments:
304 304 experiment.delete()
305 305
306 306 for id_exp in parms['experiments']['allIds']:
307 307 exp_parms = parms['experiments']['byId'][id_exp]
308 308 dum = (datetime.now() - datetime(1970, 1, 1)).total_seconds()
309 309 exp = Experiment(name='{}'.format(dum))
310 310 exp.save()
311 311 exp.dict_to_parms(parms, CONF_MODELS, id_exp=id_exp)
312 312 self.experiments.add(exp)
313 313
314 314 camp_parms = parms['campaigns']['byId'][parms['campaigns']['allIds'][0]]
315 315
316 316 self.name = '{}-{}'.format(camp_parms['name'], datetime.now().strftime('%y%m%d'))
317 317 self.start_date = camp_parms['start_date']
318 318 self.end_date = camp_parms['end_date']
319 319 self.tags = camp_parms['tags']
320 320 self.save()
321 321
322 322 return self
323 323
324 324 def get_experiments_by_radar(self, radar=None):
325 325
326 326 ret = []
327 327 if radar:
328 328 locations = Location.objects.filter(pk=radar)
329 329 else:
330 330 locations = set([e.location for e in self.experiments.all()])
331 331
332 332 for loc in locations:
333 333 dum = {}
334 334 dum['name'] = loc.name
335 335 dum['id'] = loc.pk
336 336 dum['experiments'] = [e for e in self.experiments.all() if e.location==loc]
337 337 ret.append(dum)
338 338 return ret
339 339
340 340 def get_absolute_url(self):
341 341 return reverse('url_campaign', args=[str(self.id)])
342 342
343 343 def get_absolute_url_edit(self):
344 344 return reverse('url_edit_campaign', args=[str(self.id)])
345 345
346 346 def get_absolute_url_delete(self):
347 347 return reverse('url_delete_campaign', args=[str(self.id)])
348 348
349 349 def get_absolute_url_export(self):
350 350 return reverse('url_export_campaign', args=[str(self.id)])
351 351
352 352 def get_absolute_url_import(self):
353 353 return reverse('url_import_campaign', args=[str(self.id)])
354 354
355 355
356 356 class RunningExperiment(models.Model):
357 357 radar = models.OneToOneField('Location', on_delete=models.CASCADE)
358 358 running_experiment = models.ManyToManyField('Experiment', blank = True)
359 359 status = models.PositiveSmallIntegerField(default=0, choices=RADAR_STATES)
360 360
361 361
362 362 class Experiment(models.Model):
363 363
364 364 template = models.BooleanField(default=False)
365 365 name = models.CharField(max_length=40, default='', unique=True)
366 366 location = models.ForeignKey('Location', null=True, blank=True, on_delete=models.CASCADE)
367 367 freq = models.FloatField(verbose_name='Operating Freq. (MHz)', validators=[MinValueValidator(1), MaxValueValidator(10000)], default=49.9200)
368 368 start_time = models.TimeField(default='00:00:00')
369 369 end_time = models.TimeField(default='23:59:59')
370 370 task = models.CharField(max_length=36, default='', blank=True, null=True)
371 371 status = models.PositiveSmallIntegerField(default=4, choices=EXP_STATES)
372 372 author = models.ForeignKey(User, null=True, blank=True,on_delete=models.CASCADE)
373 373 hash = models.CharField(default='', max_length=64, null=True, blank=True)
374 374
375 375 class Meta:
376 376 db_table = 'db_experiments'
377 377 ordering = ('template', 'name')
378 378
379 379 def __str__(self):
380 380 if self.template:
381 381 return u'%s (template)' % (self.name)
382 382 else:
383 383 return u'%s' % (self.name)
384 384
385 385 def jsonify(self):
386 386
387 387 data = {}
388 388
389 389 ignored = ('template')
390 390
391 391 for field in self._meta.fields:
392 392 if field.name in ignored:
393 393 continue
394 394 data[field.name] = field.value_from_object(self)
395 395
396 396 data['start_time'] = data['start_time'].strftime('%H:%M:%S')
397 397 data['end_time'] = data['end_time'].strftime('%H:%M:%S')
398 398 data['location'] = self.location.name
399 399 data['configurations'] = ['{}'.format(conf.pk) for
400 400 conf in Configuration.objects.filter(experiment=self, type=0)]
401 401
402 402 return data
403 403
404 404 @property
405 405 def radar_system(self):
406 406 return self.location
407 407
408 408 def clone(self, **kwargs):
409 409
410 410 confs = Configuration.objects.filter(experiment=self, type=0)
411 411 self.pk = None
412 412 self.name = '{}_{:%y%m%d%H%M%S}'.format(self.name, datetime.now())
413 413 for attr, value in kwargs.items():
414 414 setattr(self, attr, value)
415 415
416 416 self.save()
417 417
418 418 for conf in confs:
419 419 conf.clone(experiment=self, template=False)
420 420
421 421 return self
422 422
423 423 def start(self):
424 424 '''
425 425 Configure and start experiments's devices
426 426 ABS-CGS-DDS-RC-JARS
427 427 '''
428 428 self.status=5 #Busy
429 429 self.save()
430 430 # print("Guardando STATUS: {}".format(self.status))
431 431
432 432 confs = []
433 433 allconfs = Configuration.objects.filter(experiment=self, type = 0).order_by('-device__device_type__sequence')
434 434 rc_mix = [conf for conf in allconfs if conf.device.device_type.name=='rc' and conf.mix]
435 435 if rc_mix:
436 436 for conf in allconfs:
437 437 if conf.device.device_type.name == 'rc' and not conf.mix:
438 438 continue
439 439 confs.append(conf)
440 440 else:
441 441 confs = allconfs
442 442
443 443
444 444 for conf in confs:
445 print("conf->",conf)
445 446 print(conf.device)
446 447 print(conf.device.status)
447 448 print("--------------",flush=True)
448 449 print("Stop ",conf.name,flush=True)
449 450 if conf.stop_device() ==False:
450 451 print("FallΓ³ Stop ",conf.name)
451 452 print("Cancelando CampaΓ±a...",flush=True)
452 453 return 0
453 454 print("Write ",conf.name,flush=True)
454 455 if conf.write_device() ==False:
455 456 print("FallΓ³ Write ",conf.name)
456 457 print("Cancelando CampaΓ±a...",flush=True)
457 458 return 0
458 459 print("Save",conf.name,flush=True)
459 460 conf.device.conf_active = conf.pk
460 461 conf.device.save()
461 462 print("Start",conf.name,flush=True)
462 463 if conf.start_device()==False:
463 464 print("FallΓ³ Start ",conf.name)
464 465 print("Cancelando CampaΓ±a...",flush=True)
465 466 return 0
466 467 print("--- CONFIGURACIΓ“N EXITOSA ---",flush=True)
467 468 time.sleep(1)
468 469
469 470 return 2
470 471
471 472
472 473 def stop(self):
473 474 '''
474 475 Stop experiments's devices
475 476 DDS-JARS-RC-CGS-ABS
476 477 '''
477 478
478 479 confs = Configuration.objects.filter(experiment=self, type = 0).order_by('device__device_type__sequence')
479 480 confs = confs.exclude(device__device_type__name='cgs')
480 481 try:
481 482 for conf in confs:
482 483 conf.stop_device()
483 484 except:
484 485 return 0
485 486 return 1
486 487
487 488 def get_status(self):
488 489
489 490 if self.status == 3:
490 491 return
491 492
492 493 confs = Configuration.objects.filter(experiment=self, type=0)
493 494
494 495 for conf in confs:
495 496 conf.status_device()
496 497
497 498 total = confs.aggregate(models.Sum('device__status'))['device__status__sum']
498 499
499 500 if total==2*confs.count():
500 501 status = 1
501 502 elif total == 3*confs.count():
502 503 status = 2
503 504 else:
504 505 status = 0
505 506
506 507 self.status = status
507 508 self.save()
508 509
509 510 def status_color(self):
510 511 color = 'muted'
511 512 if self.status == 0:
512 513 color = "danger"
513 514 elif self.status == 1:
514 515 color = "warning"
515 516 elif self.status == 2:
516 517 color = "success"
517 518 elif self.status == 3:
518 519 color = "info"
519 520
520 521 return color
521 522
522 523 def parms_to_dict(self):
523 524
524 525 params = Params({})
525 526 params.add(self.jsonify(), 'experiments')
526 527
527 528 configurations = Configuration.objects.filter(experiment=self, type=0)
528 529
529 530 for conf in configurations:
530 531 params.add(conf.jsonify(), 'configurations')
531 532 if conf.device.device_type.name=='rc':
532 533 for line in conf.get_lines():
533 534 params.add(line.jsonify(), 'lines')
534 535
535 536 return params.data
536 537
537 538 def dict_to_parms(self, parms, CONF_MODELS, id_exp=None):
538 539
539 540 configurations = Configuration.objects.filter(experiment=self)
540 541
541 542 if id_exp is not None:
542 543 exp_parms = parms['experiments']['byId'][id_exp]
543 544 else:
544 545 exp_parms = parms['experiments']['byId'][parms['experiments']['allIds'][0]]
545 546
546 547 if configurations:
547 548 for configuration in configurations:
548 549 configuration.delete()
549 550
550 551 for id_conf in exp_parms['configurations']:
551 552 conf_parms = parms['configurations']['byId'][id_conf]
552 553 device = Device.objects.filter(device_type__name=conf_parms['device_type'])[0]
553 554 model = CONF_MODELS[conf_parms['device_type']]
554 555 conf = model(
555 556 experiment = self,
556 557 device = device,
557 558 )
558 559 conf.dict_to_parms(parms, id=id_conf)
559 560
560 561
561 562 location, created = Location.objects.get_or_create(name=exp_parms['location'])
562 563 self.name = '{}-{}'.format(exp_parms['name'], datetime.now().strftime('%y%m%d'))
563 564 self.location = location
564 565 self.start_time = exp_parms['start_time']
565 566 self.end_time = exp_parms['end_time']
566 567 self.save()
567 568
568 569 return self
569 570
570 571 def get_absolute_url(self):
571 572 return reverse('url_experiment', args=[str(self.id)])
572 573
573 574 def get_absolute_url_edit(self):
574 575 return reverse('url_edit_experiment', args=[str(self.id)])
575 576
576 577 def get_absolute_url_delete(self):
577 578 return reverse('url_delete_experiment', args=[str(self.id)])
578 579
579 580 def get_absolute_url_import(self):
580 581 return reverse('url_import_experiment', args=[str(self.id)])
581 582
582 583 def get_absolute_url_export(self):
583 584 return reverse('url_export_experiment', args=[str(self.id)])
584 585
585 586 def get_absolute_url_start(self):
586 587 return reverse('url_start_experiment', args=[str(self.id)])
587 588
588 589 def get_absolute_url_stop(self):
589 590 return reverse('url_stop_experiment', args=[str(self.id)])
590 591
591 592
592 593 class Configuration(PolymorphicModel):
593 594
594 595 template = models.BooleanField(default=False)
595 596 # name = models.CharField(verbose_name="Configuration Name", max_length=40, default='')
596 597 device = models.ForeignKey('Device', verbose_name='Device', null=True, on_delete=models.CASCADE)
597 598 label = models.CharField(verbose_name="Label", max_length=40, default='', blank=True, null=True)
598 599 experiment = models.ForeignKey('Experiment', verbose_name='Experiment', null=True, blank=True, on_delete=models.CASCADE)
599 600 type = models.PositiveSmallIntegerField(default=0, choices=CONF_TYPES)
600 601 created_date = models.DateTimeField(auto_now_add=True)
601 602 programmed_date = models.DateTimeField(auto_now=True)
602 603 parameters = models.TextField(default='{}')
603 604 author = models.ForeignKey(User, null=True, blank=True,on_delete=models.CASCADE)
604 605 hash = models.CharField(default='', max_length=64, null=True, blank=True)
605 606 message = ""
606 607
607 608 class Meta:
608 609 db_table = 'db_configurations'
609 610 ordering = ('device__device_type__name',)
610 611
611 612 def __str__(self):
612 613
613 614 ret = u'{} '.format(self.device.device_type.name.upper())
614 615
615 616 if 'mix' in [f.name for f in self._meta.get_fields()]:
616 617 if self.mix:
617 618 ret = '{} MIX '.format(self.device.device_type.name.upper())
618 619
619 620 if 'label' in [f.name for f in self._meta.get_fields()]:
620 621 ret += '{}'.format(self.label)
621 622
622 623 if self.template:
623 624 ret += ' (template)'
624 625
625 626 return ret
626 627
627 628 @property
628 629 def name(self):
629 630
630 631 return str(self)
631 632
632 633 def jsonify(self):
633 634
634 635 data = {}
635 636
636 637 ignored = ('type', 'polymorphic_ctype', 'configuration_ptr',
637 638 'created_date', 'programmed_date', 'template', 'device',
638 639 'experiment')
639 640
640 641 for field in self._meta.fields:
641 642 if field.name in ignored:
642 643 continue
643 644 data[field.name] = field.value_from_object(self)
644 645
645 646 data['device_type'] = self.device.device_type.name
646 647
647 648 if self.device.device_type.name == 'rc':
648 649 data['lines'] = ['{}'.format(line.pk) for line in self.get_lines()]
649 650 data['delays'] = self.get_delays()
650 651 data['pulses'] = self.get_pulses()
651 652
652 653 elif self.device.device_type.name == 'jars':
653 654 data['decode_type'] = DECODE_TYPE[self.decode_data][1]
654 655
655 656 elif self.device.device_type.name == 'dds':
656 657 data['frequencyA_Mhz'] = float(data['frequencyA_Mhz'])
657 658 data['frequencyB_Mhz'] = float(data['frequencyB_Mhz'])
658 659 data['phaseA'] = dds_data.phase_to_binary(data['phaseA_degrees'])
659 660 data['phaseB'] = dds_data.phase_to_binary(data['phaseB_degrees'])
660 661
661 662 elif self.device.device_type.name == 'dds_rest':
662 663 data['frequencyA_Mhz'] = float(data['frequencyA_Mhz'])
663 664 data['frequencyB_Mhz'] = float(data['frequencyB_Mhz'])
664 665 data['phaseA'] = dds_data.phase_to_binary(data['phaseA_degrees'])
665 666 data['phaseB'] = dds_data.phase_to_binary(data['phaseB_degrees'])
666 667 data['delta_frequency_Mhz'] = float(data['delta_frequency_Mhz'] or 0.00)
667 668 data['update_clock_Mhz'] = float(data['update_clock_Mhz'] or 0.00)
668 669 data['ramp_rate_clock_Mhz'] = float(data['ramp_rate_clock_Mhz'] or 0.0)
669 670 return data
670 671
671 672 def clone(self, **kwargs):
672 673
673 674 self.pk = None
674 675 self.id = None
675 676 for attr, value in kwargs.items():
676 677 setattr(self, attr, value)
677 678
678 679 self.save()
679 680
680 681 return self
681 682
682 683 def parms_to_dict(self):
683 684
684 685 params = Params({})
685 686 params.add(self.jsonify(), 'configurations')
686 687
687 688 if self.device.device_type.name=='rc':
688 689 for line in self.get_lines():
689 690 params.add(line.jsonify(), 'lines')
690 691
691 692 return params.data
692 693
693 694 def parms_to_text(self):
694 695
695 696 raise NotImplementedError("This method should be implemented in %s Configuration model" %str(self.device.device_type.name).upper())
696 697
697 698
698 699 def parms_to_binary(self):
699 700
700 701 raise NotImplementedError("This method should be implemented in %s Configuration model" %str(self.device.device_type.name).upper())
701 702
702 703
703 704 def dict_to_parms(self, parameters, id=None):
704 705
705 706 params = Params(parameters)
706 707
707 708 if id:
708 709 data = params.get_conf(id_conf=id)
709 710 else:
710 711 data = params.get_conf(dtype=self.device.device_type.name)
711 712
712 713 if data['device_type']=='rc':
713 714 self.clean_lines()
714 715 lines = data.pop('lines', None)
715 716 for line_id in lines:
716 717 pass
717 718
718 719 for key, value in data.items():
719 720 if key not in ('id', 'device_type'):
720 721 setattr(self, key, value)
721 722
722 723 self.save()
723 724
724 725
725 726 def export_to_file(self, format="json"):
726 727
727 728 content_type = ''
728 729
729 730 if format == 'racp':
730 731 content_type = 'text/plain'
731 732 filename = '%s_%s.%s' %(self.device.device_type.name, self.name, 'racp')
732 733 content = self.parms_to_text(file_format = 'racp')
733 734
734 735 if format == 'text':
735 736 content_type = 'text/plain'
736 737 filename = '%s_%s.%s' %(self.device.device_type.name, self.name, self.device.device_type.name)
737 738 content = self.parms_to_text()
738 739
739 740 if format == 'binary':
740 741 content_type = 'application/octet-stream'
741 742 filename = '%s_%s.bin' %(self.device.device_type.name, self.name)
742 743 content = self.parms_to_binary()
743 744
744 745 if not content_type:
745 746 content_type = 'application/json'
746 747 filename = '%s_%s.json' %(self.device.device_type.name, self.name)
747 748 content = json.dumps(self.parms_to_dict(), indent=2)
748 749
749 750 fields = {'content_type':content_type,
750 751 'filename':filename,
751 752 'content':content
752 753 }
753 754
754 755 return fields
755 756
756 757 def import_from_file(self, fp):
757 758
758 759 parms = {}
759 760
760 761 path, ext = os.path.splitext(fp.name)
761 762
762 763 if ext == '.json':
763 764 parms = json.load(fp)
764 765
765 766 if ext == '.dds':
766 767 lines = fp.readlines()
767 768 parms = dds_data.text_to_dict(lines)
768 769
769 770 if ext == '.racp':
770 771 if self.device.device_type.name == 'jars':
771 772 parms = RacpFile(fp).to_dict()
772 773 parms['filter_parms'] = json.loads(self.filter_parms)
773 774 return parms
774 775 parms = RCFile(fp).to_dict()
775 776
776 777 return parms
777 778
778 779 def status_device(self):
779 780
780 781 self.message = 'Function not implemented'
781 782 return False
782 783
783 784
784 785 def stop_device(self):
785 786
786 787 self.message = 'Function not implemented'
787 788 print("BUENAS SEΓ‘ALES??? NO LO CREO2",flush=True)
788 789 return False
789 790
790 791
791 792 def start_device(self):
792 793
793 794 self.message = 'Function not implemented'
794 795 print("BUENAS SEΓ‘ALES??? NO LO CREO",flush=True)
795 796 return False
796 797
797 798
798 799 def write_device(self, parms):
799 800
800 801 self.message = 'Function not implemented'
801 802 print("BUENAS SEΓ‘ALES??? NO LO CREO3",flush=True)
802 803 return False
803 804
804 805 def write_device_mqtt(self, parms):
805 806
806 807 self.message = 'Function not implemented'
807 808 return False
808 809
809 810 def read_device(self):
810 811
811 812 self.message = 'Function not implemented'
812 813 return False
813 814
814 815
815 816 def get_absolute_url(self):
816 817 return reverse('url_%s_conf' % self.device.device_type.name, args=[str(self.id)])
817 818
818 819 def get_absolute_url_edit(self):
819 820 return reverse('url_edit_%s_conf' % self.device.device_type.name, args=[str(self.id)])
820 821
821 822 def get_absolute_url_delete(self):
822 823 return reverse('url_delete_dev_conf', args=[str(self.id)])
823 824
824 825 def get_absolute_url_import(self):
825 826 return reverse('url_import_dev_conf', args=[str(self.id)])
826 827
827 828 def get_absolute_url_export(self):
828 829 return reverse('url_export_dev_conf', args=[str(self.id)])
829 830
830 831 def get_absolute_url_write(self):
831 832 return reverse('url_write_dev_conf', args=[str(self.id)])
832 833
833 834 def get_absolute_url_write_mqtt(self):
834 835 return reverse('url_write_mqtt_dev_conf', args=[str(self.id)])
835 836
836 837 def get_absolute_url_read(self):
837 838 return reverse('url_read_dev_conf', args=[str(self.id)])
838 839
839 840 def get_absolute_url_start(self):
840 841 return reverse('url_start_dev_conf', args=[str(self.id)])
841 842
842 843 def get_absolute_url_stop(self):
843 844 return reverse('url_stop_dev_conf', args=[str(self.id)])
844 845
845 846 def get_absolute_url_stop_mqtt(self):
846 847 return reverse('url_stop_mqtt_dev_conf', args=[str(self.id)])
847 848
848 849 def get_absolute_url_status(self):
849 850 return reverse('url_status_dev_conf', args=[str(self.id)])
@@ -1,130 +1,132
1 1 <!DOCTYPE html>
2 2 {% load static %}
3 3 {% load django_bootstrap5 %}
4 4 <html lang="en">
5 5 <head>
6 6 <meta charset="utf-8">
7 7 <title>{% block title %}Jicamarca Integrated Radar System:::::{% endblock %}</title>
8 8 <meta name="description" content="">
9 9 <meta name="author" content="">
10 10 <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
11 11 {# bootstrap_css #}
12 12
13 13 <link href="{% static 'css/fontawesome.css' %}" rel="stylesheet">
14 14 <link href="{% static 'css/bootstrap.min.css' %}" rel="stylesheet">
15 15 <link href="{% static 'css/style.css' %}" rel="stylesheet">
16 16 <link href="{% static 'css/header.css' %}" rel="stylesheet">
17 17 <link href="{% static 'css/footer.css' %}" rel="stylesheet">
18 18 <link rel="shortcut icon" href="{% static 'images/favicon.ico' %}" />
19 19
20 20
21 21 <!--link href="{% static '' %}css/bootstrap-{{theme}}.min.css" media="all" rel="stylesheet"-->
22 22 <!-- <link href="{% static 'css/bootcards-desktop.min.css' %}" media="all" rel="stylesheet"> -->
23 23 <link href="{% static 'css/font-awesome.min.css' %}" media="all" rel="stylesheet"-->
24 24 <!--link href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css" rel="stylesheet"-->
25 25
26 26 <!-- Bootcards CSS for iOS: >
27 27 <link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/bootcards/1.0.0/css/bootcards-ios.min.css"-->
28 28
29 29 <!-- Bootcards CSS for Android: >
30 30 <link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/bootcards/1.0.0/css/bootcards-android.min.css"-->
31 31
32 32 <!-- Bootcards CSS for desktop: >
33 33 <link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/bootcards/1.0.0/css/bootcards-desktop.min.css"-->
34 34
35 35 <style type="text/css">
36 36 .logo {padding-top: 5px; height: 50px}
37 37 .clickable-row {cursor: pointer;}
38 38 .col-no-padding { padding-left:0;}
39 39 .gi-2x{font-size: 2em;}
40 40 .gi-3x{font-size: 3em;}
41 41 .gi-4x{font-size: 4em;}
42 42 .gi-5x{font-size: 5em;}
43 43 </style>
44 44 <script src="{% static 'js/jquery-3.6.3.min.js' %}"></script>
45 45 {% block extra-head %}{% endblock %}
46 46 </head>
47 47
48 48 <body>
49 49
50 50 {% include "header_igp.html" %}
51 51
52 52 <div style="clear: both;"></div>
53 53
54 54 <div class="container">
55 55 <div id="page" class="row" style="min-height:600px">
56 56
57 57 {% if no_sidebar %}
58 58 <div class="col-md-0 hidden-xs hidden-sm" role="complementary"></div>
59 59
60 60 {% else %}
61 61 <div class="col-md-3 hidden-xs hidden-sm" role="complementary">
62 62 <br><br>
63 <div id="sidebar">
64 {% block sidebar%}
65 {% include "sidebar_devices.html" %}
63 <div id="sidebar">
64 {% block sidebar%}
65 {% include "sidebar_devices.html" %}
66 66 {% endblock %}
67 67 </div>
68 68 </div>
69 69 {% endif %}
70 70
71 71
72 72 {% if no_sidebar %}
73 73 <div class="col-md-12 col-xs-12" role="main">
74 74 {% else %}
75 75 <div class="col-md-9 col-xs-12" role="main">
76 76 {% endif %}
77 77
78 78 <div class="page-header">
79 79 <h1>{% block content-title %}{% endblock %} <small>{% block content-suptitle %}{% endblock %}</small></h1>
80 80 </div>
81 81 {% block messages %}
82 82 {% if messages %}
83 83 {% for message in messages %}
84 84 <div class="alert alert-{% if message.tags %}{% if 'error' in message.tags %}danger{% else %}{{ message.tags }}{% endif %}{% else %}info{% endif %} alert-dismissible" role="alert">
85 85 <button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">&times;</span></button>
86 86 <strong>{{message.tags|title}}!</strong> {{ message }}
87 87 </div>
88 88 {% endfor %}
89 89 {% endif %}
90 90 {% endblock %}
91 {% block content %}
92 {% endblock %}
91
92 {% block content %}
93 {% endblock %}
94
93 95 </div>
94 96 {% block content-graph %}
95 97 {% endblock %}
96 98
97 99 </div><!--/row-->
98 100 </div> <!-- container -->
99 101
100 102 {% include "footer_igp.html" %}
101 103
102 104
103 105
104 106 <!-- This part put block modal which is used to change parameters of my plot -->
105 107 {% block modal %}{% endblock modal %}
106 108 {% block debug %}<div class="row">{{debug}}</div>{% endblock debug %}
107 109 <!-- Optional JavaScript -->
108 110 <!-- jQuery first, then Popper.js, then Bootstrap JS -->
109 111 <!-- {# % bootstrap_javascript jquery='slim' % #} -->
110 112 {# % bootstrap_javascript % #}
111 113 <script src="{% static 'js/jquery-3.6.3.min.js' %}"></script>
112 114 <script src="{% static 'js/popper.min.js' %}"></script>
113 115 <script src="{% static 'js/moment.min.js' %}"></script>
114 116 <script src="{% static 'js/bootstrap.min.js' %}"></script>
115 117 <script src="{% static 'js/plotly-latest.min.js' %}"></script>
116 118
117 119 <!-- Here we put the script from the type of plot that we recibe -->
118 120 <script>
119 121 $("#menu-toggle").click(function (e) {
120 122 e.preventDefault();
121 123 $("#wrapper").toggleClass("toggled");
122 124 });
123 125 </script>
124 126 {% block extra-js %}
125 127 {% endblock%}
126 128
127 129
128 130
129 131 </body>
130 132 </html>
@@ -1,101 +1,99
1 1 {% extends "base.html" %}
2 2 {% load django_bootstrap5 %}
3 3 {% load static %}
4 4 {% load main_tags %}
5 5
6 6 {% block extra-head %}
7 7 <link href="{% static 'css/bootstrap-datetimepicker.min.css' %}" media="screen" rel="stylesheet">
8 8 {% endblock %}
9 9 {% block content-title %}{{title}}{% endblock %}
10 10 {% block content-suptitle %}{{suptitle}}{% endblock %}
11 11
12 12 {% block content %}
13 13
14 14 {% block content-filter %}
15 15 {% if form %}
16 16 <form class="form" method="get">
17 17 {% bootstrap_form form layout='horizontal' size='md' %}
18 18 <div class="pull-right">
19 19 <br>
20 20 <button type="button" class="btn btn-primary btn-sm" onclick="window.location.replace('?');"><span class="fas fa-sync-alt" aria-hidden="true"></span></button>
21 21 <button type="submit" class="btn btn-primary btn-sm"><span class="fas fa-search" aria-hidden="true"></span></button>
22 22 {% if add_url %}
23 23 <a class="btn btn-sm btn-info" href="{{add_url}}"><span class="fas fa-plus" aria-hidden="true"></span></a>
24 24 {% endif %}
25 25 </div>
26 26 </form>
27 27 {% endif %}
28 28 {% endblock %}
29 29 <div style="clear: both;"></div>
30 30 <br>
31 31 <table class="table table-hover">
32 32 <tr>
33 33 <th>#</th>
34 34 {% for key in keys %}
35 35 {% if key == 'location'%}
36 36 <th>System</th>
37 37 {% else %}
38 38 <th>{{ key|title }}</th>
39 39 {% endif %}
40 40 {% endfor%}
41 41 </tr>
42 42 {% for object in objects %}
43 <p>{{ object }}</p>
44 <p>{{ objects }}</p>
45 43 <tr class="clickable-row" data-href="{{object.get_absolute_url}}">
46 44 <td>{{ forloop.counter|add:offset }}</td>
47 45 {% for key in keys %}
48 46 {% if key == 'actions' %}
49 47 <td>
50 48 <a class="btn btn-sm btn-danger" href="{{object.get_absolute_url_delete}}"><span class="fas fa-times" aria-hidden="true"></span></a>
51 49 <a class="btn btn-sm btn-primary" href="{{object.get_absolute_url_edit}}"><span class="fa fa-pencil" aria-hidden="true"></span></a>
52 50 </td>
53 51 {% else %}
54 52 <td>{{ object|attr:key }}</td>
55 53 {% endif %}
56 54 {% endfor %}
57 55 </tr>
58 56 {% endfor %}
59 57 </table>
60 58
61 59 <div class="pagination">
62 60 <span class="step-links">
63 61 {% if objects.has_previous %}
64 62 <a href="?page={{ objects.previous_page_number }}&{{q}}"><span class="fas fa-chevron-left" aria-hidden="true"></span></a>
65 63 {% endif %}
66 64 <span class="current">
67 65 Page {{ objects.number }} of {{ objects.paginator.num_pages }}.
68 66 </span>
69 67 {% if objects.has_next %}
70 68 <a href="?page={{ objects.next_page_number }}&{{q}}"><span class="fas fa-chevron-right" aria-hidden="true"></span></a>
71 69 {% endif %}
72 70 </span>
73 71 </div>
74 72
75 73 {% endblock %}
76 74
77 75 {% block extra-js%}
78 76 <script src="{% static 'js/bootstrap-datetimepicker.min.js' %}"></script>
79 77 <script type="text/javascript">
80 78
81 79 $('.input-group.date').datetimepicker({
82 80 format: "YYYY-MM-DD",
83 81 icons: {
84 82 time: 'far fa-clock',
85 83 date: 'far fa-calendar-alt',
86 84 up: 'fas fa-arrow-up',
87 85 down: 'fas fa-arrow-down',
88 86 previous: 'fas fa-chevron-left',
89 87 next: 'fas fa-chevron-right',
90 88 today: 'far fa-calendar-check',
91 89 clear: 'far fa-trash-alt',
92 90 close: 'fas fa-times'
93 91 }
94 92 });
95 93
96 94 $(".clickable-row").click(function() {
97 95 document.location = $(this).data("href");
98 96 });
99 97
100 98 </script>
101 99 {% endblock %}
@@ -1,89 +1,89
1 1 {% extends "base.html" %}
2 2 {% load django_bootstrap5 %}
3 3 {% load static %}
4 4 {% load main_tags %}
5 5 {% block content-title %}{{title}}{% endblock %}
6 6 {% block content-suptitle %}{{suptitle}}{% endblock %}
7 7
8 8 {% block content %}
9 9
10 10 {% block menu-actions %}
11 11 <span class=" dropdown pull-right">
12 12 <a href="#" class="dropdown-toggle" data-toggle="dropdown"><span class="fas fa-bars" aria-hidden="true"></span></a>
13 13 <ul class="dropdown-menu" role="menu">
14 14 <li><a href="{{ dev_conf.get_absolute_url_edit }}"><span class="fa fa-pencil" aria-hidden="true"></span> Edit</a></li>
15 15 <li><a href="{{ dev_conf.get_absolute_url_delete }}"><span class="fa fa-times" aria-hidden="true"></span> Delete</a></li>
16 16 <li><a href="{{ dev_conf.get_absolute_url_import }}"><span class="fas fa-cloud-download-alt" aria-hidden="true"></span> Import </a></li>
17 17 <li><a href="{{ dev_conf.get_absolute_url_export }}"><span class="fas fa-cloud-upload-alt" aria-hidden="true"></span> Export </a></li>
18 18 {% block extra-menu-actions %}
19 19 {% endblock %}
20 20 <li><a>----------------</a></li>
21 21 <li><a href="{{ dev_conf.get_absolute_url_status }}"><span class="fas fa-sync-alt" aria-hidden="true"></span> Status</a></li>
22 22 {% if not no_play %}
23 23 {% if not only_stop %}
24 24 <li><a href="{{ dev_conf.get_absolute_url_start}}"><span class="fas fa-play" aria-hidden="true"></span> Start</a></li>
25 25 {% endif %}
26 26 <li><a href="{{ dev_conf.get_absolute_url_stop }}"><span class="fas fa-stop" aria-hidden="true"></span> Stop</a></li>
27 27 {% endif %}
28 28 <li><a href="{{ dev_conf.get_absolute_url_write }}"><span class="fas fa-arrow-circle-down" aria-hidden="true"></span> Write</a></li>
29 29 {% if dev_conf.device.device_type.name == 'abs' %}
30 30 <li><a href="{{ dev_conf.get_absolute_url_write_mqtt }}"><span class="fas fa-arrow-circle-down" aria-hidden="true"></span> Write MQTT</a></li>
31 31 <li><a href="{{ dev_conf.get_absolute_url_stop_mqtt }}"><span class="fas fa-stop" aria-hidden="true"></span> Stop MQTT</a></li>
32 32 {% endif %}
33 33 {% if dev_conf.device.device_type.name != 'abs' %}
34 34 <li><a href="{{ dev_conf.get_absolute_url_read }}"><span class="fas fa-arrow-circle-up" aria-hidden="true"></span> Read</a></li>
35 35 {% endif %}
36 36 </ul>
37 37 </span>
38 38 {% endblock %}
39 39
40 40 {% block content-detail %}
41 41 <table class="table table-bordered">
42 42 <tr>
43 43 <th>Status</th>
44 44 {% if dev_conf.pk == dev_conf.device.conf_active %}
45 45 <td class="text-{{dev_conf.device.status_color}}"><strong> {% if dev_conf.device.device_type.name == 'abs' %} {{connected_modules}} {% else %} {{dev_conf.device.get_status_display}}{% endif %}</strong></td>
46 46 {% else %}
47 47 <td class="text-info"><strong> Connected </strong></td>
48 48 {% endif %}
49 </tr>
49 </tr>
50 50
51 51 {% for key in dev_conf_keys %}
52 52 <tr>
53 53 <th>{% get_verbose_field_name dev_conf key %}</th>
54 54 <td>{{dev_conf|attr:key}}</td>
55 55 </tr>
56 56 {% endfor %}
57 57 </table>
58 58 {% endblock %}
59 59
60 60 {% block extra-content %}
61 61 {% endblock %}
62 62
63 63 {% endblock %}
64 64
65 65 {% block extra-js%}
66 66 <script type="text/javascript">
67 67
68 68 $("#bt_edit").click(function() {
69 69 document.location = "{{ dev_conf.get_absolute_url_edit }}";
70 70 });
71 71
72 72 $("#bt_read").click(function() {
73 73 document.location = "{{ dev_conf.get_absolute_url_read }}";
74 74 });
75 75
76 76 $("#bt_write").click(function() {
77 77 document.location = "{{ dev_conf.get_absolute_url_write }}";
78 78 });
79 79
80 80 $("#bt_import").click(function() {
81 81 document.location = "{{ dev_conf.get_absolute_url_import }}";
82 82 });
83 83
84 84 $("#bt_export").click(function() {
85 85 document.location = "{{ dev_conf.get_absolute_url_export }}";
86 86 });
87 87
88 88 </script>
89 89 {% endblock %}
@@ -1,2110 +1,2111
1 1 import ast
2 2 import json
3 3 import hashlib
4 4 from datetime import datetime, timedelta
5 5
6 6 from django.shortcuts import render, redirect, get_object_or_404, HttpResponse
7 7 from django.utils.safestring import mark_safe
8 8 from django.http import HttpResponseRedirect
9 9 from django.urls import reverse
10 10 from django.db.models import Q
11 11 from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
12 12 from django.contrib import messages
13 13 from django.http.request import QueryDict
14 14 from django.contrib.auth.decorators import login_required, user_passes_test
15 15
16 16 from django.utils.timezone import is_aware
17 17
18 18 try:
19 19 from urllib.parse import urlencode
20 20 except ImportError:
21 21 from urllib import urlencode
22 22
23 23 from .forms import CampaignForm, ExperimentForm, DeviceForm, ConfigurationForm, LocationForm, UploadFileForm, DownloadFileForm, OperationForm, NewForm
24 24 from .forms import OperationSearchForm, FilterForm, ChangeIpForm
25 25
26 26 from apps.rc.forms import RCConfigurationForm, RCLineCode, RCMixConfigurationForm
27 27 from apps.dds.forms import DDSConfigurationForm
28 28 from apps.jars.forms import JARSConfigurationForm
29 29 from apps.cgs.forms import CGSConfigurationForm
30 30 from apps.abs.forms import ABSConfigurationForm
31 31 from apps.usrp.forms import USRPConfigurationForm
32 32 from apps.dds_rest.forms import DDSRestConfigurationForm
33 33 from apps.atrad.forms import ATRADConfigurationForm
34 34 from .utils import Params
35 35
36 36 from .models import Campaign, Experiment, Device, Configuration, Location, RunningExperiment, DEV_STATES
37 37 from apps.cgs.models import CGSConfiguration
38 38 from apps.jars.models import JARSConfiguration, EXPERIMENT_TYPE
39 39 from apps.usrp.models import USRPConfiguration
40 40 from apps.abs.models import ABSConfiguration, ABSBeam
41 41 from apps.rc.models import RCConfiguration, RCLine, RCLineType, RCClock
42 42 from apps.dds.models import DDSConfiguration
43 43 from apps.dds_rest.models import DDSRestConfiguration
44 44 from apps.atrad.models import ATRADConfiguration
45 45
46 46 #from .tasks import task_start
47 47 from radarsys.celery import app
48 48
49 49
50 50 from .mqtt import client as mqtt_client
51 51 from radarsys.socketconfig import sio as sio
52 52
53 53 #comentario test
54 54 CONF_FORMS = {
55 55 'rc': RCConfigurationForm,
56 56 'dds': DDSConfigurationForm,
57 57 'dds_rest': DDSRestConfigurationForm,
58 58 'jars': JARSConfigurationForm,
59 59 'cgs': CGSConfigurationForm,
60 60 'abs': ABSConfigurationForm,
61 61 'usrp': USRPConfigurationForm,
62 62 'atrad': ATRADConfigurationForm,
63 63 }
64 64
65 65 CONF_MODELS = {
66 66 'rc': RCConfiguration,
67 67 'dds': DDSConfiguration,
68 68 'dds_rest': DDSRestConfiguration,
69 69 'jars': JARSConfiguration,
70 70 'cgs': CGSConfiguration,
71 71 'abs': ABSConfiguration,
72 72 'usrp': USRPConfiguration,
73 73 'atrad': ATRADConfiguration,
74 74 }
75 75
76 76 MIX_MODES = {
77 77 '0': 'P',
78 78 '1': 'S',
79 79 }
80 80
81 81 MIX_OPERATIONS = {
82 82 '0': 'OR',
83 83 '1': 'XOR',
84 84 '2': 'AND',
85 85 '3': 'NAND',
86 86 }
87 87
88 88
89 89 def is_developer(user):
90 90
91 91 groups = [str(g.name) for g in user.groups.all()]
92 92 return 'Developer' in groups or user.is_staff
93 93
94 94
95 95 def is_operator(user):
96 96
97 97 groups = [str(g.name) for g in user.groups.all()]
98 98 return 'Operator' in groups or user.is_staff
99 99
100 100
101 101 def has_been_modified(model):
102 102
103 103 prev_hash = model.hash
104 104 new_hash = hashlib.sha256(str(model.parms_to_dict).encode()).hexdigest()
105 105 if prev_hash != new_hash:
106 106 model.hash = new_hash
107 107 model.save()
108 108 return True
109 109 return False
110 110
111 111
112 112 def index(request):
113 113 kwargs = {'no_sidebar': True}
114 114
115 115 return render(request, 'index.html', kwargs)
116 116
117 117
118 118 def locations(request):
119 119
120 120 page = request.GET.get('page')
121 121 order = ('name',)
122 122
123 123 kwargs = get_paginator(Location, page, order)
124 124
125 125 kwargs['keys'] = ['name', 'description']
126 126 kwargs['title'] = 'Radar System'
127 127 kwargs['suptitle'] = 'List'
128 128 kwargs['no_sidebar'] = True
129 129
130 130 return render(request, 'base_list.html', kwargs)
131 131
132 132
133 133 def location(request, id_loc):
134 134
135 135 location = get_object_or_404(Location, pk=id_loc)
136 136
137 137 kwargs = {}
138 138 kwargs['location'] = location
139 139 kwargs['location_keys'] = ['name', 'description']
140 140
141 141 kwargs['title'] = 'Location'
142 142 kwargs['suptitle'] = 'Details'
143 143
144 144 return render(request, 'location.html', kwargs)
145 145
146 146
147 147 @login_required
148 148 def location_new(request):
149 149
150 150 if request.method == 'GET':
151 151 form = LocationForm()
152 152
153 153 if request.method == 'POST':
154 154 form = LocationForm(request.POST)
155 155
156 156 if form.is_valid():
157 157 form.save()
158 158 return redirect('url_locations')
159 159
160 160 kwargs = {}
161 161 kwargs['form'] = form
162 162 kwargs['title'] = 'Radar System'
163 163 kwargs['suptitle'] = 'New'
164 164 kwargs['button'] = 'Create'
165 165
166 166 return render(request, 'base_edit.html', kwargs)
167 167
168 168
169 169 @login_required
170 170 def location_edit(request, id_loc):
171 171
172 172 location = get_object_or_404(Location, pk=id_loc)
173 173
174 174 if request.method == 'GET':
175 175 form = LocationForm(instance=location)
176 176
177 177 if request.method == 'POST':
178 178 form = LocationForm(request.POST, instance=location)
179 179
180 180 if form.is_valid():
181 181 form.save()
182 182 return redirect('url_locations')
183 183
184 184 kwargs = {}
185 185 kwargs['form'] = form
186 186 kwargs['title'] = 'Location'
187 187 kwargs['suptitle'] = 'Edit'
188 188 kwargs['button'] = 'Update'
189 189
190 190 return render(request, 'base_edit.html', kwargs)
191 191
192 192
193 193 @login_required
194 194 def location_delete(request, id_loc):
195 195
196 196 location = get_object_or_404(Location, pk=id_loc)
197 197
198 198 if request.method == 'POST':
199 199
200 200 if is_developer(request.user):
201 201 location.delete()
202 202 return redirect('url_locations')
203 203
204 204 messages.error(request, 'Not enough permission to delete this object')
205 205 return redirect(location.get_absolute_url())
206 206
207 207 kwargs = {
208 208 'title': 'Delete',
209 209 'suptitle': 'Location',
210 210 'object': location,
211 211 'delete': True
212 212 }
213 213
214 214 return render(request, 'confirm.html', kwargs)
215 215
216 216
217 217 def devices(request):
218 218
219 219 page = request.GET.get('page')
220 220 order = ('location', 'device_type')
221 221
222 222 filters = request.GET.copy()
223 223 kwargs = get_paginator(Device, page, order, filters)
224 224 form = FilterForm(initial=request.GET, extra_fields=['tags'])
225 225
226 226 kwargs['keys'] = ['device_type', 'location',
227 227 'ip_address', 'port_address', 'actions']
228 228 kwargs['title'] = 'Device'
229 229 kwargs['suptitle'] = 'List'
230 230 kwargs['no_sidebar'] = True
231 231 kwargs['form'] = form
232 232 kwargs['add_url'] = reverse('url_add_device')
233 233 filters.pop('page', None)
234 234 kwargs['q'] = urlencode(filters)
235 235 kwargs['menu_devices'] = 'active'
236 236 return render(request, 'base_list.html', kwargs)
237 237
238 238
239 239 def device(request, id_dev):
240 240
241 241 device = get_object_or_404(Device, pk=id_dev)
242 242
243 243 kwargs = {}
244 244 kwargs['device'] = device
245 245 kwargs['device_keys'] = ['device_type',
246 246 'ip_address', 'port_address', 'description']
247 247
248 248 kwargs['title'] = 'Device'
249 249 kwargs['suptitle'] = 'Details'
250 250 kwargs['menu_devices'] = 'active'
251 251
252 252 return render(request, 'device.html', kwargs)
253 253
254 254
255 255 @login_required
256 256 def device_new(request):
257 257
258 258 if request.method == 'GET':
259 259 form = DeviceForm()
260 260
261 261 if request.method == 'POST':
262 262 form = DeviceForm(request.POST)
263 263
264 264 if form.is_valid():
265 265 form.save()
266 266 return redirect('url_devices')
267 267
268 268 kwargs = {}
269 269 kwargs['form'] = form
270 270 kwargs['title'] = 'Device'
271 271 kwargs['suptitle'] = 'New_2'
272 272 kwargs['button'] = 'Create'
273 273 kwargs['menu_devices'] = 'active'
274 274
275 275 return render(request, 'base_edit.html', kwargs)
276 276
277 277
278 278 @login_required
279 279 def device_edit(request, id_dev):
280 280
281 281 device = get_object_or_404(Device, pk=id_dev)
282 282
283 283 if request.method == 'GET':
284 284 form = DeviceForm(instance=device)
285 285
286 286 if request.method == 'POST':
287 287 form = DeviceForm(request.POST, instance=device)
288 288
289 289 if form.is_valid():
290 290 form.save()
291 291 return redirect(device.get_absolute_url())
292 292
293 293 kwargs = {}
294 294 kwargs['form'] = form
295 295 kwargs['title'] = 'Device'
296 296 kwargs['suptitle'] = 'Edit'
297 297 kwargs['button'] = 'Update'
298 298 kwargs['menu_devices'] = 'active'
299 299
300 300 return render(request, 'base_edit.html', kwargs)
301 301
302 302
303 303 @login_required
304 304 def device_delete(request, id_dev):
305 305
306 306 device = get_object_or_404(Device, pk=id_dev)
307 307
308 308 if request.method == 'POST':
309 309
310 310 if is_developer(request.user):
311 311 device.delete()
312 312 return redirect('url_devices')
313 313
314 314 messages.error(request, 'Not enough permission to delete this object')
315 315 return redirect(device.get_absolute_url())
316 316
317 317 kwargs = {
318 318 'title': 'Delete',
319 319 'suptitle': 'Device',
320 320 'object': device,
321 321 'delete': True
322 322 }
323 323 kwargs['menu_devices'] = 'active'
324 324
325 325 return render(request, 'confirm.html', kwargs)
326 326
327 327
328 328 @login_required
329 329 def device_change_ip(request, id_dev):
330 330
331 331 device = get_object_or_404(Device, pk=id_dev)
332 332
333 333 if request.method == 'POST':
334 334
335 335 if is_developer(request.user):
336 336 device.change_ip(**request.POST.dict())
337 337
338 338 print(device.ip_address, device.message)
339 339
340 340 level, message = device.message.split('|')
341 341 messages.add_message(request, level, message)
342 342 else:
343 343 messages.error(
344 344 request, 'Not enough permission to delete this object')
345 345 return redirect(device.get_absolute_url())
346 346
347 347 kwargs = {
348 348 'title': 'Device',
349 349 'suptitle': 'Change IP',
350 350 'object': device,
351 351 'previous': device.get_absolute_url(),
352 352 'form': ChangeIpForm(initial={'ip_address': device.ip_address}),
353 353 'message': ' ',
354 354 }
355 355 kwargs['menu_devices'] = 'active'
356 356
357 357 return render(request, 'confirm.html', kwargs)
358 358
359 359
360 360 def campaigns(request):
361 361
362 362 page = request.GET.get('page')
363 363 order = ('-start_date',)
364 364 filters = request.GET.copy()
365 365
366 366 kwargs = get_paginator(Campaign, page, order, filters)
367 367
368 368 form = FilterForm(initial=request.GET, extra_fields=[
369 369 'range_date', 'tags', 'template'])
370 370 kwargs['keys'] = ['name', 'start_date', 'end_date', 'actions']
371 371 kwargs['title'] = 'Campaign'
372 372 kwargs['suptitle'] = 'List'
373 373 kwargs['no_sidebar'] = True
374 374 kwargs['form'] = form
375 375 kwargs['add_url'] = reverse('url_add_campaign')
376 376 filters.pop('page', None)
377 377 kwargs['q'] = urlencode(filters)
378 378 kwargs['menu_campaigns'] = 'active'
379 379
380 380 return render(request, 'base_list.html', kwargs)
381 381
382 382
383 383 def campaign(request, id_camp):
384 384
385 385 campaign = get_object_or_404(Campaign, pk=id_camp)
386 386 experiments = Experiment.objects.filter(campaign=campaign)
387 387
388 388 form = CampaignForm(instance=campaign)
389 389
390 390 kwargs = {}
391 391 kwargs['campaign'] = campaign
392 392 kwargs['campaign_keys'] = ['template', 'name',
393 393 'start_date', 'end_date', 'tags', 'description']
394 394
395 395 kwargs['experiments'] = experiments
396 396 kwargs['experiment_keys'] = [
397 397 'name', 'radar_system', 'start_time', 'end_time']
398 398
399 399 kwargs['title'] = 'Campaign'
400 400 kwargs['suptitle'] = 'Details'
401 401
402 402 kwargs['form'] = form
403 403 kwargs['button'] = 'Add Experiment'
404 404 kwargs['menu_campaigns'] = 'active'
405 405
406 406 return render(request, 'campaign.html', kwargs)
407 407
408 408
409 409 @login_required
410 410 def campaign_new(request):
411 411
412 412 kwargs = {}
413 413
414 414 if request.method == 'GET':
415 415
416 416 if 'template' in request.GET:
417 417 if request.GET['template'] == '0':
418 418 form = NewForm(initial={'create_from': 2},
419 419 template_choices=Campaign.objects.filter(template=True).values_list('id', 'name'))
420 420 else:
421 421 kwargs['button'] = 'Create'
422 422 kwargs['experiments'] = Configuration.objects.filter(
423 423 experiment=request.GET['template'])
424 424 kwargs['experiment_keys'] = ['name', 'start_time', 'end_time']
425 425 camp = Campaign.objects.get(pk=request.GET['template'])
426 426 form = CampaignForm(instance=camp,
427 427 initial={'name': '{}_{:%Y%m%d%H%M%S}'.format(camp.name, datetime.now()),
428 428 'template': False})
429 429 elif 'blank' in request.GET:
430 430 kwargs['button'] = 'Create'
431 431 form = CampaignForm()
432 432 else:
433 433 form = NewForm()
434 434
435 435 if request.method == 'POST':
436 436 kwargs['button'] = 'Create'
437 437 post = request.POST.copy()
438 438 experiments = []
439 439
440 440 for id_exp in post.getlist('experiments'):
441 441 exp = Experiment.objects.get(pk=id_exp)
442 442 new_exp = exp.clone(template=False)
443 443 experiments.append(new_exp)
444 444
445 445 post.setlist('experiments', [])
446 446
447 447 form = CampaignForm(post)
448 448
449 449 if form.is_valid():
450 450 campaign = form.save(commit=False)
451 451 campaign.author = request.user
452 452 campaign.save()
453 453 for exp in experiments:
454 454 campaign.experiments.add(exp)
455 455
456 456 return redirect('url_campaign', id_camp=campaign.id)
457 457
458 458 kwargs['form'] = form
459 459 kwargs['title'] = 'Campaign'
460 460 kwargs['suptitle'] = 'New'
461 461 kwargs['menu_campaigns'] = 'active'
462 462
463 463 return render(request, 'campaign_edit.html', kwargs)
464 464
465 465
466 466 @login_required
467 467 def campaign_edit(request, id_camp):
468 468
469 469 campaign = get_object_or_404(Campaign, pk=id_camp)
470 470
471 471 if request.method == 'GET':
472 472 form = CampaignForm(instance=campaign)
473 473
474 474 if request.method == 'POST':
475 475 exps = campaign.experiments.all().values_list('pk', flat=True)
476 476 post = request.POST.copy()
477 477 new_exps = post.getlist('experiments')
478 478 post.setlist('experiments', [])
479 479 form = CampaignForm(post, instance=campaign)
480 480
481 481 if form.is_valid():
482 482 camp = form.save()
483 483 for id_exp in new_exps:
484 484 if int(id_exp) in exps:
485 485 exps.pop(id_exp)
486 486 else:
487 487 exp = Experiment.objects.get(pk=id_exp)
488 488 if exp.template:
489 489 camp.experiments.add(exp.clone(template=False))
490 490 else:
491 491 camp.experiments.add(exp)
492 492
493 493 for id_exp in exps:
494 494 camp.experiments.remove(Experiment.objects.get(pk=id_exp))
495 495
496 496 return redirect('url_campaign', id_camp=id_camp)
497 497
498 498 kwargs = {}
499 499 kwargs['form'] = form
500 500 kwargs['title'] = 'Campaign'
501 501 kwargs['suptitle'] = 'Edit'
502 502 kwargs['button'] = 'Update'
503 503 kwargs['menu_campaigns'] = 'active'
504 504
505 505 return render(request, 'campaign_edit.html', kwargs)
506 506
507 507
508 508 @login_required
509 509 def campaign_delete(request, id_camp):
510 510
511 511 campaign = get_object_or_404(Campaign, pk=id_camp)
512 512
513 513 if request.method == 'POST':
514 514 if is_developer(request.user):
515 515
516 516 for exp in campaign.experiments.all():
517 517 for conf in Configuration.objects.filter(experiment=exp):
518 518 conf.delete()
519 519 exp.delete()
520 520 campaign.delete()
521 521
522 522 return redirect('url_campaigns')
523 523
524 524 messages.error(request, 'Not enough permission to delete this object')
525 525 return redirect(campaign.get_absolute_url())
526 526
527 527 kwargs = {
528 528 'title': 'Delete',
529 529 'suptitle': 'Campaign',
530 530 'object': campaign,
531 531 'delete': True
532 532 }
533 533 kwargs['menu_campaigns'] = 'active'
534 534
535 535 return render(request, 'confirm.html', kwargs)
536 536
537 537
538 538 @login_required
539 539 def campaign_export(request, id_camp):
540 540
541 541 campaign = get_object_or_404(Campaign, pk=id_camp)
542 542 content = campaign.parms_to_dict()
543 543 content_type = 'application/json'
544 544 filename = '%s_%s.json' % (campaign.name, campaign.id)
545 545
546 546 response = HttpResponse(content_type=content_type)
547 547 response['Content-Disposition'] = 'attachment; filename="%s"' % filename
548 548 response.write(json.dumps(content, indent=2))
549 549
550 550 return response
551 551
552 552
553 553 @login_required
554 554 def campaign_import(request, id_camp):
555 555
556 556 campaign = get_object_or_404(Campaign, pk=id_camp)
557 557
558 558 if request.method == 'GET':
559 559 file_form = UploadFileForm()
560 560
561 561 if request.method == 'POST':
562 562 file_form = UploadFileForm(request.POST, request.FILES)
563 563
564 564 if file_form.is_valid():
565 565 new_camp = campaign.dict_to_parms(
566 566 json.load(request.FILES['file']), CONF_MODELS)
567 567 messages.success(
568 568 request, "Parameters imported from: '%s'." % request.FILES['file'].name)
569 569 return redirect(new_camp.get_absolute_url_edit())
570 570
571 571 messages.error(request, "Could not import parameters from file")
572 572
573 573 kwargs = {}
574 574 kwargs['title'] = 'Campaign'
575 575 kwargs['form'] = file_form
576 576 kwargs['suptitle'] = 'Importing file'
577 577 kwargs['button'] = 'Import'
578 578 kwargs['menu_campaigns'] = 'active'
579 579
580 580 return render(request, 'campaign_import.html', kwargs)
581 581
582 582
583 583 def experiments(request):
584 584
585 585 page = request.GET.get('page')
586 586 order = ('location',)
587 587 filters = request.GET.copy()
588 588
589 589 if 'my experiments' in filters:
590 590 filters.pop('my experiments', None)
591 591 filters['mine'] = request.user.id
592 592
593 593 kwargs = get_paginator(Experiment, page, order, filters)
594 594
595 595 fields = ['tags', 'template']
596 596 if request.user.is_authenticated:
597 597 fields.append('my experiments')
598 598
599 599 form = FilterForm(initial=request.GET, extra_fields=fields)
600 600
601 601 kwargs['keys'] = ['name', 'radar_system',
602 602 'start_time', 'end_time', 'actions']
603 603 kwargs['title'] = 'Experiment'
604 604 kwargs['suptitle'] = 'List'
605 605 kwargs['no_sidebar'] = True
606 606 kwargs['form'] = form
607 607 kwargs['add_url'] = reverse('url_add_experiment')
608 608 filters = request.GET.copy()
609 609 filters.pop('page', None)
610 610 kwargs['q'] = urlencode(filters)
611 611 kwargs['menu_experiments'] = 'active'
612 612
613 613 return render(request, 'base_list.html', kwargs)
614 614
615 615
616 616 def experiment(request, id_exp):
617 617
618 618 experiment = get_object_or_404(Experiment, pk=id_exp)
619 619
620 620 configurations = Configuration.objects.filter(
621 621 experiment=experiment, type=0)
622 622
623 623 kwargs = {}
624 624
625 625 kwargs['experiment_keys'] = ['template', 'radar_system',
626 626 'name', 'freq', 'start_time', 'end_time']
627 627 kwargs['experiment'] = experiment
628 628 kwargs['configuration_keys'] = ['name', 'device__ip_address',
629 629 'device__port_address', 'device__status']
630 630 kwargs['configurations'] = configurations
631 631 kwargs['title'] = 'Experiment'
632 632 kwargs['suptitle'] = 'Details'
633 633 kwargs['button'] = 'Add Configuration'
634 634 kwargs['menu_experiments'] = 'active'
635 635
636 636 ###### SIDEBAR ######
637 637 kwargs.update(sidebar(experiment=experiment))
638 638
639 639 return render(request, 'experiment.html', kwargs)
640 640
641 641
642 642 @login_required
643 643 def experiment_new(request, id_camp=None):
644 644
645 645 if not is_developer(request.user):
646 646 messages.error(
647 647 request, 'Developer required, to create new Experiments')
648 648 return redirect('index')
649 649 kwargs = {}
650 650
651 651 if request.method == 'GET':
652 652 if 'template' in request.GET:
653 653 if request.GET['template'] == '0':
654 654 form = NewForm(initial={'create_from': 2},
655 655 template_choices=Experiment.objects.filter(template=True).values_list('id', 'name'))
656 656 else:
657 657 kwargs['button'] = 'Create'
658 658 kwargs['configurations'] = Configuration.objects.filter(
659 659 experiment=request.GET['template'])
660 660 kwargs['configuration_keys'] = ['name', 'device__name',
661 661 'device__ip_address', 'device__port_address']
662 662 exp = Experiment.objects.get(pk=request.GET['template'])
663 663 form = ExperimentForm(instance=exp,
664 664 initial={'name': '{}_{:%y%m%d}'.format(exp.name, datetime.now()),
665 665 'template': False})
666 666 elif 'blank' in request.GET:
667 667 kwargs['button'] = 'Create'
668 668 form = ExperimentForm()
669 669 else:
670 670 form = NewForm()
671 671
672 672 if request.method == 'POST':
673 673 form = ExperimentForm(request.POST)
674 674 if form.is_valid():
675 675 experiment = form.save(commit=False)
676 676 experiment.author = request.user
677 677 experiment.save()
678 678
679 679 if 'template' in request.GET:
680 680 configurations = Configuration.objects.filter(
681 681 experiment=request.GET['template'], type=0)
682 682 for conf in configurations:
683 683 conf.clone(experiment=experiment, template=False)
684 684
685 685 return redirect('url_experiment', id_exp=experiment.id)
686 686
687 687 kwargs['form'] = form
688 688 kwargs['title'] = 'Experiment'
689 689 kwargs['suptitle'] = 'New'
690 690 kwargs['menu_experiments'] = 'active'
691 691
692 692 return render(request, 'experiment_edit.html', kwargs)
693 693
694 694
695 695 @login_required
696 696 def experiment_edit(request, id_exp):
697 697
698 698 experiment = get_object_or_404(Experiment, pk=id_exp)
699 699
700 700 if request.method == 'GET':
701 701 form = ExperimentForm(instance=experiment)
702 702
703 703 if request.method == 'POST':
704 704 form = ExperimentForm(request.POST, instance=experiment)
705 705
706 706 if form.is_valid():
707 707 experiment = form.save()
708 708 return redirect('url_experiment', id_exp=experiment.id)
709 709
710 710 kwargs = {}
711 711 kwargs['form'] = form
712 712 kwargs['title'] = 'Experiment'
713 713 kwargs['suptitle'] = 'Edit'
714 714 kwargs['button'] = 'Update'
715 715 kwargs['menu_experiments'] = 'active'
716 716
717 717 return render(request, 'experiment_edit.html', kwargs)
718 718
719 719
720 720 @login_required
721 721 def experiment_delete(request, id_exp):
722 722
723 723 experiment = get_object_or_404(Experiment, pk=id_exp)
724 724
725 725 if request.method == 'POST':
726 726 if is_developer(request.user):
727 727 for conf in Configuration.objects.filter(experiment=experiment):
728 728 conf.delete()
729 729 experiment.delete()
730 730 return redirect('url_experiments')
731 731
732 732 messages.error(request, 'Not enough permission to delete this object')
733 733 return redirect(experiment.get_absolute_url())
734 734
735 735 kwargs = {
736 736 'title': 'Delete',
737 737 'suptitle': 'Experiment',
738 738 'object': experiment,
739 739 'delete': True
740 740 }
741 741
742 742 return render(request, 'confirm.html', kwargs)
743 743
744 744
745 745 @login_required
746 746 def experiment_export(request, id_exp):
747 747
748 748 experiment = get_object_or_404(Experiment, pk=id_exp)
749 749 content = experiment.parms_to_dict()
750 750 content_type = 'application/json'
751 751 filename = '%s_%s.json' % (experiment.name, experiment.id)
752 752
753 753 response = HttpResponse(content_type=content_type)
754 754 response['Content-Disposition'] = 'attachment; filename="%s"' % filename
755 755 response.write(json.dumps(content, indent=2))
756 756
757 757 return response
758 758
759 759
760 760 @login_required
761 761 def experiment_import(request, id_exp):
762 762
763 763 experiment = get_object_or_404(Experiment, pk=id_exp)
764 764 configurations = Configuration.objects.filter(experiment=experiment)
765 765
766 766 if request.method == 'GET':
767 767 file_form = UploadFileForm()
768 768
769 769 if request.method == 'POST':
770 770 file_form = UploadFileForm(request.POST, request.FILES)
771 771
772 772 if file_form.is_valid():
773 773 new_exp = experiment.dict_to_parms(
774 774 json.load(request.FILES['file']), CONF_MODELS)
775 775 messages.success(
776 776 request, "Parameters imported from: '%s'." % request.FILES['file'].name)
777 777 return redirect(new_exp.get_absolute_url_edit())
778 778
779 779 messages.error(request, "Could not import parameters from file")
780 780
781 781 kwargs = {}
782 782 kwargs['title'] = 'Experiment'
783 783 kwargs['form'] = file_form
784 784 kwargs['suptitle'] = 'Importing file'
785 785 kwargs['button'] = 'Import'
786 786 kwargs['menu_experiments'] = 'active'
787 787
788 788 kwargs.update(sidebar(experiment=experiment))
789 789
790 790 return render(request, 'experiment_import.html', kwargs)
791 791
792 792
793 793 @login_required
794 794 def experiment_start(request, id_exp):
795 795
796 796 exp = get_object_or_404(Experiment, pk=id_exp)
797 797
798 798 if exp.status == 2:
799 799 messages.warning(request, 'Experiment {} already runnnig'.format(exp))
800 800 else:
801 801 exp.status = exp.start()
802 802 if exp.status == 0:
803 803 messages.error(request, 'Experiment {} not start'.format(exp))
804 804 if exp.status == 2:
805 805 messages.success(request, 'Experiment {} started'.format(exp))
806 806
807 807 exp.save()
808 808
809 809 return redirect(exp.get_absolute_url())
810 810
811 811
812 812 @login_required
813 813 def experiment_stop(request, id_exp):
814 814
815 815 exp = get_object_or_404(Experiment, pk=id_exp)
816 816
817 817 if exp.status == 2:
818 818 exp.status = exp.stop()
819 819 exp.save()
820 820 messages.success(request, 'Experiment {} stopped'.format(exp))
821 821 else:
822 822 messages.error(request, 'Experiment {} not running'.format(exp))
823 823
824 824 return redirect(exp.get_absolute_url())
825 825
826 826
827 827 def experiment_status(request, id_exp):
828 828
829 829 exp = get_object_or_404(Experiment, pk=id_exp)
830 830
831 831 exp.get_status()
832 832
833 833 return redirect(exp.get_absolute_url())
834 834
835 835
836 836 @login_required
837 837 def experiment_mix(request, id_exp):
838 838
839 839 experiment = get_object_or_404(Experiment, pk=id_exp)
840 840 rc_confs = [conf for conf in RCConfiguration.objects.filter(
841 841 experiment=id_exp,
842 842 type=0,
843 843 mix=False)]
844 844
845 845 if len(rc_confs) < 2:
846 846 messages.warning(
847 847 request, 'You need at least two RC Configurations to make a mix')
848 848 return redirect(experiment.get_absolute_url())
849 849
850 850 mix_confs = RCConfiguration.objects.filter(experiment=id_exp, mix=True, type=0)
851 851
852 852 if mix_confs:
853 853 mix = mix_confs[0]
854 854 else:
855 855 mix = RCConfiguration(experiment=experiment,
856 856 device=rc_confs[0].device,
857 857 ipp=rc_confs[0].ipp,
858 858 clock_in=rc_confs[0].clock_in,
859 859 clock_divider=rc_confs[0].clock_divider,
860 860 mix=True,
861 861 parameters='')
862 862 mix.save()
863 863
864 864 line_type = RCLineType.objects.get(name='mix')
865 865 print("VIew obteniendo len getlines")
866 866 print(len(rc_confs[0].get_lines()))
867 867 for i in range(len(rc_confs[0].get_lines())):
868 868 line = RCLine(rc_configuration=mix, line_type=line_type, channel=i)
869 869 line.save()
870 870
871 871 initial = {'name': mix.name,
872 872 'result': parse_mix_result(mix.parameters),
873 873 'delay': 0,
874 874 'mask': [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
875 875 }
876 876
877 877 if request.method == 'GET':
878 878 form = RCMixConfigurationForm(confs=rc_confs, initial=initial)
879 879
880 880 if request.method == 'POST':
881 881 result = mix.parameters
882 882
883 883 if '{}|'.format(request.POST['experiment']) in result:
884 884 messages.error(request, 'Configuration already added')
885 885 else:
886 886 if 'operation' in request.POST:
887 887 operation = MIX_OPERATIONS[request.POST['operation']]
888 888 else:
889 889 operation = ' '
890 890
891 891 mode = MIX_MODES[request.POST['mode']]
892 892
893 893 if result:
894 894 result = '{}-{}|{}|{}|{}|{}'.format(mix.parameters,
895 895 request.POST['experiment'],
896 896 mode,
897 897 operation,
898 898 float(
899 899 request.POST['delay']),
900 900 parse_mask(
901 901 request.POST.getlist('mask'))
902 902 )
903 903 else:
904 904 result = '{}|{}|{}|{}|{}'.format(request.POST['experiment'],
905 905 mode,
906 906 operation,
907 907 float(request.POST['delay']),
908 908 parse_mask(
909 909 request.POST.getlist('mask'))
910 910 )
911 911
912 912 mix.parameters = result
913 913 mix.save()
914 914 mix.update_pulses()
915 915
916 916 initial['result'] = parse_mix_result(result)
917 917 initial['name'] = mix.name
918 918
919 919 form = RCMixConfigurationForm(initial=initial, confs=rc_confs)
920 920
921 921 kwargs = {
922 922 'title': 'Experiment',
923 923 'suptitle': 'Mix Configurations',
924 924 'form': form,
925 925 'extra_button': 'Delete',
926 926 'button': 'Add',
927 927 'cancel': 'Back',
928 928 'previous': experiment.get_absolute_url(),
929 929 'id_exp': id_exp,
930 930
931 931 }
932 932 kwargs['menu_experiments'] = 'active'
933 933
934 934 return render(request, 'experiment_mix.html', kwargs)
935 935
936 936
937 937 @login_required
938 938 def experiment_mix_delete(request, id_exp):
939 939
940 940 conf = RCConfiguration.objects.get(experiment=id_exp, mix=True, type=0)
941 941 values = conf.parameters.split('-')
942 942 conf.parameters = '-'.join(values[:-1])
943 943 conf.save()
944 944
945 945 return redirect('url_mix_experiment', id_exp=id_exp)
946 946
947 947
948 948 def experiment_summary(request, id_exp):
949 949
950 950 experiment = get_object_or_404(Experiment, pk=id_exp)
951 951 configurations = Configuration.objects.filter(
952 952 experiment=experiment, type=0)
953 953
954 954 kwargs = {}
955 955 kwargs['experiment_keys'] = ['radar_system',
956 956 'name', 'freq', 'start_time', 'end_time']
957 957 kwargs['experiment'] = experiment
958 958 kwargs['configurations'] = []
959 959 kwargs['title'] = 'Experiment Summary'
960 960 kwargs['suptitle'] = 'Details'
961 961 kwargs['button'] = 'Verify Parameters'
962 962
963 963 c_vel = 3.0*(10**8) # m/s
964 964 ope_freq = experiment.freq*(10**6) # 1/s
965 965 radar_lambda = c_vel/ope_freq # m
966 966 kwargs['radar_lambda'] = radar_lambda
967 967
968 968 ipp = None
969 969 nsa = 1
970 970 code_id = 0
971 971 tx_line = {}
972 972
973 973 for configuration in configurations.filter(device__device_type__name = 'rc'):
974 974
975 975 if configuration.mix:
976 976 continue
977 977 conf = {'conf': configuration}
978 978 conf['keys'] = []
979 979 conf['NTxs'] = configuration.ntx
980 980 conf['keys'].append('NTxs')
981 981 ipp = configuration.ipp
982 982 conf['IPP'] = ipp
983 983 conf['keys'].append('IPP')
984 984 lines = configuration.get_lines(line_type__name='tx')
985 985
986 986 for tx_line in lines:
987 987 tx_params = json.loads(tx_line.params)
988 988 conf[tx_line.get_name()] = '{} Km'.format(tx_params['pulse_width'])
989 989 conf['keys'].append(tx_line.get_name())
990 990 delays = tx_params['delays']
991 991 if delays not in ('', '0'):
992 992 n = len(delays.split(','))
993 993 taus = '{} Taus: {}'.format(n, delays)
994 994 else:
995 995 taus = '-'
996 996 conf['Taus ({})'.format(tx_line.get_name())] = taus
997 997 conf['keys'].append('Taus ({})'.format(tx_line.get_name()))
998 998 for code_line in configuration.get_lines(line_type__name='codes'):
999 999 code_params = json.loads(code_line.params)
1000 1000 code_id = code_params['code']
1001 1001 if tx_line.pk == int(code_params['TX_ref']):
1002 1002 conf['Code ({})'.format(tx_line.get_name())] = '{}:{}'.format(RCLineCode.objects.get(pk=code_params['code']),
1003 1003 '-'.join(code_params['codes']))
1004 1004 conf['keys'].append('Code ({})'.format(tx_line.get_name()))
1005 1005
1006 1006 for windows_line in configuration.get_lines(line_type__name='windows'):
1007 1007 win_params = json.loads(windows_line.params)
1008 1008 if tx_line.pk == int(win_params['TX_ref']):
1009 1009 windows = ''
1010 1010 nsa = win_params['params'][0]['number_of_samples']
1011 1011 for i, params in enumerate(win_params['params']):
1012 1012 windows += 'W{}: Ho={first_height} km DH={resolution} km NSA={number_of_samples}<br>'.format(
1013 1013 i, **params)
1014 1014 conf['Window'] = mark_safe(windows)
1015 1015 conf['keys'].append('Window')
1016 1016
1017 1017 kwargs['configurations'].append(conf)
1018 1018
1019 1019 for configuration in configurations.filter(device__device_type__name = 'jars'):
1020 1020
1021 1021 conf = {'conf': configuration}
1022 1022 conf['keys'] = []
1023 1023 conf['Type of Data'] = EXPERIMENT_TYPE[configuration.exp_type][1]
1024 1024 conf['keys'].append('Type of Data')
1025 1025 channels_number = configuration.channels_number
1026 1026 exp_type = configuration.exp_type
1027 1027 fftpoints = configuration.fftpoints
1028 1028 filter_parms = json.loads(configuration.filter_parms)
1029 1029 spectral_number = configuration.spectral_number
1030 1030 acq_profiles = configuration.acq_profiles
1031 1031 cohe_integr = configuration.cohe_integr
1032 1032 profiles_block = configuration.profiles_block
1033 1033
1034 1034 conf['Num of Profiles'] = acq_profiles
1035 1035 conf['keys'].append('Num of Profiles')
1036 1036
1037 1037 conf['Prof per Block'] = profiles_block
1038 1038 conf['keys'].append('Prof per Block')
1039 1039
1040 1040 conf['Blocks per File'] = configuration.raw_data_blocks
1041 1041 conf['keys'].append('Blocks per File')
1042 1042
1043 1043 if exp_type == 0: # Short
1044 1044 bytes_ = 2
1045 1045 b = nsa*2*bytes_*channels_number
1046 1046 else: # Float
1047 1047 bytes_ = 4
1048 1048 channels = channels_number + spectral_number
1049 1049 b = nsa*2*bytes_*fftpoints*channels
1050 1050
1051 1051 codes_num = 7
1052 1052 if code_id == 2:
1053 1053 codes_num = 7
1054 1054 elif code_id == 12:
1055 1055 codes_num = 15
1056 1056
1057 1057 #Jars filter values:
1058 1058
1059 1059 clock = float(filter_parms['clock'])
1060 1060 filter_2 = int(filter_parms['cic_2'])
1061 1061 filter_5 = int(filter_parms['cic_5'])
1062 1062 filter_fir = int(filter_parms['fir'])
1063 1063 Fs_MHz = clock/(filter_2*filter_5*filter_fir)
1064 1064
1065 1065 #Jars values:
1066 1066 if ipp is not None:
1067 1067 IPP_units = ipp/0.15*Fs_MHz
1068 1068 IPP_us = IPP_units / Fs_MHz
1069 1069 IPP_s = IPP_units / (Fs_MHz * (10**6))
1070 1070 Ts = 1/(Fs_MHz*(10**6))
1071 1071
1072 1072 Va = radar_lambda/(4*Ts*cohe_integr)
1073 1073 rate_bh = ((nsa-codes_num)*channels_number*2 *
1074 1074 bytes_/IPP_us)*(36*(10**8)/cohe_integr)
1075 1075 rate_gh = rate_bh/(1024*1024*1024)
1076 1076
1077 1077 conf['Time per Block'] = IPP_s * profiles_block * cohe_integr
1078 1078 conf['keys'].append('Time per Block')
1079 1079 conf['Acq time'] = IPP_s * acq_profiles
1080 1080 conf['keys'].append('Acq time')
1081 1081 conf['Data rate'] = str(rate_gh)+" (GB/h)"
1082 1082 conf['keys'].append('Data rate')
1083 1083 conf['Va (m/s)'] = Va
1084 1084 conf['keys'].append('Va (m/s)')
1085 1085 conf['Vrange (m/s)'] = 3/(2*IPP_s*cohe_integr)
1086 1086 conf['keys'].append('Vrange (m/s)')
1087 1087
1088 1088 kwargs['configurations'].append(conf)
1089 1089 kwargs['menu_experiments'] = 'active'
1090 1090
1091 1091 ###### SIDEBAR ######
1092 1092 kwargs.update(sidebar(experiment=experiment))
1093 1093
1094 1094 return render(request, 'experiment_summary.html', kwargs)
1095 1095
1096 1096
1097 1097 @login_required
1098 1098 def experiment_verify(request, id_exp):
1099 1099
1100 1100 experiment = get_object_or_404(Experiment, pk=id_exp)
1101 1101 experiment_data = experiment.parms_to_dict()
1102 1102 configurations = Configuration.objects.filter(
1103 1103 experiment=experiment, type=0)
1104 1104
1105 1105 kwargs = {}
1106 1106
1107 1107 kwargs['experiment_keys'] = ['template',
1108 1108 'radar_system', 'name', 'start_time', 'end_time']
1109 1109 kwargs['experiment'] = experiment
1110 1110
1111 1111 kwargs['configuration_keys'] = ['name', 'device__ip_address',
1112 1112 'device__port_address', 'device__status']
1113 1113 kwargs['configurations'] = configurations
1114 1114 kwargs['experiment_data'] = experiment_data
1115 1115
1116 1116 kwargs['title'] = 'Verify Experiment'
1117 1117 kwargs['suptitle'] = 'Parameters'
1118 1118
1119 1119 kwargs['button'] = 'Update'
1120 1120
1121 1121 jars_conf = False
1122 1122 rc_conf = False
1123 1123 dds_conf = False
1124 1124
1125 1125 for configuration in configurations:
1126 1126 #-------------------- JARS -----------------------:
1127 1127 if configuration.device.device_type.name == 'jars':
1128 1128 jars_conf = True
1129 1129 jars = configuration
1130 1130 kwargs['jars_conf'] = jars_conf
1131 1131 filter_parms = json.loads(jars.filter_parms)
1132 1132 kwargs['filter_parms'] = filter_parms
1133 1133 #--Sampling Frequency
1134 1134 clock = filter_parms['clock']
1135 1135 filter_2 = filter_parms['cic_2']
1136 1136 filter_5 = filter_parms['cic_5']
1137 1137 filter_fir = filter_parms['fir']
1138 1138 samp_freq_jars = clock/filter_2/filter_5/filter_fir
1139 1139
1140 1140 kwargs['samp_freq_jars'] = samp_freq_jars
1141 1141 kwargs['jars'] = configuration
1142 1142
1143 1143 #--------------------- RC ----------------------:
1144 1144 if configuration.device.device_type.name == 'rc' and not configuration.mix:
1145 1145 rc_conf = True
1146 1146 rc = configuration
1147 1147
1148 1148 rc_parms = configuration.parms_to_dict()
1149 1149
1150 1150 win_lines = rc.get_lines(line_type__name='windows')
1151 1151 if win_lines:
1152 1152 dh = json.loads(win_lines[0].params)['params'][0]['resolution']
1153 1153 #--Sampling Frequency
1154 1154 samp_freq_rc = 0.15/dh
1155 1155 kwargs['samp_freq_rc'] = samp_freq_rc
1156 1156
1157 1157 kwargs['rc_conf'] = rc_conf
1158 1158 kwargs['rc'] = configuration
1159 1159
1160 1160 #-------------------- DDS ----------------------:
1161 1161 if configuration.device.device_type.name == 'dds':
1162 1162 dds_conf = True
1163 1163 dds = configuration
1164 1164 dds_parms = configuration.parms_to_dict()
1165 1165
1166 1166 kwargs['dds_conf'] = dds_conf
1167 1167 kwargs['dds'] = configuration
1168 1168
1169 1169 #------------Validation------------:
1170 1170 #Clock
1171 1171 if dds_conf and rc_conf and jars_conf:
1172 1172 if float(filter_parms['clock']) != float(rc_parms['configurations']['byId'][str(rc.pk)]['clock_in']) and float(rc_parms['configurations']['byId'][str(rc.pk)]['clock_in']) != float(dds_parms['configurations']['byId'][str(dds.pk)]['clock']):
1173 1173 messages.warning(request, "Devices don't have the same clock.")
1174 1174 elif rc_conf and jars_conf:
1175 1175 if float(filter_parms['clock']) != float(rc_parms['configurations']['byId'][str(rc.pk)]['clock_in']):
1176 1176 messages.warning(request, "Devices don't have the same clock.")
1177 1177 elif rc_conf and dds_conf:
1178 1178 if float(rc_parms['configurations']['byId'][str(rc.pk)]['clock_in']) != float(dds_parms['configurations']['byId'][str(dds.pk)]['clock']):
1179 1179 messages.warning(request, "Devices don't have the same clock.")
1180 1180 if float(samp_freq_rc) != float(dds_parms['configurations']['byId'][str(dds.pk)]['frequencyA']):
1181 1181 messages.warning(
1182 1182 request, "Devices don't have the same Frequency A.")
1183 1183
1184 1184 #------------POST METHOD------------:
1185 1185 if request.method == 'POST':
1186 1186 if request.POST['suggest_clock']:
1187 1187 try:
1188 1188 suggest_clock = float(request.POST['suggest_clock'])
1189 1189 except:
1190 1190 messages.warning(request, "Invalid value in CLOCK IN.")
1191 1191 return redirect('url_verify_experiment', id_exp=experiment.id)
1192 1192 else:
1193 1193 suggest_clock = ""
1194 1194 if suggest_clock:
1195 1195 if rc_conf:
1196 1196 rc.clock_in = suggest_clock
1197 1197 rc.save()
1198 1198 if jars_conf:
1199 1199 filter_parms = jars.filter_parms
1200 1200 filter_parms = ast.literal_eval(filter_parms)
1201 1201 filter_parms['clock'] = suggest_clock
1202 1202 jars.filter_parms = json.dumps(filter_parms)
1203 1203 jars.save()
1204 1204 kwargs['filter_parms'] = filter_parms
1205 1205 if dds_conf:
1206 1206 dds.clock = suggest_clock
1207 1207 dds.save()
1208 1208
1209 1209 if request.POST['suggest_frequencyA']:
1210 1210 try:
1211 1211 suggest_frequencyA = float(request.POST['suggest_frequencyA'])
1212 1212 except:
1213 1213 messages.warning(request, "Invalid value in FREQUENCY A.")
1214 1214 return redirect('url_verify_experiment', id_exp=experiment.id)
1215 1215 else:
1216 1216 suggest_frequencyA = ""
1217 1217 if suggest_frequencyA:
1218 1218 if jars_conf:
1219 1219 filter_parms = jars.filter_parms
1220 1220 filter_parms = ast.literal_eval(filter_parms)
1221 1221 filter_parms['fch'] = suggest_frequencyA
1222 1222 jars.filter_parms = json.dumps(filter_parms)
1223 1223 jars.save()
1224 1224 kwargs['filter_parms'] = filter_parms
1225 1225 if dds_conf:
1226 1226 dds.frequencyA_Mhz = request.POST['suggest_frequencyA']
1227 1227 dds.save()
1228 1228
1229 1229 kwargs['menu_experiments'] = 'active'
1230 1230 kwargs.update(sidebar(experiment=experiment))
1231 1231 return render(request, 'experiment_verify.html', kwargs)
1232 1232
1233 1233
1234 1234 def parse_mix_result(s):
1235 1235
1236 1236 values = s.split('-')
1237 1237 html = 'EXP MOD OPE DELAY MASK\r\n'
1238 1238
1239 1239 if not values or values[0] in ('', ' '):
1240 1240 return mark_safe(html)
1241 1241
1242 1242 for i, value in enumerate(values):
1243 1243 if not value:
1244 1244 continue
1245 1245 pk, mode, operation, delay, mask = value.split('|')
1246 1246 conf = RCConfiguration.objects.get(pk=pk)
1247 1247 if i == 0:
1248 1248 html += '{:20.18}{:3}{:4}{:9}km{:>6}\r\n'.format(
1249 1249 conf.name,
1250 1250 mode,
1251 1251 ' ',
1252 1252 delay,
1253 1253 mask)
1254 1254 else:
1255 1255 html += '{:20.18}{:3}{:4}{:9}km{:>6}\r\n'.format(
1256 1256 conf.name,
1257 1257 mode,
1258 1258 operation,
1259 1259 delay,
1260 1260 mask)
1261 1261
1262 1262 return mark_safe(html)
1263 1263
1264 1264
1265 1265 def parse_mask(l):
1266 1266
1267 1267 values = []
1268 1268
1269 1269 for x in range(16):
1270 1270 if '{}'.format(x) in l:
1271 1271 values.append(1)
1272 1272 else:
1273 1273 values.append(0)
1274 1274
1275 1275 values.reverse()
1276 1276
1277 1277 return int(''.join([str(x) for x in values]), 2)
1278 1278
1279 1279
1280 1280 def dev_confs(request):
1281 1281
1282 1282 page = request.GET.get('page')
1283 1283 order = ('-programmed_date', )
1284 1284 filters = request.GET.copy()
1285 1285 if 'my configurations' in filters:
1286 1286 filters.pop('my configurations', None)
1287 1287 filters['mine'] = request.user.id
1288 1288 kwargs = get_paginator(Configuration, page, order, filters)
1289 1289 fields = ['tags', 'template', 'historical']
1290 1290 if request.user.is_authenticated:
1291 1291 fields.append('my configurations')
1292 1292 form = FilterForm(initial=request.GET, extra_fields=fields)
1293 1293 kwargs['keys'] = ['name', 'experiment',
1294 1294 'type', 'programmed_date', 'actions']
1295 1295 kwargs['title'] = 'Configuration'
1296 1296 kwargs['suptitle'] = 'List'
1297 1297 kwargs['no_sidebar'] = True
1298 1298 kwargs['form'] = form
1299 1299 kwargs['add_url'] = reverse('url_add_dev_conf', args=[0])
1300 1300 filters = request.GET.copy()
1301 1301 filters.pop('page', None)
1302 1302 kwargs['q'] = urlencode(filters)
1303 1303 kwargs['menu_configurations'] = 'active'
1304 1304
1305 1305 return render(request, 'base_list.html', kwargs)
1306 1306
1307 1307
1308 1308 def dev_conf(request, id_conf):
1309 1309
1310 1310 conf = get_object_or_404(Configuration, pk=id_conf)
1311 1311
1312 1312 return redirect(conf.get_absolute_url())
1313 1313
1314 1314
1315 1315 @login_required
1316 1316 def dev_conf_new(request, id_exp=0, id_dev=0):
1317 1317
1318 1318 if not is_developer(request.user):
1319 1319 messages.error(
1320 1320 request, 'Developer required, to create new configurations')
1321 1321 return redirect('index')
1322 1322
1323 1323 initial = {}
1324 1324 kwargs = {}
1325 1325
1326 1326 if id_exp != 0:
1327 1327 initial['experiment'] = id_exp
1328 1328
1329 1329 if id_dev != 0:
1330 1330 initial['device'] = id_dev
1331 1331
1332 1332 if request.method == 'GET':
1333 1333
1334 1334 if id_dev:
1335 1335 kwargs['button'] = 'Create'
1336 1336 device = Device.objects.get(pk=id_dev)
1337 1337 DevConfForm = CONF_FORMS[device.device_type.name]
1338 1338 initial['name'] = request.GET['name']
1339 1339 form = DevConfForm(initial=initial)
1340 1340 else:
1341 1341 if 'template' in request.GET:
1342 1342 if request.GET['template'] == '0':
1343 1343 choices = [(conf.pk, '{}'.format(conf))
1344 1344 for conf in Configuration.objects.filter(template=True)]
1345 1345 form = NewForm(initial={'create_from': 2},
1346 1346 template_choices=choices)
1347 1347 else:
1348 1348 kwargs['button'] = 'Create'
1349 1349 conf = Configuration.objects.get(
1350 1350 pk=request.GET['template'])
1351 1351 id_dev = conf.device.pk
1352 1352 DevConfForm = CONF_FORMS[conf.device.device_type.name]
1353 1353 form = DevConfForm(instance=conf,
1354 1354 initial={'name': '{}_{:%y%m%d}'.format(conf.name, datetime.now()),
1355 1355 'template': False,
1356 1356 'experiment': id_exp})
1357 1357 elif 'blank' in request.GET:
1358 1358 kwargs['button'] = 'Create'
1359 1359 form = ConfigurationForm(initial=initial)
1360 1360 else:
1361 1361 form = NewForm()
1362 1362
1363 1363 if request.method == 'POST':
1364 1364
1365 1365 device = Device.objects.get(pk=request.POST['device'])
1366 1366 DevConfForm = CONF_FORMS[device.device_type.name]
1367 1367
1368 1368 form = DevConfForm(request.POST)
1369 1369 kwargs['button'] = 'Create'
1370 1370 if form.is_valid():
1371 1371 conf = form.save(commit=False)
1372 1372 conf.author = request.user
1373 1373 conf.save()
1374 1374
1375 1375 if 'template' in request.GET and conf.device.device_type.name == 'rc':
1376 1376 lines = RCLine.objects.filter(
1377 1377 rc_configuration=request.GET['template'])
1378 1378 for line in lines:
1379 1379 line.clone(rc_configuration=conf)
1380 1380
1381 1381 new_lines = conf.get_lines()
1382 1382 for line in new_lines:
1383 1383 line_params = json.loads(line.params)
1384 1384 if 'TX_ref' in line_params:
1385 1385 ref_line = RCLine.objects.get(pk=line_params['TX_ref'])
1386 1386 line_params['TX_ref'] = ['{}'.format(
1387 1387 l.pk) for l in new_lines if l.get_name() == ref_line.get_name()][0]
1388 1388 line.params = json.dumps(line_params)
1389 1389 line.save()
1390 1390 elif conf.device.device_type.name == 'rc':
1391 1391 clk = RCClock(rc_configuration=conf)
1392 1392 clk.save()
1393 1393
1394 1394 return redirect('url_dev_conf', id_conf=conf.pk)
1395 1395
1396 1396 kwargs['id_exp'] = id_exp
1397 1397 kwargs['form'] = form
1398 1398 kwargs['title'] = 'Configuration'
1399 1399 kwargs['suptitle'] = 'New'
1400 1400 kwargs['menu_configurations'] = 'active'
1401 1401
1402 1402 if id_dev != 0:
1403 1403 device = Device.objects.get(pk=id_dev)
1404 1404 kwargs['device'] = device.device_type.name
1405 1405 print(id_exp)
1406 1406 return render(request, 'dev_conf_edit.html', kwargs)
1407 1407
1408 1408
1409 1409 @login_required
1410 1410 def dev_conf_edit(request, id_conf):
1411 1411
1412 1412 conf = get_object_or_404(Configuration, pk=id_conf)
1413 1413
1414 1414 DevConfForm = CONF_FORMS[conf.device.device_type.name]
1415 1415
1416 1416 if request.method == 'GET':
1417 1417 form = DevConfForm(instance=conf)
1418 1418
1419 1419 if request.method == 'POST':
1420 1420 form = DevConfForm(request.POST, instance=conf)
1421 1421
1422 1422 if form.is_valid():
1423 1423 form.save()
1424 1424 return redirect('url_dev_conf', id_conf=id_conf)
1425 1425
1426 1426 kwargs = {}
1427 1427 kwargs['form'] = form
1428 1428 kwargs['title'] = 'Device Configuration'
1429 1429 kwargs['suptitle'] = 'Edit'
1430 1430 kwargs['button'] = 'Update'
1431 1431 kwargs['menu_configurations'] = 'active'
1432 1432
1433 1433 ###### SIDEBAR ######
1434 1434 kwargs.update(sidebar(conf=conf))
1435 1435
1436 1436 return render(request, '%s_conf_edit.html' % conf.device.device_type.name, kwargs)
1437 1437
1438 1438
1439 1439 @login_required
1440 1440 def dev_conf_start(request, id_conf):
1441 1441
1442 1442 conf = get_object_or_404(Configuration, pk=id_conf)
1443 1443
1444 1444 if conf.start_device():
1445 1445 messages.success(request, conf.message)
1446 1446 else:
1447 1447 messages.error(request, conf.message)
1448 1448
1449 1449 #conf.status_device()
1450 1450
1451 1451 return redirect(conf.get_absolute_url())
1452 1452
1453 1453
1454 1454 @login_required
1455 1455 def dev_conf_stop(request, id_conf):
1456 1456
1457 1457 conf = get_object_or_404(Configuration, pk=id_conf)
1458 1458
1459 1459 if conf.stop_device():
1460 1460 messages.success(request, conf.message)
1461 1461 else:
1462 1462 messages.error(request, conf.message)
1463 1463
1464 1464 #conf.status_device()
1465 1465
1466 1466 return redirect(conf.get_absolute_url())
1467 1467
1468 1468 @login_required
1469 1469 def dev_conf_stop_mqtt(request, id_conf):
1470 1470
1471 1471 conf = get_object_or_404(Configuration, pk=id_conf)
1472 1472
1473 1473 if conf.stop_device_mqtt():
1474 1474 messages.success(request, conf.message)
1475 1475 else:
1476 1476 messages.error(request, conf.message)
1477 1477
1478 1478 #conf.status_device()
1479 1479
1480 1480 return redirect(conf.get_absolute_url())
1481 1481
1482 1482 @login_required
1483 1483 def dev_conf_status(request, id_conf):
1484 1484
1485 1485 conf = get_object_or_404(Configuration, pk=id_conf)
1486 1486
1487 1487 conf_active = Configuration.objects.filter(pk=conf.device.conf_active).first()
1488 1488 if conf_active!=conf:
1489 1489 url = '#' if conf_active is None else conf_active.get_absolute_url()
1490 1490 label = 'None' if conf_active is None else conf_active.label
1491 1491 messages.warning(
1492 1492 request,
1493 1493 mark_safe('The current configuration has not been written to device, the active configuration is <a href="{}">{}</a>'.format(
1494 1494 url,
1495 1495 label
1496 1496 ))
1497 1497 )
1498 1498
1499 1499 return redirect(conf.get_absolute_url())
1500 1500
1501 1501 if conf.status_device():
1502 1502 messages.success(request, conf.message)
1503 1503 else:
1504 1504 messages.error(request, conf.message)
1505 1505
1506 1506 return redirect(conf.get_absolute_url())
1507 1507
1508 1508
1509 1509 @login_required
1510 1510 def dev_conf_reset(request, id_conf):
1511 1511
1512 1512 conf = get_object_or_404(Configuration, pk=id_conf)
1513 1513
1514 1514 if conf.reset_device():
1515 1515 messages.success(request, conf.message)
1516 1516 else:
1517 1517 messages.error(request, conf.message)
1518 1518
1519 1519 return redirect(conf.get_absolute_url())
1520 1520
1521 1521
1522 1522 @login_required
1523 1523 def dev_conf_write(request, id_conf):
1524 1524
1525 1525 conf = get_object_or_404(Configuration, pk=id_conf)
1526 1526
1527 1527 if request.method == 'POST':
1528 1528 if conf.write_device():
1529 1529 conf.device.conf_active = conf.pk
1530 1530 conf.device.save()
1531 1531 messages.success(request, conf.message)
1532 1532 if has_been_modified(conf):
1533 1533 conf.clone(type=1, template=False)
1534 1534 else:
1535 1535 messages.error(request, conf.message)
1536 1536
1537 1537 return redirect(get_object_or_404(Configuration, pk=id_conf).get_absolute_url())
1538 1538
1539 1539 kwargs = {
1540 1540 'title': 'Write Configuration',
1541 1541 'suptitle': conf.label,
1542 1542 'message': 'Are you sure yo want to write this {} configuration?'.format(conf.device),
1543 1543 'delete': False
1544 1544 }
1545 1545 kwargs['menu_configurations'] = 'active'
1546 1546
1547 1547 return render(request, 'confirm.html', kwargs)
1548 1548
1549 1549
1550 1550 @login_required
1551 1551 def dev_conf_write_mqtt(request,id_conf):
1552 1552
1553 1553 conf = get_object_or_404(Configuration, pk=id_conf)
1554 1554 beams = ABSBeam.objects.filter(abs_conf=conf)
1555 1555
1556 1556 if request.method == 'POST':
1557 1557 if conf.write_device_mqtt():
1558 1558 conf.device.conf_active = conf.pk
1559 1559 conf.device.save()
1560 1560 messages.success(request, conf.message)
1561 1561 if has_been_modified(conf):
1562 1562 conf.clone(type=1, template=False)
1563 1563 else:
1564 1564 messages.error(request, conf.message)
1565 1565 print("return",flush=True)
1566 1566 #return redirect(get_object_or_404(Configuration, pk=id_conf).get_absolute_url())
1567 1567
1568 1568 module_messages = json.loads(conf.module_messages)
1569 1569 kwargs = {}
1570 1570 kwargs['connected_modules'] = str(conf.connected_modules())+'/64'
1571 1571 kwargs['dev_conf'] = conf
1572 1572
1573 1573 if conf.operation_mode == 0:
1574 1574 kwargs['dev_conf_keys'] = ['label', 'operation_mode']
1575 1575 else:
1576 1576 kwargs['dev_conf_keys'] = ['label', 'operation_mode', 'operation_value']
1577 1577
1578 1578 kwargs['title'] = 'ABS Configuration'
1579 1579 kwargs['suptitle'] = 'Details'
1580 1580 kwargs['button'] = 'Edit Configuration'
1581 1581
1582 print("conf.active_beam: {}".format(conf.active_beam))
1582 1583 if conf.active_beam != 0:
1583 1584 kwargs['active_beam'] = int(conf.active_beam)
1584 1585
1585 1586
1586 1587 kwargs['beams'] = beams
1587 1588 # kwargs['modules_status'] = all_status
1588 1589 # kwargs['color_status'] = color_status
1589 1590
1590 1591
1591 1592 kwargs['module_messages'] = module_messages
1592 1593
1593 1594 ###### SIDEBAR ######
1594 1595 kwargs.update(sidebar(conf=conf))
1595 1596
1596 1597
1597 1598 return render(request, 'abs_conf_mqtt.html',kwargs)
1598 1599
1599 1600 kwargs = {
1600 1601 'title': 'MQTT Write Configuration',
1601 1602 'suptitle': conf.label,
1602 1603 'message': 'Are you sure yo want to write through MQTT this {} configuration?'.format(conf.device),
1603 1604 'delete': False
1604 1605 }
1605 1606 kwargs['menu_configurations'] = 'active'
1606 1607 print("Confirm",flush=True)
1607 1608 return render(request, 'confirm.html', kwargs)
1608 1609
1609 1610
1610 1611 @login_required
1611 1612 def dev_conf_read(request, id_conf):
1612 1613
1613 1614 conf = get_object_or_404(Configuration, pk=id_conf)
1614 1615
1615 1616 DevConfForm = CONF_FORMS[conf.device.device_type.name]
1616 1617
1617 1618 if request.method == 'GET':
1618 1619
1619 1620 parms = conf.read_device()
1620 1621 #conf.status_device()
1621 1622
1622 1623 if not parms:
1623 1624 messages.error(request, conf.message)
1624 1625 return redirect(conf.get_absolute_url())
1625 1626
1626 1627 form = DevConfForm(initial=parms, instance=conf)
1627 1628
1628 1629 if request.method == 'POST':
1629 1630 form = DevConfForm(request.POST, instance=conf)
1630 1631
1631 1632 if form.is_valid():
1632 1633 form.save()
1633 1634 return redirect(conf.get_absolute_url())
1634 1635
1635 1636 messages.error(request, "Parameters could not be saved")
1636 1637
1637 1638 kwargs = {}
1638 1639 kwargs['id_dev'] = conf.id
1639 1640 kwargs['form'] = form
1640 1641 kwargs['title'] = 'Device Configuration'
1641 1642 kwargs['suptitle'] = 'Parameters read from device'
1642 1643 kwargs['button'] = 'Save'
1643 1644
1644 1645 ###### SIDEBAR ######
1645 1646 kwargs.update(sidebar(conf=conf))
1646 1647
1647 1648 return render(request, '%s_conf_edit.html' % conf.device.device_type.name, kwargs)
1648 1649
1649 1650
1650 1651 @login_required
1651 1652 def dev_conf_import(request, id_conf):
1652 1653
1653 1654 conf = get_object_or_404(Configuration, pk=id_conf)
1654 1655 DevConfForm = CONF_FORMS[conf.device.device_type.name]
1655 1656
1656 1657 if request.method == 'GET':
1657 1658 file_form = UploadFileForm()
1658 1659
1659 1660 if request.method == 'POST':
1660 1661 file_form = UploadFileForm(request.POST, request.FILES)
1661 1662
1662 1663 if file_form.is_valid():
1663 1664
1664 1665 data = conf.import_from_file(request.FILES['file'])
1665 1666 parms = Params(data=data).get_conf(
1666 1667 dtype=conf.device.device_type.name)
1667 1668
1668 1669 if parms:
1669 1670
1670 1671 form = DevConfForm(initial=parms, instance=conf)
1671 1672
1672 1673 kwargs = {}
1673 1674 kwargs['id_dev'] = conf.id
1674 1675 kwargs['form'] = form
1675 1676 kwargs['title'] = 'Device Configuration'
1676 1677 kwargs['suptitle'] = 'Parameters imported'
1677 1678 kwargs['button'] = 'Save'
1678 1679 kwargs['action'] = conf.get_absolute_url_edit()
1679 1680 kwargs['previous'] = conf.get_absolute_url()
1680 1681
1681 1682 ###### SIDEBAR ######
1682 1683 kwargs.update(sidebar(conf=conf))
1683 1684
1684 1685 messages.success(
1685 1686 request, "Parameters imported from: '%s'." % request.FILES['file'].name)
1686 1687
1687 1688 return render(request, '%s_conf_edit.html' % conf.device.device_type.name, kwargs)
1688 1689
1689 1690 messages.error(request, "Could not import parameters from file")
1690 1691
1691 1692 kwargs = {}
1692 1693 kwargs['id_dev'] = conf.id
1693 1694 kwargs['title'] = 'Device Configuration'
1694 1695 kwargs['form'] = file_form
1695 1696 kwargs['suptitle'] = 'Importing file'
1696 1697 kwargs['button'] = 'Import'
1697 1698 kwargs['menu_configurations'] = 'active'
1698 1699
1699 1700 kwargs.update(sidebar(conf=conf))
1700 1701
1701 1702 return render(request, 'dev_conf_import.html', kwargs)
1702 1703
1703 1704
1704 1705 @login_required
1705 1706 def dev_conf_export(request, id_conf):
1706 1707
1707 1708 conf = get_object_or_404(Configuration, pk=id_conf)
1708 1709
1709 1710 if request.method == 'GET':
1710 1711 file_form = DownloadFileForm(conf.device.device_type.name)
1711 1712
1712 1713 if request.method == 'POST':
1713 1714 file_form = DownloadFileForm(
1714 1715 conf.device.device_type.name, request.POST)
1715 1716
1716 1717 if file_form.is_valid():
1717 1718 fields = conf.export_to_file(
1718 1719 format=file_form.cleaned_data['format'])
1719 1720 if not fields['content']:
1720 1721 messages.error(request, conf.message)
1721 1722 return redirect(conf.get_absolute_url_export())
1722 1723 response = HttpResponse(content_type=fields['content_type'])
1723 1724 response['Content-Disposition'] = 'attachment; filename="%s"' % fields['filename']
1724 1725 response.write(fields['content'])
1725 1726
1726 1727 return response
1727 1728
1728 1729 messages.error(request, "Could not export parameters")
1729 1730
1730 1731 kwargs = {}
1731 1732 kwargs['id_dev'] = conf.id
1732 1733 kwargs['title'] = 'Device Configuration'
1733 1734 kwargs['form'] = file_form
1734 1735 kwargs['suptitle'] = 'Exporting file'
1735 1736 kwargs['button'] = 'Export'
1736 1737 kwargs['menu_configurations'] = 'active'
1737 1738
1738 1739 return render(request, 'dev_conf_export.html', kwargs)
1739 1740
1740 1741
1741 1742 @login_required
1742 1743 def dev_conf_delete(request, id_conf):
1743 1744
1744 1745 conf = get_object_or_404(Configuration, pk=id_conf)
1745 1746
1746 1747 if request.method == 'POST':
1747 1748 if is_developer(request.user):
1748 1749 conf.delete()
1749 1750 return redirect('url_dev_confs')
1750 1751
1751 1752 messages.error(request, 'Not enough permission to delete this object')
1752 1753 return redirect(conf.get_absolute_url())
1753 1754
1754 1755 kwargs = {
1755 1756 'title': 'Delete',
1756 1757 'suptitle': 'Configuration',
1757 1758 'object': conf,
1758 1759 'delete': True
1759 1760 }
1760 1761 kwargs['menu_configurations'] = 'active'
1761 1762
1762 1763 return render(request, 'confirm.html', kwargs)
1763 1764
1764 1765
1765 1766 def sidebar(**kwargs):
1766 1767
1767 1768 side_data = {}
1768 1769
1769 1770 conf = kwargs.get('conf', None)
1770 1771 experiment = kwargs.get('experiment', None)
1771 1772
1772 1773 if not experiment:
1773 1774 experiment = conf.experiment
1774 1775
1775 1776 if experiment:
1776 1777 side_data['experiment'] = experiment
1777 1778 campaign = experiment.campaign_set.all()
1778 1779 if campaign:
1779 1780 side_data['campaign'] = campaign[0]
1780 1781 experiments = campaign[0].experiments.all().order_by('name')
1781 1782 else:
1782 1783 experiments = [experiment]
1783 1784 configurations = experiment.configuration_set.filter(type=0)
1784 1785 side_data['side_experiments'] = experiments
1785 1786 side_data['side_configurations'] = configurations.order_by(
1786 1787 'device__device_type__name')
1787 1788
1788 1789 return side_data
1789 1790
1790 1791 def get_paginator(model, page, order, filters={}, n=8):
1791 1792 kwargs = {}
1792 1793 query = Q()
1793 1794 if isinstance(filters, QueryDict):
1794 1795 filters = filters.dict()
1795 1796 copy_filters=filters.copy()
1796 1797 [filters.pop(key) for key in copy_filters.keys() if copy_filters[key] in (' ', ' ')]
1797 1798 filters.pop('page', None)
1798 1799
1799 1800 fields = [f.name for f in model._meta.get_fields()]
1800 1801
1801 1802 if 'template' in copy_filters:
1802 1803 filters['template'] = True
1803 1804 if 'historical' in copy_filters:
1804 1805 filters.pop('historical')
1805 1806 filters['type'] = 1
1806 1807 elif 'type' in fields:
1807 1808 filters['type'] = 0
1808 1809 if 'start_date' in copy_filters:
1809 1810 filters['start_date__gte'] =filters.pop('start_date')
1810 1811 if 'end_date' in copy_filters:
1811 1812 filters['start_date__lte'] =filters.pop('end_date')
1812 1813 if 'tags' in copy_filters:
1813 1814 tags =filters.pop('tags')
1814 1815 if 'tags' in fields:
1815 1816 query = query | Q(tags__icontains=tags)
1816 1817 if 'label' in fields:
1817 1818 query = query | Q(label__icontains=tags)
1818 1819 if 'location' in fields:
1819 1820 query = query | Q(location__name__icontains=tags)
1820 1821 if 'device' in fields:
1821 1822 query = query | Q(device__device_type__name__icontains=tags)
1822 1823 query = query | Q(device__location__name__icontains=tags)
1823 1824 if 'device_type' in fields:
1824 1825 query = query | Q(device_type__name__icontains=tags)
1825 1826
1826 1827 if 'mine' in copy_filters:
1827 1828 filters['author_id'] =filters['mine']
1828 1829 filters.pop('mine')
1829 1830 object_list = model.objects.filter(query, **filters).order_by(*order)
1830 1831 paginator = Paginator(object_list, n)
1831 1832
1832 1833 try:
1833 1834 objects = paginator.page(page)
1834 1835 except PageNotAnInteger:
1835 1836 objects = paginator.page(1)
1836 1837 except EmptyPage:
1837 1838 objects = paginator.page(paginator.num_pages)
1838 1839
1839 1840 kwargs['objects'] = objects
1840 1841 kwargs['offset'] = (int(page)-1)*n if page else 0
1841 1842
1842 1843 return kwargs
1843 1844
1844 1845 # def get_paginator(model, page, order, filters={}, n=8):
1845 1846 # kwargs = {}
1846 1847 # query = Q()
1847 1848 # if isinstance(filters, QueryDict):
1848 1849 # filters = filters.dict()
1849 1850 # [filters.pop(key) for key in filters.keys() if filters[key] in ('', ' ')]
1850 1851 # filters.pop('page', None)
1851 1852
1852 1853 # fields = [f.name for f in model._meta.get_fields()]
1853 1854
1854 1855 # if 'template' in filters:
1855 1856 # filters['template'] = True
1856 1857 # if 'historical' in filters:
1857 1858 # filters.pop('historical')
1858 1859 # filters['type'] = 1
1859 1860 # elif 'type' in fields:
1860 1861 # filters['type'] = 0
1861 1862 # if 'start_date' in filters:
1862 1863 # filters['start_date__gte'] = filters.pop('start_date')
1863 1864 # if 'end_date' in filters:
1864 1865 # filters['start_date__lte'] = filters.pop('end_date')
1865 1866 # if 'tags' in filters:
1866 1867 # tags = filters.pop('tags')
1867 1868 # if 'tags' in fields:
1868 1869 # query = query | Q(tags__icontains=tags)
1869 1870 # if 'label' in fields:
1870 1871 # query = query | Q(label__icontains=tags)
1871 1872 # if 'location' in fields:
1872 1873 # query = query | Q(location__name__icontains=tags)
1873 1874 # if 'device' in fields:
1874 1875 # query = query | Q(device__device_type__name__icontains=tags)
1875 1876 # query = query | Q(device__location__name__icontains=tags)
1876 1877 # if 'device_type' in fields:
1877 1878 # query = query | Q(device_type__name__icontains=tags)
1878 1879
1879 1880 # if 'mine' in filters:
1880 1881 # filters['author_id'] = filters['mine']
1881 1882 # filters.pop('mine')
1882 1883 # object_list = model.objects.filter(query, **filters).order_by(*order)
1883 1884 # paginator = Paginator(object_list, n)
1884 1885
1885 1886 # try:
1886 1887 # objects = paginator.page(page)
1887 1888 # except PageNotAnInteger:
1888 1889 # objects = paginator.page(1)
1889 1890 # except EmptyPage:
1890 1891 # objects = paginator.page(paginator.num_pages)
1891 1892
1892 1893 # kwargs['objects'] = objects
1893 1894 # kwargs['offset'] = (int(page)-1)*n if page else 0
1894 1895
1895 1896 # return kwargs
1896 1897
1897 1898
1898 1899 def operation(request, id_camp=None):
1899 1900
1900 1901 kwargs = {}
1901 1902 kwargs['title'] = 'Radars Operation'
1902 1903 kwargs['no_sidebar'] = True
1903 1904 kwargs['menu_operation'] = 'active'
1904 1905 campaigns = Campaign.objects.filter(start_date__lte=datetime.now(),
1905 1906 end_date__gte=datetime.now()).order_by('-start_date')
1906 1907
1907 1908 if id_camp:
1908 1909 campaign = get_object_or_404(Campaign, pk=id_camp)
1909 1910 form = OperationForm(
1910 1911 initial={'campaign': campaign.id}, campaigns=campaigns)
1911 1912 kwargs['campaign'] = campaign
1912 1913 else:
1913 1914 # form = OperationForm(campaigns=campaigns)
1914 1915 kwargs['campaigns'] = campaigns
1915 1916 return render(request, 'operation.html', kwargs)
1916 1917
1917 1918 #---Experiment
1918 1919 keys = ['id', 'name', 'start_time', 'end_time', 'status']
1919 1920 kwargs['experiment_keys'] = keys[1:]
1920 1921 kwargs['experiments'] = experiments
1921 1922 #---Radar
1922 1923 kwargs['locations'] = campaign.get_experiments_by_radar()
1923 1924 kwargs['form'] = form
1924 1925
1925 1926 return render(request, 'operation.html', kwargs)
1926 1927
1927 1928
1928 1929 @login_required
1929 1930 def radar_start(request, id_camp, id_radar):
1930 1931 print("Boton presionados",flush=True)
1931 1932 campaign = get_object_or_404(Campaign, pk=id_camp)
1932 1933 experiments = campaign.get_experiments_by_radar(id_radar)[0]['experiments']
1933 1934 now = datetime.now()
1934 1935
1935 1936 for exp in experiments:
1936 1937 #app.control.revoke(exp.task)
1937 1938 print("----------------------")
1938 1939 print("status:->", exp.status,flush=True)
1939 1940 start = datetime.combine(datetime.now().date(), exp.start_time)
1940 1941 end = datetime.combine(datetime.now().date(), exp.end_time)
1941 1942 print("start exp: ",exp.start_time,flush=True)
1942 1943 print("end exp: ",exp.end_time,flush=True)
1943 1944
1944 1945 print("start comb: ",start,flush=True)
1945 1946 print("end comb: ",end,flush=True)
1946 1947 print(is_aware(start),flush=True)
1947 1948 print("start camp",campaign.start_date,flush=True)
1948 1949 print("end camp",campaign.end_date,flush=True)
1949 1950 print(is_aware(campaign.start_date),flush=True)
1950 1951 if end < start:
1951 1952 end += timedelta(1)
1952 1953
1953 1954 if exp.status == 2:
1954 1955 messages.warning(
1955 1956 request, 'Experiment {} already running'.format(exp))
1956 1957 #continue
1957 1958
1958 1959 if exp.status == 3:
1959 1960 messages.warning(
1960 1961 request, 'Experiment {} already programmed'.format(exp))
1961 1962 #continue
1962 1963
1963 1964 if exp.status == 1:
1964 1965 messages.warning(
1965 1966 request, 'Experiment {} stopped'.format(exp))
1966 1967 #continue
1967 1968
1968 1969 if start > campaign.end_date:
1969 1970 messages.warning(
1970 1971 request, 'Experiment {} out of date'.format(exp))
1971 1972
1972 1973 #app.control.revoke(exp.task)
1973 1974 print("Llego luego del revoke",flush=True)
1974 1975 if now >= start and now <= end:
1975 1976
1976 1977 print("Caso now > start and < end -- (1)",flush=True)
1977 1978
1978 1979 # -------------------------------------------
1979 1980
1980 1981 # task = task_start.delay(exp.id)
1981 1982 # exp.task = task.id
1982 1983 # exp.status = task.get()
1983 1984 # -------------------------------------------
1984 1985
1985 1986 #exp.status = task.wait()
1986 1987
1987 1988 if exp.status == 0:
1988 1989 messages.error(request, 'Experiment {} not start'.format(exp))
1989 1990 if exp.status == 2:
1990 1991 messages.success(request, 'Experiment {} started'.format(exp))
1991 1992 elif now < start:
1992 1993 print("Caso now <= start -- (2)",exp.pk)
1993 1994 #task = task_start.apply_async((exp.pk, ), eta=start)#start+timedelta(hours=5))
1994 1995 # task = task_start.apply_async((exp.pk, ), eta=start+timedelta(hours=5))#)
1995 1996 # exp.task = task.id
1996 1997 # exp.status = 3
1997 1998 messages.success(request, 'Experiment {} programmed to start at {}'.format(exp, start))
1998 1999 else:
1999 2000 print("Caso now > end -- (3)")
2000 2001 exp.status = 4
2001 2002 messages.warning(
2002 2003 request, 'Experiment {} out of date'.format(exp))
2003 2004
2004 2005 exp.save()
2005 2006
2006 2007 return HttpResponseRedirect(reverse('url_operation', args=[id_camp]))
2007 2008
2008 2009
2009 2010 @login_required
2010 2011 def radar_stop(request, id_camp, id_radar):
2011 2012
2012 2013 campaign = get_object_or_404(Campaign, pk=id_camp)
2013 2014 experiments = campaign.get_experiments_by_radar(id_radar)[0]['experiments']
2014 2015 print("Ingreso en stop radar_stop")
2015 2016 #for exp in experiments:
2016 2017
2017 2018 # if exp.task:
2018 2019 # print("Ingreso antes de revoke stop")
2019 2020 # app.control.revoke(exp.task)
2020 2021
2021 2022
2022 2023 # if exp.status == 2: #status 2 es started
2023 2024 # print("llama a exp.stop")
2024 2025 # exp.stop()
2025 2026 # messages.warning(request, 'Experiment {} stopped'.format(exp))
2026 2027 # exp.status = 1
2027 2028 # exp.save()
2028 2029
2029 2030 #return HttpResponseRedirect(reverse('url_operation', args=[id_camp]))
2030 2031
2031 2032
2032 2033 @login_required
2033 2034 def radar_refresh(request, id_camp, id_radar):
2034 2035
2035 2036 campaign = get_object_or_404(Campaign, pk=id_camp)
2036 2037 experiments = campaign.get_experiments_by_radar(id_radar)[0]['experiments']
2037 2038
2038 2039 i = app.control.inspect()
2039 2040 print("inspect",i)
2040 2041 print(i.scheduled())
2041 2042 print(i.scheduled().values())
2042 2043 scheduled = list(i.scheduled().values())[0]
2043 2044 revoked = list(i.revoked().values())[0]
2044 2045
2045 2046 # for exp in experiments:
2046 2047 # if exp.task in revoked:
2047 2048 # exp.status = 1
2048 2049 # elif exp.task in [t['request']['id'] for t in scheduled if 'task_stop' in t['request']['name']]:
2049 2050 # exp.status = 2
2050 2051 # elif exp.task in [t['request']['id'] for t in scheduled if 'task_start' in t['request']['name']]:
2051 2052 # exp.status = 3
2052 2053 # else:
2053 2054 # exp.status = 4
2054 2055 # exp.save()
2055 2056 # return HttpResponseRedirect(reverse('url_operation', args=[id_camp]))
2056 2057
2057 2058 #@login_required
2058 2059 # def revoke_tasks(request, id_camp):
2059 2060
2060 2061 # i = app.control.inspect()
2061 2062 # scheduled = list(i.scheduled().values())[0]
2062 2063 # revoked = list(i.revoked().values())[0]
2063 2064
2064 2065 # for t in scheduled:
2065 2066 # if t['request']['id'] in revoked:
2066 2067 # continue
2067 2068 # app.control.revoke(t['request']['id'])
2068 2069 # exp = Experiment.objects.get(pk=eval(str(t['request']['args']))[0])
2069 2070 # eta = t['eta']
2070 2071 # #task = t['request']['name'].split('.')[-1]
2071 2072 # messages.warning(request, 'Scheduled {} at {} for experiment {} revoked'.format(task, eta, exp.name))
2072 2073
2073 2074 # return HttpResponseRedirect(reverse('url_operation', args=[id_camp]))
2074 2075
2075 2076 # @login_required
2076 2077 # def show_tasks(request, id_camp):
2077 2078
2078 2079 # i = app.control.inspect()
2079 2080 # scheduled = list(i.scheduled().values())[0]
2080 2081 # revoked = list(i.revoked().values())[0]
2081 2082
2082 2083 # for t in scheduled:
2083 2084 # if t['request']['id'] in revoked:
2084 2085 # continue
2085 2086 # exp = Experiment.objects.get(pk=eval(str(t['request']['args']))[0])
2086 2087 # eta = t['eta']
2087 2088 # #task = t['request']['name'].split('.')[-1]
2088 2089 # #messages.success(request, 'Task {} scheduled at {} for experiment {}'.format(task, eta, exp.name))
2089 2090
2090 2091 # return HttpResponseRedirect(reverse('url_operation', args=[id_camp]))
2091 2092
2092 2093 def real_time(request):
2093 2094
2094 2095 graphic_path = "/home/fiorella/Pictures/catwbeanie.jpg"
2095 2096
2096 2097 kwargs = {}
2097 2098 kwargs['title'] = 'CLAIRE'
2098 2099 kwargs['suptitle'] = 'Real Time'
2099 2100 kwargs['no_sidebar'] = True
2100 2101 kwargs['graphic_path'] = graphic_path
2101 2102 kwargs['graphic1_path'] = 'http://www.bluemaize.net/im/girls-accessories/shark-beanie-11.jpg'
2102 2103
2103 2104 return render(request, 'real_time.html', kwargs)
2104 2105
2105 2106 def theme(request, theme):
2106 2107
2107 2108 user = request.user
2108 2109 user.profile.theme = theme
2109 2110 user.save()
2110 2111 return redirect('index')
@@ -1,1051 +1,1051
1 1
2 2
3 3 import ast
4 4 import json
5 5 import requests
6 6 import numpy as np
7 7 from base64 import b64encode
8 8 from struct import pack
9 9
10 10 from django.db import models
11 11 from django.urls import reverse
12 12 from django.core.validators import MinValueValidator, MaxValueValidator
13 13
14 14 from apps.main.models import Configuration
15 15 from apps.main.utils import Params
16 16 from devices.rc import api
17 17 from apps.rc.utils import RCFile
18 18
19 19
20 20 LINE_TYPES = (
21 21 ('none', 'Not used'),
22 22 ('tr', 'Transmission/reception selector signal'),
23 23 ('tx', 'A modulating signal (Transmission pulse)'),
24 24 ('codes', 'BPSK modulating signal'),
25 25 ('windows', 'Sample window signal'),
26 26 ('sync', 'Synchronizing signal'),
27 27 ('flip', 'IPP related periodic signal'),
28 28 ('prog_pulses', 'Programmable pulse'),
29 29 ('mix', 'Mixed line'),
30 30 )
31 31
32 32
33 33 SAMPLING_REFS = (
34 34 ('none', 'No Reference'),
35 35 ('begin_baud', 'Begin of the first baud'),
36 36 ('first_baud', 'Middle of the first baud'),
37 37 ('sub_baud', 'Middle of the sub-baud')
38 38 )
39 39
40 40 DAT_CMDS = {
41 41 # Pulse Design commands
42 42 'DISABLE' : 0, # Disables pulse generation
43 43 'ENABLE' : 24, # Enables pulse generation
44 44 'DELAY_START' : 40, # Write delay status to memory
45 45 'FLIP_START' : 48, # Write flip status to memory
46 46 'SAMPLING_PERIOD' : 64, # Establish Sampling Period
47 47 'TX_ONE' : 72, # Output '0' in line TX
48 48 'TX_ZERO' : 88, # Output '0' in line TX
49 49 'SW_ONE' : 104, # Output '0' in line SW
50 50 'SW_ZERO' : 112, # Output '1' in line SW
51 51 'RESTART': 120, # Restarts CR8 Firmware
52 52 'CONTINUE' : 253, # Function Unknown
53 53 # Commands available to new controllers
54 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.
55 55 'CLOCK_DIVISOR_INIT' : 12, # Specifies Clock Divisor. Legacy command, ignored in the actual .dat conversion
56 56 'CLOCK_DIVISOR_LAST' : 22, # Specifies Clock Divisor (default 60 if not included) syntax: 255,22 254,N-1.
57 57 'CLOCK_DIVIDER' : 8,
58 58 }
59 59
60 60 MAX_BITS = 8
61 61
62 62 # Rotate left: 0b1001 --> 0b0011
63 63 rol = lambda val, r_bits: \
64 64 (val << r_bits%MAX_BITS) & (2**MAX_BITS-1) | \
65 65 ((val & (2**MAX_BITS-1)) >> (MAX_BITS-(r_bits%MAX_BITS)))
66 66
67 67 # Rotate right: 0b1001 --> 0b1100
68 68 ror = lambda val, r_bits: \
69 69 ((val & (2**MAX_BITS-1)) >> r_bits%MAX_BITS) | \
70 70 (val << (MAX_BITS-(r_bits%MAX_BITS)) & (2**MAX_BITS-1))
71 71
72 72
73 73 class RCConfiguration(Configuration):
74 74
75 75 ipp = models.FloatField(verbose_name='IPP [Km]', validators=[MinValueValidator(1)], default=300)
76 76 ntx = models.PositiveIntegerField(verbose_name='Number of TX', validators=[MinValueValidator(1)], default=1)
77 77 clock_in = models.FloatField(verbose_name='Clock in [MHz]', validators=[MinValueValidator(1), MaxValueValidator(80)], default=1)
78 78 clock_divider = models.PositiveIntegerField(verbose_name='Clock divider', validators=[MinValueValidator(1), MaxValueValidator(256)], default=1)
79 79 clock = models.FloatField(verbose_name='Clock Master [MHz]', blank=True, default=1)
80 80 time_before = models.PositiveIntegerField(verbose_name='Time before [&mu;S]', default=12)
81 81 time_after = models.PositiveIntegerField(verbose_name='Time after [&mu;S]', default=1)
82 82 sync = models.PositiveIntegerField(verbose_name='Synchro delay', default=0)
83 83 sampling_reference = models.CharField(verbose_name='Sampling Reference', choices=SAMPLING_REFS, default='none', max_length=40)
84 84 control_tx = models.BooleanField(verbose_name='Control Switch TX', default=False)
85 85 control_sw = models.BooleanField(verbose_name='Control Switch SW', default=False)
86 86 total_units = models.PositiveIntegerField(default=0)
87 87 mix = models.BooleanField(default=False)
88 88
89 89 class Meta:
90 90 db_table = 'rc_configurations'
91 91
92 92 def get_absolute_url_plot(self):
93 93 return reverse('url_plot_rc_pulses', args=[str(self.id)])
94 94
95 95 @property
96 96 def ipp_unit(self):
97 97
98 98 return '{} ({})'.format(self.ipp, int(self.ipp*self.km2unit))
99 99
100 100 @property
101 101 def us2unit(self):
102 102
103 103 return self.clock_in/self.clock_divider
104 104
105 105 @property
106 106 def km2unit(self):
107 107
108 108 return 20./3*(self.clock_in/self.clock_divider)
109 109
110 110 def clone(self, **kwargs):
111 111
112 112 lines = self.get_lines()
113 113 self.pk = None
114 114 self.id = None
115 115 for attr, value in kwargs.items():
116 116 setattr(self, attr, value)
117 117 self.save()
118 118
119 119 for line in lines:
120 120 line.clone(rc_configuration=self)
121 121
122 122 new_lines = self.get_lines()
123 123 for line in new_lines:
124 124 line_params = json.loads(line.params)
125 125 if 'TX_ref' in line_params and (line_params['TX_ref'] != '0'):
126 126 ref_line = RCLine.objects.get(pk=line_params['TX_ref'])
127 127 line_params['TX_ref'] = ['{}'.format(l.pk) for l in new_lines if l.get_name()==ref_line.get_name()][0]
128 128 line.params = json.dumps(line_params)
129 129 line.save()
130 130
131 131 return self
132 132
133 133 def get_lines(self, **kwargs):
134 134 '''
135 135 Retrieve configuration lines
136 136 '''
137 137
138 138 return RCLine.objects.filter(rc_configuration=self.pk, **kwargs)
139 139
140 140
141 141 def clean_lines(self):
142 142 '''
143 143 '''
144 144
145 145 empty_line = RCLineType.objects.get(name='none')
146 146
147 147 for line in self.get_lines():
148 148 line.line_type = empty_line
149 149 line.params = '{}'
150 150 line.save()
151 151
152 152 def dict_to_parms(self, params, id=None):
153 153 '''
154 154 '''
155 155
156 156 if id:
157 157 data = Params(params).get_conf(id_conf=id)
158 158 else:
159 159 data = Params(params).get_conf(dtype='rc')
160 160
161 161 #print(data)
162 162 # self.name = data['name']
163 163 self.ipp = data['ipp']
164 164 self.ntx = data['ntx']
165 165 self.clock_in = data['clock_in']
166 166 self.clock_divider = data['clock_divider']
167 167 self.clock = data['clock']
168 168 self.time_before = data['time_before']
169 169 self.time_after = data['time_after']
170 170 self.sync = data['sync']
171 171 self.sampling_reference = data['sampling_reference']
172 172 self.total_units = self.ipp*self.ntx*self.km2unit
173 173 self.save()
174 174 self.clean_lines()
175 175
176 176 #print(params)
177 177
178 178 positions = {'tx':0, 'tr':0}
179 179 for i, id in enumerate(data['lines']):
180 180 line_data = params['lines']['byId'][id]
181 181 line_type = RCLineType.objects.get(name=line_data['line_type'])
182 182 if line_type.name == 'codes':
183 183 code = RCLineCode.objects.get(name=line_data['params']['code'])
184 184 line_data['params']['code'] = code.pk
185 185 if line_type.name == 'tx':
186 186 position = positions['tx']
187 187 positions['tx'] += 1
188 188 elif line_type.name == 'tr':
189 189 position = positions['tr']
190 190 positions['tr'] += 1
191 191 else:
192 192 position = 0
193 193 line, dum = RCLine.objects.update_or_create(
194 194 rc_configuration=self,
195 195 channel=i,
196 196 position=position,
197 197 defaults={
198 198 'line_type': line_type,
199 199 'params': json.dumps(line_data['params'])
200 200 }
201 201 )
202 print(line,flush=True)
202 # print(line,flush=True)
203 203
204 204 for i, line in enumerate(self.get_lines()):
205 205 line_params = json.loads(line.params)
206 206 print("accedimos a dict_to5",flush=True)
207 207 if 'TX_ref' in line_params:
208 208 if line_params['TX_ref'] in (0, '0'):
209 209 line_params['TX_ref'] = '0'
210 210 else:
211 211 ref_id = '{}'.format(line_params['TX_ref'])
212 212 ref_line = params['lines']['byId'][ref_id]
213 213 line_params['TX_ref'] = RCLine.objects.get(
214 214 rc_configuration=self,
215 215 params=json.dumps(ref_line['params'])
216 216 ).pk
217 217 line.params = json.dumps(line_params)
218 218 print(line.params)
219 219 line.save()
220 220 print("Fin de dict to param")
221 221
222 222 def get_delays(self):
223 223
224 224 pulses = [line.pulses_as_points() for line in self.get_lines()]
225 225 points = [tup for tups in pulses for tup in tups]
226 226 points = set([x for tup in points for x in tup])
227 227 points = list(points)
228 228 points.sort()
229 229
230 230 if points[0]!=0:
231 231 points.insert(0, 0)
232 232
233 233 return [points[i+1]-points[i] for i in range(len(points)-1)]
234 234
235 235
236 236 def get_pulses(self, binary=True):
237 237
238 238 pulses = [line.pulses_as_points() for line in self.get_lines()]
239 239 tuples = [tup for tups in pulses for tup in tups]
240 240 points = set([x for tup in tuples for x in tup])
241 241 points = list(points)
242 242 points.sort()
243 243 states = []
244 244 last = [0 for x in pulses]
245 245
246 246 for x in points:
247 247 dum = []
248 248 for i, tups in enumerate(pulses):
249 249 ups = [tup[0] for tup in tups if tup!=(0,0)]
250 250 dws = [tup[1] for tup in tups if tup!=(0,0)]
251 251 if x in ups:
252 252 dum.append(1)
253 253 elif x in dws:
254 254 dum.append(0)
255 255 else:
256 256 dum.append(last[i])
257 257 states.append(dum)
258 258 last = dum
259 259
260 260 if binary:
261 261 ret = []
262 262 for flips in states:
263 263 flips.reverse()
264 264 ret.append(int(''.join([str(x) for x in flips]), 2))
265 265 states = ret
266 266
267 267 return states[:-1]
268 268
269 269 def add_cmd(self, cmd):
270 270
271 271 if cmd in DAT_CMDS:
272 272 return (255, DAT_CMDS[cmd])
273 273
274 274 def add_data(self, value):
275 275
276 276 return (254, value-1)
277 277
278 278 def parms_to_binary(self, dat=True):
279 279 '''
280 280 Create "dat" stream to be send to CR
281 281 '''
282 282
283 283 data = bytearray()
284 284 # create header
285 285 data.extend(self.add_cmd('DISABLE'))
286 286 data.extend(self.add_cmd('CONTINUE'))
287 287 data.extend(self.add_cmd('RESTART'))
288 288
289 289 if self.control_sw:
290 290 data.extend(self.add_cmd('SW_ONE'))
291 291 else:
292 292 data.extend(self.add_cmd('SW_ZERO'))
293 293
294 294 if self.control_tx:
295 295 data.extend(self.add_cmd('TX_ONE'))
296 296 else:
297 297 data.extend(self.add_cmd('TX_ZERO'))
298 298
299 299 # write divider
300 300 data.extend(self.add_cmd('CLOCK_DIVIDER'))
301 301 data.extend(self.add_data(self.clock_divider))
302 302
303 303 # write delays
304 304 data.extend(self.add_cmd('DELAY_START'))
305 305 # first delay is always zero
306 306 data.extend(self.add_data(1))
307 307
308 308 delays = self.get_delays()
309 309
310 310 for delay in delays:
311 311 while delay>252:
312 312 data.extend(self.add_data(253))
313 313 delay -= 253
314 314 data.extend(self.add_data(int(delay)))
315 315
316 316 # write flips
317 317 data.extend(self.add_cmd('FLIP_START'))
318 318
319 319 states = self.get_pulses(binary=True)
320 320
321 321
322 322 last = 0
323 323 for flip, delay in zip(states, delays):
324 324 data.extend(self.add_data((flip^last)+1))
325 325 last = flip
326 326 while delay>252:
327 327 data.extend(self.add_data(1))
328 328 delay -= 253
329 329
330 330 # write sampling period
331 331 data.extend(self.add_cmd('SAMPLING_PERIOD'))
332 332 wins = self.get_lines(line_type__name='windows')
333 333 if wins:
334 334 win_params = json.loads(wins[0].params)['params']
335 335 if win_params:
336 336 dh = int(win_params[0]['resolution']*self.km2unit)
337 337 else:
338 338 dh = 1
339 339 else:
340 340 dh = 1
341 341 data.extend(self.add_data(dh))
342 342
343 343 # write enable
344 344 data.extend(self.add_cmd('ENABLE'))
345 345
346 346 if not dat:
347 347 return data
348 348
349 349 return '\n'.join(['{}'.format(x) for x in data])
350 350
351 351 def update_pulses(self):
352 352 contador = 0
353 353 for line in self.get_lines():
354 354 contador=contador+1
355 355 print(contador)
356 356 line.update_pulses()
357 357
358 358 def plot_pulses2(self, km=False):
359 359
360 360 import matplotlib
361 361 matplotlib.use('Agg')
362 362 import matplotlib.pyplot as plt
363 363 from bokeh.resources import CDN
364 364 from bokeh.embed import components
365 365 from bokeh.mpl import to_bokeh
366 366 from bokeh.models.tools import WheelZoomTool, ResetTool, PanTool, HoverTool, SaveTool
367 367
368 368 lines = self.get_lines()
369 369
370 370 N = len(lines)
371 371 npoints = self.total_units/self.km2unit if km else self.total_units
372 372 fig = plt.figure(figsize=(12, 2+N*0.5))
373 373 ax = fig.add_subplot(111)
374 374 labels = ['IPP']
375 375
376 376 for i, line in enumerate(lines):
377 377 labels.append(line.get_name(channel=True))
378 378 l = ax.plot((0, npoints),(N-i-1, N-i-1))
379 379 points = [(tup[0], tup[1]-tup[0]) for tup in line.pulses_as_points(km=km) if tup!=(0,0)]
380 380 ax.broken_barh(points, (N-i-1, 0.5),
381 381 edgecolor=l[0].get_color(), facecolor='none')
382 382
383 383 n = 0
384 384 f = ((self.ntx+50)/100)*5 if ((self.ntx+50)/100)*10>0 else 2
385 385 for x in np.arange(0, npoints, self.ipp if km else self.ipp*self.km2unit):
386 386 if n%f==0:
387 387 ax.text(x, N, '%s' % n, size=10)
388 388 n += 1
389 389
390 390 labels.reverse()
391 391 ax.set_yticks(range(len(labels)))
392 392 ax.set_yticklabels(labels)
393 393 ax.set_xlabel = 'Units'
394 394 plot = to_bokeh(fig, use_pandas=False)
395 395 plot.tools = [PanTool(dimensions="width"), WheelZoomTool(dimensions="width"), ResetTool(), SaveTool()]
396 396 plot.toolbar_location="above"
397 397
398 398 return components(plot, CDN)
399 399
400 400 def plot_pulses(self, km=False):
401 401
402 402 from bokeh.plotting import figure
403 403 from bokeh.resources import CDN
404 404 from bokeh.embed import components
405 405 from bokeh.models import FixedTicker, PrintfTickFormatter
406 406 from bokeh.models.tools import WheelZoomTool, ResetTool, PanTool, HoverTool, SaveTool
407 407 from bokeh.models.sources import ColumnDataSource
408 408
409 409 lines = self.get_lines().reverse()
410 410
411 411 N = len(lines)
412 412 npoints = self.total_units/self.km2unit if km else self.total_units
413 413 ipp = self.ipp if km else self.ipp*self.km2unit
414 414
415 415 hover = HoverTool(tooltips=[("Line", "@name"),
416 416 ("IPP", "@ipp"),
417 417 ("X", "@left")])
418 418
419 419 tools = [PanTool(dimensions="width"),
420 420 WheelZoomTool(dimensions="width"),
421 421 hover, SaveTool()]
422 422
423 423 plot = figure(width=1000,
424 424 height=40+N*50,
425 425 y_range = (0, N),
426 426 tools=tools,
427 427 toolbar_location='above',
428 428 toolbar_sticky=False,)
429 429
430 430 plot.xaxis.axis_label = 'Km' if km else 'Units'
431 431 plot.xaxis[0].formatter = PrintfTickFormatter(format='%d')
432 432 plot.yaxis.axis_label = 'Pulses'
433 433 plot.yaxis[0].ticker=FixedTicker(ticks=list(range(N)))
434 434 plot.yaxis[0].formatter = PrintfTickFormatter(format='Line %d')
435 435
436 436 for i, line in enumerate(lines):
437 437
438 438 points = [tup for tup in line.pulses_as_points(km=km) if tup!=(0,0)]
439 439
440 440 source = ColumnDataSource(data = dict(
441 441 bottom = [i for tup in points],
442 442 top = [i+0.5 for tup in points],
443 443 left = [tup[0] for tup in points],
444 444 right = [tup[1] for tup in points],
445 445 ipp = [int(tup[0]/ipp) for tup in points],
446 446 name = [line.get_name() for tup in points]
447 447 ))
448 448
449 449 plot.quad(
450 450 bottom = 'bottom',
451 451 top = 'top',
452 452 left = 'left',
453 453 right = 'right',
454 454 source = source,
455 455 fill_alpha = 0,
456 456 #line_color = 'blue',
457 457 )
458 458
459 459 plot.line([0, npoints], [i, i])#, color='blue')
460 460
461 461 return components(plot, CDN)
462 462
463 463 def request(self, cmd, method='get', **kwargs):
464 464
465 465 req = getattr(requests, method)(self.device.url(cmd), **kwargs)
466 466 payload = req.json()
467 467
468 468 return payload
469 469
470 470 def status_device(self):
471 471
472 472 try:
473 473 self.device.status = 0
474 474 payload = self.request('status')
475 475 if payload['status']=='enable':
476 476 self.device.status = 3
477 477 elif payload['status']=='disable':
478 478 self.device.status = 2
479 479 else:
480 480 self.device.status = 1
481 481 self.device.save()
482 482 self.message = 'RC status: {}'.format(payload['status'])
483 483 return False
484 484 except Exception as e:
485 485 if 'No route to host' not in str(e):
486 486 self.device.status = 4
487 487 self.device.save()
488 488 self.message = 'RC status: {}'.format(str(e))
489 489 return False
490 490
491 491 self.device.save()
492 492 return True
493 493
494 494 def reset_device(self):
495 495
496 496 try:
497 497 payload = self.request('reset', 'post')
498 498 if payload['reset']=='ok':
499 499 self.message = 'RC restarted OK'
500 500 self.device.status = 2
501 501 self.device.save()
502 502 else:
503 503 self.message = 'RC restart fail'
504 504 self.device.status = 4
505 505 self.device.save()
506 506 except Exception as e:
507 507 self.message = 'RC reset: {}'.format(str(e))
508 508 return False
509 509
510 510 return True
511 511
512 512 def stop_device(self):
513 513
514 514 try:
515 515 payload = self.request('stop', 'post')
516 516 self.message = 'RC stop: {}'.format(payload['stop'])
517 517 if payload['stop']=='ok':
518 518 self.device.status = 2
519 519 self.device.save()
520 520 else:
521 521 self.device.status = 4
522 522 self.device.save()
523 523 return False
524 524 except Exception as e:
525 525 if 'No route to host' not in str(e):
526 526 self.device.status = 4
527 527 else:
528 528 self.device.status = 0
529 529 self.message = 'RC stop: {}'.format(str(e))
530 530 self.device.save()
531 531 return False
532 532
533 533 return True
534 534
535 535 def start_device(self):
536 536
537 537 try:
538 538 payload = self.request('start', 'post')
539 539 self.message = 'RC start: {}'.format(payload['start'])
540 540 if payload['start']=='ok':
541 541 self.device.status = 3
542 542 self.device.save()
543 543 else:
544 544 return False
545 545 except Exception as e:
546 546 if 'No route to host' not in str(e):
547 547 self.device.status = 4
548 548 else:
549 549 self.device.status = 0
550 550 self.message = 'RC start: {}'.format(str(e))
551 551 self.device.save()
552 552 return False
553 553
554 554 return True
555 555
556 556 def write_device(self, raw=False):
557 557 print("write device",flush=True)
558 558
559 559 if not raw:
560 560 clock = RCClock.objects.get(rc_configuration=self)
561 561 if clock.mode:
562 562 data = {'default': clock.frequency}
563 563 else:
564 564 data = {'manual': [clock.multiplier, clock.divisor, clock.reference]}
565 565 payload = self.request('setfreq', 'post', data=json.dumps(data))
566 print(payload)
566 # print(payload)
567 567 if payload['command'] != 'ok':
568 568 self.message = 'RC write: {}'.format(payload['command'])
569 print('RC write: {}'.format(payload['command']))
569 # print('RC write: {}'.format(payload['command']))
570 570 else:
571 571 self.message = payload['programming']
572 572 if payload['programming'] == 'fail':
573 573 self.message = 'RC write: error programming CGS chip'
574 574
575 575 values = []
576 576 for pulse, delay in zip(self.get_pulses(), self.get_delays()):
577 577 while delay > 65536:
578 578 values.append((pulse, 65535))
579 579 delay -= 65536
580 580 values.append((pulse, delay-1))
581 581 data = bytearray()
582 582 #reset
583 583 data.extend((128, 0))
584 584 #disable
585 585 data.extend((129, 0))
586 586 #SW switch
587 587 if self.control_sw:
588 588 data.extend((130, 2))
589 589 else:
590 590 data.extend((130, 0))
591 591 #divider
592 592 data.extend((131, self.clock_divider-1))
593 593 #enable writing
594 594 data.extend((139, 62))
595 595
596 596 last = 0
597 597 for tup in values:
598 598 vals = pack('<HH', last^tup[0], tup[1])
599 599 last = tup[0]
600 600 data.extend((133, vals[1], 132, vals[0], 133, vals[3], 132, vals[2]))
601 601
602 602 #enable
603 603 data.extend((129, 1))
604 604
605 605 if raw:
606 606 return b64encode(data)
607 607
608 608 #try:
609 609 payload = self.request('stop', 'post')
610 610 payload = self.request('reset', 'post')
611 611 #payload = self.request('divider', 'post', data={'divider': self.clock_divider-1})
612 612 #payload = self.request('write', 'post', data=b64encode(bytearray((139, 62))), timeout=20)
613 613 n = len(data)
614 614 x = 0
615 615 #while x < n:
616 616 payload = self.request('write', 'post', data=b64encode(data))
617 617 # x += 1024
618 618
619 619 if payload['write']=='ok':
620 620 self.device.status = 3
621 621 self.device.save()
622 622 self.message = 'RC configured and started'
623 print('RC configured and started')
623 # print('RC configured and started')
624 624 else:
625 625 self.device.status = 1
626 626 self.device.save()
627 627 self.message = 'RC write: {}'.format(payload['write'])
628 print('RC write: {}'.format(payload['write']))
628 # print('RC write: {}'.format(payload['write']))
629 629 return False
630 630
631 631 #payload = self.request('start', 'post')
632 632
633 633 #except Exception as e:
634 634 # if 'No route to host' not in str(e):
635 635 # self.device.status = 4
636 636 # else:
637 637 # self.device.status = 0
638 638 # self.message = 'RC write: {}'.format(str(e))
639 639 # self.device.save()
640 640 # return False
641 641
642 642 return True
643 643
644 644
645 645 def get_absolute_url_import(self):
646 646 return reverse('url_import_rc_conf', args=[str(self.id)])
647 647
648 648
649 649 class RCLineCode(models.Model):
650 650
651 651 name = models.CharField(max_length=40)
652 652 bits_per_code = models.PositiveIntegerField(default=0)
653 653 number_of_codes = models.PositiveIntegerField(default=0)
654 654 codes = models.TextField(blank=True, null=True)
655 655
656 656 class Meta:
657 657 db_table = 'rc_line_codes'
658 658 ordering = ('name',)
659 659
660 660 def __str__(self):
661 661 return u'%s' % self.name
662 662
663 663
664 664 class RCLineType(models.Model):
665 665
666 666 name = models.CharField(choices=LINE_TYPES, max_length=40)
667 667 description = models.TextField(blank=True, null=True)
668 668 params = models.TextField(default='[]')
669 669
670 670 class Meta:
671 671 db_table = 'rc_line_types'
672 672
673 673 def __str__(self):
674 674 return u'%s - %s' % (self.name.upper(), self.get_name_display())
675 675
676 676
677 677 class RCLine(models.Model):
678 678
679 679 rc_configuration = models.ForeignKey('RCConfiguration', on_delete=models.CASCADE)
680 680 line_type = models.ForeignKey('RCLineType',on_delete=models.CASCADE)
681 681 channel = models.PositiveIntegerField(default=0)
682 682 position = models.PositiveIntegerField(default=0)
683 683 params = models.TextField(default='{}')
684 684 pulses = models.TextField(default='')
685 685
686 686 class Meta:
687 687 db_table = 'rc_lines'
688 688 ordering = ['channel']
689 689
690 690 def __str__(self):
691 print("AAAA: ",self.rc_configuration,flush=True)
692 ret = u'{}|{} - {}'.format(self.pk, self.get_name(),self.rc_configuration.name)
693 return ret
694 # if self.rc_configuration:
695 # return u'{}|{} - {}'.format(self.pk, self.get_name(), self.rc_configuration.name)
691 # print("AAAA: ",self.rc_configuration,flush=True)
692 # ret = u'{}|{} - {}'.format(self.pk, self.get_name(),self.rc_configuration.name)
693 # return ret
694 if self.rc_configuration:
695 return u'{}|{} - {}'.format(self.pk, self.get_name(), self.rc_configuration.name)
696 696
697 697 def jsonify(self):
698 698
699 699 data = {}
700 700 data['params'] = json.loads(self.params)
701 701 data['id'] = '{}'.format(self.pk)
702 702 data['line_type'] = self.line_type.name
703 703 data['name'] = self.get_name()
704 704 if data['line_type']=='codes':
705 705 data['params']['code'] = RCLineCode.objects.get(pk=data['params']['code']).name
706 706
707 707 return data
708 708
709 709
710 710 def clone(self, **kwargs):
711 711
712 712 self.pk = None
713 713 self.id = None
714 714
715 715 for attr, value in kwargs.items():
716 716 setattr(self, attr, value)
717 717
718 718 self.save()
719 719
720 720 return self
721 721
722 722 def get_name(self, channel=False):
723 723
724 724 chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
725 725 s = ''
726 726
727 727 if self.line_type.name in ('tx',):
728 728 s = chars[self.position]
729 729 elif self.line_type.name in ('codes', 'windows', 'tr'):
730 730 if 'TX_ref' in json.loads(self.params):
731 731 pk = json.loads(self.params)['TX_ref']
732 732 if pk in (0, '0'):
733 733 s = ','.join(chars[l.position] for l in self.rc_configuration.get_lines(line_type__name='tx'))
734 734 else:
735 735 ref = RCLine.objects.get(pk=pk)
736 736 s = chars[ref.position]
737 737 s = '({})'.format(s)
738 738
739 739 s = '{}{}'.format(self.line_type.name.upper(), s)
740 740
741 741 if channel:
742 742 return '{} {}'.format(s, self.channel)
743 743 else:
744 744 return s
745 745
746 746 def get_lines(self, **kwargs):
747 747
748 748 return RCLine.objects.filter(rc_configuration=self.rc_configuration, **kwargs)
749 749
750 750 def pulses_as_array(self):
751 751
752 752 y = np.zeros(self.rc_configuration.total_units)
753 753
754 754 for tup in ast.literal_eval(self.pulses):
755 755 y[tup[0]:tup[1]] = 1
756 756
757 757 return y.astype(np.int8)
758 758
759 759 def pulses_as_points(self, km=False):
760 760
761 761 if km:
762 762 unit2km = 1/self.rc_configuration.km2unit
763 763 return [(tup[0]*unit2km, tup[1]*unit2km) for tup in ast.literal_eval(self.pulses)]
764 764 else:
765 765 return ast.literal_eval(self.pulses)
766 766
767 767 def get_win_ref(self, params, tx_id, km2unit):
768 768
769 769 ref = self.rc_configuration.sampling_reference
770 770 codes = [line for line in self.get_lines(line_type__name='codes') if int(json.loads(line.params)['TX_ref'])==int(tx_id)]
771 771
772 772 if codes:
773 773 tx_width = float(json.loads(RCLine.objects.get(pk=tx_id).params)['pulse_width'])*km2unit/len(json.loads(codes[0].params)['codes'][0])
774 774 else:
775 775 tx_width = float(json.loads(RCLine.objects.get(pk=tx_id).params)['pulse_width'])*km2unit
776 776
777 777 if ref=='first_baud':
778 778 return int(1 + round((tx_width + 1)/2 + params['first_height']*km2unit - params['resolution']*km2unit))
779 779 elif ref=='sub_baud':
780 780 return np.ceil(1 + params['first_height']*km2unit - params['resolution']*km2unit/2)
781 781 else:
782 782 return 0
783 783
784 784 def update_pulses(self):
785 785 '''
786 786 Update pulses field
787 787 '''
788 788
789 789 km2unit = self.rc_configuration.km2unit
790 790 us2unit = self.rc_configuration.us2unit
791 791 ipp = self.rc_configuration.ipp
792 792 ntx = int(self.rc_configuration.ntx)
793 793 ipp_u = int(ipp*km2unit)
794 794 total = ipp_u*ntx if self.rc_configuration.total_units==0 else self.rc_configuration.total_units
795 795 y = []
796 796
797 797 if self.line_type.name=='tr':
798 798 tr_params = json.loads(self.params)
799 799 #print(tr_params)
800 800 #print(tr_params['TX_ref'])
801 801 if tr_params['TX_ref'] in ('0', 0):
802 802 txs = self.get_lines(line_type__name='tx')
803 803 else:
804 804 txs = RCLine.objects.filter(pk=tr_params['TX_ref'])
805 805
806 806 for tx in txs:
807 807 params = json.loads(tx.params)
808 808
809 809 if float(params['pulse_width'])==0:
810 810 continue
811 811 delays = [float(d)*km2unit for d in params['delays'].split(',') if d]
812 812 width = float(params['pulse_width'])*km2unit+int(self.rc_configuration.time_before*us2unit)
813 813 before = 0
814 814 after = int(self.rc_configuration.time_after*us2unit)
815 815
816 816 y_tx = self.points(ntx, ipp_u, width,
817 817 delay=delays,
818 818 before=before,
819 819 after=after,
820 820 sync=self.rc_configuration.sync)
821 821
822 822 ranges = params['range'].split(',')
823 823
824 824 if len(ranges)>0 and ranges[0]!='0':
825 825 y_tx = self.mask_ranges(y_tx, ranges)
826 826
827 827 tr_ranges = tr_params['range'].split(',')
828 828
829 829 if len(tr_ranges)>0 and tr_ranges[0]!='0':
830 830 y_tx = self.mask_ranges(y_tx, tr_ranges)
831 831
832 832 y.extend(y_tx)
833 833
834 834 self.pulses = str(y)
835 835 y = self.array_to_points(self.pulses_as_array())
836 836
837 837 elif self.line_type.name=='tx':
838 838 params = json.loads(self.params)
839 839 delays = [float(d)*km2unit for d in params['delays'].split(',') if d]
840 840 width = float(params['pulse_width'])*km2unit
841 841
842 842 if width>0:
843 843 before = int(self.rc_configuration.time_before*us2unit)
844 844 after = 0
845 845
846 846 y = self.points(ntx, ipp_u, width,
847 847 delay=delays,
848 848 before=before,
849 849 after=after,
850 850 sync=self.rc_configuration.sync)
851 851
852 852 ranges = params['range'].split(',')
853 853
854 854 if len(ranges)>0 and ranges[0]!='0':
855 855 y = self.mask_ranges(y, ranges)
856 856
857 857 elif self.line_type.name=='flip':
858 858 n = float(json.loads(self.params)['number_of_flips'])
859 859 width = n*ipp*km2unit
860 860 y = self.points(int((ntx+1)/(2*n)), ipp_u*n*2, width)
861 861
862 862 elif self.line_type.name=='codes':
863 863 params = json.loads(self.params)
864 864 tx = RCLine.objects.get(pk=params['TX_ref'])
865 865 tx_params = json.loads(tx.params)
866 866 delays = [float(d)*km2unit for d in tx_params['delays'].split(',') if d]
867 867 f = int(float(tx_params['pulse_width'])*km2unit/len(params['codes'][0]))
868 868 codes = [(np.fromstring(''.join([s*f for s in code]), dtype=np.uint8)-48).astype(np.int8) for code in params['codes']]
869 869 codes = [self.array_to_points(code) for code in codes]
870 870 n = len(codes)
871 871
872 872 ranges = tx_params['range'].split(',')
873 873 if len(ranges)>0 and ranges[0]!='0':
874 874 dum = self.mask_ranges(tx.pulses_as_points(), ranges)
875 875 else:
876 876 dum = tx.pulses_as_points()
877 877
878 878 for i, tup in enumerate(dum):
879 879 if tup==(0,0): continue
880 880 code = codes[i%n]
881 881 y.extend([(c[0]+tup[0], c[1]+tup[0]) for c in code])
882 882
883 883 elif self.line_type.name=='sync':
884 884 params = json.loads(self.params)
885 885 n = ipp_u*ntx
886 886 if params['invert'] in ('1', 1):
887 887 y = [(n-1, n)]
888 888 else:
889 889 y = [(0, 1)]
890 890
891 891 elif self.line_type.name=='prog_pulses':
892 892 params = json.loads(self.params)
893 893 if int(params['periodic'])==0:
894 894 nntx = 1
895 895 nipp = ipp_u*ntx
896 896 else:
897 897 nntx = ntx
898 898 nipp = ipp_u
899 899
900 900 if 'params' in params and len(params['params'])>0:
901 901 for p in params['params']:
902 902 y_pp = self.points(nntx, nipp,
903 903 p['end']-p['begin'],
904 904 before=p['begin'])
905 905
906 906 y.extend(y_pp)
907 907
908 908 elif self.line_type.name=='windows':
909 909 params = json.loads(self.params)
910 910 if 'params' in params and len(params['params'])>0:
911 911 tx = RCLine.objects.get(pk=params['TX_ref'])
912 912 tx_params = json.loads(tx.params)
913 913 ranges = tx_params['range'].split(',')
914 914 for p in params['params']:
915 915 y_win = self.points(ntx, ipp_u,
916 916 p['resolution']*p['number_of_samples']*km2unit,
917 917 before=int(self.rc_configuration.time_before*us2unit)+p['first_height']*km2unit,
918 918 sync=self.rc_configuration.sync+self.get_win_ref(p, params['TX_ref'], km2unit))
919 919
920 920
921 921 if len(ranges)>0 and ranges[0]!='0':
922 922 y_win = self.mask_ranges(y_win, ranges)
923 923
924 924 y.extend(y_win)
925 925
926 926 elif self.line_type.name=='mix':
927 927 values = self.rc_configuration.parameters.split('-')
928 928 confs = [RCConfiguration.objects.get(pk=value.split('|')[0]) for value in values]
929 929 modes = [value.split('|')[1] for value in values]
930 930 ops = [value.split('|')[2] for value in values]
931 931 delays = [value.split('|')[3] for value in values]
932 932 masks = [value.split('|')[4] for value in values]
933 933 print("masks")
934 934 print(masks)
935 935 print('{:8b}'.format(int(masks[0])))
936 936 mask = list('{:8b}'.format(int(masks[0])))
937 937 print("mask")
938 938 print(mask)
939 939 mask.reverse()
940 940 print("mask reverse")
941 941 print(mask)
942 942 if mask[self.channel] in ('0', '', ' '):
943 943 y = np.zeros(confs[0].total_units, dtype=np.int8)
944 944 else:
945 945 y = confs[0].get_lines(channel=self.channel)[0].pulses_as_array()
946 946
947 947 for i in range(1, len(values)):
948 948 mask = list('{:8b}'.format(int(masks[i])))
949 949 mask.reverse()
950 950
951 951 if mask[self.channel] in ('0', '', ' '):
952 952 continue
953 953 Y = confs[i].get_lines(channel=self.channel)[0].pulses_as_array()
954 954 delay = float(delays[i])*km2unit
955 955
956 956 if modes[i]=='P':
957 957 if delay>0:
958 958 if delay<self.rc_configuration.ipp*km2unit and len(Y)==len(y):
959 959 y_temp = np.empty_like(Y)
960 960 y_temp[:delay] = 0
961 961 y_temp[delay:] = Y[:-delay]
962 962 elif delay+len(Y)>len(y):
963 963 y_new = np.zeros(delay+len(Y), dtype=np.int8)
964 964 y_new[:len(y)] = y
965 965 y = y_new
966 966 y_temp = np.zeros(delay+len(Y), dtype=np.int8)
967 967 y_temp[-len(Y):] = Y
968 968 elif delay+len(Y)==len(y):
969 969 y_temp = np.zeros(delay+len(Y))
970 970 y_temp[-len(Y):] = Y
971 971 elif delay+len(Y)<len(y):
972 972 y_temp = np.zeros(len(y), dtype=np.int8)
973 973 y_temp[delay:delay+len(Y)] = Y
974 974 else:
975 975 y_temp = Y.copy()
976 976
977 977 if ops[i]=='OR':
978 978 y = y | y_temp
979 979 elif ops[i]=='XOR':
980 980 y = y ^ y_temp
981 981 elif ops[i]=='AND':
982 982 y = y & y_temp
983 983 elif ops[i]=='NAND':
984 984 y = y & ~y_temp
985 985 else:
986 986 y = np.concatenate([y, Y])
987 987
988 988 total = len(y)
989 989 y = self.array_to_points(y)
990 990
991 991 else:
992 992 y = []
993 993
994 994 if self.rc_configuration.total_units != total:
995 995 self.rc_configuration.total_units = total
996 996 self.rc_configuration.save()
997 997
998 998 self.pulses = str(y)
999 999 self.save()
1000 1000
1001 1001 @staticmethod
1002 1002 def array_to_points(X):
1003 1003
1004 1004 if X.size==0:
1005 1005 return []
1006 1006
1007 1007 d = X[1:]-X[:-1]
1008 1008
1009 1009 up = np.where(d==1)[0]
1010 1010 if X[0]==1:
1011 1011 up = np.concatenate((np.array([-1]), up))
1012 1012 up += 1
1013 1013
1014 1014 dw = np.where(d==-1)[0]
1015 1015 if X[-1]==1:
1016 1016 dw = np.concatenate((dw, np.array([len(X)-1])))
1017 1017 dw += 1
1018 1018
1019 1019 return [(tup[0], tup[1]) for tup in zip(up, dw)]
1020 1020
1021 1021 @staticmethod
1022 1022 def mask_ranges(Y, ranges):
1023 1023
1024 1024 y = [(0, 0) for __ in Y]
1025 1025
1026 1026 for index in ranges:
1027 1027 if '-' in index:
1028 1028 args = [int(a) for a in index.split('-')]
1029 1029 y[args[0]-1:args[1]] = Y[args[0]-1:args[1]]
1030 1030 else:
1031 1031 y[int(index)-1] = Y[int(index)-1]
1032 1032
1033 1033 return y
1034 1034
1035 1035 @staticmethod
1036 1036 def points(ntx, ipp, width, delay=[0], before=0, after=0, sync=0):
1037 1037
1038 1038 delays = len(delay)
1039 1039
1040 1040 Y = [(int(ipp*x+before+delay[x%delays]+sync), int(ipp*x+width+before+delay[x%delays]+after+sync)) for x in range(ntx)]
1041 1041
1042 1042 return Y
1043 1043
1044 1044 class RCClock(models.Model):
1045 1045
1046 1046 rc_configuration = models.ForeignKey('RCConfiguration', on_delete=models.CASCADE)
1047 1047 mode = models.BooleanField(default=True, choices=((True, 'Auto'), (False, 'Manual')))
1048 1048 multiplier = models.PositiveIntegerField(default=60)
1049 1049 divisor = models.PositiveIntegerField(default=10)
1050 1050 reference = models.PositiveSmallIntegerField(default=1, choices=((0, 'Internal (25MHz)'), (1, 'External (10MHz)')))
1051 1051 frequency = models.FloatField(default=60.0) No newline at end of file
@@ -1,444 +1,444
1 1
2 2 import json
3 3
4 4 from django.contrib import messages
5 5 from django.utils.safestring import mark_safe
6 6 from django.shortcuts import render, redirect, get_object_or_404, HttpResponse
7 7 from django.contrib.auth.decorators import login_required
8 8
9 9 from apps.main.models import Experiment, Device
10 10 from apps.main.views import sidebar
11 11
12 12 from .models import RCConfiguration, RCLine, RCLineType, RCLineCode, RCClock
13 13 from .forms import RCConfigurationForm, RCLineForm, RCLineViewForm, RCLineEditForm, RCImportForm, RCLineCodesForm, RCClockForm
14 14
15 15
16 16 def conf(request, conf_id):
17 17
18 18 conf = get_object_or_404(RCConfiguration, pk=conf_id)
19 19
20 20 lines = RCLine.objects.filter(rc_configuration=conf).order_by('channel')
21 21 clk = RCClock.objects.filter(rc_configuration=conf).first()
22 22 if clk is None:
23 23 clk = RCClock(rc_configuration=conf)
24 24 clk.save()
25 25
26 26 for line in lines:
27 27 params = json.loads(line.params)
28 28 line.form = RCLineViewForm(extra_fields=params, line=line)
29 29 if 'params' in params:
30 30 line.subforms = [RCLineViewForm(extra_fields=fields, line=line, subform=True) for fields in params['params']]
31 31
32 32 kwargs = {}
33 33 kwargs['clock'] = clk
34 34 kwargs['dev_conf'] = conf
35 35 kwargs['rc_lines'] = lines
36 36 kwargs['dev_conf_keys'] = ['ipp_unit', 'ntx', 'clock_divider', 'clock',
37 37 'time_before', 'time_after', 'sync', 'sampling_reference',
38 38 'control_tx', 'control_sw']
39 39
40 40 kwargs['title'] = 'Configuration'
41 41 kwargs['suptitle'] = 'Detail'
42 42
43 43 kwargs['button'] = 'Edit Configuration'
44 44 ###### SIDEBAR ######
45 45 kwargs.update(sidebar(conf=conf))
46 46
47 47 return render(request, 'rc_conf.html', kwargs)
48 48
49 49 @login_required
50 50 def conf_edit(request, conf_id):
51 51
52 52 conf = get_object_or_404(RCConfiguration, pk=conf_id)
53 53 clock = RCClock.objects.get(rc_configuration=conf)
54 54 lines = RCLine.objects.filter(rc_configuration=conf).order_by('channel')
55 55
56 56 for line in lines:
57 57 params = json.loads(line.params)
58 58 #print(params)
59 59 line.form = RCLineEditForm(conf=conf, line=line, extra_fields=params)
60 60 line.subform = False
61 61
62 62 if 'params' in params:
63 63 line.subforms = [RCLineEditForm(extra_fields=fields, line=line, subform=i) for i, fields in enumerate(params['params'])]
64 64 line.subform = True
65 65 print(params)
66 66 print("fin de sub carga de params")
67 67 #print("fin de carga de params")
68 68 if request.method=='GET':
69 69 print("GET case")
70 70 form = RCConfigurationForm(instance=conf)
71 71 form_clock = RCClockForm(instance=clock)
72 72
73 73 elif request.method=='POST':
74 74 #print("ingreso a post conf edit")
75 75 line_data = {}
76 76 conf_data = {}
77 77 clock_data = {}
78 78 extras = []
79 79 print("Inicio impresion POST#####")
80 80 print(request.POST.items)
81 81 print("Fin impresion de POST items#####")
82 82 #classified post fields
83 83 for label,value in request.POST.items():
84 84 if label=='csrfmiddlewaretoken':
85 85 continue
86 86
87 87 if label.count('|')==0:
88 88 if label in ('mode', 'multiplier', 'divisor', 'reference', 'frequency'):
89 89 clock_data[label] = value
90 90 else:
91 91 conf_data[label] = value
92 92 continue
93 93
94 94 elif label.split('|')[0]!='-1':
95 95 extras.append(label)
96 96 continue
97 97
98 98 #print(label)
99 99 x, pk, name = label.split('|')
100 100
101 101 if name=='codes':
102 102 value = [s for s in value.split('\r\n') if s]
103 103
104 104 if pk in line_data:
105 105 line_data[pk][name] = value
106 106 else:
107 107 line_data[pk] = {name:value}
108 108 #print(line_data[pk])
109 109 #update conf
110 110
111 111 form_clock = RCClockForm(clock_data, instance=clock)
112 112 form = RCConfigurationForm(conf_data, instance=conf)
113 113
114 114 #print(request.POST.items())
115 115
116 116 if form_clock.is_valid() and form.is_valid():
117 117 form_clock.save()
118 118 form.save()
119 119
120 120 #update lines fields
121 121 extras.sort()
122 122 #print("Inicio extras")
123 123 #print(extras)
124 124 #print("Fin extras")
125 125 for label in extras:
126 126 x, pk, name = label.split('|')
127 127 if pk not in line_data:
128 128 line_data[pk] = {}
129 129 if 'params' not in line_data[pk]:
130 130 line_data[pk]['params'] = []
131 131 if len(line_data[pk]['params'])<int(x)+1:
132 132 line_data[pk]['params'].append({})
133 133 line_data[pk]['params'][int(x)][name] = float(request.POST[label])
134 134
135 135 for pk, params in line_data.items():
136 136 line = RCLine.objects.get(pk=pk)
137 137 if line.line_type.name in ('windows', 'prog_pulses'):
138 138 if 'params' not in params:
139 139 params['params'] = []
140 140 line.params = json.dumps(params)
141 141 #print(line.params)
142 142 line.save()
143 143
144 144
145 145 #update pulses field
146 146 conf.update_pulses()
147 147
148 148 messages.success(request, 'RC Configuration successfully updated')
149 149
150 150 return redirect(conf.get_absolute_url())
151 151
152 152 kwargs = {}
153 153 kwargs['dev_conf'] = conf
154 154 kwargs['form'] = form
155 155 kwargs['form_clock'] = form_clock
156 156 kwargs['rc_lines'] = lines
157 157 kwargs['edit'] = True
158 158
159 159 kwargs['title'] = 'RC Configuration'
160 160 kwargs['suptitle'] = 'Edit'
161 161 kwargs['button'] = 'Update'
162 162
163 163 return render(request, 'rc_conf_edit.html', kwargs)
164 164
165 165
166 166 def add_line(request, conf_id, line_type_id=None, code_id=None):
167 167
168 168 conf = get_object_or_404(RCConfiguration, pk=conf_id)
169 169
170 170 if request.method=='GET':
171 171 if line_type_id:
172 172 line_type = get_object_or_404(RCLineType, pk=line_type_id)
173 173
174 174 if code_id:
175 175 form = RCLineForm(initial={'rc_configuration':conf_id, 'line_type': line_type_id, 'code_id': code_id},
176 176 extra_fields=json.loads(line_type.params))
177 177 else:
178 178 form = RCLineForm(initial={'rc_configuration':conf_id, 'line_type': line_type_id},
179 179 extra_fields=json.loads(line_type.params))
180 180 else:
181 181 line_type = {'id':0}
182 182 form = RCLineForm(initial={'rc_configuration':conf_id})
183 183
184 184 if request.method=='POST':
185 185
186 186 line_type = get_object_or_404(RCLineType, pk=line_type_id)
187 187 form = RCLineForm(request.POST,
188 188 extra_fields=json.loads(line_type.params))
189 189
190 190 if form.is_valid():
191 191 form.save()
192 192 form.instance.update_pulses()
193 193 return redirect('url_edit_rc_conf', conf.id)
194 194
195 195 kwargs = {}
196 196 kwargs['form'] = form
197 197 kwargs['title'] = 'RC Configuration'
198 198 kwargs['suptitle'] = 'Add Line'
199 199 kwargs['button'] = 'Add'
200 200 kwargs['previous'] = conf.get_absolute_url_edit()
201 201 kwargs['dev_conf'] = conf
202 202 kwargs['line_type'] = line_type
203 203
204 204 return render(request, 'rc_add_line.html', kwargs)
205 205
206 206 def edit_codes(request, conf_id, line_id, code_id=None):
207 207
208 208 conf = get_object_or_404(RCConfiguration, pk=conf_id)
209 209 line = get_object_or_404(RCLine, pk=line_id)
210 210 params = json.loads(line.params)
211 211
212 212 if request.method=='GET':
213 213 if code_id:
214 214 code = get_object_or_404(RCLineCode, pk=code_id)
215 215 form = RCLineCodesForm(instance=code)
216 216 else:
217 217 initial = {'code': params['code'],
218 218 'codes': params['codes'] if 'codes' in params else [],
219 219 'number_of_codes': len(params['codes']) if 'codes' in params else 0,
220 220 'bits_per_code': len(params['codes'][0]) if 'codes' in params else 0,
221 221 }
222 222 form = RCLineCodesForm(initial=initial)
223 223
224 224 if request.method=='POST':
225 225 form = RCLineCodesForm(request.POST)
226 226 if form.is_valid():
227 227 params['code'] = request.POST['code']
228 228 params['codes'] = [s for s in request.POST['codes'].split('\r\n') if s]
229 229 line.params = json.dumps(params)
230 230 line.save()
231 231 messages.success(request, 'Line: "%s" has been updated.' % line)
232 232 return redirect('url_edit_rc_conf', conf.id)
233 233
234 234 kwargs = {}
235 235 kwargs['form'] = form
236 236 kwargs['title'] = line
237 237 kwargs['suptitle'] = 'Edit'
238 238 kwargs['button'] = 'Update'
239 239 kwargs['dev_conf'] = conf
240 240 kwargs['previous'] = conf.get_absolute_url_edit()
241 241 kwargs['line'] = line
242 242
243 243 return render(request, 'rc_edit_codes.html', kwargs)
244 244
245 245 def add_subline(request, conf_id, line_id):
246 246
247 247 conf = get_object_or_404(RCConfiguration, pk=conf_id)
248 248 line = get_object_or_404(RCLine, pk=line_id)
249 249
250 250 if request.method == 'POST':
251 251 if line:
252 252 params = json.loads(line.params)
253 253 subparams = json.loads(line.line_type.params)
254 254 if 'params' in subparams:
255 255 dum = {}
256 256 for key, value in subparams['params'].items():
257 257 dum[key] = value['value']
258 258 params['params'].append(dum)
259 259 line.params = json.dumps(params)
260 260 line.save()
261 261 return redirect('url_edit_rc_conf', conf.id)
262 262
263 263 kwargs = {}
264 264
265 265 kwargs['title'] = 'Add new'
266 266 kwargs['suptitle'] = '%s to %s' % (line.line_type.name, line)
267 267
268 268 return render(request, 'confirm.html', kwargs)
269 269
270 270 def remove_line(request, conf_id, line_id):
271 271
272 272 conf = get_object_or_404(RCConfiguration, pk=conf_id)
273 273 line = get_object_or_404(RCLine, pk=line_id)
274 274
275 275 if request.method == 'POST':
276 276 if line:
277 277 try:
278 278 channel = line.channel
279 279 line.delete()
280 280 for ch in range(channel+1, RCLine.objects.filter(rc_configuration=conf).count()+1):
281 281 l = RCLine.objects.get(rc_configuration=conf, channel=ch)
282 282 l.channel = l.channel-1
283 283 l.save()
284 284 messages.success(request, 'Line: "%s" has been deleted.' % line)
285 285 except:
286 286 messages.error(request, 'Unable to delete line: "%s".' % line)
287 287
288 288 return redirect('url_edit_rc_conf', conf.id)
289 289
290 290 kwargs = {}
291 291
292 292 kwargs['object'] = line
293 293 kwargs['delete'] = True
294 294 kwargs['title'] = 'Delete'
295 295 kwargs['suptitle'] = 'Line'
296 296 kwargs['previous'] = conf.get_absolute_url_edit()
297 297 return render(request, 'confirm.html', kwargs)
298 298
299 299
300 300 def remove_subline(request, conf_id, line_id, subline_id):
301 301
302 302 conf = get_object_or_404(RCConfiguration, pk=conf_id)
303 303 line = get_object_or_404(RCLine, pk=line_id)
304 304
305 305 if request.method == 'POST':
306 306 if line:
307 307 params = json.loads(line.params)
308 308 params['params'].remove(params['params'][int(subline_id)-1])
309 309 line.params = json.dumps(params)
310 310 line.save()
311 311
312 312 return redirect('url_edit_rc_conf', conf.id)
313 313
314 314 kwargs = {}
315 315
316 316 kwargs['object'] = line
317 317 kwargs['object_name'] = line.line_type.name
318 318 kwargs['delete_view'] = True
319 319 kwargs['title'] = 'Confirm delete'
320 320
321 321 return render(request, 'confirm.html', kwargs)
322 322
323 323
324 324 def update_lines_position(request, conf_id):
325 325
326 326 conf = get_object_or_404(RCConfiguration, pk=conf_id)
327 327 print("ingreso a update_lines_position")
328 328 if request.method=='POST':
329 329 ch = 0
330 330 for item in request.POST['items'].split('&'):
331 331 line = RCLine.objects.get(pk=item.split('=')[-1])
332 332 line.channel = ch
333 333 line.save()
334 334 ch += 1
335 335
336 336 lines = RCLine.objects.filter(rc_configuration=conf).order_by('channel')
337 337
338 338 for line in lines:
339 339
340 340 params = json.loads(line.params)
341 341 print(params)
342 342 print("Fin de impresion_lines_position")
343 343 line.form = RCLineEditForm(conf=conf, line=line, extra_fields=params)
344 344
345 345 if 'params' in params:
346 346 line.subform = True
347 347 line.subforms = [RCLineEditForm(extra_fields=fields, line=line, subform=i) for i, fields in enumerate(params['params'])]
348 348
349 349 html = render(request, 'rc_lines.html', {'dev_conf':conf, 'rc_lines':lines, 'edit':True})
350 350 #html = render('rc_lines.html', {'dev_conf':conf, 'rc_lines':lines, 'edit':True},request)
351 351 data = {'html': html.content.decode('utf8')}
352 352
353 353 return HttpResponse(json.dumps(data), content_type="application/json")
354 354 return redirect('url_edit_rc_conf', conf.id)
355 355
356 356
357 357 def import_file(request, conf_id):
358 print("HOLA",flush=True)
358 # print("HOLA",flush=True)
359 359 conf = get_object_or_404(RCConfiguration, pk=conf_id)
360 print("HOLA2",flush=True)
360 # print("HOLA2",flush=True)
361 361 if request.method=='POST':
362 362 form = RCImportForm(request.POST, request.FILES)
363 print("HOLA3",flush=True)
363 # print("HOLA3",flush=True)
364 364 if form.is_valid():
365 print("HOLA4",flush=True)
365 #print("HOLA4",flush=True)
366 366 # try:
367 print("HOLA5",flush=True)
367 #print("HOLA5",flush=True)
368 368 data = conf.import_from_file(request.FILES['file_name'])
369 print("HOLA6",flush=True)
369 #print("HOLA6",flush=True)
370 370 conf.dict_to_parms(data)
371 print("1",flush=True)
371 #print("1",flush=True)
372 372 conf.update_pulses()
373 print("2",flush=True)
373 #print("2",flush=True)
374 374 messages.success(request, 'Configuration "%s" loaded succesfully' % request.FILES['file_name'])
375 375 return redirect(conf.get_absolute_url_edit())
376 376
377 377 # except Exception as e:
378 378 # messages.error(request, 'Error parsing file: "%s" - %s' % (request.FILES['file_name'], repr(e)))
379 379 else:
380 380 messages.warning(request, 'Your current configuration will be replaced')
381 381 form = RCImportForm()
382 382
383 383 kwargs = {}
384 384 kwargs['form'] = form
385 385 kwargs['title'] = 'RC Configuration'
386 386 kwargs['suptitle'] = 'Import file'
387 387 kwargs['button'] = 'Upload'
388 388 kwargs['previous'] = conf.get_absolute_url()
389 389
390 390 return render(request, 'rc_import.html', kwargs)
391 391
392 392
393 393 def plot_pulses(request, conf_id):
394 394
395 395 conf = get_object_or_404(RCConfiguration, pk=conf_id)
396 396 km = True if 'km' in request.GET else False
397 397
398 398 script, div = conf.plot_pulses(km=km)
399 399
400 400 kwargs = {}
401 401 kwargs['no_sidebar'] = True
402 402 kwargs['title'] = 'RC Pulses'
403 403 kwargs['suptitle'] = conf.name
404 404 kwargs['div'] = mark_safe(div)
405 405 kwargs['script'] = mark_safe(script)
406 406 kwargs['units'] = conf.km2unit
407 407 kwargs['kms'] = 1/conf.km2unit
408 408
409 409 if km:
410 410 kwargs['km_selected'] = True
411 411
412 412 if 'json' in request.GET:
413 413 return HttpResponse(json.dumps({'div':mark_safe(div), 'script':mark_safe(script)}), content_type="application/json")
414 414 else:
415 415 return render(request, 'rc_pulses.html', kwargs)
416 416
417 417 def plot_pulses2(request, conf_id):
418 418
419 419 conf = get_object_or_404(RCConfiguration, pk=conf_id)
420 420 km = True if 'km' in request.GET else False
421 421
422 422 script, div = conf.plot_pulses2(km=km)
423 423
424 424 kwargs = {}
425 425 kwargs['no_sidebar'] = True
426 426 kwargs['title'] = 'RC Pulses'
427 427 kwargs['suptitle'] = conf.name
428 428 kwargs['div'] = mark_safe(div)
429 429 kwargs['script'] = mark_safe(script)
430 430 kwargs['units'] = conf.km2unit
431 431 kwargs['kms'] = 1/conf.km2unit
432 432
433 433 if km:
434 434 kwargs['km_selected'] = True
435 435
436 436 if 'json' in request.GET:
437 437 return HttpResponse(json.dumps({'div':mark_safe(div), 'script':mark_safe(script)}), content_type="application/json")
438 438 else:
439 439 return render(request, 'rc_pulses.html', kwargs)
440 440
441 441 def conf_raw(request, conf_id):
442 442 conf = get_object_or_404(RCConfiguration, pk=conf_id)
443 443 raw = conf.write_device(raw=True)
444 444 return HttpResponse(raw, content_type='application/json') No newline at end of file
General Comments 0
You need to be logged in to leave comments. Login now