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