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