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