##// END OF EJS Templates
Add control_sw value in write_device RC
jespinoza -
r304:ef15cc8a2bad
parent child
Show More
@@ -1,999 +1,1001
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.core.urlresolvers 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 self.name = data['name']
162 162 self.ipp = data['ipp']
163 163 self.ntx = data['ntx']
164 164 self.clock_in = data['clock_in']
165 165 self.clock_divider = data['clock_divider']
166 166 self.clock = data['clock']
167 167 self.time_before = data['time_before']
168 168 self.time_after = data['time_after']
169 169 self.sync = data['sync']
170 170 self.sampling_reference = data['sampling_reference']
171 171 self.total_units = self.ipp*self.ntx*self.km2unit
172 172 self.save()
173 173 self.clean_lines()
174 174
175 175 positions = {'tx':0, 'tr':0}
176 176 for i, id in enumerate(data['lines']):
177 177 line_data = params['lines']['byId'][id]
178 178 line_type = RCLineType.objects.get(name=line_data['line_type'])
179 179 if line_type.name == 'codes':
180 180 code = RCLineCode.objects.get(name=line_data['params']['code'])
181 181 line_data['params']['code'] = code.pk
182 182 if line_type.name == 'tx':
183 183 position = positions['tx']
184 184 positions['tx'] += 1
185 185 elif line_type.name == 'tr':
186 186 position = positions['tr']
187 187 positions['tr'] += 1
188 188 else:
189 189 position = 0
190 190 line, dum = RCLine.objects.update_or_create(
191 191 rc_configuration=self,
192 192 channel=i,
193 193 position=position,
194 194 defaults={
195 195 'line_type': line_type,
196 196 'params': json.dumps(line_data['params'])
197 197 }
198 198 )
199 199
200 200 for i, line in enumerate(self.get_lines()):
201 201 line_params = json.loads(line.params)
202 202 if 'TX_ref' in line_params:
203 203 if line_params['TX_ref'] in (0, '0'):
204 204 line_params['TX_ref'] = '0'
205 205 else:
206 206 ref_id = '{}'.format(line_params['TX_ref'])
207 207 ref_line = params['lines']['byId'][ref_id]
208 208 line_params['TX_ref'] = RCLine.objects.get(
209 209 rc_configuration=self,
210 210 params=json.dumps(ref_line['params'])
211 211 ).pk
212 212 line.params = json.dumps(line_params)
213 213 line.save()
214 214
215 215
216 216 def get_delays(self):
217 217
218 218 pulses = [line.pulses_as_points() for line in self.get_lines()]
219 219 points = [tup for tups in pulses for tup in tups]
220 220 points = set([x for tup in points for x in tup])
221 221 points = list(points)
222 222 points.sort()
223 223
224 224 if points[0]!=0:
225 225 points.insert(0, 0)
226 226
227 227 return [points[i+1]-points[i] for i in range(len(points)-1)]
228 228
229 229
230 230 def get_pulses(self, binary=True):
231 231
232 232 pulses = [line.pulses_as_points() for line in self.get_lines()]
233 233 tuples = [tup for tups in pulses for tup in tups]
234 234 points = set([x for tup in tuples for x in tup])
235 235 points = list(points)
236 236 points.sort()
237 237 states = []
238 238 last = [0 for x in pulses]
239 239
240 240 for x in points:
241 241 dum = []
242 242 for i, tups in enumerate(pulses):
243 243 ups = [tup[0] for tup in tups if tup!=(0,0)]
244 244 dws = [tup[1] for tup in tups if tup!=(0,0)]
245 245 if x in ups:
246 246 dum.append(1)
247 247 elif x in dws:
248 248 dum.append(0)
249 249 else:
250 250 dum.append(last[i])
251 251 states.append(dum)
252 252 last = dum
253 253
254 254 if binary:
255 255 ret = []
256 256 for flips in states:
257 257 flips.reverse()
258 258 ret.append(int(''.join([str(x) for x in flips]), 2))
259 259 states = ret
260 260
261 261 return states[:-1]
262 262
263 263 def add_cmd(self, cmd):
264 264
265 265 if cmd in DAT_CMDS:
266 266 return (255, DAT_CMDS[cmd])
267 267
268 268 def add_data(self, value):
269 269
270 270 return (254, value-1)
271 271
272 272 def parms_to_binary(self, dat=True):
273 273 '''
274 274 Create "dat" stream to be send to CR
275 275 '''
276 276
277 277 data = bytearray()
278 278 # create header
279 279 data.extend(self.add_cmd('DISABLE'))
280 280 data.extend(self.add_cmd('CONTINUE'))
281 281 data.extend(self.add_cmd('RESTART'))
282 282
283 283 if self.control_sw:
284 284 data.extend(self.add_cmd('SW_ONE'))
285 285 else:
286 286 data.extend(self.add_cmd('SW_ZERO'))
287 287
288 288 if self.control_tx:
289 289 data.extend(self.add_cmd('TX_ONE'))
290 290 else:
291 291 data.extend(self.add_cmd('TX_ZERO'))
292 292
293 293 # write divider
294 294 data.extend(self.add_cmd('CLOCK_DIVIDER'))
295 295 data.extend(self.add_data(self.clock_divider))
296 296
297 297 # write delays
298 298 data.extend(self.add_cmd('DELAY_START'))
299 299 # first delay is always zero
300 300 data.extend(self.add_data(1))
301 301
302 302 delays = self.get_delays()
303 303
304 304 for delay in delays:
305 305 while delay>252:
306 306 data.extend(self.add_data(253))
307 307 delay -= 253
308 308 data.extend(self.add_data(int(delay)))
309 309
310 310 # write flips
311 311 data.extend(self.add_cmd('FLIP_START'))
312 312
313 313 states = self.get_pulses(binary=True)
314 314
315 315
316 316 last = 0
317 317 for flip, delay in zip(states, delays):
318 318 data.extend(self.add_data((flip^last)+1))
319 319 last = flip
320 320 while delay>252:
321 321 data.extend(self.add_data(1))
322 322 delay -= 253
323 323
324 324 # write sampling period
325 325 data.extend(self.add_cmd('SAMPLING_PERIOD'))
326 326 wins = self.get_lines(line_type__name='windows')
327 327 if wins:
328 328 win_params = json.loads(wins[0].params)['params']
329 329 if win_params:
330 330 dh = int(win_params[0]['resolution']*self.km2unit)
331 331 else:
332 332 dh = 1
333 333 else:
334 334 dh = 1
335 335 data.extend(self.add_data(dh))
336 336
337 337 # write enable
338 338 data.extend(self.add_cmd('ENABLE'))
339 339
340 340 if not dat:
341 341 return data
342 342
343 343 return '\n'.join(['{}'.format(x) for x in data])
344 344
345 345 def update_pulses(self):
346 346
347 347 for line in self.get_lines():
348 348 line.update_pulses()
349 349
350 350 def plot_pulses2(self, km=False):
351 351
352 352 import matplotlib
353 353 matplotlib.use('Agg')
354 354 import matplotlib.pyplot as plt
355 355 from bokeh.resources import CDN
356 356 from bokeh.embed import components
357 357 from bokeh.mpl import to_bokeh
358 358 from bokeh.models.tools import WheelZoomTool, ResetTool, PanTool, HoverTool, SaveTool
359 359
360 360 lines = self.get_lines()
361 361
362 362 N = len(lines)
363 363 npoints = self.total_units/self.km2unit if km else self.total_units
364 364 fig = plt.figure(figsize=(12, 2+N*0.5))
365 365 ax = fig.add_subplot(111)
366 366 labels = ['IPP']
367 367
368 368 for i, line in enumerate(lines):
369 369 labels.append(line.get_name(channel=True))
370 370 l = ax.plot((0, npoints),(N-i-1, N-i-1))
371 371 points = [(tup[0], tup[1]-tup[0]) for tup in line.pulses_as_points(km=km) if tup!=(0,0)]
372 372 ax.broken_barh(points, (N-i-1, 0.5),
373 373 edgecolor=l[0].get_color(), facecolor='none')
374 374
375 375 n = 0
376 376 f = ((self.ntx+50)/100)*5 if ((self.ntx+50)/100)*10>0 else 2
377 377 for x in np.arange(0, npoints, self.ipp if km else self.ipp*self.km2unit):
378 378 if n%f==0:
379 379 ax.text(x, N, '%s' % n, size=10)
380 380 n += 1
381 381
382 382 labels.reverse()
383 383 ax.set_yticks(range(len(labels)))
384 384 ax.set_yticklabels(labels)
385 385 ax.set_xlabel = 'Units'
386 386 plot = to_bokeh(fig, use_pandas=False)
387 387 plot.tools = [PanTool(dimensions=['width']), WheelZoomTool(dimensions=['width']), ResetTool(), SaveTool()]
388 388 plot.toolbar_location="above"
389 389
390 390 return components(plot, CDN)
391 391
392 392 def plot_pulses(self, km=False):
393 393
394 394 from bokeh.plotting import figure
395 395 from bokeh.resources import CDN
396 396 from bokeh.embed import components
397 397 from bokeh.models import FixedTicker, PrintfTickFormatter
398 398 from bokeh.models.tools import WheelZoomTool, ResetTool, PanTool, HoverTool, SaveTool
399 399 from bokeh.models.sources import ColumnDataSource
400 400
401 401 lines = self.get_lines().reverse()
402 402
403 403 N = len(lines)
404 404 npoints = self.total_units/self.km2unit if km else self.total_units
405 405 ipp = self.ipp if km else self.ipp*self.km2unit
406 406
407 407 hover = HoverTool(tooltips=[("Line", "@name"),
408 408 ("IPP", "@ipp"),
409 409 ("X", "@left")])
410 410
411 411 tools = [PanTool(dimensions=['width']),
412 412 WheelZoomTool(dimensions=['width']),
413 413 hover, SaveTool()]
414 414
415 415 plot = figure(width=1000,
416 416 height=40+N*50,
417 417 y_range = (0, N),
418 418 tools=tools,
419 419 toolbar_location='above',
420 420 toolbar_sticky=False,)
421 421
422 422 plot.xaxis.axis_label = 'Km' if km else 'Units'
423 423 plot.xaxis[0].formatter = PrintfTickFormatter(format='%d')
424 424 plot.yaxis.axis_label = 'Pulses'
425 425 plot.yaxis[0].ticker=FixedTicker(ticks=list(range(N)))
426 426 plot.yaxis[0].formatter = PrintfTickFormatter(format='Line %d')
427 427
428 428 for i, line in enumerate(lines):
429 429
430 430 points = [tup for tup in line.pulses_as_points(km=km) if tup!=(0,0)]
431 431
432 432 source = ColumnDataSource(data = dict(
433 433 bottom = [i for tup in points],
434 434 top = [i+0.5 for tup in points],
435 435 left = [tup[0] for tup in points],
436 436 right = [tup[1] for tup in points],
437 437 ipp = [int(tup[0]/ipp) for tup in points],
438 438 name = [line.get_name() for tup in points]
439 439 ))
440 440
441 441 plot.quad(
442 442 bottom = 'bottom',
443 443 top = 'top',
444 444 left = 'left',
445 445 right = 'right',
446 446 source = source,
447 447 fill_alpha = 0,
448 448 #line_color = 'blue',
449 449 )
450 450
451 451 plot.line([0, npoints], [i, i])#, color='blue')
452 452
453 453 return components(plot, CDN)
454 454
455 455 def request(self, cmd, method='get', **kwargs):
456 456
457 457 req = getattr(requests, method)(self.device.url(cmd), **kwargs)
458 458 payload = req.json()
459 459
460 460 return payload
461 461
462 462 def status_device(self):
463 463
464 464 try:
465 465 self.device.status = 0
466 466 payload = self.request('status')
467 467 if payload['status']=='enable':
468 468 self.device.status = 3
469 469 elif payload['status']=='disable':
470 470 self.device.status = 2
471 471 else:
472 472 self.device.status = 1
473 473 self.device.save()
474 474 self.message = 'RC status: {}'.format(payload['status'])
475 475 return False
476 476 except Exception as e:
477 477 if 'No route to host' not in str(e):
478 478 self.device.status = 4
479 479 self.device.save()
480 480 self.message = 'RC status: {}'.format(str(e))
481 481 return False
482 482
483 483 self.device.save()
484 484 return True
485 485
486 486 def reset_device(self):
487 487
488 488 try:
489 489 payload = self.request('reset', 'post')
490 490 if payload['reset']=='ok':
491 491 self.message = 'RC restarted OK'
492 492 self.device.status = 2
493 493 self.device.save()
494 494 else:
495 495 self.message = 'RC restart fail'
496 496 self.device.status = 4
497 497 self.device.save()
498 498 except Exception as e:
499 499 self.message = 'RC reset: {}'.format(str(e))
500 500 return False
501 501
502 502 return True
503 503
504 504 def stop_device(self):
505 505
506 506 try:
507 507 payload = self.request('stop', 'post')
508 508 self.message = 'RC stop: {}'.format(payload['stop'])
509 509 if payload['stop']=='ok':
510 510 self.device.status = 2
511 511 self.device.save()
512 512 else:
513 513 self.device.status = 4
514 514 self.device.save()
515 515 return False
516 516 except Exception as e:
517 517 if 'No route to host' not in str(e):
518 518 self.device.status = 4
519 519 else:
520 520 self.device.status = 0
521 521 self.message = 'RC stop: {}'.format(str(e))
522 522 self.device.save()
523 523 return False
524 524
525 525 return True
526 526
527 527 def start_device(self):
528 528
529 529 try:
530 530 payload = self.request('start', 'post')
531 531 self.message = 'RC start: {}'.format(payload['start'])
532 532 if payload['start']=='ok':
533 533 self.device.status = 3
534 534 self.device.save()
535 535 else:
536 536 return False
537 537 except Exception as e:
538 538 if 'No route to host' not in str(e):
539 539 self.device.status = 4
540 540 else:
541 541 self.device.status = 0
542 542 self.message = 'RC start: {}'.format(str(e))
543 543 self.device.save()
544 544 return False
545 545
546 546 return True
547 547
548 548 def write_device(self):
549 549
550 #values = zip(self.get_pulses(), [x-1 for x in self.get_delays()])
551
552 550 values = []
553 551 for pulse, delay in zip(self.get_pulses(), self.get_delays()):
554 552 while delay>65536:
555 553 values.append((pulse, 65535))
556 554 delay -= 65536
557 555 values.append((pulse, delay-1))
558
559 556 data = bytearray()
560 557 #reset
561 558 data.extend((128, 0))
562 559 #disable
563 560 data.extend((129, 0))
561 #SW switch
562 if self.control_sw:
563 data.extend((130, 2))
564 else:
565 data.extend((130, 0))
564 566 #divider
565 567 data.extend((131, self.clock_divider-1))
566 568 #enable writing
567 569 data.extend((139, 62))
568 570
569 571 last = 0
570 572 for tup in values:
571 573 vals = pack('<HH', last^tup[0], tup[1])
572 574 last = tup[0]
573 575 data.extend((133, vals[1], 132, vals[0], 133, vals[3], 132, vals[2]))
574 576
575 577 #enable
576 578 data.extend((129, 1))
577 579
578 580 try:
579 581 payload = self.request('stop', 'post')
580 582 payload = self.request('reset', 'post')
581 583 #payload = self.request('divider', 'post', data={'divider': self.clock_divider-1})
582 584 #payload = self.request('write', 'post', data=b64encode(bytearray((139, 62))), timeout=20)
583 585 n = len(data)
584 586 x = 0
585 587 #while x < n:
586 588 payload = self.request('write', 'post', data=b64encode(data))
587 589 # x += 1024
588 590
589 591 if payload['write']=='ok':
590 592 self.device.status = 3
591 593 self.device.save()
592 594 self.message = 'RC configured and started'
593 595 else:
594 596 self.device.status = 1
595 597 self.device.save()
596 598 self.message = 'RC write: {}'.format(payload['write'])
597 599 return False
598 600
599 601 #payload = self.request('start', 'post')
600 602
601 603 except Exception as e:
602 604 if 'No route to host' not in str(e):
603 605 self.device.status = 4
604 606 else:
605 607 self.device.status = 0
606 608 self.message = 'RC write: {}'.format(str(e))
607 609 self.device.save()
608 610 return False
609 611
610 612 return True
611 613
612 614
613 615 def get_absolute_url_import(self):
614 616 return reverse('url_import_rc_conf', args=[str(self.id)])
615 617
616 618
617 619 class RCLineCode(models.Model):
618 620
619 621 name = models.CharField(max_length=40)
620 622 bits_per_code = models.PositiveIntegerField(default=0)
621 623 number_of_codes = models.PositiveIntegerField(default=0)
622 624 codes = models.TextField(blank=True, null=True)
623 625
624 626 class Meta:
625 627 db_table = 'rc_line_codes'
626 628 ordering = ('name',)
627 629
628 630 def __str__(self):
629 631 return u'%s' % self.name
630 632
631 633
632 634 class RCLineType(models.Model):
633 635
634 636 name = models.CharField(choices=LINE_TYPES, max_length=40)
635 637 description = models.TextField(blank=True, null=True)
636 638 params = models.TextField(default='[]')
637 639
638 640 class Meta:
639 641 db_table = 'rc_line_types'
640 642
641 643 def __str__(self):
642 644 return u'%s - %s' % (self.name.upper(), self.get_name_display())
643 645
644 646
645 647 class RCLine(models.Model):
646 648
647 649 rc_configuration = models.ForeignKey(RCConfiguration, on_delete=models.CASCADE)
648 650 line_type = models.ForeignKey(RCLineType)
649 651 channel = models.PositiveIntegerField(default=0)
650 652 position = models.PositiveIntegerField(default=0)
651 653 params = models.TextField(default='{}')
652 654 pulses = models.TextField(default='')
653 655
654 656 class Meta:
655 657 db_table = 'rc_lines'
656 658 ordering = ['channel']
657 659
658 660 def __str__(self):
659 661 if self.rc_configuration:
660 662 return u'{}|{} - {}'.format(self.pk, self.get_name(), self.rc_configuration.name)
661 663
662 664 def jsonify(self):
663 665
664 666 data = {}
665 667 data['params'] = json.loads(self.params)
666 668 data['id'] = '{}'.format(self.pk)
667 669 data['line_type'] = self.line_type.name
668 670 data['name'] = self.get_name()
669 671 if data['line_type']=='codes':
670 672 data['params']['code'] = RCLineCode.objects.get(pk=data['params']['code']).name
671 673
672 674 return data
673 675
674 676
675 677 def clone(self, **kwargs):
676 678
677 679 self.pk = None
678 680 self.id = None
679 681
680 682 for attr, value in kwargs.items():
681 683 setattr(self, attr, value)
682 684
683 685 self.save()
684 686
685 687 return self
686 688
687 689 def get_name(self, channel=False):
688 690
689 691 chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
690 692 s = ''
691 693
692 694 if self.line_type.name in ('tx',):
693 695 s = chars[self.position]
694 696 elif self.line_type.name in ('codes', 'windows', 'tr'):
695 697 if 'TX_ref' in json.loads(self.params):
696 698 pk = json.loads(self.params)['TX_ref']
697 699 if pk in (0, '0'):
698 700 s = ','.join(chars[l.position] for l in self.rc_configuration.get_lines(line_type__name='tx'))
699 701 else:
700 702 ref = RCLine.objects.get(pk=pk)
701 703 s = chars[ref.position]
702 704 s = '({})'.format(s)
703 705
704 706 s = '{}{}'.format(self.line_type.name.upper(), s)
705 707
706 708 if channel:
707 709 return '{} {}'.format(s, self.channel)
708 710 else:
709 711 return s
710 712
711 713 def get_lines(self, **kwargs):
712 714
713 715 return RCLine.objects.filter(rc_configuration=self.rc_configuration, **kwargs)
714 716
715 717 def pulses_as_array(self):
716 718
717 719 y = np.zeros(self.rc_configuration.total_units)
718 720
719 721 for tup in ast.literal_eval(self.pulses):
720 722 y[tup[0]:tup[1]] = 1
721 723
722 724 return y.astype(np.int8)
723 725
724 726 def pulses_as_points(self, km=False):
725 727
726 728 if km:
727 729 unit2km = 1/self.rc_configuration.km2unit
728 730 return [(tup[0]*unit2km, tup[1]*unit2km) for tup in ast.literal_eval(self.pulses)]
729 731 else:
730 732 return ast.literal_eval(self.pulses)
731 733
732 734 def get_win_ref(self, params, tx_id, km2unit):
733 735
734 736 ref = self.rc_configuration.sampling_reference
735 737 codes = [line for line in self.get_lines(line_type__name='codes') if int(json.loads(line.params)['TX_ref'])==int(tx_id)]
736 738
737 739 if codes:
738 740 tx_width = float(json.loads(RCLine.objects.get(pk=tx_id).params)['pulse_width'])*km2unit/len(json.loads(codes[0].params)['codes'][0])
739 741 else:
740 742 tx_width = float(json.loads(RCLine.objects.get(pk=tx_id).params)['pulse_width'])*km2unit
741 743
742 744 if ref=='first_baud':
743 745 return int(1 + round((tx_width + 1)/2 + params['first_height']*km2unit - params['resolution']*km2unit))
744 746 elif ref=='sub_baud':
745 747 return np.ceil(1 + params['first_height']*km2unit - params['resolution']*km2unit/2)
746 748 else:
747 749 return 0
748 750
749 751 def update_pulses(self):
750 752 '''
751 753 Update pulses field
752 754 '''
753 755
754 756 km2unit = self.rc_configuration.km2unit
755 757 us2unit = self.rc_configuration.us2unit
756 758 ipp = self.rc_configuration.ipp
757 759 ntx = int(self.rc_configuration.ntx)
758 760 ipp_u = int(ipp*km2unit)
759 761 total = ipp_u*ntx if self.rc_configuration.total_units==0 else self.rc_configuration.total_units
760 762 y = []
761 763
762 764 if self.line_type.name=='tr':
763 765 tr_params = json.loads(self.params)
764 766
765 767 if tr_params['TX_ref'] in ('0', 0):
766 768 txs = self.get_lines(line_type__name='tx')
767 769 else:
768 770 txs = RCLine.objects.filter(pk=tr_params['TX_ref'])
769 771
770 772 for tx in txs:
771 773 params = json.loads(tx.params)
772 774
773 775 if float(params['pulse_width'])==0:
774 776 continue
775 777 delays = [float(d)*km2unit for d in params['delays'].split(',') if d]
776 778 width = float(params['pulse_width'])*km2unit+int(self.rc_configuration.time_before*us2unit)
777 779 before = 0
778 780 after = int(self.rc_configuration.time_after*us2unit)
779 781
780 782 y_tx = self.points(ntx, ipp_u, width,
781 783 delay=delays,
782 784 before=before,
783 785 after=after,
784 786 sync=self.rc_configuration.sync)
785 787
786 788 ranges = params['range'].split(',')
787 789
788 790 if len(ranges)>0 and ranges[0]!='0':
789 791 y_tx = self.mask_ranges(y_tx, ranges)
790 792
791 793 tr_ranges = tr_params['range'].split(',')
792 794
793 795 if len(tr_ranges)>0 and tr_ranges[0]!='0':
794 796 y_tx = self.mask_ranges(y_tx, tr_ranges)
795 797
796 798 y.extend(y_tx)
797 799
798 800 self.pulses = str(y)
799 801 y = self.array_to_points(self.pulses_as_array())
800 802
801 803 elif self.line_type.name=='tx':
802 804 params = json.loads(self.params)
803 805 delays = [float(d)*km2unit for d in params['delays'].split(',') if d]
804 806 width = float(params['pulse_width'])*km2unit
805 807
806 808 if width>0:
807 809 before = int(self.rc_configuration.time_before*us2unit)
808 810 after = 0
809 811
810 812 y = self.points(ntx, ipp_u, width,
811 813 delay=delays,
812 814 before=before,
813 815 after=after,
814 816 sync=self.rc_configuration.sync)
815 817
816 818 ranges = params['range'].split(',')
817 819
818 820 if len(ranges)>0 and ranges[0]!='0':
819 821 y = self.mask_ranges(y, ranges)
820 822
821 823 elif self.line_type.name=='flip':
822 824 n = float(json.loads(self.params)['number_of_flips'])
823 825 width = n*ipp*km2unit
824 826 y = self.points(int((ntx+1)/(2*n)), ipp_u*n*2, width)
825 827
826 828 elif self.line_type.name=='codes':
827 829 params = json.loads(self.params)
828 830 tx = RCLine.objects.get(pk=params['TX_ref'])
829 831 tx_params = json.loads(tx.params)
830 832 delays = [float(d)*km2unit for d in tx_params['delays'].split(',') if d]
831 833 f = int(float(tx_params['pulse_width'])*km2unit/len(params['codes'][0]))
832 834 codes = [(np.fromstring(''.join([s*f for s in code]), dtype=np.uint8)-48).astype(np.int8) for code in params['codes']]
833 835 codes = [self.array_to_points(code) for code in codes]
834 836 n = len(codes)
835 837
836 838 ranges = tx_params['range'].split(',')
837 839 if len(ranges)>0 and ranges[0]!='0':
838 840 dum = self.mask_ranges(tx.pulses_as_points(), ranges)
839 841 else:
840 842 dum = tx.pulses_as_points()
841 843
842 844 for i, tup in enumerate(dum):
843 845 if tup==(0,0): continue
844 846 code = codes[i%n]
845 847 y.extend([(c[0]+tup[0], c[1]+tup[0]) for c in code])
846 848
847 849 elif self.line_type.name=='sync':
848 850 params = json.loads(self.params)
849 851 n = ipp_u*ntx
850 852 if params['invert'] in ('1', 1):
851 853 y = [(n-1, n)]
852 854 else:
853 855 y = [(0, 1)]
854 856
855 857 elif self.line_type.name=='prog_pulses':
856 858 params = json.loads(self.params)
857 859 if int(params['periodic'])==0:
858 860 nntx = 1
859 861 nipp = ipp_u*ntx
860 862 else:
861 863 nntx = ntx
862 864 nipp = ipp_u
863 865
864 866 if 'params' in params and len(params['params'])>0:
865 867 for p in params['params']:
866 868 y_pp = self.points(nntx, nipp,
867 869 p['end']-p['begin'],
868 870 before=p['begin'])
869 871
870 872 y.extend(y_pp)
871 873
872 874 elif self.line_type.name=='windows':
873 875 params = json.loads(self.params)
874 876 if 'params' in params and len(params['params'])>0:
875 877 tx = RCLine.objects.get(pk=params['TX_ref'])
876 878 tx_params = json.loads(tx.params)
877 879 ranges = tx_params['range'].split(',')
878 880 for p in params['params']:
879 881 y_win = self.points(ntx, ipp_u,
880 882 p['resolution']*p['number_of_samples']*km2unit,
881 883 before=int(self.rc_configuration.time_before*us2unit)+p['first_height']*km2unit,
882 884 sync=self.rc_configuration.sync+self.get_win_ref(p, params['TX_ref'], km2unit))
883 885
884 886
885 887 if len(ranges)>0 and ranges[0]!='0':
886 888 y_win = self.mask_ranges(y_win, ranges)
887 889
888 890 y.extend(y_win)
889 891
890 892 elif self.line_type.name=='mix':
891 893 values = self.rc_configuration.parameters.split('-')
892 894 confs = [RCConfiguration.objects.get(pk=value.split('|')[0]) for value in values]
893 895 modes = [value.split('|')[1] for value in values]
894 896 ops = [value.split('|')[2] for value in values]
895 897 delays = [value.split('|')[3] for value in values]
896 898 masks = [value.split('|')[4] for value in values]
897 899 mask = list('{:8b}'.format(int(masks[0])))
898 900 mask.reverse()
899 901 if mask[self.channel] in ('0', '', ' '):
900 902 y = np.zeros(confs[0].total_units, dtype=np.int8)
901 903 else:
902 904 y = confs[0].get_lines(channel=self.channel)[0].pulses_as_array()
903 905
904 906 for i in range(1, len(values)):
905 907 mask = list('{:8b}'.format(int(masks[i])))
906 908 mask.reverse()
907 909
908 910 if mask[self.channel] in ('0', '', ' '):
909 911 continue
910 912 Y = confs[i].get_lines(channel=self.channel)[0].pulses_as_array()
911 913 delay = float(delays[i])*km2unit
912 914
913 915 if modes[i]=='P':
914 916 if delay>0:
915 917 if delay<self.rc_configuration.ipp*km2unit and len(Y)==len(y):
916 918 y_temp = np.empty_like(Y)
917 919 y_temp[:delay] = 0
918 920 y_temp[delay:] = Y[:-delay]
919 921 elif delay+len(Y)>len(y):
920 922 y_new = np.zeros(delay+len(Y), dtype=np.int8)
921 923 y_new[:len(y)] = y
922 924 y = y_new
923 925 y_temp = np.zeros(delay+len(Y), dtype=np.int8)
924 926 y_temp[-len(Y):] = Y
925 927 elif delay+len(Y)==len(y):
926 928 y_temp = np.zeros(delay+len(Y))
927 929 y_temp[-len(Y):] = Y
928 930 elif delay+len(Y)<len(y):
929 931 y_temp = np.zeros(len(y), dtype=np.int8)
930 932 y_temp[delay:delay+len(Y)] = Y
931 933 else:
932 934 y_temp = Y.copy()
933 935
934 936 if ops[i]=='OR':
935 937 y = y | y_temp
936 938 elif ops[i]=='XOR':
937 939 y = y ^ y_temp
938 940 elif ops[i]=='AND':
939 941 y = y & y_temp
940 942 elif ops[i]=='NAND':
941 943 y = y & ~y_temp
942 944 else:
943 945 y = np.concatenate([y, Y])
944 946
945 947 total = len(y)
946 948 y = self.array_to_points(y)
947 949
948 950 else:
949 951 y = []
950 952
951 953 if self.rc_configuration.total_units != total:
952 954 self.rc_configuration.total_units = total
953 955 self.rc_configuration.save()
954 956
955 957 self.pulses = str(y)
956 958 self.save()
957 959
958 960 @staticmethod
959 961 def array_to_points(X):
960 962
961 963 if X.size==0:
962 964 return []
963 965
964 966 d = X[1:]-X[:-1]
965 967
966 968 up = np.where(d==1)[0]
967 969 if X[0]==1:
968 970 up = np.concatenate((np.array([-1]), up))
969 971 up += 1
970 972
971 973 dw = np.where(d==-1)[0]
972 974 if X[-1]==1:
973 975 dw = np.concatenate((dw, np.array([len(X)-1])))
974 976 dw += 1
975 977
976 978 return [(tup[0], tup[1]) for tup in zip(up, dw)]
977 979
978 980 @staticmethod
979 981 def mask_ranges(Y, ranges):
980 982
981 983 y = [(0, 0) for __ in Y]
982 984
983 985 for index in ranges:
984 986 if '-' in index:
985 987 args = [int(a) for a in index.split('-')]
986 988 y[args[0]-1:args[1]] = Y[args[0]-1:args[1]]
987 989 else:
988 990 y[int(index)-1] = Y[int(index)-1]
989 991
990 992 return y
991 993
992 994 @staticmethod
993 995 def points(ntx, ipp, width, delay=[0], before=0, after=0, sync=0):
994 996
995 997 delays = len(delay)
996 998
997 999 Y = [(int(ipp*x+before+delay[x%delays]+sync), int(ipp*x+width+before+delay[x%delays]+after+sync)) for x in range(ntx)]
998 1000
999 1001 return Y
General Comments 0
You need to be logged in to leave comments. Login now