##// END OF EJS Templates
RC files have been updated...
Fiorella Quino -
r264:17ec69be4c00
parent child
Show More
@@ -1,382 +1,382
1 1 import os
2 2 import json
3 3
4 4 from django import forms
5 5 from django.utils.safestring import mark_safe
6 6 from apps.main.models import Device
7 7 from apps.main.forms import add_empty_choice
8 8 from .models import RCConfiguration, RCLine, RCLineType, RCLineCode
9 9 from .widgets import KmUnitWidget, KmUnitHzWidget, KmUnitDcWidget, UnitKmWidget, DefaultWidget, CodesWidget, HiddenWidget, HCheckboxSelectMultiple
10 10
11 11 def create_choices_from_model(model, conf_id, all_choice=False):
12 12
13 13 if model=='RCLine':
14 14 instance = RCConfiguration.objects.get(pk=conf_id)
15 15 choices = [(line.pk, line.get_name()) for line in instance.get_lines(line_type__name='tx')]
16 16 if all_choice:
17 17 choices = add_empty_choice(choices, label='All')
18 18 else:
19 19 instance = globals()[model]
20 20 choices = instance.objects.all().values_list('pk', 'name')
21 21
22 22 return choices
23 23
24 24
25 25 class ExtFileField(forms.FileField):
26 26 """
27 27 Same as forms.FileField, but you can specify a file extension whitelist.
28 28
29 29 >>> from django.core.files.uploadedfile import SimpleUploadedFile
30 30 >>>
31 31 >>> t = ExtFileField(ext_whitelist=(".pdf", ".txt"))
32 32 >>>
33 33 >>> t.clean(SimpleUploadedFile('filename.pdf', 'Some File Content'))
34 34 >>> t.clean(SimpleUploadedFile('filename.txt', 'Some File Content'))
35 35 >>>
36 36 >>> t.clean(SimpleUploadedFile('filename.exe', 'Some File Content'))
37 37 Traceback (most recent call last):
38 38 ...
39 39 ValidationError: [u'Not allowed filetype!']
40 40 """
41 41 def __init__(self, *args, **kwargs):
42 42 extensions = kwargs.pop("extensions")
43 43 self.extensions = [i.lower() for i in extensions]
44 44
45 45 super(ExtFileField, self).__init__(*args, **kwargs)
46 46
47 47 def clean(self, *args, **kwargs):
48 48 data = super(ExtFileField, self).clean(*args, **kwargs)
49 49 filename = data.name
50 50 ext = os.path.splitext(filename)[1]
51 51 ext = ext.lower()
52 52 if ext not in self.extensions:
53 53 raise forms.ValidationError('Not allowed file type: %s' % ext)
54 54
55 55
56 56 class RCConfigurationForm(forms.ModelForm):
57 57
58 58 def __init__(self, *args, **kwargs):
59 59 super(RCConfigurationForm, self).__init__(*args, **kwargs)
60 60
61 61 instance = getattr(self, 'instance', None)
62 62
63 63 if instance and instance.pk:
64 64
65 65 devices = Device.objects.filter(device_type__name='rc')
66 66 if instance.experiment:
67 67 self.fields['experiment'].widget.attrs['read_only'] = True
68 68 #self.fields['experiment'].widget.choices = [(instance.experiment.id, instance.experiment)]
69 69 self.fields['device'].widget.choices = [(device.id, device) for device in devices]
70 70 self.fields['ipp'].widget = KmUnitHzWidget(attrs={'km2unit':instance.km2unit})
71 71 self.fields['clock'].widget.attrs['readonly'] = True
72 72
73 73 self.fields['time_before'].label = mark_safe(self.fields['time_before'].label)
74 74 self.fields['time_after'].label = mark_safe(self.fields['time_after'].label)
75 75
76 76 if 'initial' in kwargs and 'experiment' in kwargs['initial'] and kwargs['initial']['experiment'] not in (0, '0'):
77 77 self.fields['experiment'].widget.attrs['readonly'] = True
78 78
79 79 class Meta:
80 80 model = RCConfiguration
81 81 exclude = ('type', 'parameters', 'status', 'total_units', 'mix')
82 82
83 83 def clean(self):
84 84 form_data = super(RCConfigurationForm, self).clean()
85 85
86 86 if 'clock_divider' in form_data:
87 87 if form_data['clock_divider']<1:
88 88 self.add_error('clock_divider', 'Invalid Value')
89 else:
90 if form_data['ipp']*(20./3*(form_data['clock_in']/form_data['clock_divider']))%10!=0:
91 self.add_error('ipp', 'Invalid IPP units={}'.format(form_data['ipp']*(20./3*(form_data['clock_in']/form_data['clock_divider']))))
89 #else:
90 # if form_data['ipp']*(20./3*(form_data['clock_in']/form_data['clock_divider']))%10!=0:
91 # self.add_error('ipp', 'Invalid IPP units={}'.format(form_data['ipp']*(20./3*(form_data['clock_in']/form_data['clock_divider']))))
92 92
93 93 return form_data
94 94
95 95 def save(self):
96 96 conf = super(RCConfigurationForm, self).save()
97 97 conf.total_units = conf.ipp*conf.ntx*conf.km2unit
98 98 conf.save()
99 99 return conf
100 100
101 101
102 102 class RCMixConfigurationForm(forms.Form):
103 103
104 104 clock_in = forms.CharField(widget=forms.HiddenInput())
105 105 clock_divider = forms.CharField(widget=forms.HiddenInput())
106 106 name = forms.CharField()
107 107 experiment = forms.ChoiceField()
108 108 mode = forms.ChoiceField(widget=forms.RadioSelect(),
109 109 choices=[(0, 'Parallel'), (1, 'Sequence')],
110 110 initial=0)
111 111 operation = forms.ChoiceField(widget=forms.RadioSelect(),
112 112 choices=[(0, 'OR'), (1, 'XOR'), (2, 'AND'), (3, 'NAND')],
113 113 initial=1)
114 114 delay = forms.CharField()
115 115 mask = forms.MultipleChoiceField(choices=[(0, 'L1'),(1, 'L2'),(2, 'L3'),(3, 'L4'),(4, 'L5'),(5, 'L6'),(6, 'L7'),(7, 'L8')],
116 116 widget=HCheckboxSelectMultiple())
117 117 result = forms.CharField(required=False,
118 118 widget=forms.Textarea(attrs={'readonly':True, 'rows':5, 'class':'tabuled'}))
119 119
120 120 def __init__(self, *args, **kwargs):
121 121 confs = kwargs.pop('confs', [])
122 122 if confs:
123 123 km2unit = confs[0].km2unit
124 124 clock_in = confs[0].clock_in
125 125 clock_divider = confs[0].clock_divider
126 126 else:
127 127 km2unit = clock_in = clock_divider = 0
128 128 super(RCMixConfigurationForm, self).__init__(*args, **kwargs)
129 129 self.fields['experiment'].choices = [(conf.pk, '{} | {}'.format(conf.pk, conf.name)) for conf in confs]
130 130 self.fields['delay'].widget = KmUnitWidget(attrs = {'km2unit':km2unit})
131 131 self.fields['clock_in'].initial = clock_in
132 132 self.fields['clock_divider'].initial = clock_divider
133 133
134 134
135 135 class RCLineForm(forms.ModelForm):
136 136
137 137 def __init__(self, *args, **kwargs):
138 138 self.extra_fields = kwargs.pop('extra_fields', [])
139 139 super(RCLineForm, self).__init__(*args, **kwargs)
140 140
141 141 if 'initial' in kwargs and 'line_type' in kwargs['initial']:
142 142 line_type = RCLineType.objects.get(pk=kwargs['initial']['line_type'])
143 143
144 144 if 'code_id' in kwargs['initial']:
145 145 model_initial = kwargs['initial']['code_id']
146 146 else:
147 147 model_initial = 0
148 148
149 149 params = json.loads(line_type.params)
150 150
151 151 for label, value in self.extra_fields.items():
152 152 if label=='params':
153 153 continue
154 154
155 155 if 'model' in params[label]:
156 156 self.fields[label] = forms.ChoiceField(choices=create_choices_from_model(params[label]['model'],
157 157 kwargs['initial']['rc_configuration']),
158 158 initial=model_initial)
159 159
160 160
161 161 else:
162 162 if label=='codes' and 'code_id' in kwargs['initial']:
163 163 self.fields[label] = forms.CharField(initial=RCLineCode.objects.get(pk=kwargs['initial']['code_id']).codes)
164 164 else:
165 165 self.fields[label] = forms.CharField(initial=value['value'])
166 166
167 167 if label=='codes':
168 168 self.fields[label].widget = CodesWidget()
169 169
170 170 if self.data:
171 171 line_type = RCLineType.objects.get(pk=self.data['line_type'])
172 172
173 173 if 'code_id' in self.data:
174 174 model_initial = self.data['code_id']
175 175 else:
176 176 model_initial = 0
177 177
178 178 params = json.loads(line_type.params)
179 179
180 180 for label, value in self.extra_fields.items():
181 181 if label=='params':
182 182 continue
183 183
184 184 if 'model' in params[label]:
185 185 self.fields[label] = forms.ChoiceField(choices=create_choices_from_model(params[label]['model'],
186 186 self.data['rc_configuration']),
187 187 initial=model_initial)
188 188
189 189
190 190 else:
191 191 if label=='codes' and 'code' in self.data:
192 192 self.fields[label] = forms.CharField(initial=self.data['codes'])
193 193 else:
194 194 self.fields[label] = forms.CharField(initial=self.data[label])
195 195
196 196 if label=='codes':
197 197 self.fields[label].widget = CodesWidget()
198 198
199 199
200 200 class Meta:
201 201 model = RCLine
202 202 fields = ('rc_configuration', 'line_type', 'channel')
203 203 widgets = {
204 204 'channel': forms.HiddenInput(),
205 205 }
206 206
207 207
208 208 def clean(self):
209 209
210 210 form_data = self.cleaned_data
211 211 if 'code' in self.data and self.data['TX_ref']=="0":
212 212 self.add_error('TX_ref', 'Choose a valid TX reference')
213 213
214 214 if RCLineType.objects.get(pk=self.data['line_type']).name=='mix':
215 215 self.add_error('line_type', 'Invalid Line type')
216 216
217 217 return form_data
218 218
219 219
220 220 def save(self):
221 221 line = super(RCLineForm, self).save()
222 222
223 223 #auto add channel
224 224 line.channel = RCLine.objects.filter(rc_configuration=line.rc_configuration).count()-1
225 225
226 226 #auto add position for TX, TR & CODE
227 227 if line.line_type.name in ('tx', ):
228 228 line.position = RCLine.objects.filter(rc_configuration=line.rc_configuration, line_type=line.line_type).count()-1
229 229
230 230 #save extra fields in params
231 231 params = {}
232 232 for label, value in self.extra_fields.items():
233 233 if label=='params':
234 234 params['params'] = []
235 235 elif label=='codes':
236 236 params[label] = [s for s in self.data[label].split('\r\n') if s]
237 237 else:
238 238 params[label] = self.data[label]
239 239 line.params = json.dumps(params)
240 240 line.save()
241 241 return
242 242
243 243
244 244 class RCLineViewForm(forms.Form):
245 245
246 246 def __init__(self, *args, **kwargs):
247 247
248 248 extra_fields = kwargs.pop('extra_fields')
249 249 line = kwargs.pop('line')
250 250 subform = kwargs.pop('subform', False)
251 251 super(RCLineViewForm, self).__init__(*args, **kwargs)
252 252
253 253 if subform:
254 254 params = json.loads(line.line_type.params)['params']
255 255 else:
256 256 params = json.loads(line.line_type.params)
257 257
258 258 for label, value in extra_fields.items():
259 259
260 260 if label=='params':
261 261 continue
262 262 if 'ref' in label:
263 263 if value in (0, '0'):
264 264 value = 'All'
265 265 else:
266 266 value = RCLine.objects.get(pk=value).get_name()
267 267 elif label=='code':
268 268 value = RCLineCode.objects.get(pk=value).name
269 269
270 270 self.fields[label] = forms.CharField(initial=value)
271 271
272 272 if 'widget' in params[label]:
273 273 km2unit = line.rc_configuration.km2unit
274 274 if params[label]['widget']=='km':
275 275 self.fields[label].widget = KmUnitWidget(attrs={'line':line, 'km2unit':km2unit, 'disabled':True})
276 276 elif params[label]['widget']=='unit':
277 277 self.fields[label].widget = UnitKmWidget(attrs={'line':line, 'km2unit':km2unit, 'disabled':True})
278 278 elif params[label]['widget']=='dc':
279 279 self.fields[label].widget = KmUnitDcWidget(attrs={'line':line, 'km2unit':km2unit, 'disabled':True})
280 280 elif params[label]['widget']=='codes':
281 281 self.fields[label].widget = CodesWidget(attrs={'line':line, 'km2unit':km2unit, 'disabled':True})
282 282 else:
283 283 self.fields[label].widget = DefaultWidget(attrs={'disabled':True})
284 284
285 285
286 286 class RCLineEditForm(forms.ModelForm):
287 287
288 288 def __init__(self, *args, **kwargs):
289 289
290 290 extra_fields = kwargs.pop('extra_fields', [])
291 291 conf = kwargs.pop('conf', False)
292 292 line = kwargs.pop('line')
293 293 subform = kwargs.pop('subform', False)
294 294
295 295 super(RCLineEditForm, self).__init__(*args, **kwargs)
296 296
297 297 if subform is not False:
298 298 params = json.loads(line.line_type.params)['params']
299 299 count = subform
300 300 else:
301 301 params = json.loads(line.line_type.params)
302 302 count = -1
303 303
304 304 for label, value in extra_fields.items():
305 305
306 306 if label in ('params',):
307 307 continue
308 308 if 'help' in params[label]:
309 309 help_text = params[label]['help']
310 310 else:
311 311 help_text = ''
312 312
313 313 if 'model' in params[label]:
314 314 if line.line_type.name=='tr':
315 315 all_choice = True
316 316 else:
317 317 all_choice = False
318 318 self.fields[label] = forms.ChoiceField(choices=create_choices_from_model(params[label]['model'], conf.id, all_choice=all_choice),
319 319 initial=value,
320 320 widget=forms.Select(attrs={'name':'%s|%s|%s' % (count, line.id, label)}),
321 321 help_text=help_text)
322 322
323 323 else:
324 324 self.fields[label] = forms.CharField(initial=value, help_text=help_text)
325 325
326 326 if label in ('code', ):
327 327 self.fields[label].widget = HiddenWidget(attrs={'name':'%s|%s|%s' % (count, line.id, label)})
328 328
329 329 elif 'widget' in params[label]:
330 330 km2unit = line.rc_configuration.km2unit
331 331 if params[label]['widget']=='km':
332 332 self.fields[label].widget = KmUnitWidget(attrs={'line':line, 'km2unit':km2unit, 'name':'%s|%s|%s' % (count, line.id, label)})
333 333 elif params[label]['widget']=='unit':
334 334 self.fields[label].widget = UnitKmWidget(attrs={'line':line, 'km2unit':km2unit, 'name':'%s|%s|%s' % (count, line.id, label)})
335 335 elif params[label]['widget']=='dc':
336 336 self.fields[label].widget = KmUnitDcWidget(attrs={'line':line, 'km2unit':km2unit, 'name':'%s|%s|%s' % (count, line.id, label)})
337 337 elif params[label]['widget']=='codes':
338 338 self.fields[label].widget = CodesWidget(attrs={'line':line, 'km2unit':km2unit, 'name':'%s|%s|%s' % (count, line.id, label)})
339 339 else:
340 340 self.fields[label].widget = DefaultWidget(attrs={'line':line, 'name':'%s|%s|%s' % (count, line.id, label)})
341 341
342 342
343 343 class Meta:
344 344 model = RCLine
345 345 exclude = ('rc_configuration', 'line_type', 'channel', 'position', 'params', 'pulses')
346 346
347 347
348 348 class RCSubLineEditForm(forms.Form):
349 349
350 350 def __init__(self, *args, **kwargs):
351 351 extra_fields = kwargs.pop('extra_fields')
352 352 count = kwargs.pop('count')
353 353 line = kwargs.pop('line')
354 354 super(RCSubLineEditForm, self).__init__(*args, **kwargs)
355 355 for label, value in extra_fields.items():
356 356 self.fields[label] = forms.CharField(initial=value,
357 357 widget=forms.TextInput(attrs={'name':'%s|%s|%s' % (count, line, label)}))
358 358
359 359
360 360 class RCImportForm(forms.Form):
361 361
362 362 file_name = ExtFileField(extensions=['.racp', '.json', '.dat'])
363 363
364 364
365 365 class RCLineCodesForm(forms.ModelForm):
366 366
367 367 def __init__(self, *args, **kwargs):
368 368 super(RCLineCodesForm, self).__init__(*args, **kwargs)
369 369
370 370 if 'initial' in kwargs:
371 371 self.fields['code'] = forms.ChoiceField(choices=RCLineCode.objects.all().values_list('pk', 'name'),
372 372 initial=kwargs['initial']['code'])
373 373 if 'instance' in kwargs:
374 374 self.fields['code'] = forms.ChoiceField(choices=RCLineCode.objects.all().values_list('pk', 'name'),
375 375 initial=kwargs['instance'].pk)
376 376
377 377 self.fields['codes'].widget = CodesWidget()
378 378
379 379
380 380 class Meta:
381 381 model = RCLineCode
382 382 exclude = ('name',)
@@ -1,978 +1,982
1 1
2
2 3 import ast
3 4 import json
4 5 import requests
5 6 import numpy as np
6 7 from base64 import b64encode
7 8 from struct import pack
8 9
9 10 from django.db import models
10 11 from django.core.urlresolvers import reverse
11 12 from django.core.validators import MinValueValidator, MaxValueValidator
12 13
13 14 from apps.main.models import Configuration
15 from apps.main.utils import Params
14 16 from devices.rc import api
15 from .utils import RCFile
16 from django.template.defaultfilters import last
17 from apps.rc.utils import RCFile
17 18
18 # Create your models here.
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 MAX_BITS = 8
61
62 # Rotate left: 0b1001 --> 0b0011
63 rol = lambda val, r_bits: \
64 (val << r_bits%MAX_BITS) & (2**MAX_BITS-1) | \
65 ((val & (2**MAX_BITS-1)) >> (MAX_BITS-(r_bits%MAX_BITS)))
66
67 # Rotate right: 0b1001 --> 0b1100
68 ror = lambda val, r_bits: \
69 ((val & (2**MAX_BITS-1)) >> r_bits%MAX_BITS) | \
70 (val << (MAX_BITS-(r_bits%MAX_BITS)) & (2**MAX_BITS-1))
71
60 72
61 73 class RCConfiguration(Configuration):
62 74
63 75 ipp = models.FloatField(verbose_name='IPP [Km]', validators=[MinValueValidator(1), MaxValueValidator(9000)], default=300)
64 76 ntx = models.PositiveIntegerField(verbose_name='Number of TX', validators=[MinValueValidator(1), MaxValueValidator(400)], default=1)
65 77 clock_in = models.FloatField(verbose_name='Clock in [MHz]', validators=[MinValueValidator(1), MaxValueValidator(80)], default=1)
66 78 clock_divider = models.PositiveIntegerField(verbose_name='Clock divider', validators=[MinValueValidator(1), MaxValueValidator(256)], default=1)
67 79 clock = models.FloatField(verbose_name='Clock Master [MHz]', blank=True, default=1)
68 80 time_before = models.PositiveIntegerField(verbose_name='Time before [&mu;S]', default=12)
69 81 time_after = models.PositiveIntegerField(verbose_name='Time after [&mu;S]', default=1)
70 82 sync = models.PositiveIntegerField(verbose_name='Synchro delay', default=0)
71 83 sampling_reference = models.CharField(verbose_name='Sampling Reference', choices=SAMPLING_REFS, default='none', max_length=40)
72 84 control_tx = models.BooleanField(verbose_name='Control Switch TX', default=False)
73 85 control_sw = models.BooleanField(verbose_name='Control Switch SW', default=False)
74 86 total_units = models.PositiveIntegerField(default=0)
75 87 mix = models.BooleanField(default=False)
76 88
77 89 class Meta:
78 90 db_table = 'rc_configurations'
79 91
80 92 def get_absolute_url_plot(self):
81 93 return reverse('url_plot_rc_pulses', args=[str(self.id)])
82 94
83 def get_absolute_url_import(self):
84 return reverse('url_import_rc_conf', args=[str(self.id)])
85
86 95 @property
87 96 def ipp_unit(self):
88 97
89 98 return '{} ({})'.format(self.ipp, int(self.ipp*self.km2unit))
90 99
91 100 @property
92 101 def us2unit(self):
93 102
94 103 return self.clock_in/self.clock_divider
95 104
96 105 @property
97 106 def km2unit(self):
98 107
99 108 return 20./3*(self.clock_in/self.clock_divider)
100 109
101 110 def clone(self, **kwargs):
102 111
103 112 lines = self.get_lines()
113 print 'LINES'
114 print lines
104 115 self.pk = None
105 116 self.id = None
106 117 for attr, value in kwargs.items():
107 118 setattr(self, attr, value)
108 119 self.save()
109 120
110 121 for line in lines:
111 122 line.clone(rc_configuration=self)
112 123
124 new_lines = self.get_lines()
125 for line in new_lines:
126 line_params = json.loads(line.params)
127 if 'TX_ref' in line_params:
128 ref_line = RCLine.objects.get(pk=line_params['TX_ref'])
129 line_params['TX_ref'] = ['{}'.format(l.pk) for l in new_lines if l.get_name()==ref_line.get_name()][0]
130 line.params = json.dumps(line_params)
131 line.save()
132
113 133 return self
114 134
115 135 def get_lines(self, **kwargs):
116 136 '''
117 137 Retrieve configuration lines
118 138 '''
119 139
120 140 return RCLine.objects.filter(rc_configuration=self.pk, **kwargs)
121 141
122 142
123 143 def clean_lines(self):
124 144 '''
125 145 '''
126 146
127 147 empty_line = RCLineType.objects.get(name='none')
128 148
129 149 for line in self.get_lines():
130 150 line.line_type = empty_line
131 151 line.params = '{}'
132 152 line.save()
133 153
134 def parms_to_dict(self):
154 def dict_to_parms(self, params, id=None):
135 155 '''
136 156 '''
137 157
138 ignored = ('parameters', 'type','polymorphic_ctype', 'configuration_ptr',
139 'created_date', 'programmed_date', 'mix')
140
141 data = {}
142 for field in self._meta.fields:
143 if field.name in ignored:
144 continue
145 data[field.name] = '{}'.format(field.value_from_object(self))
146
147 data['device_id'] = data.pop('device')
148 data['device_type'] = self.device.device_type.name
149 data['lines'] = []
150 data['mix'] = self.mix
151
152 for line in self.get_lines():
153 line_data = json.loads(line.params)
154 if 'TX_ref' in line_data and line_data['TX_ref'] not in (0, '0'):
155 line_data['TX_ref'] = RCLine.objects.get(pk=line_data['TX_ref']).get_name()
156 if 'code' in line_data:
157 line_data['code'] = RCLineCode.objects.get(pk=line_data['code']).name
158 line_data['type'] = line.line_type.name
159 line_data['name'] = line.get_name()
160 data['lines'].append(line_data)
161
162 data['delays'] = self.get_delays()
163 data['pulses'] = self.get_pulses()
164
165 return data
166
167 def dict_to_parms(self, data):
168 '''
169 '''
158 if id:
159 data = Params(params).get_conf(id_conf=id)
160 else:
161 data = Params(params).get_conf(dtype='rc')
170 162
171 163 self.name = data['name']
172 self.ipp = float(data['ipp'])
173 self.ntx = int(data['ntx'])
174 self.clock_in = float(data['clock_in'])
175 self.clock_divider = int(data['clock_divider'])
176 self.clock = float(data['clock'])
164 self.ipp = data['ipp']
165 self.ntx = data['ntx']
166 self.clock_in = data['clock_in']
167 self.clock_divider = data['clock_divider']
168 self.clock = data['clock']
177 169 self.time_before = data['time_before']
178 170 self.time_after = data['time_after']
179 171 self.sync = data['sync']
180 172 self.sampling_reference = data['sampling_reference']
181 173 self.total_units = self.ipp*self.ntx*self.km2unit
182 174 self.save()
183 175 self.clean_lines()
184 176
185 lines = []
186 177 positions = {'tx':0, 'tr':0}
187
188 for i, line_data in enumerate(data['lines']):
189 name = line_data.pop('name', '')
190 line_type = RCLineType.objects.get(name=line_data.pop('type'))
178 for i, id in enumerate(data['lines']):
179 line_data = params['lines']['byId'][id]
180 line_type = RCLineType.objects.get(name=line_data['line_type'])
191 181 if line_type.name=='codes':
192 code = RCLineCode.objects.get(name=line_data['code'])
193 line_data['code'] = code.pk
194 line = RCLine.objects.filter(rc_configuration=self, channel=i)
195 if line:
196 line = line[0]
197 line.line_type = line_type
198 line.params = json.dumps(line_data)
199 else:
200 line = RCLine(rc_configuration=self, line_type=line_type,
201 params=json.dumps(line_data),
202 channel=i)
203
182 code = RCLineCode.objects.get(name=line_data['params']['code'])
183 line_data['params']['code'] = code.pk
204 184 if line_type.name=='tx':
205 line.position = positions['tx']
185 position = positions['tx']
206 186 positions['tx'] += 1
207
208 if line_type.name=='tr':
209 line.position = positions['tr']
187 elif line_type.name == 'tr':
188 position = positions['tr']
210 189 positions['tr'] += 1
190 else:
191 position = 0
192 line, dum = RCLine.objects.update_or_create(
193 rc_configuration=self,
194 channel=i,
195 position=position,
196 defaults={
197 'line_type': line_type,
198 'params': json.dumps(line_data['params'])
199 }
200 )
211 201
212 line.save()
213 lines.append(line)
214
215 for line, line_data in zip(lines, data['lines']):
216 if 'TX_ref' in line_data:
217 params = json.loads(line.params)
218 if line_data['TX_ref'] in (0, '0'):
219 params['TX_ref'] = '0'
202 for i, line in enumerate(self.get_lines()):
203 line_params = json.loads(line.params)
204 if 'TX_ref' in line_params:
205 if line_params['TX_ref'] in (0, '0'):
206 line_params['TX_ref'] = '0'
220 207 else:
221 params['TX_ref'] = [l.pk for l in lines if l.line_type.name=='tx' and line_data['TX_ref'] in l.get_name()][0]
222 line.params = json.dumps(params)
208 ref_id = '{}'.format(line_params['TX_ref'])
209 ref_line = params['lines']['byId'][ref_id]
210 line_params['TX_ref'] = RCLine.objects.get(
211 rc_configuration=self,
212 params=json.dumps(ref_line['params'])
213 ).pk
214 line.params = json.dumps(line_params)
223 215 line.save()
224 216
225 217
226 218 def get_delays(self):
227 219
228 220 pulses = [line.pulses_as_points() for line in self.get_lines()]
229 221 points = [tup for tups in pulses for tup in tups]
230 222 points = set([x for tup in points for x in tup])
231 223 points = list(points)
232 224 points.sort()
233 225
234 226 if points[0]!=0:
235 227 points.insert(0, 0)
236 228
237 229 return [points[i+1]-points[i] for i in range(len(points)-1)]
238 230
239 231
240 232 def get_pulses(self, binary=True):
241 233
242
243 234 pulses = [line.pulses_as_points() for line in self.get_lines()]
244 235 tuples = [tup for tups in pulses for tup in tups]
245 236 points = set([x for tup in tuples for x in tup])
246 237 points = list(points)
247 238 points.sort()
248 239 states = []
249 240 last = [0 for x in pulses]
250 241
251 242 for x in points:
252 243 dum = []
253 244 for i,tups in enumerate(pulses):
254 245 ups = [tup[0] for tup in tups]
255 246 dws = [tup[1] for tup in tups]
256 247 if x in ups:
257 248 dum.append(1)
258 249 elif x in dws:
259 250 dum.append(0)
260 251 else:
261 252 dum.append(last[i])
262 253 states.append(dum)
263 254 last = dum
264 255
265 256 if binary:
266 257 ret = []
267 258 for flips in states:
268 259 flips.reverse()
269 260 ret.append(int(''.join([str(x) for x in flips]), 2))
270 261 states = ret
271 262
272 263 return states[:-1]
273 264
274 265 def add_cmd(self, cmd):
275 266
276 267 if cmd in DAT_CMDS:
277 268 return (255, DAT_CMDS[cmd])
278 269
279 270 def add_data(self, value):
280 271
281 272 return (254, value-1)
282 273
283 274 def parms_to_binary(self, dat=True):
284 275 '''
285 276 Create "dat" stream to be send to CR
286 277 '''
287 278
288 279 data = bytearray()
289 280 # create header
290 281 data.extend(self.add_cmd('DISABLE'))
291 282 data.extend(self.add_cmd('CONTINUE'))
292 283 data.extend(self.add_cmd('RESTART'))
293 284
294 285 if self.control_sw:
295 286 data.extend(self.add_cmd('SW_ONE'))
296 287 else:
297 288 data.extend(self.add_cmd('SW_ZERO'))
298 289
299 290 if self.control_tx:
300 291 data.extend(self.add_cmd('TX_ONE'))
301 292 else:
302 293 data.extend(self.add_cmd('TX_ZERO'))
303 294
304 295 # write divider
305 296 data.extend(self.add_cmd('CLOCK_DIVIDER'))
306 297 data.extend(self.add_data(self.clock_divider))
307 298
308 299 # write delays
309 300 data.extend(self.add_cmd('DELAY_START'))
310 301 # first delay is always zero
311 302 data.extend(self.add_data(1))
312 303
313 304 delays = self.get_delays()
314 305
315 306 for delay in delays:
316 307 while delay>252:
317 308 data.extend(self.add_data(253))
318 309 delay -= 253
319 310 data.extend(self.add_data(int(delay)))
320 311
321 312 # write flips
322 313 data.extend(self.add_cmd('FLIP_START'))
323 314
324 315 states = self.get_pulses(binary=True)
325 316
326 317
327 318 last = 0
328 319 for flip, delay in zip(states, delays):
329 320 data.extend(self.add_data((flip^last)+1))
330 321 last = flip
331 322 while delay>252:
332 323 data.extend(self.add_data(1))
333 324 delay -= 253
334 325
335 326 # write sampling period
336 327 data.extend(self.add_cmd('SAMPLING_PERIOD'))
337 328 wins = self.get_lines(line_type__name='windows')
338 329 if wins:
339 330 win_params = json.loads(wins[0].params)['params']
340 331 if win_params:
341 332 dh = int(win_params[0]['resolution']*self.km2unit)
342 333 else:
343 334 dh = 1
344 335 else:
345 336 dh = 1
346 337 data.extend(self.add_data(dh))
347 338
348 339 # write enable
349 340 data.extend(self.add_cmd('ENABLE'))
350 341
351 342 if not dat:
352 343 return data
353 344
354 345 return '\n'.join(['{}'.format(x) for x in data])
355 346
356
357 def update_from_file(self, filename):
358 '''
359 Update instance from file
360 '''
361
362 f = RCFile(filename)
363 self.dict_to_parms(f.data)
364 self.update_pulses()
365
366 347 def update_pulses(self):
367 348
368 349 for line in self.get_lines():
369 350 line.update_pulses()
370 351
371 352 def plot_pulses2(self, km=False):
372 353
373 354 import matplotlib.pyplot as plt
374 355 from bokeh.resources import CDN
375 356 from bokeh.embed import components
376 357 from bokeh.mpl import to_bokeh
377 358 from bokeh.models.tools import WheelZoomTool, ResetTool, PanTool, HoverTool, SaveTool
378 359
379 360 lines = self.get_lines()
380 361
381 362 N = len(lines)
382 363 npoints = self.total_units/self.km2unit if km else self.total_units
383 364 fig = plt.figure(figsize=(12, 2+N*0.5))
384 365 ax = fig.add_subplot(111)
385 366 labels = ['IPP']
386 367
387 368 for i, line in enumerate(lines):
388 369 labels.append(line.get_name(channel=True))
389 370 l = ax.plot((0, npoints),(N-i-1, N-i-1))
390 371 points = [(tup[0], tup[1]-tup[0]) for tup in line.pulses_as_points(km=km) if tup!=(0,0)]
391 372 ax.broken_barh(points, (N-i-1, 0.5),
392 373 edgecolor=l[0].get_color(), facecolor='none')
393 374
394 375 n = 0
395 376 f = ((self.ntx+50)/100)*5 if ((self.ntx+50)/100)*10>0 else 2
396 377 for x in np.arange(0, npoints, self.ipp if km else self.ipp*self.km2unit):
397 378 if n%f==0:
398 379 ax.text(x, N, '%s' % n, size=10)
399 380 n += 1
400 381
401
402 382 labels.reverse()
403 383 ax.set_yticks(range(len(labels)))
404 384 ax.set_yticklabels(labels)
405 385 ax.set_xlabel = 'Units'
406 386 plot = to_bokeh(fig, use_pandas=False)
407 387 plot.tools = [PanTool(dimensions=['width']), WheelZoomTool(dimensions=['width']), ResetTool(), SaveTool()]
408 388 plot.toolbar_location="above"
409 389
410 390 return components(plot, CDN)
411 391
412 392 def plot_pulses(self, km=False):
413 393
414 394 from bokeh.plotting import figure
415 395 from bokeh.resources import CDN
416 396 from bokeh.embed import components
417 397 from bokeh.models import FixedTicker, PrintfTickFormatter
418 398 from bokeh.models.tools import WheelZoomTool, ResetTool, PanTool, HoverTool, SaveTool
419 399 from bokeh.models.sources import ColumnDataSource
420 400
421 401 lines = self.get_lines().reverse()
422 402
423 403 N = len(lines)
424 404 npoints = self.total_units/self.km2unit if km else self.total_units
425 405 ipp = self.ipp if km else self.ipp*self.km2unit
426 406
427 407 hover = HoverTool(tooltips=[("Line", "@name"),
428 408 ("IPP", "@ipp"),
429 409 ("X", "@left")])
430 410
431 411 tools = [PanTool(dimensions=['width']),
432 412 WheelZoomTool(dimensions=['width']),
433 413 hover, SaveTool()]
434 414
435 415 plot = figure(width=1000,
436 416 height=40+N*50,
437 417 y_range = (0, N),
438 418 tools=tools,
439 419 toolbar_location='above',
440 420 toolbar_sticky=False,)
441 421
442 422 plot.xaxis.axis_label = 'Km' if km else 'Units'
443 423 plot.xaxis[0].formatter = PrintfTickFormatter(format='%d')
444 424 plot.yaxis.axis_label = 'Pulses'
445 425 plot.yaxis[0].ticker=FixedTicker(ticks=list(range(N)))
446 426 plot.yaxis[0].formatter = PrintfTickFormatter(format='Line %d')
447 427
448 428 for i, line in enumerate(lines):
449 429
450 430 points = [tup for tup in line.pulses_as_points(km=km) if tup!=(0,0)]
451 431
452 432 source = ColumnDataSource(data = dict(
453 433 bottom = [i for tup in points],
454 434 top = [i+0.5 for tup in points],
455 435 left = [tup[0] for tup in points],
456 436 right = [tup[1] for tup in points],
457 437 ipp = [int(tup[0]/ipp) for tup in points],
458 438 name = [line.get_name() for tup in points]
459 439 ))
460 440
461 441 plot.quad(
462 442 bottom = 'bottom',
463 443 top = 'top',
464 444 left = 'left',
465 445 right = 'right',
466 446 source = source,
467 447 fill_alpha = 0,
468 448 #line_color = 'blue',
469 449 )
470 450
471 451 plot.line([0, npoints], [i, i])#, color='blue')
472 452
473 453 return components(plot, CDN)
474 454
455 def request(self, cmd, method='get', **kwargs):
456
457 req = getattr(requests, method)(self.device.url(cmd), **kwargs)
458 payload = req.json()
459
460 return payload
461
475 462 def status_device(self):
476 463
477 464 try:
478 465 self.device.status = 0
479 req = requests.get(self.device.url('status'))
480 payload = req.json()
481 if payload['status']=='enabled':
466 payload = self.request('status')
467 if payload['status']=='enable':
482 468 self.device.status = 3
483 elif payload['status']=='disabled':
469 elif payload['status']=='disable':
484 470 self.device.status = 2
485 471 else:
486 472 self.device.status = 1
487 473 self.device.save()
488 self.message = payload['status']
474 self.message = 'RC status: {}'.format(payload['status'])
489 475 return False
490 476 except Exception as e:
491 477 if 'No route to host' not in str(e):
492 478 self.device.status = 4
493 479 self.device.save()
494 self.message = str(e)
480 self.message = 'RC status: {}'.format(str(e))
495 481 return False
496 482
497 483 self.device.save()
498 484 return True
499 485
500 486 def reset_device(self):
501 487
502 488 try:
503 req = requests.post(self.device.url('reset'))
504 payload = req.json()
489 payload = self.request('reset', 'post')
505 490 if payload['reset']=='ok':
506 self.message = 'RC restarted'
491 self.message = 'RC restarted OK'
492 self.device.status = 2
493 self.device.save()
507 494 else:
508 self.message = 'RC restart not ok'
495 self.message = 'RC restart fail'
509 496 self.device.status = 4
510 497 self.device.save()
511 498 except Exception as e:
512 self.message = str(e)
499 self.message = 'RC reset: {}'.format(str(e))
513 500 return False
514 501
515 502 return True
516 503
517 504 def stop_device(self):
518 505
519 506 try:
520 req = requests.post(self.device.url('stop'))
521 payload = req.json()
507 payload = self.request('stop', 'post')
508 self.message = 'RC stop: {}'.format(payload['stop'])
522 509 if payload['stop']=='ok':
523 510 self.device.status = 2
524 511 self.device.save()
525 self.message = 'RC stopped'
526 512 else:
527 self.message = 'RC stop not ok'
528 513 self.device.status = 4
529 514 self.device.save()
530 515 return False
531 516 except Exception as e:
532 517 if 'No route to host' not in str(e):
533 518 self.device.status = 4
534 519 else:
535 520 self.device.status = 0
536 self.message = str(e)
521 self.message = 'RC stop: {}'.format(str(e))
537 522 self.device.save()
538 523 return False
539 524
540 525 return True
541 526
542 527 def start_device(self):
543 528
544 529 try:
545 req = requests.post(self.device.url('start'))
546 payload = req.json()
530 payload = self.request('start', 'post')
531 self.message = 'RC start: {}'.format(payload['start'])
547 532 if payload['start']=='ok':
548 533 self.device.status = 3
549 534 self.device.save()
550 self.message = 'RC running'
551 535 else:
552 self.message = 'RC start not ok'
553 536 return False
554 537 except Exception as e:
555 538 if 'No route to host' not in str(e):
556 539 self.device.status = 4
557 540 else:
558 541 self.device.status = 0
559 self.message = str(e)
542 self.message = 'RC start: {}'.format(str(e))
560 543 self.device.save()
561 544 return False
562 545
563 546 return True
564 547
565 548 def write_device(self):
566 549
567 550 values = zip(self.get_pulses(),
568 551 [x-1 for x in self.get_delays()])
569 552
570 553 data = bytearray()
571 554 #reset
572 555 data.extend((128, 0))
573 556 #disable
574 557 data.extend((129, 0))
575 558 #divider
576 559 data.extend((131, self.clock_divider-1))
577 560 #enable writing
578 561 data.extend((139, 62))
579 562
580 563 last = 0
581 564 for tup in values:
582 565 vals = pack('<HH', last^tup[0], tup[1])
583 566 last = tup[0]
584 567 data.extend((133, vals[1], 132, vals[0], 133, vals[3], 132, vals[2]))
585 568
586 569 #enable
587 570 data.extend((129, 1))
588 571
589 572 try:
590 req = requests.post(self.device.url('write'), data=b64encode(data))
591 payload = req.json()
573 payload = self.request('write', 'post', data=b64encode(data))
574
592 575 if payload['write']=='ok':
593 self.device.status = 2
576 self.device.status = 3
594 577 self.device.save()
595 self.message = 'RC configured'
578 self.message = 'RC configured and started'
596 579 else:
597 580 self.device.status = 1
598 581 self.device.save()
599 self.message = 'RC write not ok'
582 self.message = 'RC write: {}'.format(payload['write'])
600 583 return False
601 584
602 585 except Exception as e:
603 586 if 'No route to host' not in str(e):
604 587 self.device.status = 4
605 588 else:
606 589 self.device.status = 0
607 self.message = str(e)
590 self.message = 'RC write: {}'.format(str(e))
608 591 self.device.save()
609 592 return False
610 593
611 594 return True
612 595
613 596
597 def get_absolute_url_import(self):
598 return reverse('url_import_rc_conf', args=[str(self.id)])
599
600
614 601 class RCLineCode(models.Model):
615 602
616 603 name = models.CharField(max_length=40)
617 604 bits_per_code = models.PositiveIntegerField(default=0)
618 605 number_of_codes = models.PositiveIntegerField(default=0)
619 606 codes = models.TextField(blank=True, null=True)
620 607
621 608 class Meta:
622 609 db_table = 'rc_line_codes'
623 610 ordering = ('name',)
624 611
625 612 def __str__(self):
626 613 return u'%s' % self.name
627 614
628 615
629 616 class RCLineType(models.Model):
630 617
631 618 name = models.CharField(choices=LINE_TYPES, max_length=40)
632 619 description = models.TextField(blank=True, null=True)
633 620 params = models.TextField(default='[]')
634 621
635 622 class Meta:
636 623 db_table = 'rc_line_types'
637 624
638 625 def __str__(self):
639 626 return u'%s - %s' % (self.name.upper(), self.get_name_display())
640 627
641 628
642 629 class RCLine(models.Model):
643 630
644 631 rc_configuration = models.ForeignKey(RCConfiguration, on_delete=models.CASCADE)
645 632 line_type = models.ForeignKey(RCLineType)
646 633 channel = models.PositiveIntegerField(default=0)
647 634 position = models.PositiveIntegerField(default=0)
648 635 params = models.TextField(default='{}')
649 636 pulses = models.TextField(default='')
650 637
651 638 class Meta:
652 639 db_table = 'rc_lines'
653 640 ordering = ['channel']
654 641
655 642 def __str__(self):
656 643 if self.rc_configuration:
657 644 return u'%s - %s' % (self.rc_configuration, self.get_name())
658 645
646 def jsonify(self):
647
648 data = {}
649 data['params'] = json.loads(self.params)
650 data['id'] = '{}'.format(self.pk)
651 data['line_type'] = self.line_type.name
652 data['name'] = self.get_name()
653 if data['line_type']=='codes':
654 data['params']['code'] = RCLineCode.objects.get(pk=data['params']['code']).name
655
656 return data
657
658
659 659 def clone(self, **kwargs):
660 660
661 661 self.pk = None
662 self.id = None
662 663
663 664 for attr, value in kwargs.items():
664 665 setattr(self, attr, value)
665 666
666 667 self.save()
667 668
668 669 return self
669 670
670 671 def get_name(self, channel=False):
671 672
672 673 chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
673 674 s = ''
674 675
675 676 if self.line_type.name in ('tx',):
676 677 s = chars[self.position]
677 678 elif self.line_type.name in ('codes', 'windows', 'tr'):
678 679 if 'TX_ref' in json.loads(self.params):
679 680 pk = json.loads(self.params)['TX_ref']
680 681 if pk in (0, '0'):
681 682 s = ','.join(chars[l.position] for l in self.rc_configuration.get_lines(line_type__name='tx'))
682 683 else:
683 684 ref = RCLine.objects.get(pk=pk)
684 685 s = chars[ref.position]
685 686 s = '({})'.format(s)
686 687
687 688 s = '{}{}'.format(self.line_type.name.upper(), s)
688 689
689 690 if channel:
690 691 return '{} {}'.format(s, self.channel)
691 692 else:
692 693 return s
693 694
694 695 def get_lines(self, **kwargs):
695 696
696 697 return RCLine.objects.filter(rc_configuration=self.rc_configuration, **kwargs)
697 698
698 699 def pulses_as_array(self):
699 700
700 701 y = np.zeros(self.rc_configuration.total_units)
701 702
702 703 for tup in ast.literal_eval(self.pulses):
703 704 y[tup[0]:tup[1]] = 1
704 705
705 706 return y.astype(np.int8)
706 707
707 708 def pulses_as_points(self, km=False):
708 709
709 710 if km:
710 711 unit2km = 1/self.rc_configuration.km2unit
711 712 return [(tup[0]*unit2km, tup[1]*unit2km) for tup in ast.literal_eval(self.pulses)]
712 713 else:
713 714 return ast.literal_eval(self.pulses)
714 715
715 716 def get_win_ref(self, params, tx_id, km2unit):
716 717
717 718 ref = self.rc_configuration.sampling_reference
718 719 codes = [line for line in self.get_lines(line_type__name='codes') if int(json.loads(line.params)['TX_ref'])==int(tx_id)]
719 720
720 721 if codes:
721 722 tx_width = float(json.loads(RCLine.objects.get(pk=tx_id).params)['pulse_width'])*km2unit/len(json.loads(codes[0].params)['codes'][0])
722 723 else:
723 724 tx_width = float(json.loads(RCLine.objects.get(pk=tx_id).params)['pulse_width'])*km2unit
724 725
725 726 if ref=='first_baud':
726 727 return int(1 + round((tx_width + 1)/2 + params['first_height']*km2unit - params['resolution']*km2unit))
727 728 elif ref=='sub_baud':
728 729 return np.ceil(1 + params['first_height']*km2unit - params['resolution']*km2unit/2)
729 730 else:
730 731 return 0
731 732
732 733 def update_pulses(self):
733 734 '''
734 735 Update pulses field
735 736 '''
736 737
737 738 km2unit = self.rc_configuration.km2unit
738 739 us2unit = self.rc_configuration.us2unit
739 740 ipp = self.rc_configuration.ipp
740 741 ntx = int(self.rc_configuration.ntx)
741 742 ipp_u = int(ipp*km2unit)
742 743 total = ipp_u*ntx if self.rc_configuration.total_units==0 else self.rc_configuration.total_units
743 744 y = []
744 745
745 746 if self.line_type.name=='tr':
746 747 tr_params = json.loads(self.params)
747 748
748 749 if tr_params['TX_ref'] in ('0', 0):
749 750 txs = self.get_lines(line_type__name='tx')
750 751 else:
751 752 txs = RCLine.objects.filter(pk=tr_params['TX_ref'])
752 753
753 754 for tx in txs:
754 755 params = json.loads(tx.params)
755 756
756 757 if float(params['pulse_width'])==0:
757 758 continue
758 759 delays = [float(d)*km2unit for d in params['delays'].split(',') if d]
759 760 width = float(params['pulse_width'])*km2unit+int(self.rc_configuration.time_before*us2unit)
760 761 before = 0
761 762 after = int(self.rc_configuration.time_after*us2unit)
762 763
763 764 y_tx = self.points(ntx, ipp_u, width,
764 765 delay=delays,
765 766 before=before,
766 767 after=after,
767 768 sync=self.rc_configuration.sync)
768 769
769 770 ranges = params['range'].split(',')
770 771
771 772 if len(ranges)>0 and ranges[0]!='0':
772 773 y_tx = self.mask_ranges(y_tx, ranges)
773 774
774 775 tr_ranges = tr_params['range'].split(',')
775 776
776 777 if len(tr_ranges)>0 and tr_ranges[0]!='0':
777 778 y_tx = self.mask_ranges(y_tx, tr_ranges)
778 779
779 780 y.extend(y_tx)
780 781
781 782 self.pulses = str(y)
782 783 y = self.array_to_points(self.pulses_as_array())
783 784
784 785 elif self.line_type.name=='tx':
785 786 params = json.loads(self.params)
786 787 delays = [float(d)*km2unit for d in params['delays'].split(',') if d]
787 788 width = float(params['pulse_width'])*km2unit
788 789
789 790 if width>0:
790 791 before = int(self.rc_configuration.time_before*us2unit)
791 792 after = 0
792 793
793 794 y = self.points(ntx, ipp_u, width,
794 795 delay=delays,
795 796 before=before,
796 797 after=after,
797 798 sync=self.rc_configuration.sync)
798 799
799 800 ranges = params['range'].split(',')
800 801
801 802 if len(ranges)>0 and ranges[0]!='0':
802 803 y = self.mask_ranges(y, ranges)
803 804
804 805 elif self.line_type.name=='flip':
805 806 n = float(json.loads(self.params)['number_of_flips'])
806 807 width = n*ipp*km2unit
807 808 y = self.points(int((ntx+1)/(2*n)), ipp_u*n*2, width)
808 809
809 810 elif self.line_type.name=='codes':
810 811 params = json.loads(self.params)
811 812 tx = RCLine.objects.get(pk=params['TX_ref'])
812 813 tx_params = json.loads(tx.params)
813 814 delays = [float(d)*km2unit for d in tx_params['delays'].split(',') if d]
814 815 f = int(float(tx_params['pulse_width'])*km2unit/len(params['codes'][0]))
815 816 codes = [(np.fromstring(''.join([s*f for s in code]), dtype=np.uint8)-48).astype(np.int8) for code in params['codes']]
816 817 codes = [self.array_to_points(code) for code in codes]
817 818 n = len(codes)
818 819
819 820 ranges = tx_params['range'].split(',')
820 821 if len(ranges)>0 and ranges[0]!='0':
821 822 dum = self.mask_ranges(tx.pulses_as_points(), ranges)
822 823 else:
823 824 dum = tx.pulses_as_points()
824 825
825 826 for i, tup in enumerate(dum):
826 827 if tup==(0,0): continue
827 828 code = codes[i%n]
828 829 y.extend([(c[0]+tup[0], c[1]+tup[0]) for c in code])
829 830
830 831 elif self.line_type.name=='sync':
831 832 params = json.loads(self.params)
832 833 n = ipp_u*ntx
833 834 if params['invert'] in ('1', 1):
834 835 y = [(n-1, n)]
835 836 else:
836 837 y = [(0, 1)]
837 838
838 839 elif self.line_type.name=='prog_pulses':
839 840 params = json.loads(self.params)
840 841 if int(params['periodic'])==0:
841 842 nntx = 1
842 843 nipp = ipp_u*ntx
843 844 else:
844 845 nntx = ntx
845 846 nipp = ipp_u
846 847
847 848 if 'params' in params and len(params['params'])>0:
848 849 for p in params['params']:
849 850 y_pp = self.points(nntx, nipp,
850 851 p['end']-p['begin'],
851 852 before=p['begin'])
852 853
853 854 y.extend(y_pp)
854 855
855 856 elif self.line_type.name=='windows':
856 857 params = json.loads(self.params)
857 858 if 'params' in params and len(params['params'])>0:
858 859 tr_params = json.loads(self.get_lines(line_type__name='tr')[0].params)
859 860 tr_ranges = tr_params['range'].split(',')
860 861 for p in params['params']:
861 862 y_win = self.points(ntx, ipp_u,
862 863 p['resolution']*p['number_of_samples']*km2unit,
863 864 before=int(self.rc_configuration.time_before*us2unit),
864 865 sync=self.rc_configuration.sync+self.get_win_ref(p, params['TX_ref'], km2unit))
865 866
866 867
867 868 if len(tr_ranges)>0 and tr_ranges[0]!='0':
868 869 y_win = self.mask_ranges(y_win, tr_ranges)
869 870
870 871 y.extend(y_win)
871 872
872 873 elif self.line_type.name=='mix':
873 874 values = self.rc_configuration.parameters.split('-')
874 875 confs = [RCConfiguration.objects.get(pk=value.split('|')[0]) for value in values]
875 876 modes = [value.split('|')[1] for value in values]
876 877 ops = [value.split('|')[2] for value in values]
877 878 delays = [value.split('|')[3] for value in values]
878 879 masks = [value.split('|')[4] for value in values]
879 880 mask = list('{:8b}'.format(int(masks[0])))
880 881 mask.reverse()
881 882 if mask[self.channel] in ('0', '', ' '):
882 883 y = np.zeros(confs[0].total_units, dtype=np.int8)
883 884 else:
884 885 y = confs[0].get_lines(channel=self.channel)[0].pulses_as_array()
885 886
886 887 for i in range(1, len(values)):
887 888 mask = list('{:8b}'.format(int(masks[i])))
888 889 mask.reverse()
889 890
890 891 if mask[self.channel] in ('0', '', ' '):
891 892 continue
892 893 Y = confs[i].get_lines(channel=self.channel)[0].pulses_as_array()
893 894 delay = float(delays[i])*km2unit
894 895
895 896 if modes[i]=='P':
896 897 if delay>0:
897 898 if delay<self.rc_configuration.ipp*km2unit and len(Y)==len(y):
898 899 y_temp = np.empty_like(Y)
899 900 y_temp[:delay] = 0
900 901 y_temp[delay:] = Y[:-delay]
901 902 elif delay+len(Y)>len(y):
902 903 y_new = np.zeros(delay+len(Y), dtype=np.int8)
903 904 y_new[:len(y)] = y
904 905 y = y_new
905 906 y_temp = np.zeros(delay+len(Y), dtype=np.int8)
906 907 y_temp[-len(Y):] = Y
907 908 elif delay+len(Y)==len(y):
908 909 y_temp = np.zeros(delay+len(Y))
909 910 y_temp[-len(Y):] = Y
910 911 elif delay+len(Y)<len(y):
911 912 y_temp = np.zeros(len(y), dtype=np.int8)
912 913 y_temp[delay:delay+len(Y)] = Y
913 914 else:
914 915 y_temp = Y.copy()
915 916
916 917 if ops[i]=='OR':
917 918 y = y | y_temp
918 919 elif ops[i]=='XOR':
919 920 y = y ^ y_temp
920 921 elif ops[i]=='AND':
921 922 y = y & y_temp
922 923 elif ops[i]=='NAND':
923 924 y = y & ~y_temp
924 925 else:
925 926 y = np.concatenate([y, Y])
926 927
927 928 total = len(y)
928 929 y = self.array_to_points(y)
929 930
930 931 else:
931 932 y = []
932 933
933 934 if self.rc_configuration.total_units != total:
934 935 self.rc_configuration.total_units = total
935 936 self.rc_configuration.save()
936 937
937 938 self.pulses = str(y)
938 939 self.save()
939 940
940 941 @staticmethod
941 942 def array_to_points(X):
942 943
944 if X.size==0:
945 return []
946
943 947 d = X[1:]-X[:-1]
944 948
945 949 up = np.where(d==1)[0]
946 950 if X[0]==1:
947 951 up = np.concatenate((np.array([-1]), up))
948 952 up += 1
949 953
950 954 dw = np.where(d==-1)[0]
951 955 if X[-1]==1:
952 956 dw = np.concatenate((dw, np.array([len(X)-1])))
953 957 dw += 1
954 958
955 959 return [(tup[0], tup[1]) for tup in zip(up, dw)]
956 960
957 961 @staticmethod
958 962 def mask_ranges(Y, ranges):
959 963
960 964 y = [(0, 0) for __ in Y]
961 965
962 966 for index in ranges:
963 967 if '-' in index:
964 968 args = [int(a) for a in index.split('-')]
965 969 y[args[0]-1:args[1]] = Y[args[0]-1:args[1]]
966 970 else:
967 971 y[int(index)-1] = Y[int(index)-1]
968 972
969 973 return y
970 974
971 975 @staticmethod
972 976 def points(ntx, ipp, width, delay=[0], before=0, after=0, sync=0):
973 977
974 978 delays = len(delay)
975 979
976 980 Y = [(int(ipp*x+before+delay[x%delays]+sync), int(ipp*x+width+before+delay[x%delays]+after+sync)) for x in range(ntx)]
977 981
978 982 return Y
@@ -1,401 +1,401
1 1
2 2 import json
3 3
4 4 from django.contrib import messages
5 5 from django.utils.safestring import mark_safe
6 6 from django.shortcuts import render, redirect, get_object_or_404, HttpResponse
7 7
8 8 from apps.main.models import Experiment, Device
9 9 from apps.main.views import sidebar
10 10
11 11 from .models import RCConfiguration, RCLine, RCLineType, RCLineCode
12 12 from .forms import RCConfigurationForm, RCLineForm, RCLineViewForm, RCLineEditForm, RCImportForm, RCLineCodesForm
13 13
14 14
15 15 def conf(request, conf_id):
16 16
17 17 conf = get_object_or_404(RCConfiguration, pk=conf_id)
18 18
19 19 lines = RCLine.objects.filter(rc_configuration=conf).order_by('channel')
20 20
21 21 for line in lines:
22 22 params = json.loads(line.params)
23 23 line.form = RCLineViewForm(extra_fields=params, line=line)
24 24 if 'params' in params:
25 25 line.subforms = [RCLineViewForm(extra_fields=fields, line=line, subform=True) for fields in params['params']]
26 26
27 27 kwargs = {}
28 28 kwargs['dev_conf'] = conf
29 29 kwargs['rc_lines'] = lines
30 30 kwargs['dev_conf_keys'] = ['name', 'ipp_unit', 'ntx', 'clock_in', 'clock_divider', 'clock',
31 31 'time_before', 'time_after', 'sync', 'sampling_reference', 'control_tx', 'control_sw']
32 32
33 33 kwargs['title'] = 'RC Configuration'
34 34 kwargs['suptitle'] = 'Details'
35 35
36 36 kwargs['button'] = 'Edit Configuration'
37 37 ###### SIDEBAR ######
38 38 kwargs.update(sidebar(conf=conf))
39 39
40 40 return render(request, 'rc_conf.html', kwargs)
41 41
42 42
43 43 def conf_edit(request, conf_id):
44 44
45 45 conf = get_object_or_404(RCConfiguration, pk=conf_id)
46 46
47 47 lines = RCLine.objects.filter(rc_configuration=conf).order_by('channel')
48 48
49 49 for line in lines:
50 50 params = json.loads(line.params)
51 51 line.form = RCLineEditForm(conf=conf, line=line, extra_fields=params)
52 52 line.subform = False
53 53
54 54 if 'params' in params:
55 55 line.subforms = [RCLineEditForm(extra_fields=fields, line=line, subform=i) for i, fields in enumerate(params['params'])]
56 56 line.subform = True
57 57
58 58 if request.method=='GET':
59 59
60 60 form = RCConfigurationForm(instance=conf)
61 61
62 62 elif request.method=='POST':
63 63
64 64 line_data = {}
65 65 conf_data = {}
66 66 extras = []
67 67
68 68 #classified post fields
69 69 for label,value in request.POST.items():
70 70 if label=='csrfmiddlewaretoken':
71 71 continue
72 72
73 73 if label.count('|')==0:
74 74 conf_data[label] = value
75 75 continue
76 76
77 77 elif label.split('|')[0]!='-1':
78 78 extras.append(label)
79 79 continue
80 80
81 81 x, pk, name = label.split('|')
82 82
83 83 if name=='codes':
84 84 value = [s for s in value.split('\r\n') if s]
85 85
86 86 if pk in line_data:
87 87 line_data[pk][name] = value
88 88 else:
89 89 line_data[pk] = {name:value}
90 90
91 91 #update conf
92 92 form = RCConfigurationForm(conf_data, instance=conf)
93 93
94 94 if form.is_valid():
95 95
96 96 form.save()
97 97
98 98 #update lines fields
99 99 extras.sort()
100 100 for label in extras:
101 101 x, pk, name = label.split('|')
102 102 if pk not in line_data:
103 103 line_data[pk] = {}
104 104 if 'params' not in line_data[pk]:
105 105 line_data[pk]['params'] = []
106 106 if len(line_data[pk]['params'])<int(x)+1:
107 107 line_data[pk]['params'].append({})
108 108 line_data[pk]['params'][int(x)][name] = float(request.POST[label])
109 109
110 110 for pk, params in line_data.items():
111 111 line = RCLine.objects.get(pk=pk)
112 112 if line.line_type.name in ('windows', 'prog_pulses'):
113 113 if 'params' not in params:
114 114 params['params'] = []
115 115 line.params = json.dumps(params)
116 116 line.save()
117 117
118 118 #update pulses field
119 119 conf.update_pulses()
120 120
121 121 messages.success(request, 'RC Configuration successfully updated')
122 122
123 123 return redirect(conf.get_absolute_url())
124 124
125 125 kwargs = {}
126 126 kwargs['dev_conf'] = conf
127 127 kwargs['form'] = form
128 128 kwargs['rc_lines'] = lines
129 129 kwargs['edit'] = True
130 130
131 131 kwargs['title'] = 'RC Configuration'
132 132 kwargs['suptitle'] = 'Edit'
133 133 kwargs['button'] = 'Update'
134 134 kwargs['previous'] = conf.get_absolute_url()
135 135
136 136 return render(request, 'rc_conf_edit.html', kwargs)
137 137
138 138
139 139 def add_line(request, conf_id, line_type_id=None, code_id=None):
140 140
141 141 conf = get_object_or_404(RCConfiguration, pk=conf_id)
142 142
143 143 if request.method=='GET':
144 144 if line_type_id:
145 145 line_type = get_object_or_404(RCLineType, pk=line_type_id)
146 146
147 147 if code_id:
148 148 form = RCLineForm(initial={'rc_configuration':conf_id, 'line_type': line_type_id, 'code_id': code_id},
149 149 extra_fields=json.loads(line_type.params))
150 150 else:
151 151 form = RCLineForm(initial={'rc_configuration':conf_id, 'line_type': line_type_id},
152 152 extra_fields=json.loads(line_type.params))
153 153 else:
154 154 line_type = {'id':0}
155 155 form = RCLineForm(initial={'rc_configuration':conf_id})
156 156
157 157 if request.method=='POST':
158 158
159 159 line_type = get_object_or_404(RCLineType, pk=line_type_id)
160 160 form = RCLineForm(request.POST,
161 161 extra_fields=json.loads(line_type.params))
162 162
163 163 if form.is_valid():
164 164 form.save()
165 165 form.instance.update_pulses()
166 166 return redirect('url_edit_rc_conf', conf.id)
167 167
168 168 kwargs = {}
169 169 kwargs['form'] = form
170 170 kwargs['title'] = 'RC Configuration'
171 171 kwargs['suptitle'] = 'Add Line'
172 172 kwargs['button'] = 'Add'
173 173 kwargs['previous'] = conf.get_absolute_url_edit()
174 174 kwargs['dev_conf'] = conf
175 175 kwargs['line_type'] = line_type
176 176
177 177 return render(request, 'rc_add_line.html', kwargs)
178 178
179 179 def edit_codes(request, conf_id, line_id, code_id=None):
180 180
181 181 conf = get_object_or_404(RCConfiguration, pk=conf_id)
182 182 line = get_object_or_404(RCLine, pk=line_id)
183 183 params = json.loads(line.params)
184 184
185 185 if request.method=='GET':
186 186 if code_id:
187 187 code = get_object_or_404(RCLineCode, pk=code_id)
188 188 form = RCLineCodesForm(instance=code)
189 189 else:
190 190 initial = {'code': params['code'],
191 191 'codes': params['codes'] if 'codes' in params else [],
192 192 'number_of_codes': len(params['codes']) if 'codes' in params else 0,
193 193 'bits_per_code': len(params['codes'][0]) if 'codes' in params else 0,
194 194 }
195 195 form = RCLineCodesForm(initial=initial)
196 196
197 197 if request.method=='POST':
198 198 form = RCLineCodesForm(request.POST)
199 199 if form.is_valid():
200 200 params['code'] = request.POST['code']
201 201 params['codes'] = [s for s in request.POST['codes'].split('\r\n') if s]
202 202 line.params = json.dumps(params)
203 203 line.save()
204 204 messages.success(request, 'Line: "%s" has been updated.' % line)
205 205 return redirect('url_edit_rc_conf', conf.id)
206 206
207 207 kwargs = {}
208 208 kwargs['form'] = form
209 209 kwargs['title'] = line
210 210 kwargs['suptitle'] = 'Edit'
211 211 kwargs['button'] = 'Update'
212 212 kwargs['dev_conf'] = conf
213 213 kwargs['previous'] = conf.get_absolute_url_edit()
214 214 kwargs['line'] = line
215 215
216 216 return render(request, 'rc_edit_codes.html', kwargs)
217 217
218 218 def add_subline(request, conf_id, line_id):
219 219
220 220 conf = get_object_or_404(RCConfiguration, pk=conf_id)
221 221 line = get_object_or_404(RCLine, pk=line_id)
222 222
223 223 if request.method == 'POST':
224 224 if line:
225 225 params = json.loads(line.params)
226 226 subparams = json.loads(line.line_type.params)
227 227 if 'params' in subparams:
228 228 dum = {}
229 229 for key, value in subparams['params'].items():
230 230 dum[key] = value['value']
231 231 params['params'].append(dum)
232 232 line.params = json.dumps(params)
233 233 line.save()
234 234 return redirect('url_edit_rc_conf', conf.id)
235 235
236 236 kwargs = {}
237 237
238 238 kwargs['title'] = 'Add new'
239 239 kwargs['suptitle'] = '%s to %s' % (line.line_type.name, line)
240 240
241 241 return render(request, 'confirm.html', kwargs)
242 242
243 243 def remove_line(request, conf_id, line_id):
244 244
245 245 conf = get_object_or_404(RCConfiguration, pk=conf_id)
246 246 line = get_object_or_404(RCLine, pk=line_id)
247 247
248 248 if request.method == 'POST':
249 249 if line:
250 250 try:
251 251 channel = line.channel
252 252 line.delete()
253 253 for ch in range(channel+1, RCLine.objects.filter(rc_configuration=conf).count()+1):
254 254 l = RCLine.objects.get(rc_configuration=conf, channel=ch)
255 255 l.channel = l.channel-1
256 256 l.save()
257 257 messages.success(request, 'Line: "%s" has been deleted.' % line)
258 258 except:
259 259 messages.error(request, 'Unable to delete line: "%s".' % line)
260 260
261 261 return redirect('url_edit_rc_conf', conf.id)
262 262
263 263 kwargs = {}
264 264
265 265 kwargs['object'] = line
266 266 kwargs['delete'] = True
267 267 kwargs['title'] = 'Delete'
268 268 kwargs['suptitle'] = 'Line'
269 269 kwargs['previous'] = conf.get_absolute_url_edit()
270 270 return render(request, 'confirm.html', kwargs)
271 271
272 272
273 273 def remove_subline(request, conf_id, line_id, subline_id):
274 274
275 275 conf = get_object_or_404(RCConfiguration, pk=conf_id)
276 276 line = get_object_or_404(RCLine, pk=line_id)
277 277
278 278 if request.method == 'POST':
279 279 if line:
280 280 params = json.loads(line.params)
281 281 params['params'].remove(params['params'][int(subline_id)-1])
282 282 line.params = json.dumps(params)
283 283 line.save()
284 284
285 285 return redirect('url_edit_rc_conf', conf.id)
286 286
287 287 kwargs = {}
288 288
289 289 kwargs['object'] = line
290 290 kwargs['object_name'] = line.line_type.name
291 291 kwargs['delete_view'] = True
292 292 kwargs['title'] = 'Confirm delete'
293 293
294 294 return render(request, 'confirm.html', kwargs)
295 295
296 296
297 297 def update_lines_position(request, conf_id):
298 298
299 299 conf = get_object_or_404(RCConfiguration, pk=conf_id)
300 300
301 301 if request.method=='POST':
302 302 ch = 0
303 303 for item in request.POST['items'].split('&'):
304 304 line = RCLine.objects.get(pk=item.split('=')[-1])
305 305 line.channel = ch
306 306 line.save()
307 307 ch += 1
308 308
309 309 lines = RCLine.objects.filter(rc_configuration=conf).order_by('channel')
310 310
311 311 for line in lines:
312 312 params = json.loads(line.params)
313 313 line.form = RCLineEditForm(conf=conf, line=line, extra_fields=params)
314 314
315 315 if 'params' in params:
316 316 line.subform = True
317 317 line.subforms = [RCLineEditForm(extra_fields=fields, line=line, subform=i) for i, fields in enumerate(params['params'])]
318 318
319 319 html = render(request, 'rc_lines.html', {'dev_conf':conf, 'rc_lines':lines, 'edit':True})
320 320 data = {'html': html.content.decode('utf8')}
321 321
322 322 return HttpResponse(json.dumps(data), content_type="application/json")
323 323 return redirect('url_edit_rc_conf', conf.id)
324 324
325 325
326 326 def import_file(request, conf_id):
327 327
328 328 conf = get_object_or_404(RCConfiguration, pk=conf_id)
329 329 if request.method=='POST':
330 330 form = RCImportForm(request.POST, request.FILES)
331 331 if form.is_valid():
332 332 try:
333 #if True:
334 conf.update_from_file(request.FILES['file_name'])
333 data = conf.import_from_file(request.FILES['file_name'])
334 conf.dict_to_parms(data)
335 conf.update_pulses()
335 336 messages.success(request, 'Configuration "%s" loaded succesfully' % request.FILES['file_name'])
336 337 return redirect(conf.get_absolute_url_edit())
337 338
338 339 except Exception as e:
339 messages.error(request, 'Error parsing file: "%s" - %s' % (request.FILES['file_name'], e))
340
340 messages.error(request, 'Error parsing file: "%s" - %s' % (request.FILES['file_name'], repr(e)))
341 341 else:
342 342 messages.warning(request, 'Your current configuration will be replaced')
343 343 form = RCImportForm()
344 344
345 345 kwargs = {}
346 346 kwargs['form'] = form
347 347 kwargs['title'] = 'RC Configuration'
348 348 kwargs['suptitle'] = 'Import file'
349 349 kwargs['button'] = 'Upload'
350 350 kwargs['previous'] = conf.get_absolute_url()
351 351
352 352 return render(request, 'rc_import.html', kwargs)
353 353
354 354
355 355 def plot_pulses(request, conf_id):
356 356
357 357 conf = get_object_or_404(RCConfiguration, pk=conf_id)
358 358 km = True if 'km' in request.GET else False
359 359
360 360 script, div = conf.plot_pulses(km=km)
361 361
362 362 kwargs = {}
363 363 kwargs['no_sidebar'] = True
364 364 kwargs['title'] = 'RC Pulses'
365 365 kwargs['suptitle'] = conf.name
366 366 kwargs['div'] = mark_safe(div)
367 367 kwargs['script'] = mark_safe(script)
368 368 kwargs['units'] = conf.km2unit
369 369 kwargs['kms'] = 1/conf.km2unit
370 370
371 371 if km:
372 372 kwargs['km_selected'] = True
373 373
374 374 if 'json' in request.GET:
375 375 return HttpResponse(json.dumps({'div':mark_safe(div), 'script':mark_safe(script)}), content_type="application/json")
376 376 else:
377 377 return render(request, 'rc_pulses.html', kwargs)
378 378
379 379 def plot_pulses2(request, conf_id):
380 380
381 381 conf = get_object_or_404(RCConfiguration, pk=conf_id)
382 382 km = True if 'km' in request.GET else False
383 383
384 384 script, div = conf.plot_pulses2(km=km)
385 385
386 386 kwargs = {}
387 387 kwargs['no_sidebar'] = True
388 388 kwargs['title'] = 'RC Pulses'
389 389 kwargs['suptitle'] = conf.name
390 390 kwargs['div'] = mark_safe(div)
391 391 kwargs['script'] = mark_safe(script)
392 392 kwargs['units'] = conf.km2unit
393 393 kwargs['kms'] = 1/conf.km2unit
394 394
395 395 if km:
396 396 kwargs['km_selected'] = True
397 397
398 398 if 'json' in request.GET:
399 399 return HttpResponse(json.dumps({'div':mark_safe(div), 'script':mark_safe(script)}), content_type="application/json")
400 400 else:
401 401 return render(request, 'rc_pulses.html', kwargs)
@@ -1,315 +1,319
1 1
2 2 import ast
3 3 import json
4 4 from itertools import chain
5 5
6 6 from django import forms
7 7 from django.utils.safestring import mark_safe
8 8 from django.utils.encoding import force_text
9 9 from django.utils.html import conditional_escape
10 10
11 11 try:
12 12 basestring # attempt to evaluate basestring
13 13 def isstr(s):
14 14 return isinstance(s, basestring)
15 15 except NameError:
16 16 def isstr(s):
17 17 return isinstance(s, str)
18 18
19 19 class KmUnitWidget(forms.widgets.TextInput):
20 20
21 21 def render(self, label, value, attrs=None):
22 22
23 23 if isinstance(value, (int, float)):
24 24 unit = int(value*attrs['km2unit'])
25 25 elif isstr(value):
26 26 units = []
27 27 values = [s for s in value.split(',') if s]
28 28 for val in values:
29 29 units.append('{0:.0f}'.format(float(val)*attrs['km2unit']))
30 30
31 31 unit = ','.join(units)
32 32
33 33 disabled = 'disabled' if attrs.get('disabled', False) else ''
34 34 name = attrs.get('name', label)
35 35 if attrs['id'] in ('id_delays',):
36 36 input_type = 'text'
37 37 else:
38 38 input_type = 'number'
39 39
40 40 if 'line' in attrs:
41 41 label += '_{0}_{1}'.format(attrs['line'].pk, name.split('|')[0])
42 42
43 43 html = '''<div class="col-md-12 col-no-padding">
44 44 <div class="col-md-5 col-no-padding"><input type="{0}" step="any" {1} class="form-control" id="id_{2}" name="{3}" value="{4}"></div>
45 45 <div class="col-md-1 col-no-padding">Km</div>
46 <div class="col-md-5 col-no-padding"><input type="{0}" {1} class="form-control" id="id_{2}_unit" value="{5}"></div>
46 <div class="col-md-5 col-no-padding"><input type="{0}" step="any" {1} class="form-control" id="id_{2}_unit" value="{5}"></div>
47 47 <div class="col-md-1 col-no-padding">Units</div></div><br>'''.format(input_type, disabled, label, name, value, unit)
48 48
49 49 script = '''<script type="text/javascript">
50 50 $(document).ready(function () {{
51 51
52 52 km_fields.push("id_{label}");
53 53 unit_fields.push("id_{label}_unit");
54 54
55 55 $("#id_{label}").change(function() {{
56 56 $("#id_{label}_unit").val(str2unit($(this).val()));
57 57 $("#id_{label}").val(str2km($("#id_{label}_unit").val()));
58 58 updateWindows("#id_{label}");
59 59 }});
60 60 $("#id_{label}_unit").change(function() {{
61 61 $(this).val(str2int($(this).val()));
62 62 $("#id_{label}").val(str2km($(this).val()));
63 63 updateWindows("#id_{label}");
64 64 }});
65 65 }});
66 66 </script>'''.format(label=label)
67 67
68 68 if disabled:
69 69 return mark_safe(html)
70 70 else:
71 71 return mark_safe(html+script)
72 72
73 73
74 74 class UnitKmWidget(forms.widgets.TextInput):
75 75
76 76 def render(self, label, value, attrs=None):
77 77
78 78 if isinstance(value, (int, float)):
79 79 km = value/attrs['km2unit']
80 80 elif isinstance(value, basestring):
81 81 kms = []
82 82 values = [s for s in value.split(',') if s]
83 83 for val in values:
84 84 kms.append('{0:.0f}'.format(float(val)/attrs['km2unit']))
85 85
86 86 km = ','.join(kms)
87 87
88 88 disabled = 'disabled' if attrs.get('disabled', False) else ''
89 89 name = attrs.get('name', label)
90 90
91 91 if 'line' in attrs:
92 92 label += '_{0}_{1}'.format(attrs['line'].pk, name.split('|')[0])
93 93
94 94 html = '''<div class="col-md-12 col-no-padding">
95 <div class="col-md-5 col-no-padding"><input type="number" {0} class="form-control" id="id_{1}_unit" name="{2}" value="{3}"></div>
95 <div class="col-md-5 col-no-padding"><input type="number" step="any" {0} class="form-control" id="id_{1}_unit" name="{2}" value="{3}"></div>
96 96 <div class="col-md-1 col-no-padding">Units</div>
97 97 <div class="col-md-5 col-no-padding"><input type="number" step="any" {4} class="form-control" id="id_{5}" value="{6}"></div>
98 98 <div class="col-md-1 col-no-padding">Km</div></div>'''.format(disabled, label, name, value, disabled, label, km)
99 99
100 100 script = '''<script type="text/javascript">
101 101 $(document).ready(function () {{
102 102
103 103 km_fields.push("id_{label}");
104 104 unit_fields.push("id_{label}_unit");
105 105
106 106 $("#id_{label}").change(function() {{
107 107 $("#id_{label}_unit").val(str2unit($(this).val()));
108 108 }});
109 109 $("#id_{label}_unit").change(function() {{
110 110 $("#id_{label}").val(str2km($(this).val()));
111 111 }});
112 112 }});
113 113 </script>'''.format(label=label)
114 114
115 115 if disabled:
116 116 return mark_safe(html)
117 117 else:
118 118 return mark_safe(html+script)
119 119
120 120
121 121 class KmUnitHzWidget(forms.widgets.TextInput):
122 122
123 123 def render(self, label, value, attrs=None):
124 124
125 125 unit = float(value)*attrs['km2unit']
126 126 if unit%10==0:
127 127 unit = int(unit)
128 128 hz = 150000*float(value)**-1
129 129
130 130 disabled = 'disabled' if attrs.get('disabled', False) else ''
131 131 name = attrs.get('name', label)
132 132
133 133 if 'line' in attrs:
134 134 label += '_{0}'.format(attrs['line'].pk)
135 135
136 136 html = '''<div class="col-md-12 col-no-padding">
137 137 <div class="col-md-3 col-no-padding"><input type="number" step="any" {0} class="form-control" id="id_{1}" name="{2}" value="{3}"></div>
138 138 <div class="col-md-1 col-no-padding">Km</div>
139 <div class="col-md-3 col-no-padding"><input type="number" {4} class="form-control" id="id_{1}_unit" value="{5}"></div>
139 <div class="col-md-3 col-no-padding"><input type="number" step="any" {4} class="form-control" id="id_{1}_unit" value="{5}"></div>
140 140 <div class="col-md-1 col-no-padding">Units</div>
141 141 <div class="col-md-3 col-no-padding"><input type="number" step="any" {4} class="form-control" id="id_{1}_hz" value="{6}"></div>
142 142 <div class="col-md-1 col-no-padding">Hz</div>
143 143 </div>'''.format(disabled, label, name, value, disabled, unit, hz)
144 144
145 145 script = '''<script type="text/javascript">
146 146 $(document).ready(function () {{
147 147 km_fields.push("id_{label}");
148 148 unit_fields.push("id_{label}_unit");
149 149 $("#id_{label}").change(function() {{
150 150 $("#id_{label}_unit").val(str2unit($(this).val()));
151 151 $("#id_{label}").val(str2km($("#id_{label}_unit").val()));
152 152 $("#id_{label}_hz").val(str2hz($(this).val()));
153 153 updateDc();
154 154 }});
155 155 $("#id_{label}_unit").change(function() {{
156 156 $(this).val(Math.round(parseFloat($(this).val())/10)*10);
157 157 $("#id_{label}").val(str2km($(this).val()));
158 158 $("#id_{label}_hz").val(str2hz($("#id_{label}").val()));
159 159 updateDc();
160 160 }});
161 161 $("#id_{label}_hz").change(function() {{
162 162 $("#id_{label}").val(str2hz($(this).val()));
163 163 $("#id_{label}_unit").val(str2unit($("#id_{label}").val()));
164 164 updateDc();
165 165 }});
166 166 }});
167 167 </script>'''.format(label=label)
168 168
169 169 if disabled:
170 170 return mark_safe(html)
171 171 else:
172 172 return mark_safe(html+script)
173 173
174 174
175 175 class KmUnitDcWidget(forms.widgets.TextInput):
176 176
177 177 def render(self, label, value, attrs=None):
178 178
179 179 unit = int(float(value)*attrs['km2unit'])
180 180
181 181 disabled = 'disabled' if attrs.get('disabled', False) else ''
182 182 name = attrs.get('name', label)
183 183
184 184 label += '_{0}'.format(attrs['line'].pk)
185 185
186 186 dc = float(json.loads(attrs['line'].params)['pulse_width'])*100/attrs['line'].rc_configuration.ipp
187 187
188 188 html = '''<div class="col-md-12 col-no-padding">
189 189 <div class="col-md-3 col-no-padding"><input type="number" step="any" {0} class="form-control" id="id_{1}" name="{2}" value="{3}"></div>
190 190 <div class="col-md-1 col-no-padding">Km</div>
191 <div class="col-md-3 col-no-padding"><input type="number" {4} class="form-control" id="id_{1}_unit" value="{5}"></div>
191 <div class="col-md-3 col-no-padding"><input type="number" step="any" {4} class="form-control" id="id_{1}_unit" value="{5}"></div>
192 192 <div class="col-md-1 col-no-padding">Units</div>
193 193 <div class="col-md-3 col-no-padding"><input type="number" step="any" {4} class="form-control" id="id_{1}_dc" value="{6}"></div>
194 194 <div class="col-md-1 col-no-padding">DC[%]</div>
195 195 </div>'''.format(disabled, label, name, value, disabled, unit, dc)
196 196
197 197 script = '''<script type="text/javascript">
198 198 $(document).ready(function () {{
199 199 km_fields.push("id_{label}");
200 200 unit_fields.push("id_{label}_unit");
201 201 dc_fields.push("id_{label}");
202 202 $("#id_{label}").change(function() {{
203 203 $("#id_{label}_unit").val(str2unit($(this).val()));
204 204 $("#id_{label}").val(str2km($("#id_{label}_unit").val()));
205 205 $("#id_{label}_dc").val(str2dc($("#id_{label}").val()));
206 206 }});
207 207 $("#id_{label}_unit").change(function() {{
208 208 $("#id_{label}").val(str2km($(this).val()));
209 209 $("#id_{label}_dc").val(str2dc($("#id_{label}").val()));
210 210 }});
211 211
212 212 $("#id_{label}_dc").change(function() {{
213 213 $("#id_{label}").val(parseFloat($(this).val())*100/parseFloat($("#id_ipp").val()));
214 214 $("#id_{label}_unit").val(str2unit($("#id_{label}").val()));
215 215 }});
216 216 }});
217 217 </script>'''.format(label=label)
218 218
219 219 if disabled:
220 220 return mark_safe(html)
221 221 else:
222 222 return mark_safe(html+script)
223 223
224 224
225 225 class DefaultWidget(forms.widgets.TextInput):
226 226
227 227 def render(self, label, value, attrs=None):
228 228
229 229 disabled = 'disabled' if attrs.get('disabled', False) else ''
230 230 itype = 'number' if label in ('number_of_samples', 'last_height') else 'text'
231 231 name = attrs.get('name', label)
232 232 if 'line' in attrs:
233 233 label += '_{0}_{1}'.format(attrs['line'].pk, name.split('|')[0])
234 html = '<div class="col-md-12 col-no-padding"><div class="col-md-5 col-no-padding"><input {0} type="{1}" class="form-control" id="id_{2}" name="{3}" value="{4}"></div></div>'.format(disabled, itype, label, name, value)
234
235 if itype=='number':
236 html = '<div class="col-md-12 col-no-padding"><div class="col-md-5 col-no-padding"><input {0} type="{1}" step="any" class="form-control" id="id_{2}" name="{3}" value="{4}"></div></div>'.format(disabled, itype, label, name, value)
237 else:
238 html = '<div class="col-md-12 col-no-padding"><div class="col-md-5 col-no-padding"><input {0} type="{1}" step="any" class="form-control" id="id_{2}" name="{3}" value="{4}"></div></div>'.format(disabled, itype, label, name, value)
235 239
236 240 if 'last_height' in label or 'number_of_samples' in label:
237 241 script = '''<script type="text/javascript">
238 242 $(document).ready(function () {{
239 243
240 244 $("#id_{label}").change(function() {{
241 245 updateWindows("#id_{label}");
242 246 }});
243 247
244 248 }});
245 249 </script>'''.format(label=label)
246 250 else:
247 251 script = ''
248 252
249 253 if disabled:
250 254 return mark_safe(html)
251 255 else:
252 256 return mark_safe(html+script)
253 257
254 258
255 259
256 260 return mark_safe(html)
257 261
258 262
259 263 class HiddenWidget(forms.widgets.HiddenInput):
260 264
261 265 def render(self, label, value, attrs=None):
262 266
263 267 disabled = 'disabled' if attrs.get('disabled', False) else ''
264 268 name = self.attrs.get('name', label)
265 269
266 270 html = '<input {0} type="hidden" class="form-control" id="id_{1}" name="{2}" value="{3}">'.format(disabled, label, name, value)
267 271
268 272 return mark_safe(html)
269 273
270 274
271 275 class CodesWidget(forms.widgets.Textarea):
272 276
273 277 def render(self, label, value, attrs=None):
274 278
275 279 disabled = 'disabled' if attrs.get('disabled', False) else ''
276 280 name = attrs.get('name', label)
277 281
278 282 if '[' in value:
279 283 value = ast.literal_eval(value)
280 284
281 285 if isinstance(value, list):
282 286 codes = '\r\n'.join(value)
283 287 else:
284 288 codes = value
285 289
286 290 html = '<textarea rows="5" {0} class="form-control" id="id_{1}" name="{2}" style="white-space:nowrap; overflow:scroll;">{3}</textarea>'.format(disabled, label, name, codes)
287 291
288 292 return mark_safe(html)
289 293
290 294 class HCheckboxSelectMultiple(forms.CheckboxSelectMultiple):
291 295
292 296 def render(self, name, value, attrs=None, choices=()):
293 297
294 298 if value is None: value = []
295 299 has_id = attrs and 'id' in attrs
296 300 final_attrs = self.build_attrs(attrs, name=name)
297 301 output = [u'<br><ul>']
298 302 # Normalize to strings
299 303 str_values = set([force_text(v) for v in value])
300 304 for i, (option_value, option_label) in enumerate(chain(self.choices, choices)):
301 305 # If an ID attribute was given, add a numeric index as a suffix,
302 306 # so that the checkboxes don't all have the same ID attribute.
303 307 if has_id:
304 308 final_attrs = dict(final_attrs, id='%s_%s' % (attrs['id'], i))
305 309 label_for = u' for="%s"' % final_attrs['id']
306 310 else:
307 311 label_for = ''
308 312
309 313 cb = forms.CheckboxInput(final_attrs, check_test=lambda value: value in str_values)
310 314 option_value = force_text(option_value)
311 315 rendered_cb = cb.render(name, option_value)
312 316 option_label = conditional_escape(force_text(option_label))
313 317 output.append(u'<span><label%s>%s %s</label></span>' % (label_for, rendered_cb, option_label))
314 318 output.append(u'</div><br>')
315 319 return mark_safe(u'\n'.join(output))
General Comments 0
You need to be logged in to leave comments. Login now