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