##// END OF EJS Templates
Optimize pulses's plot and generation ...
Juan C. Espinoza -
r111:e02ef9acb4e3
parent child
Show More
@@ -1,26 +1,27
1 1 [{"fields": {"number_of_codes": 0, "codes": "[]", "name": "None", "bits_per_code": 0}, "model": "rc.rclinecode", "pk": 1},
2 2 {"fields": {"number_of_codes": 2, "codes": "[u'11101101', u'11100010']", "name": "COMPLEMENTARY_CODE_8", "bits_per_code": 8}, "model": "rc.rclinecode", "pk": 2},
3 3 {"fields": {"number_of_codes": 1, "codes": "[u'1101101001000100010001111000']", "name": "BINARY_CODE_28", "bits_per_code": 28}, "model": "rc.rclinecode", "pk": 3},
4 4 {"fields": {"number_of_codes": 2, "codes": "[u'11', u'10']", "name": "COMPLEMENTARY_CODE_2", "bits_per_code": 2}, "model": "rc.rclinecode", "pk": 4},
5 5 {"fields": {"number_of_codes": 2, "codes": "[u'1110110111100010111011010001110111101101111000100001001011100010', u'1110110111100010111011010001110100010010000111011110110100011101']", "name": "COMPLEMENTARY_CODE_64", "bits_per_code": 64}, "model": "rc.rclinecode", "pk": 5},
6 6 {"fields": {"number_of_codes": 1, "codes": "[u'11100010010']", "name": "BARKER11", "bits_per_code": 11}, "model": "rc.rclinecode", "pk": 6},
7 7 {"fields": {"number_of_codes": 2, "codes": "[u'1111100110101' ]", "name": "BARKER13", "bits_per_code": 13}, "model": "rc.rclinecode", "pk": 7},
8 8 {"fields": {"number_of_codes": 2, "codes": "[u'1101101001000100010001111000', u'0010010110111011101110000111']", "name": "BINARY_CODE_28_FLIP", "bits_per_code": 28}, "model": "rc.rclinecode", "pk": 8},
9 9 {"fields": {"number_of_codes": 2, "codes": "[u'11101101111000101110110100011101', u'11101101111000100001001011100010']", "name": "COMPLEMENTARY_CODE_32", "bits_per_code": 32}, "model": "rc.rclinecode", "pk": 9},
10 10 {"fields": {"number_of_codes": 128, "codes": "[u'1111000100100101', u'1011001010010111', u'1101001000100000', u'1001000110010010', u'1110001001111011', u'1010000111001001', u'1100000101111110', u'1000001011001100', u'1111101001010110', u'1011100111100100', u'1101100101010011', u'1001101011100001', u'1110100100001000', u'1010101010111010', u'1100101000001101', u'1000100110111111', u'1111010010011100', u'1011011100101110', u'1101011110011001', u'1001010000101011', u'1110011111000010', u'1010010001110000', u'1100010011000111', u'1000011101110101', u'1111111111101111', u'1011110001011101', u'1101110011101010', u'1001111101011000', u'1110110010110001', u'1010111100000011', u'1100111110110100', u'1000110000000110', u'0011111000000011', u'0111110110110001', u'0001110100000110', u'0101111010110100', u'0010110101011101', u'0110111011101111', u'0000111001011000', u'0100110111101010', u'0011010101110000', u'0111011011000010', u'0001011001110101', u'0101010111000111', u'0010011000101110', u'0110010110011100', u'0000010100101011', u'0100011010011001', u'0011101110111010', u'0111100000001000', u'0001100010111111', u'0101101100001101', u'0010100011100100', u'0110101101010110', u'0000101111100001', u'0100100001010011', u'0011000011001001', u'0111001101111011', u'0001001111001100', u'0101000001111110', u'0010001110010111', u'0110000000100101', u'0000000010010010', u'0100001100100000', u'1010110011001110', u'1110111101111100', u'1000111111001011', u'1100110001111001', u'1011111110010000', u'1111110000100010', u'1001110010010101', u'1101111100100111', u'1010011110111101', u'1110010000001111', u'1000010010111000', u'1100011100001010', u'1011010011100011', u'1111011101010001', u'1001011111100110', u'1101010001010100', u'1010100101110111', u'1110101011000101', u'1000101001110010', u'1100100111000000', u'1011101000101001', u'1111100110011011', u'1001100100101100', u'1101101010011110', u'1010001000000100', u'1110000110110110', u'1000000100000001', u'1100001010110011', u'1011000101011010', u'1111001011101000', u'1001001001011111', u'1101000111101101', u'1100100111000110', u'1000101001110100', u'1110101011000011', u'1010100101110001', u'1101101010011000', u'1001100100101010', u'1111100110011101', u'1011101000101111', u'1100001010110101', u'1000000100000111', u'1110000110110000', u'1010001000000010', u'1101000111101011', u'1001001001011001', u'1111001011101110', u'1011000101011100', u'1100110001111111', u'1000111111001101', u'1110111101111010', u'1010110011001000', u'1101111100100001', u'1001110010010011', u'1111110000100100', u'1011111110010110', u'1100011100001100', u'1000010010111110', u'1110010000001001', u'1010011110111011', u'1101010001010010', u'1001011111100000', u'1111011101010111', u'1011010011100101']", "name": "AC128", "bits_per_code": 16}, "model": "rc.rclinecode", "pk": 10},
11 11 {"fields": {"number_of_codes": 2, "codes": "[u'11101101111000101110110100011101111011011110001000010010111000101110110111100010111011010001110100010010000111011110110100011101', u'11101101111000101110110100011101111011011110001000010010111000100001001000011101000100101110001011101101111000100001001011100010']", "name": "COMPLEMENTARY_CODE_128", "bits_per_code": 128}, "model": "rc.rclinecode", "pk": 11},
12 12 {"fields": {"number_of_codes": 2, "codes": "[u'1110110111100010', u'1110110100011101']", "name": "COMPLEMENTARY_CODE_16", "bits_per_code": 16}, "model": "rc.rclinecode", "pk": 12},
13 13 {"fields": {"number_of_codes": 1, "codes": "[u'11']", "name": "BARKER2", "bits_per_code": 2}, "model": "rc.rclinecode", "pk": 13},
14 14 {"fields": {"number_of_codes": 1, "codes": "[u'110']", "name": "BARKER3", "bits_per_code": 3}, "model": "rc.rclinecode", "pk": 14},
15 15 {"fields": {"number_of_codes": 2, "codes": "[u'1110', u'1101']", "name": "COMPLEMENTARY_CODE_4", "bits_per_code": 4}, "model": "rc.rclinecode", "pk": 15},
16 16 {"fields": {"number_of_codes": 1, "codes": "[u'1110010']", "name": "BARKER7", "bits_per_code": 7}, "model": "rc.rclinecode", "pk": 16},
17 17 {"fields": {"number_of_codes": 1, "codes": "[u'1101']", "name": "BARKER4", "bits_per_code": 4}, "model": "rc.rclinecode", "pk": 17},
18 18 {"fields": {"number_of_codes": 1, "codes": "[u'11101']", "name": "BARKER5", "bits_per_code": 5}, "model": "rc.rclinecode", "pk": 18},
19 19 {"fields": {"params": "{\"TX_ref\": {\"model\": \"RCLine\", \"value\": \"\"}, \"range\": { \"value\": 0, \"help\": \"Frame numbers or frame ranges separated by commas, use 0 for all frames eg: 1,2,10-15\"}}", "name": "tr", "description": ""}, "model": "rc.rclinetype", "pk": 1},
20 20 {"fields": {"params": "{\"pulse_width\":{\"value\": 0, \"widget\":\"dc\"},\r\n \"delays\":{\"value\": \"\", \"widget\":\"km\", \"help\": \"Delay entries separated by commas (TAUs)\"},\r\n \"range\":{\"value\": 0, \"help\": \"Frame numbers or frame ranges separated by commas, use 0 for all frames eg: 1,2,10-15\"}}", "name": "tx", "description": ""}, "model": "rc.rclinetype", "pk": 2},
21 21 {"fields": {"params": "{\"TX_ref\": {\"model\": \"RCLine\", \"value\": \"\"}, \"code\": {\"model\":\"RCLineCode\",\"value\": \"\"}, \"codes\":{\"value\":\"\", \"widget\":\"codes\"}}", "name": "codes", "description": ""}, "model": "rc.rclinetype", "pk": 3},
22 22 {"fields": {"params": "{ \"TX_ref\":{\"model\": \"RCLine\", \"value\": \"\"}, \"params\": {\"first_height\":{ \"value\": 0, \"widget\":\"km\"},\"resolution\": {\"value\": 0, \"widget\":\"km\"}, \"number_of_samples\": { \"value\": 0, \"help\":\"number of samples (NSA)\"}}}", "name": "windows", "description": ""}, "model": "rc.rclinetype", "pk": 4},
23 23 {"fields": {"params": "{\"invert\":{\"value\": 0, \"help\": \"Set to 1 for synchro pulse at the end\"}}", "name": "sync", "description": ""}, "model": "rc.rclinetype", "pk": 5},
24 24 {"fields": {"params": "{ \"periodic\": { \"value\": 0, \"help\": \"Set to 1 for IPP periodic\"}, \"params\": {\"begin\": { \"value\": 0, \"widget\":\"unit\"}, \"end\": {\"value\": 0, \"widget\":\"unit\"}}}", "name": "prog_pulses", "description": ""}, "model": "rc.rclinetype", "pk": 6},
25 25 {"fields": {"params": "{\"number_of_flips\": {\"value\": 0}}", "name": "flip", "description": ""}, "model": "rc.rclinetype", "pk": 7},
26 {"fields": {"params": "{}", "name": "none", "description": ""}, "model": "rc.rclinetype", "pk": 8}]
26 {"fields": {"params": "{}", "name": "none", "description": ""}, "model": "rc.rclinetype", "pk": 8},
27 {"fields": {"params": "{}", "name": "mix", "description": ""}, "model": "rc.rclinetype", "pk": 9}] No newline at end of file
@@ -1,370 +1,370
1 1 import os
2 2 import ast
3 3 import json
4 4
5 5 from django import forms
6 6 from django.utils.safestring import mark_safe
7 7 from apps.main.models import Device
8 8 from apps.main.forms import add_empty_choice
9 9 from .models import RCConfiguration, RCLine, RCLineType, RCLineCode
10 10 from .widgets import KmUnitWidget, KmUnitHzWidget, KmUnitDcWidget, UnitKmWidget, DefaultWidget, CodesWidget, HiddenWidget, HCheckboxSelectMultiple
11 11
12 12 def create_choices_from_model(model, conf_id, all=False):
13 13
14 14 if model=='RCLine':
15 15 instance = RCConfiguration.objects.get(pk=conf_id)
16 16 choices = [(line.pk, line.get_name()) for line in instance.get_lines(line_type__name='tx')]
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['disabled'] = 'disabled'
78 78
79 79 class Meta:
80 80 model = RCConfiguration
81 exclude = ('type', 'parameters', 'status')
81 exclude = ('type', 'parameters', 'status', '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 89 else:
90 90 if form_data['ipp']*(20./3*(form_data['clock_in']/form_data['clock_divider']))%10<>0:
91 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
96 96 class RCMixConfigurationForm(forms.Form):
97 97
98 98 clock_in = forms.CharField(widget=forms.HiddenInput())
99 99 clock_divider = forms.CharField(widget=forms.HiddenInput())
100 100 name = forms.CharField()
101 101 experiment = forms.ChoiceField()
102 102 operation = forms.ChoiceField(widget=forms.RadioSelect(),
103 103 choices=[(0, 'OR'), (1, 'XOR'), (2, 'AND'), (3, 'NAND')],
104 104 initial=1)
105 105 delay = forms.CharField()
106 106 mask = forms.MultipleChoiceField(choices=[(0, 'L1'),(1, 'L2'),(2, 'L3'),(3, 'L4'),(4, 'L5'),(5, 'L6'),(6, 'L7'),(7, 'L8')],
107 107 widget=HCheckboxSelectMultiple())
108 108 result = forms.CharField(required=False,
109 109 widget=forms.Textarea(attrs={'readonly':True, 'rows':5, 'class':'tabuled'}))
110 110
111 111 def __init__(self, *args, **kwargs):
112 112 confs = kwargs.pop('confs', [])
113 113 if confs:
114 114 km2unit = confs[0].km2unit
115 115 clock_in = confs[0].clock_in
116 116 clock_divider = confs[0].clock_divider
117 117 else:
118 118 km2unit = clock_in = clock_divider = 0
119 119 super(RCMixConfigurationForm, self).__init__(*args, **kwargs)
120 120 self.fields['experiment'].choices = [(conf.pk, '{} | {}'.format(conf.pk, conf.name)) for conf in confs]
121 121 self.fields['delay'].widget = KmUnitWidget(attrs = {'km2unit':km2unit})
122 122 self.fields['clock_in'].initial = clock_in
123 123 self.fields['clock_divider'].initial = clock_divider
124 124
125 125
126 126
127 127 class RCLineForm(forms.ModelForm):
128 128
129 129 def __init__(self, *args, **kwargs):
130 130 self.extra_fields = kwargs.pop('extra_fields', [])
131 131 super(RCLineForm, self).__init__(*args, **kwargs)
132 132
133 133 if 'initial' in kwargs and 'line_type' in kwargs['initial']:
134 134 line_type = RCLineType.objects.get(pk=kwargs['initial']['line_type'])
135 135
136 136 if 'code_id' in kwargs['initial']:
137 137 model_initial = kwargs['initial']['code_id']
138 138 else:
139 139 model_initial = 0
140 140
141 141 params = json.loads(line_type.params)
142 142
143 143 for label, value in self.extra_fields.items():
144 144 if label=='params':
145 145 continue
146 146
147 147 if 'model' in params[label]:
148 148 self.fields[label] = forms.ChoiceField(choices=create_choices_from_model(params[label]['model'],
149 149 kwargs['initial']['rc_configuration']),
150 150 initial=model_initial)
151 151
152 152
153 153 else:
154 154 if label=='codes' and 'code_id' in kwargs['initial']:
155 155 self.fields[label] = forms.CharField(initial=RCLineCode.objects.get(pk=kwargs['initial']['code_id']).codes)
156 156 else:
157 157 self.fields[label] = forms.CharField(initial=value['value'])
158 158
159 159 if label=='codes':
160 160 self.fields[label].widget = CodesWidget()
161 161
162 162 if self.data:
163 163 line_type = RCLineType.objects.get(pk=self.data['line_type'])
164 164
165 165 if 'code_id' in self.data:
166 166 model_initial = self.data['code_id']
167 167 else:
168 168 model_initial = 0
169 169
170 170 params = json.loads(line_type.params)
171 171
172 172 for label, value in self.extra_fields.items():
173 173 if label=='params':
174 174 continue
175 175
176 176 if 'model' in params[label]:
177 177 self.fields[label] = forms.ChoiceField(choices=create_choices_from_model(params[label]['model'],
178 178 self.data['rc_configuration']),
179 179 initial=model_initial)
180 180
181 181
182 182 else:
183 183 if label=='codes' and 'code' in self.data:
184 184 self.fields[label] = forms.CharField(initial=self.data['codes'])
185 185 else:
186 186 self.fields[label] = forms.CharField(initial=self.data[label])
187 187
188 188 if label=='codes':
189 189 self.fields[label].widget = CodesWidget()
190 190
191 191
192 192 class Meta:
193 193 model = RCLine
194 194 fields = ('rc_configuration', 'line_type', 'channel')
195 195 widgets = {
196 196 'channel': forms.HiddenInput(),
197 197 }
198 198
199 199
200 200 def clean(self):
201 201
202 202 form_data = self.cleaned_data
203 203 if 'code' in self.data and self.data['TX_ref']=="0":
204 204 self.add_error('TX_ref', 'Choose a valid TX reference')
205 205
206 206 return form_data
207 207
208 208
209 209 def save(self):
210 210 line = super(RCLineForm, self).save()
211 211
212 212 #auto add channel
213 213 line.channel = RCLine.objects.filter(rc_configuration=line.rc_configuration).count()-1
214 214
215 215 #auto add position for TX, TR & CODE
216 216 if line.line_type.name in ('tx', ):
217 217 line.position = RCLine.objects.filter(rc_configuration=line.rc_configuration, line_type=line.line_type).count()-1
218 218
219 219 #save extra fields in params
220 220 params = {}
221 221 for label, value in self.extra_fields.items():
222 222 if label=='params':
223 223 params['params'] = []
224 224 elif label=='codes':
225 225 params[label] = [s for s in self.data[label].split('\r\n') if s]
226 226 else:
227 227 params[label] = self.data[label]
228 228 line.params = json.dumps(params)
229 229 line.save()
230 230 return
231 231
232 232
233 233 class RCLineViewForm(forms.Form):
234 234
235 235 def __init__(self, *args, **kwargs):
236 236
237 237 extra_fields = kwargs.pop('extra_fields')
238 238 line = kwargs.pop('line')
239 239 subform = kwargs.pop('subform', False)
240 240 super(RCLineViewForm, self).__init__(*args, **kwargs)
241 241
242 242 if subform:
243 243 params = json.loads(line.line_type.params)['params']
244 244 else:
245 245 params = json.loads(line.line_type.params)
246 246
247 247 for label, value in extra_fields.items():
248 248
249 249 if label=='params':
250 250 continue
251 251 if 'ref' in label:
252 252 if value in (0, '0'):
253 253 value = 'All'
254 254 else:
255 255 value = RCLine.objects.get(pk=value).get_name()
256 256 elif label=='code':
257 257 value = RCLineCode.objects.get(pk=value).name
258 258
259 259 self.fields[label] = forms.CharField(initial=value)
260 260
261 261 if 'widget' in params[label]:
262 262 km2unit = line.rc_configuration.km2unit
263 263 if params[label]['widget']=='km':
264 264 self.fields[label].widget = KmUnitWidget(attrs={'line':line, 'km2unit':km2unit, 'disabled':True})
265 265 elif params[label]['widget']=='unit':
266 266 self.fields[label].widget = UnitKmWidget(attrs={'line':line, 'km2unit':km2unit, 'disabled':True})
267 267 elif params[label]['widget']=='dc':
268 268 self.fields[label].widget = KmUnitDcWidget(attrs={'line':line, 'km2unit':km2unit, 'disabled':True})
269 269 elif params[label]['widget']=='codes':
270 270 self.fields[label].widget = CodesWidget(attrs={'line':line, 'km2unit':km2unit, 'disabled':True})
271 271 else:
272 272 self.fields[label].widget = DefaultWidget(attrs={'disabled':True})
273 273
274 274
275 275 class RCLineEditForm(forms.ModelForm):
276 276
277 277 def __init__(self, *args, **kwargs):
278 278
279 279 extra_fields = kwargs.pop('extra_fields', [])
280 280 conf = kwargs.pop('conf', False)
281 281 line = kwargs.pop('line')
282 282 subform = kwargs.pop('subform', False)
283 283
284 284 super(RCLineEditForm, self).__init__(*args, **kwargs)
285 285
286 286 if subform is not False:
287 287 params = json.loads(line.line_type.params)['params']
288 288 count = subform
289 289 else:
290 290 params = json.loads(line.line_type.params)
291 291 count = -1
292 292
293 293 for label, value in extra_fields.items():
294 294
295 295 if label in ('params',):
296 296 continue
297 297 if 'help' in params[label]:
298 298 help_text = params[label]['help']
299 299 else:
300 300 help_text = ''
301 301
302 302 if 'model' in params[label]:
303 303 self.fields[label] = forms.ChoiceField(choices=create_choices_from_model(params[label]['model'], conf.id),
304 304 initial=value,
305 305 widget=forms.Select(attrs={'name':'%s|%s|%s' % (count, line.id, label)}),
306 306 help_text=help_text)
307 307
308 308 else:
309 309
310 310 self.fields[label] = forms.CharField(initial=value, help_text=help_text)
311 311
312 312 if label in ('code', ):
313 313 self.fields[label].widget = HiddenWidget(attrs={'name':'%s|%s|%s' % (count, line.id, label)})
314 314
315 315 elif 'widget' in params[label]:
316 316 km2unit = line.rc_configuration.km2unit
317 317 if params[label]['widget']=='km':
318 318 self.fields[label].widget = KmUnitWidget(attrs={'line':line, 'km2unit':km2unit, 'name':'%s|%s|%s' % (count, line.id, label)})
319 319 elif params[label]['widget']=='unit':
320 320 self.fields[label].widget = UnitKmWidget(attrs={'line':line, 'km2unit':km2unit, 'name':'%s|%s|%s' % (count, line.id, label)})
321 321 elif params[label]['widget']=='dc':
322 322 self.fields[label].widget = KmUnitDcWidget(attrs={'line':line, 'km2unit':km2unit, 'name':'%s|%s|%s' % (count, line.id, label)})
323 323 elif params[label]['widget']=='codes':
324 324 self.fields[label].widget = CodesWidget(attrs={'line':line, 'km2unit':km2unit, 'name':'%s|%s|%s' % (count, line.id, label)})
325 325 else:
326 326 self.fields[label].widget = DefaultWidget(attrs={'name':'%s|%s|%s' % (count, line.id, label)})
327 327
328 328
329 329 class Meta:
330 330 model = RCLine
331 331 exclude = ('rc_configuration', 'line_type', 'channel', 'position', 'params', 'pulses')
332 332
333 333
334 334 class RCSubLineEditForm(forms.Form):
335 335
336 336 def __init__(self, *args, **kwargs):
337 337 extra_fields = kwargs.pop('extra_fields')
338 338 count = kwargs.pop('count')
339 339 line = kwargs.pop('line')
340 340 super(RCSubLineEditForm, self).__init__(*args, **kwargs)
341 341 for label, value in extra_fields.items():
342 342 self.fields[label] = forms.CharField(initial=value,
343 343 widget=forms.TextInput(attrs={'name':'%s|%s|%s' % (count, line, label)}))
344 344
345 345
346 346 class RCImportForm(forms.Form):
347 347
348 348 file_name = ExtFileField(extensions=['.racp', '.json', '.dat'])
349 349
350 350
351 351 class RCLineCodesForm(forms.ModelForm):
352 352
353 353 def __init__(self, *args, **kwargs):
354 354 super(RCLineCodesForm, self).__init__(*args, **kwargs)
355 355
356 356 if 'initial' in kwargs:
357 357 self.fields['code'] = forms.ChoiceField(choices=RCLineCode.objects.all().values_list('pk', 'name'),
358 358 initial=kwargs['initial']['code'])
359 359 if 'instance' in kwargs:
360 360 self.fields['code'] = forms.ChoiceField(choices=RCLineCode.objects.all().values_list('pk', 'name'),
361 361 initial=kwargs['instance'].pk)
362 362
363 363 self.fields['codes'].widget = CodesWidget()
364 364
365 365
366 366 class Meta:
367 367 model = RCLineCode
368 368 exclude = ('name',)
369 369
370 370 No newline at end of file
@@ -1,645 +1,737
1 1
2 2 import ast
3 3 import json
4 4 import numpy as np
5 5
6 6 from polymorphic import PolymorphicModel
7 7
8 8 from django.db import models
9 9 from django.core.urlresolvers import reverse
10 10 from django.core.validators import MinValueValidator, MaxValueValidator
11 11
12 12 from apps.main.models import Configuration
13 13 from devices.rc import api
14 from .utils import RCFile, pulses, pulses_from_code, create_mask, pulses_to_points
14 from .utils import RCFile
15 15
16 16 # Create your models here.
17 17
18 18 LINE_TYPES = (
19 19 ('none', 'Not used'),
20 20 ('tr', 'Transmission/reception selector signal'),
21 21 ('tx', 'A modulating signal (Transmission pulse)'),
22 22 ('codes', 'BPSK modulating signal'),
23 23 ('windows', 'Sample window signal'),
24 24 ('sync', 'Synchronizing signal'),
25 25 ('flip', 'IPP related periodic signal'),
26 26 ('prog_pulses', 'Programmable pulse'),
27 27 ('mix', 'Mixed line'),
28 28 )
29 29
30 30
31 31 SAMPLING_REFS = (
32 32 ('none', 'No Reference'),
33 33 ('first_baud', 'Middle of the first baud'),
34 34 ('sub_baud', 'Middle of the sub-baud')
35 35 )
36 36
37 37 DAT_CMDS = {
38 38 # Pulse Design commands
39 39 'DISABLE' : 0, # Disables pulse generation
40 40 'ENABLE' : 24, # Enables pulse generation
41 41 'DELAY_START' : 40, # Write delay status to memory
42 42 'FLIP_START' : 48, # Write flip status to memory
43 43 'SAMPLING_PERIOD' : 64, # Establish Sampling Period
44 44 'TX_ONE' : 72, # Output '0' in line TX
45 45 'TX_ZERO' : 88, # Output '0' in line TX
46 46 'SW_ONE' : 104, # Output '0' in line SW
47 47 'SW_ZERO' : 112, # Output '1' in line SW
48 48 'RESTART': 120, # Restarts CR8 Firmware
49 49 'CONTINUE' : 253, # Function Unknown
50 50 # Commands available to new controllers
51 51 # 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.
52 52 'CLOCK_DIVISOR_INIT' : 12, # Specifies Clock Divisor. Legacy command, ignored in the actual .dat conversion
53 53 'CLOCK_DIVISOR_LAST' : 22, # Specifies Clock Divisor (default 60 if not included) syntax: 255,22 254,N-1.
54 54 'CLOCK_DIVIDER' : 8,
55 55 }
56 56
57 57
58 58 class RCConfiguration(Configuration):
59 59
60 60 ipp = models.FloatField(verbose_name='Inter pulse period (Km)', validators=[MinValueValidator(1), MaxValueValidator(9000)], default=300)
61 61 ntx = models.PositiveIntegerField(verbose_name='Number of TX', validators=[MinValueValidator(1), MaxValueValidator(300)], default=1)
62 62 clock_in = models.FloatField(verbose_name='Clock in (MHz)', validators=[MinValueValidator(1), MaxValueValidator(80)], default=1)
63 63 clock_divider = models.PositiveIntegerField(verbose_name='Clock divider', validators=[MinValueValidator(1), MaxValueValidator(256)], default=1)
64 64 clock = models.FloatField(verbose_name='Clock Master (MHz)', blank=True, default=1)
65 65 time_before = models.PositiveIntegerField(verbose_name='Time before (&mu;S)', default=12)
66 66 time_after = models.PositiveIntegerField(verbose_name='Time after (&mu;S)', default=1)
67 67 sync = models.PositiveIntegerField(verbose_name='Synchro delay', default=0)
68 68 sampling_reference = models.CharField(verbose_name='Sampling Reference', choices=SAMPLING_REFS, default='none', max_length=40)
69 69 control_tx = models.BooleanField(verbose_name='Control Switch TX', default=False)
70 70 control_sw = models.BooleanField(verbose_name='Control Switch SW', default=False)
71 71 mix = models.BooleanField(default=False)
72 72
73 73 class Meta:
74 74 db_table = 'rc_configurations'
75 75
76 76
77 77 def __unicode__(self):
78 78
79 79 if self.mix:
80 80 return u'[MIXED]: %s' % self.name
81 81 else:
82 82 return u'[%s]: %s' % (self.device.name, self.name)
83 83
84 84 def get_absolute_url_plot(self):
85 85 return reverse('url_plot_rc_pulses', args=[str(self.id)])
86 86
87 87 def get_absolute_url_import(self):
88 88 return reverse('url_import_rc_conf', args=[str(self.id)])
89 89
90 90 @property
91 91 def us2unit(self):
92 92
93 93 return self.clock_in/self.clock_divider
94 94
95 95 @property
96 96 def km2unit(self):
97 97
98 98 return 20./3*(self.clock_in/self.clock_divider)
99 99
100 100 def clone(self, **kwargs):
101 101
102 102 lines = self.get_lines()
103 103 self.pk = None
104 104 self.id = None
105 105 for attr, value in kwargs.items():
106 106 setattr(self, attr, value)
107 107 self.save()
108 108
109 109 for line in lines:
110 110 line.clone(rc_configuration=self)
111 111
112 112 return self
113 113
114 114 def get_lines(self, **kwargs):
115 115 '''
116 116 Retrieve configuration lines
117 117 '''
118 118
119 119 return RCLine.objects.filter(rc_configuration=self.pk, **kwargs)
120 120
121 121
122 122 def clean_lines(self):
123 123 '''
124 124 '''
125 125
126 empty_line = RCLineType.objects.get(pk=8)
126 empty_line = RCLineType.objects.get(name='none')
127 127
128 128 for line in self.get_lines():
129 129 line.line_type = empty_line
130 130 line.params = '{}'
131 131 line.save()
132 132
133 133 def parms_to_dict(self):
134 134 '''
135 135 '''
136 136
137 ignored = ('parameters', 'type', 'polymorphic_ctype', 'configuration_ptr',
138 'created_date', 'programmed_date')
139
137 140 data = {}
138 141 for field in self._meta.fields:
139
142 if field.name in ignored:
143 continue
140 144 data[field.name] = '{}'.format(field.value_from_object(self))
141 145
142 data.pop('parameters')
143 146 data['lines'] = []
144 147
145 148 for line in self.get_lines():
146 149 line_data = json.loads(line.params)
147 150 if 'TX_ref' in line_data and line_data['TX_ref'] not in (0, '0'):
148 151 line_data['TX_ref'] = RCLine.objects.get(pk=line_data['TX_ref']).get_name()
149 152 if 'code' in line_data:
150 153 line_data['code'] = RCLineCode.objects.get(pk=line_data['code']).name
151 154 line_data['type'] = line.line_type.name
152 155 data['lines'].append(line_data)
153 156
154 157 data['delays'] = self.get_delays()
155 158 data['pulses'] = self.get_pulses()
156 159
157 160 return data
158 161
159 162 def dict_to_parms(self, data):
160 163 '''
161 164 '''
162 165
163 166 self.name = data['name']
164 167 self.ipp = data['ipp']
165 168 self.ntx = data['ntx']
166 169 self.clock_in = data['clock_in']
167 170 self.clock_divider = data['clock_divider']
168 171 self.clock = data['clock']
169 172 self.time_before = data['time_before']
170 173 self.time_after = data['time_after']
171 174 self.sync = data['sync']
172 175 self.sampling_reference = data['sampling_reference']
173 176 self.clean_lines()
174 177
175 178 lines = []
176 179 positions = {'tx':0, 'tr':0}
177 180
178 181 for i, line_data in enumerate(data['lines']):
179 182 line_type = RCLineType.objects.get(name=line_data.pop('type'))
180 183 if line_type.name=='codes':
181 184 code = RCLineCode.objects.get(name=line_data['code'])
182 185 line_data['code'] = code.pk
183 186 line = RCLine.objects.filter(rc_configuration=self, channel=i)
184 187 if line:
185 188 line = line[0]
186 189 line.line_type = line_type
187 190 line.params = json.dumps(line_data)
188 191 else:
189 192 line = RCLine(rc_configuration=self, line_type=line_type,
190 193 params=json.dumps(line_data),
191 194 channel=i)
192 195
193 196 if line_type.name=='tx':
194 197 line.position = positions['tx']
195 198 positions['tx'] += 1
196 199
197 200 if line_type.name=='tr':
198 201 line.position = positions['tr']
199 202 positions['tr'] += 1
200 203
201 204 line.save()
202 205 lines.append(line)
203 206
204 207 for line, line_data in zip(lines, data['lines']):
205 208 if 'TX_ref' in line_data:
206 209 params = json.loads(line.params)
207 210 if line_data['TX_ref'] in (0, '0'):
208 211 params['TX_ref'] = '0'
209 212 else:
210 213 params['TX_ref'] = [l.pk for l in lines if l.line_type.name=='tx' and l.get_name()==line_data['TX_ref']][0]
211 214 line.params = json.dumps(params)
212 215 line.save()
213 216
214 217
215 218 def get_delays(self):
216 219
217 pulses = [line.get_pulses() for line in self.get_lines()]
220 pulses = [line.pulses_as_points() for line in self.get_lines()]
218 221 points = [tup for tups in pulses for tup in tups]
219 222 points = set([x for tup in points for x in tup])
220 223 points = list(points)
221 224 points.sort()
222 225
223 226 if points[0]<>0:
224 227 points.insert(0, 0)
225 228
226 229 return [points[i+1]-points[i] for i in range(len(points)-1)]
227 230
228 231
229 232 def get_pulses(self, binary=True):
230 233
231 pulses = [line.get_pulses() for line in self.get_lines()]
234 pulses = [line.pulses_as_points() for line in self.get_lines()]
232 235 points = [tup for tups in pulses for tup in tups]
233 236 points = set([x for tup in points for x in tup])
234 237 points = list(points)
235 238 points.sort()
236 239
237 line_points = [pulses_to_points(line.pulses_as_array()) for line in self.get_lines()]
240 line_points = [line.pulses_as_points() for line in self.get_lines()]
238 241 line_points = [[(x, x+y) for x,y in tups] for tups in line_points]
239 242 line_points = [[t for x in tups for t in x] for tups in line_points]
240 243 states = [[1 if x in tups else 0 for tups in line_points] for x in points]
241 244
242 245 if binary:
243 246 states.reverse()
244 247 states = [int(''.join([str(x) for x in flips]), 2) for flips in states]
245 248
246 249 return states[:-1]
247 250
248 251 def add_cmd(self, cmd):
249 252
250 253 if cmd in DAT_CMDS:
251 254 return (255, DAT_CMDS[cmd])
252 255
253 256 def add_data(self, value):
254 257
255 258 return (254, value-1)
256 259
257 260 def parms_to_binary(self):
258 261 '''
259 262 Create "dat" stream to be send to CR
260 263 '''
261 264
262 265 data = []
263 266 # create header
264 267 data.append(self.add_cmd('DISABLE'))
265 268 data.append(self.add_cmd('CONTINUE'))
266 269 data.append(self.add_cmd('RESTART'))
267 270
268 271 if self.control_sw:
269 272 data.append(self.add_cmd('SW_ONE'))
270 273 else:
271 274 data.append(self.add_cmd('SW_ZERO'))
272 275
273 276 if self.control_tx:
274 277 data.append(self.add_cmd('TX_ONE'))
275 278 else:
276 279 data.append(self.add_cmd('TX_ZERO'))
277 280
278 281 # write divider
279 282 data.append(self.add_cmd('CLOCK_DIVIDER'))
280 283 data.append(self.add_data(self.clock_divider))
281 284
282 285 # write delays
283 286 data.append(self.add_cmd('DELAY_START'))
284 287 # first delay is always zero
285 288 data.append(self.add_data(1))
286 289
287 290 delays = self.get_delays()
288 291
289 292 for delay in delays:
290 293 while delay>252:
291 294 data.append(self.add_data(253))
292 295 delay -= 253
293 296 data.append(self.add_data(delay))
294 297
295 298 # write flips
296 299 data.append(self.add_cmd('FLIP_START'))
297 300
298 301 states = self.get_pulses(binary=False)
299 302
300 303 for flips, delay in zip(states, delays):
301 304 flips.reverse()
302 305 flip = int(''.join([str(x) for x in flips]), 2)
303 306 data.append(self.add_data(flip+1))
304 307 while delay>252:
305 308 data.append(self.add_data(1))
306 309 delay -= 253
307 310
308 311 # write sampling period
309 312 data.append(self.add_cmd('SAMPLING_PERIOD'))
310 313 wins = self.get_lines(line_type__name='windows')
311 314 if wins:
312 315 win_params = json.loads(wins[0].params)['params']
313 316 if win_params:
314 317 dh = int(win_params[0]['resolution']*self.km2unit)
315 318 else:
316 319 dh = 1
317 320 else:
318 321 dh = 1
319 322 data.append(self.add_data(dh))
320 323
321 324 # write enable
322 325 data.append(self.add_cmd('ENABLE'))
323 326
324 327 return '\n'.join(['{}'.format(x) for tup in data for x in tup])
325 328
326 329 def update_from_file(self, filename):
327 330 '''
328 331 Update instance from file
329 332 '''
330 333
331 334 f = RCFile(filename)
332 335 self.dict_to_parms(f.data)
336 self.update_pulses()
337 self.save()
333 338
334 339 def update_pulses(self):
335 340
336 341 for line in self.get_lines():
337 if line.line_type.name=='tr':
338 continue
339 342 line.update_pulses()
343
344 def plot_pulses(self):
345
346 import matplotlib.pyplot as plt
347 from bokeh.resources import CDN
348 from bokeh.embed import components
349 from bokeh.mpl import to_bokeh
350 from bokeh.models.tools import WheelZoomTool, ResetTool, PanTool, PreviewSaveTool
351
352 lines = self.get_lines()
340 353
341 for tr in self.get_lines(line_type__name='tr'):
342 tr.update_pulses()
354 max_value = self.ipp*self.km2unit*self.ntx
355
356 N = len(lines)
357 fig = plt.figure(figsize=(10, 2+N*0.5))
358 ax = fig.add_subplot(111)
359 labels = []
360
361 for i, line in enumerate(lines):
362 labels.append(line.get_name())
363 l = ax.plot((0, max_value),(N-i-1, N-i-1))
364 points = [(tup[0], tup[1]-tup[0]) for tup in line.pulses_as_points() if tup<>(0,0)]
365 ax.broken_barh(points, (N-i-1, 0.5),
366 edgecolor=l[0].get_color(), facecolor='none')
367
368 labels.reverse()
369 ax.set_yticklabels(labels)
370 plot = to_bokeh(fig, use_pandas=False)
371 plot.tools = [PanTool(dimensions=['width']), WheelZoomTool(dimensions=['width']), ResetTool(), PreviewSaveTool()]
372
373 return components(plot, CDN)
343 374
344 375 def status_device(self):
345 376
346 377 return 0
347 378
348 379 def stop_device(self):
349 380
350 381 answer = api.disable(ip = self.device.ip_address,
351 382 port = self.device.port_address)
352 383
353 384 if answer[0] != "1":
354 385 self.message = answer[0:]
355 386 return 0
356 387
357 388 self.message = answer[2:]
358 389 return 1
359 390
360 391 def start_device(self):
361 392
362 393 answer = api.enable(ip = self.device.ip_address,
363 394 port = self.device.port_address)
364 395
365 396 if answer[0] != "1":
366 397 self.message = answer[0:]
367 398 return 0
368 399
369 400 self.message = answer[2:]
370 401 return 1
371 402
372 403 def write_device(self):
373 404 answer = api.write_config(ip = self.device.ip_address,
374 405 port = self.device.port_address,
375 406 parms = self.parms_to_dict())
376 407
377 408 if answer[0] != "1":
378 409 self.message = answer[0:]
379 410 return 0
380 411
381 412 self.message = answer[2:]
382 413 return 1
383 414
384 415
385 416 class RCLineCode(models.Model):
386 417
387 418 name = models.CharField(max_length=40)
388 419 bits_per_code = models.PositiveIntegerField(default=0)
389 420 number_of_codes = models.PositiveIntegerField(default=0)
390 421 codes = models.TextField(blank=True, null=True)
391 422
392 423 class Meta:
393 424 db_table = 'rc_line_codes'
394 425 ordering = ('name',)
395 426
396 427 def __unicode__(self):
397 428 return u'%s' % self.name
398 429
399 430
400 431 class RCLineType(models.Model):
401 432
402 433 name = models.CharField(choices=LINE_TYPES, max_length=40)
403 434 description = models.TextField(blank=True, null=True)
404 435 params = models.TextField(default='[]')
405 436
406 437 class Meta:
407 438 db_table = 'rc_line_types'
408 439
409 440 def __unicode__(self):
410 441 return u'%s - %s' % (self.name.upper(), self.get_name_display())
411 442
412 443
413 444 class RCLine(models.Model):
414 445
415 446 rc_configuration = models.ForeignKey(RCConfiguration, on_delete=models.CASCADE)
416 447 line_type = models.ForeignKey(RCLineType)
417 448 channel = models.PositiveIntegerField(default=0)
418 449 position = models.PositiveIntegerField(default=0)
419 450 params = models.TextField(default='{}')
420 451 pulses = models.TextField(default='')
421 452
422 453 class Meta:
423 454 db_table = 'rc_lines'
424 455 ordering = ['channel']
425 456
426 457 def __unicode__(self):
427 458 if self.rc_configuration:
428 459 return u'%s - %s' % (self.rc_configuration, self.get_name())
429 460
430 461 def clone(self, **kwargs):
431 462
432 463 self.pk = None
433 464
434 465 for attr, value in kwargs.items():
435 466 setattr(self, attr, value)
436 467
437 468 self.save()
438 469
439 470 return self
440 471
441 472 def get_name(self):
442 473
443 474 chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
475 s = ''
444 476
445 477 if self.line_type.name in ('tx',):
446 return '%s%s' % (self.line_type.name.upper(), chars[self.position])
478 s = chars[self.position]
447 479 elif self.line_type.name in ('codes', 'windows', 'tr'):
448 if 'TX_ref' not in json.loads(self.params):
449 return self.line_type.name.upper()
450 pk = json.loads(self.params)['TX_ref']
451 if pk in (0, '0'):
452 refs = ','.join(chars[l.position] for l in self.rc_configuration.get_lines(line_type__name='tx'))
453 return '%s (%s)' % (self.line_type.name.upper(), refs)
454 else:
455 ref = RCLine.objects.get(pk=pk)
456 return '%s (%s)' % (self.line_type.name.upper(), chars[ref.position])
457 elif self.line_type.name in ('flip', 'prog_pulses', 'sync', 'none', 'mix'):
458 return '%s %s' % (self.line_type.name.upper(), self.channel)
480 if 'TX_ref' in json.loads(self.params):
481 pk = json.loads(self.params)['TX_ref']
482 if pk in (0, '0'):
483 s = ','.join(chars[l.position] for l in self.rc_configuration.get_lines(line_type__name='tx'))
484 else:
485 ref = RCLine.objects.get(pk=pk)
486 s = chars[ref.position]
487
488 if s:
489 return '{}({}) {}'.format(self.line_type.name.upper(), s, self.channel)
459 490 else:
460 return self.line_type.name.upper()
491 return '{} {}'.format(self.line_type.name.upper(), self.channel)
461 492
462 493 def get_lines(self, **kwargs):
463 494
464 495 return RCLine.objects.filter(rc_configuration=self.rc_configuration, **kwargs)
465 496
466 497 def pulses_as_array(self):
467 498
468 return (np.fromstring(self.pulses, dtype=np.uint8)-48).astype(np.int8)
469
470 def get_pulses(self):
471
472 X = self.pulses_as_array()
499 y = np.zeros(self.rc_configuration.ntx*self.rc_configuration.ipp*self.rc_configuration.km2unit)
473 500
474 d = X[1:]-X[:-1]
501 for tup in ast.literal_eval(self.pulses):
502 y[tup[0]:tup[1]] = 1
503
504 return y.astype(np.int8)
475 505
476 up = np.where(d==1)[0]
477 if X[0]==1:
478 up = np.concatenate((np.array([-1]), up))
479 up += 1
506 def pulses_as_points(self):
480 507
481 dw = np.where(d==-1)[0]
482 if X[-1]==1:
483 dw = np.concatenate((dw, np.array([len(X)-1])))
484 dw += 1
485
486 return [(tup[0], tup[1]) for tup in zip(up, dw)]
508 return ast.literal_eval(self.pulses)
487 509
488 510 def get_win_ref(self, params, tx_id, km2unit):
489 511
490 512 ref = self.rc_configuration.sampling_reference
491 513 codes = [line for line in self.get_lines(line_type__name='codes') if int(json.loads(line.params)['TX_ref'])==int(tx_id)]
492 514
493 515 if codes:
494 516 tx_width = float(json.loads(RCLine.objects.get(pk=tx_id).params)['pulse_width'])*km2unit/len(json.loads(codes[0].params)['codes'][0])
495 517 else:
496 518 tx_width = float(json.loads(RCLine.objects.get(pk=tx_id).params)['pulse_width'])*km2unit
497 519
498 520 if ref=='first_baud':
499 521 return int(1 + (tx_width + 1)/2 + params['first_height']*km2unit - params['resolution']*km2unit)
500 522 elif ref=='sub_baud':
501 523 return int(1 + params['first_height']*km2unit - params['resolution']*km2unit/2)
502 524 else:
503 525 return 0
504 526
505 def update_pulses(self, save=True, tr=False):
527 def update_pulses(self):
506 528 '''
507 529 Update pulses field
508 530 '''
509 531
510 532 km2unit = self.rc_configuration.km2unit
511 533 us2unit = self.rc_configuration.us2unit
512 534 ipp = self.rc_configuration.ipp
513 535 ntx = self.rc_configuration.ntx
514 536 ipp_u = int(ipp*km2unit)
515 537
516 x = np.arange(0, ipp_u*ntx)
538 y = []
517 539
518 540 if self.line_type.name=='tr':
519 params = json.loads(self.params)
520 if params['TX_ref'] in ('0', 0):
521 txs = [tx.update_pulses(save=False, tr=True) for tx in self.get_lines(line_type__name='tx')]
541 tr_params = json.loads(self.params)
542
543 if tr_params['TX_ref'] in ('0', 0):
544 txs = self.get_lines(line_type__name='tx')
522 545 else:
523 txs = [tx.update_pulses(save=False, tr=True) for tx in RCLine.objects.filter(pk=params['TX_ref'])]
524 if len(txs)==0 or 0 in [len(tx) for tx in txs]:
525 return
546 txs = [RCLine.objects.filter(pk=tr_params['TX_ref'])]
526 547
527 y = np.any(txs, axis=0, out=np.ones(ipp_u*ntx))
528
529 ranges = params['range'].split(',')
530 if len(ranges)>0 and ranges[0]<>'0':
531 mask = create_mask(ranges, ipp_u, ntx, self.rc_configuration.sync)
532 y = y.astype(np.int8) & mask
548 for tx in txs:
549 params = json.loads(tx.params)
550 if float(params['pulse_width'])==0:
551 continue
552 delays = [float(d)*km2unit for d in params['delays'].split(',') if d]
553 width = float(params['pulse_width'])*km2unit+int(self.rc_configuration.time_before*us2unit)
554 before = 0
555 after = int(self.rc_configuration.time_after*us2unit)
556
557 y_tx = self.points(ntx, ipp_u, width,
558 delay=delays,
559 before=before,
560 after=after,
561 sync=self.rc_configuration.sync)
562
563 ranges = params['range'].split(',')
564
565 if len(ranges)>0 and ranges[0]<>'0':
566 y_tx = self.mask_ranges(y_tx, ranges)
567
568 tr_ranges = tr_params['range'].split(',')
569
570 if len(tr_ranges)>0 and tr_ranges[0]<>'0':
571 y_tx = self.mask_ranges(y_tx, tr_ranges)
572
573 y.extend(y_tx)
533 574
534 575 elif self.line_type.name=='tx':
535 576 params = json.loads(self.params)
536 delays = [float(d)*km2unit for d in params['delays'].split(',') if d]
537 y = pulses(x, ipp_u, float(params['pulse_width'])*km2unit,
538 delay=delays,
539 before=int(self.rc_configuration.time_before*us2unit),
540 after=int(self.rc_configuration.time_after*us2unit) if tr else 0,
541 sync=self.rc_configuration.sync)
542
543 ranges = params['range'].split(',')
577 delays = [float(d)*km2unit for d in params['delays'].split(',') if d]
578 width = float(params['pulse_width'])*km2unit
544 579
545 if len(ranges)>0 and ranges[0]<>'0':
546 mask = create_mask(ranges, ipp_u, ntx, self.rc_configuration.sync)
547 y = y & mask
580 if width>0:
581 before = int(self.rc_configuration.time_before*us2unit)
582 after = 0
583
584 y = self.points(ntx, ipp_u, width,
585 delay=delays,
586 before=before,
587 after=after,
588 sync=self.rc_configuration.sync)
589
590 ranges = params['range'].split(',')
591
592 if len(ranges)>0 and ranges[0]<>'0':
593 y = self.mask_ranges(y, ranges)
548 594
549 595 elif self.line_type.name=='flip':
550 width = float(json.loads(self.params)['number_of_flips'])*ipp*km2unit
551 y = pulses(x, 2*width, width)
596 n = float(json.loads(self.params)['number_of_flips'])
597 width = n*ipp*km2unit
598 y = self.points(int((ntx+1)/(2*n)), ipp_u*n*2, width)
552 599
553 600 elif self.line_type.name=='codes':
554 601 params = json.loads(self.params)
555 602 tx = RCLine.objects.get(pk=params['TX_ref'])
556 603 tx_params = json.loads(tx.params)
557 delays = [float(d)*km2unit for d in tx_params['delays'].split(',') if d]
558 y = pulses_from_code(tx.pulses_as_array(),
559 params['codes'],
560 int(float(tx_params['pulse_width'])*km2unit))
604 delays = [float(d)*km2unit for d in tx_params['delays'].split(',') if d]
605 f = int(float(tx_params['pulse_width'])*km2unit)/len(params['codes'][0])
606 codes = [(np.fromstring(''.join([s*f for s in code]), dtype=np.uint8)-48).astype(np.int8) for code in params['codes']]
607 codes = [self.array_to_points(code) for code in codes]
608 n = len(codes)
561 609
610 for i, tup in enumerate(tx.pulses_as_points()):
611 code = codes[i%n]
612 y.extend([(c[0]+tup[0], c[1]+tup[0]) for c in code])
613
562 614 ranges = tx_params['range'].split(',')
563 615 if len(ranges)>0 and ranges[0]<>'0':
564 mask = create_mask(ranges, ipp_u, ntx, self.rc_configuration.sync)
565 y = y.astype(np.int8) & mask
616 y = self.mask_ranges(y, ranges)
566 617
567 618 elif self.line_type.name=='sync':
568 619 params = json.loads(self.params)
569 y = np.zeros(ipp_u*ntx)
620 n = ipp_u*ntx
570 621 if params['invert'] in ('1', 1):
571 y[-1] = 1
622 y = [(n-1, n)]
572 623 else:
573 y[0] = 1
624 y = [(0, 1)]
574 625
575 626 elif self.line_type.name=='prog_pulses':
576 627 params = json.loads(self.params)
577 628 if int(params['periodic'])==0:
578 nntx = ntx
579 else:
580 629 nntx = 1
630 nipp = ipp_u*ntx
631 else:
632 nntx = ntx
633 nipp = ipp_u
581 634
582 635 if 'params' in params and len(params['params'])>0:
583 y = sum([pulses(x, ipp_u*nntx, (pp['end']-pp['begin']), shift=pp['begin']) for pp in params['params']])
584 else:
585 y = np.zeros(ipp_u*ntx)
586
636 for p in params['params']:
637 y_pp = self.points(nntx, nipp,
638 p['end']-p['begin'],
639 before=p['begin'])
640
641 y.extend(y_pp)
642
587 643 elif self.line_type.name=='windows':
588 params = json.loads(self.params)
644 params = json.loads(self.params)
589 645
590 646 if 'params' in params and len(params['params'])>0:
591 y = sum([pulses(x, ipp_u, pp['resolution']*pp['number_of_samples']*km2unit,
592 shift=0,
593 before=int(self.rc_configuration.time_before*us2unit)+self.get_win_ref(pp, params['TX_ref'],km2unit),
594 sync=self.rc_configuration.sync) for pp in params['params']])
595 tr = self.get_lines(line_type__name='tr')[0]
596 ranges = json.loads(tr.params)['range'].split(',')
597 if len(ranges)>0 and ranges[0]<>'0':
598 mask = create_mask(ranges, ipp_u, ntx, self.rc_configuration.sync)
599 y = y & mask
600 else:
601 y = np.zeros(ipp_u*ntx)
602
647 tr_params = json.loads(self.get_lines(line_type__name='tr')[0].params)
648 tr_ranges = tr_params['range'].split(',')
649 for p in params['params']:
650 y_win = self.points(ntx, ipp_u,
651 p['resolution']*p['number_of_samples']*km2unit,
652 before=int(self.rc_configuration.time_before*us2unit)+self.get_win_ref(p, params['TX_ref'], km2unit),
653 sync=self.rc_configuration.sync)
654
655 if len(tr_ranges)>0 and tr_ranges[0]<>'0':
656 y_win = self.mask_ranges(y_win, tr_ranges)
657
658 y.extend(y_win)
659
603 660 elif self.line_type.name=='mix':
604 661 values = self.rc_configuration.parameters.split('-')
605 662 confs = RCConfiguration.objects.filter(pk__in=[value.split('|')[0] for value in values])
606 663 modes = [value.split('|')[1] for value in values]
607 664 delays = [value.split('|')[2] for value in values]
608 665 masks = [value.split('|')[3] for value in values]
609 666
610 667 y = confs[0].get_lines(channel=self.channel)[0].pulses_as_array()
611
668 ysize = len(y)
612 669 for i in range(1, len(values)):
613 670 mask = list('{:8b}'.format(int(masks[i])))
614 671 mask.reverse()
615 672
616 673 if mask[self.channel] in ('0', '', ' '):
617 674 continue
618 675 Y = confs[i].get_lines(channel=self.channel)[0].pulses_as_array()
619 676 delay = float(delays[i])*km2unit
620 677 if delay>0:
621 678 y_temp = np.empty_like(Y)
622 679 y_temp[:delay] = 0
623 680 y_temp[delay:] = Y[:-delay]
624
681 y_tempsize = len(y_temp)
625 682 if modes[i]=='OR':
626 y2 = y | y_temp
683 y = y | y_temp
627 684 elif modes[i]=='XOR':
628 y2 = y ^ y_temp
685 y = y ^ y_temp
629 686 elif modes[i]=='AND':
630 y2 = y & y_temp
687 y = y & y_temp
631 688 elif modes[i]=='NAND':
632 y2 = y & ~y_temp
689 y = y & ~y_temp
633 690
634 y = y2
691 y = self.array_to_points(y)
635 692
636 693 else:
637 y = np.zeros(ipp_u*ntx)
694 y = []
638 695
639 if save:
640 self.pulses = (y+48).astype(np.uint8).tostring()
641 self.save()
642 else:
643 return y
696 self.pulses = y
697 self.save()
698
699 @staticmethod
700 def array_to_points(X):
701
702 d = X[1:]-X[:-1]
703
704 up = np.where(d==1)[0]
705 if X[0]==1:
706 up = np.concatenate((np.array([-1]), up))
707 up += 1
708
709 dw = np.where(d==-1)[0]
710 if X[-1]==1:
711 dw = np.concatenate((dw, np.array([len(X)-1])))
712 dw += 1
713
714 return [(tup[0], tup[1]) for tup in zip(up, dw)]
715
716 @staticmethod
717 def mask_ranges(Y, ranges):
718
719 y = [(0, 0) for __ in Y]
720
721 for index in ranges:
722 if '-' in index:
723 args = [int(a) for a in index.split('-')]
724 y[args[0]-1:args[1]] = Y[args[0]-1:args[1]]
725 else:
726 y[int(index-1)] = Y[int(index-1)]
727
728 return y
729
730 @staticmethod
731 def points(ntx, ipp, width, delay=[0], before=0, after=0, sync=0):
732
733 delays = len(delay)
734
735 Y = [(ipp*x+before+delay[x%delays], ipp*x+width+before+delay[x%delays]+after) for x in range(ntx)]
644 736
645 No newline at end of file
737 return Y No newline at end of file
@@ -1,20 +1,20
1 1 from django.conf.urls import url
2 2
3 3 urlpatterns = (
4 4 url(r'^(?P<conf_id>-?\d+)/$', 'apps.rc.views.conf', name='url_rc_conf'),
5 5 url(r'^(?P<conf_id>-?\d+)/import/$', 'apps.rc.views.import_file', name='url_import_rc_conf'),
6 6 url(r'^(?P<conf_id>-?\d+)/edit/$', 'apps.rc.views.conf_edit', name='url_edit_rc_conf'),
7 url(r'^(?P<conf_id>-?\d+)/plot/$', 'apps.rc.views.view_pulses', name='url_plot_rc_pulses'),
7 url(r'^(?P<conf_id>-?\d+)/plot/$', 'apps.rc.views.plot_pulses', name='url_plot_rc_pulses'),
8 8 url(r'^(?P<id_conf>-?\d+)/write/$', 'apps.main.views.dev_conf_write', name='url_write_rc_conf'),
9 9 url(r'^(?P<id_conf>-?\d+)/read/$', 'apps.main.views.dev_conf_read', name='url_read_rc_conf'),
10 10
11 11 url(r'^(?P<conf_id>-?\d+)/add_line/$', 'apps.rc.views.add_line', name='url_add_rc_line'),
12 12 url(r'^(?P<conf_id>-?\d+)/add_line/(?P<line_type_id>-?\d+)/$', 'apps.rc.views.add_line', name='url_add_rc_line'),
13 13 url(r'^(?P<conf_id>-?\d+)/add_line/(?P<line_type_id>-?\d+)/code/(?P<code_id>-?\d+)/$', 'apps.rc.views.add_line', name='url_add_rc_line_code'),
14 14 url(r'^(?P<conf_id>-?\d+)/update_position/$', 'apps.rc.views.update_lines_position', name='url_update_rc_lines_position'),
15 15 url(r'^(?P<conf_id>-?\d+)/line/(?P<line_id>-?\d+)/delete/$', 'apps.rc.views.remove_line', name='url_remove_rc_line'),
16 16 url(r'^(?P<conf_id>-?\d+)/line/(?P<line_id>-?\d+)/add_subline/$', 'apps.rc.views.add_subline', name='url_add_rc_subline'),
17 17 url(r'^(?P<conf_id>-?\d+)/line/(?P<line_id>-?\d+)/codes/$', 'apps.rc.views.edit_codes', name='url_edit_rc_codes'),
18 18 url(r'^(?P<conf_id>-?\d+)/line/(?P<line_id>-?\d+)/codes/(?P<code_id>-?\d+)/$', 'apps.rc.views.edit_codes', name='url_edit_rc_codes'),
19 19 url(r'^(?P<conf_id>-?\d+)/line/(?P<line_id>-?\d+)/subline/(?P<subline_id>-?\d+)/delete/$', 'apps.rc.views.remove_subline', name='url_remove_rc_subline'),
20 20 )
@@ -1,315 +1,206
1 1
2 2 import json
3 import numpy as np
4 import matplotlib.pyplot as plt
5
6 3
7 4 class RCFile(object):
8 5 '''
9 6 Class to handle Radar controller configuration files
10 7 '''
11 8
12 9 def __init__(self, f=None):
13 10
14 11 self.data = {}
15 12 if isinstance(f, str):
16 13 self.f = open(f)
17 14 self.name = f.split('/')[-1]
18 15 elif hasattr(f, 'read'):
19 16 self.f = f
20 17 self.name = f.name.split('/')[-1]
21 18 else:
22 19 self.f = f
23 20 self.name = None
24 21
25 22 if self.f:
26 23 if 'racp' in self.name:
27 24 self.parse_racp()
28 25 elif 'dat' in self.name:
29 26 self.parse_dat()
30 27 elif 'json' in self.name:
31 28 self.data = json.load(self.f)
32 29
33 30 self.f.close()
34 31
35 32 def get_line_parameters(self, data, line):
36 33
37 34 line_params = {}
38 35 for label in data:
39 36 if 'L%d' % line in label or '(Line %d)' % line in label or 'Line%d' % line in label:
40 37 line_params[label] = data[label]
41 38 return line_params
42 39
43 40 def parse_racp(self):
44 41
45 42 data = {}
46 43 raw_data = [s.strip() for s in self.f.readlines()]
47 44
48 45 for line in raw_data:
49 46 if line and '=' in line:
50 47 label, value = line.strip().split('=')
51 48 data[label] = value
52 49
53 50 self.data['experiment_type'] = data['EXPERIMENT TYPE']
54 51 self.data['header_version'] = data['HEADER VERSION']
55 52 self.data['name'] = data['EXPERIMENT NAME']
56 53 self.data['ipp'] = float(data['IPP'])
57 54 self.data['ntx'] = int(data['NTX'])
58 55
59 56 if 'CLOCK DIVIDER' in data:
60 57 self.data['clock_divider'] = int(data['CLOCK DIVIDER'])
61 58 else:
62 59 self.data['clock_divider'] = 1
63 60 self.data['clock_in'] = float(data['RELOJ'])*self.data['clock_divider']
64 61 self.data['clock'] = float(data['RELOJ'])
65 62 self.data['time_before'] = int(data['TR_BEFORE'])
66 63 self.data['time_after'] = int(data['TR_AFTER'])
67 64
68 65 if 'SYNCHRO DELAY' in data:
69 66 self.data['sync'] = int(data['SYNCHRO DELAY'])
70 67 else:
71 68 self.data['sync'] = 0
72 69 self.data['lines'] = []
73 70
74 71 if 'SAMPLING REFERENCE' in data:
75 72 if data['SAMPLING REFERENCE']=='MIDDLE OF FIRST BAUD':
76 73 self.data['sampling_reference'] = 'first_baud'
77 74 elif data['SAMPLING REFERENCE']=='MIDDLE OF FIRST SUB-BAUD':
78 75 self.data['sampling_reference'] = 'sub_baud'
79 76 else:
80 77 self.data['sampling_reference'] = 'none'
81 78
82 79 #Add TR line
83 80 if 'Pulse selection_TR' in data:
84 81 if 'A,' in data['Pulse selection_TR']:
85 82 rng = data['Pulse selection_TR'].replace('A,', '')
86 83 ref = 'TXA'
87 84 elif 'A' in data['Pulse selection_TR']:
88 85 rng = data['Pulse selection_TR'].replace('A', '')
89 86 ref = 'TXA'
90 87 elif 'B,' in data['Pulse selection_TR']:
91 88 rng = data['Pulse selection_TR'].replace('B,', '')
92 89 ref = 'TXB'
93 90 elif 'B' in data['Pulse selection_TR']:
94 91 rng = data['Pulse selection_TR'].replace('B', '')
95 92 ref = 'TXB'
96 93 else:
97 94 rng = data['Pulse selection_TR']
98 95 ref = '0'
99 96 line = {'type':'tr', 'range': rng if rng else '0', 'TX_ref':ref}
100 97 else:
101 98 line = {'type': 'tr', 'range': '0', 'TX_ref': '0'}
102 99
103 100 self.data['lines'].append(line)
104 101
105 102 #Add TX's lines
106 103 if 'TXA' in data:
107 104 line = {'type':'tx', 'pulse_width':data['TXA'], 'delays':'0'}
108 105 if 'Pulse selection_TXA' in data:
109 106 line['range'] = data['Pulse selection_TXA']
110 107 else:
111 108 line['range'] = '0'
112 109 self.data['lines'].append(line)
113 110 else:
114 111 self.data['lines'].append({'type':'tx', 'pulse_width':'0', 'delays':'0', 'range':'0'})
115 112
116 113 if 'TXB' in data:
117 114 line = {'type':'tx', 'pulse_width':data['TXB'], 'delays':'0'}
118 115 if 'Pulse selection_TXB' in data:
119 116 line['range'] = data['Pulse selection_TXB']
120 117 else:
121 118 line['range'] = '0'
122 119
123 120 if 'Number of Taus' in data:
124 121 delays = [data['TAU({0})'.format(i)] for i in range(int(data['Number of Taus']))]
125 122 line['delays'] = ','.join(delays)
126 123
127 124 self.data['lines'].append(line)
128 125 else:
129 126 self.data['lines'].append({'type':'tx', 'pulse_width':'0', 'delays':'0', 'range':'0'})
130 127
131 128 #Add Other lines (4-6)
132 129 for n in range(4, 7):
133 130 params = self.get_line_parameters(data, n)
134 131 labels = params.keys()
135 132
136 133 if 'L%d_FLIP' % n in labels:
137 134 line = {'type':'flip', 'number_of_flips':data['L%d_FLIP' % n]}
138 135 elif 'Code Type' in data and n==4:
139 136 line = {'type':'codes', 'code':data['Code Type'], 'TX_ref':data['L%d_REFERENCE' % n]}
140 137 if 'Number of Codes' in data:
141 138 line['codes'] = [data['COD({})'.format(x)] for x in range(int(data['Number of Codes']))]
142 139 elif 'Code Type (Line %d)' % n in labels:
143 140 line = {'type':'codes', 'code':data['Code Type (Line %d)' % n], 'TX_ref':data['L%d_REFERENCE' % n]}
144 141 if 'Number of Codes (Line %d)' % n in data:
145 142 line['codes'] = [data['L{}_COD({})'.format(n, x)] for x in range(int(data['Number of Codes (Line %d)' % n]))]
146 143 elif 'Sampling Windows (Line %d)' % n in data:
147 144 line = {'type':'windows', 'TX_ref':data['L%d_REFERENCE' % n]}
148 145 windows = []
149 146 for w in range(int(data['Sampling Windows (Line %d)' % n])):
150 147 windows.append({'first_height':float(data['L%d_H0(%d)' % (n, w)]),
151 148 'number_of_samples':int(data['L%d_NSA(%d)' % (n, w)]),
152 149 'resolution':float(data['L%d_DH(%d)' % (n, w)])}
153 150 )
154 151 line['params'] = windows
155 152 elif 'Line%d' % n in labels and data['Line%d' % n]=='Synchro':
156 153 line = {'type':'sync', 'invert':0}
157 154 elif 'L%d Number Of Portions' % n in labels:
158 155 line = {'type':'prog_pulses'}
159 156 if 'L%s Portions IPP Periodic' % n in data:
160 157 line['periodic'] = 1 if data['L%s Portions IPP Periodic' % n]=='YES' else 0
161 158 portions = []
162 159 x = raw_data.index('L%d Number Of Portions=%s' % (n, data['L%d Number Of Portions' % n]))
163 160 for w in range(int(data['L%d Number Of Portions' % n])):
164 161 begin = raw_data[x+1+2*w].split('=')[-1]
165 162 end = raw_data[x+2+2*w].split('=')[-1]
166 163 portions.append({'begin':int(begin),
167 164 'end':int(end)}
168 165 )
169 166 line['params'] = portions
170 167 elif 'FLIP1' in data and n==5:
171 168 line = {'type':'flip', 'number_of_flips':data['FLIP1']}
172 169 elif 'FLIP2' in data and n==6:
173 170 line = {'type':'flip', 'number_of_flips':data['FLIP2']}
174 171 else:
175 172 line = {'type':'none'}
176 173
177 174 self.data['lines'].append(line)
178 175
179 176 #Add line 7 (windows)
180 177 if 'Sampling Windows' in data:
181 178 line = {'type':'windows', 'TX_ref':data['L7_REFERENCE']}
182 179 windows = []
183 180 x = raw_data.index('Sampling Windows=%s' % data['Sampling Windows'])
184 181 for w in range(int(data['Sampling Windows'])):
185 182 h0 = raw_data[x+1+3*w].split('=')[-1]
186 183 nsa = raw_data[x+2+3*w].split('=')[-1]
187 184 dh = raw_data[x+3+3*w].split('=')[-1]
188 185 windows.append({'first_height':float(h0),
189 186 'number_of_samples':int(nsa),
190 187 'resolution':float(dh)}
191 188 )
192 189 line['params'] = windows
193 190 self.data['lines'].append(line)
194 191 else:
195 192 self.data['lines'].append({'type':'none'})
196 193
197 194 #Add line 8 (synchro inverted)
198 195 self.data['lines'].append({'type':'sync', 'invert':1})
199 196
200 197 return
201 198
202 199 def parse_dat(self):
203 200 pass
204 201
205 202
206 203 def get_json(self, indent=None):
207 204 return json.dumps(self.data, indent=indent)
208 205
209 206
210 def pulses_to_points(X):
211
212
213 d = X[1:]-X[:-1]
214
215 up = np.where(d==1)[0]
216 if X[0]==1:
217 up = np.concatenate((np.array([-1]), up))
218 up += 1
219
220 dw = np.where(d==-1)[0]
221 if X[-1]==1:
222 dw = np.concatenate((dw, np.array([len(X)-1])))
223 dw += 1
224
225 return [(tup[0], tup[1]-tup[0]) for tup in zip(up, dw)]
226
227 def pulses_from_code(X, codes, width):
228
229 d = X[1:]-X[:-1]
230
231 up = np.where(d==1)[0]
232 if X[0]==1:
233 up = np.concatenate((np.array([-1]), up))
234 up += 1
235
236 f = width/len(codes[0])
237 codes = [(np.fromstring(''.join([s*f for s in code]), dtype=np.uint8)-48).astype(np.int8) for code in codes]
238
239 y = np.zeros(len(X))
240
241 j=0
242 n = len(codes)
243 for i in up:
244 y[i:i+width] = codes[j%n]
245 j += 1
246
247 return y
248
249
250 def create_mask(ranges, ipp, ntx, sync):
251
252 x = np.arange(ipp*ntx)
253 iranges = set()
254
255 for index in ranges:
256 if '-' in index:
257 args = [int(a) for a in index.split('-')]
258 iranges = iranges.union([i for i in range(args[0], args[1]+1)])
259 else:
260 iranges.add(int(index))
261
262 y = np.any([(x>=(idx-1)*ipp+sync) & (x<idx*ipp+sync) for idx in iranges], axis=0).astype(np.int8)
263
264 return y
265
266
267 def pulses(X, period, width, delay=0, before=0, after=0, sync=0, shift=0):
268
269 delay_array = delay
270
271 if isinstance(delay, (list, tuple)):
272 delay_array = np.ones(len(X))
273 delays = [d for __ in xrange(len(X)/(period*len(delay))) for d in delay]
274 for i, delay in enumerate(delays):
275 delay_array[np.arange(period*i, period*(i+1))] *= delay
276
277 if after>0:
278 width += after+before
279 before = 0
280
281 Y = ((X%period<width+delay_array+before+sync) & (X%period>=delay_array+before+sync)).astype(np.int8)
282
283 if shift>0:
284 y = np.empty_like(Y)
285 y[:shift] = 0
286 y[shift:] = Y[:-shift]
287 return y
288 else:
289 return Y
290
291
292 def plot_pulses(unit, maximun, lines):
293
294 from bokeh.resources import CDN
295 from bokeh.embed import components
296 from bokeh.mpl import to_bokeh
297 from bokeh.models.tools import WheelZoomTool, ResetTool, PanTool, PreviewSaveTool
298
299 N = len(lines)
300 fig = plt.figure(figsize=(10, 2+N*0.5))
301 ax = fig.add_subplot(111)
302 labels = []
303
304 for i, line in enumerate(lines):
305 labels.append(line.get_name())
306 l = ax.plot((0, maximun),(N-i-1, N-i-1))
307 ax.broken_barh(pulses_to_points(line.pulses_as_array()), (N-i-1, 0.5),
308 edgecolor=l[0].get_color(), facecolor='none')
309
310 labels.reverse()
311 ax.set_yticklabels(labels)
312 plot = to_bokeh(fig, use_pandas=False)
313 plot.tools = [PanTool(dimensions=['width']), WheelZoomTool(dimensions=['width']), ResetTool(), PreviewSaveTool()]
314
315 return components(plot, CDN)
@@ -1,385 +1,370
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 Configuration, 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 from .utils import plot_pulses
14 13
15 14
16 15 def conf(request, conf_id):
17 16
18 17 conf = get_object_or_404(RCConfiguration, pk=conf_id)
19 18
20 19 lines = RCLine.objects.filter(rc_configuration=conf).order_by('channel')
21 20
22 21 for line in lines:
23 22 params = json.loads(line.params)
24 23 line.form = RCLineViewForm(extra_fields=params, line=line)
25 24 if 'params' in params:
26 25 line.subforms = [RCLineViewForm(extra_fields=fields, line=line, subform=True) for fields in params['params']]
27 26
28 27 kwargs = {}
29 28 kwargs['dev_conf'] = conf
30 29 kwargs['rc_lines'] = lines
31 30 kwargs['dev_conf_keys'] = ['name', 'ipp', 'ntx', 'clock_in', 'clock_divider', 'clock',
32 31 'time_before', 'time_after', 'sync', 'sampling_reference', 'control_tx', 'control_sw']
33 32
34 33 kwargs['title'] = 'RC Configuration'
35 34 kwargs['suptitle'] = 'Details'
36 35
37 36 kwargs['button'] = 'Edit Configuration'
38 37 ###### SIDEBAR ######
39 38 kwargs.update(sidebar(conf=conf))
40 39
41 40 return render(request, 'rc_conf.html', kwargs)
42 41
43 42
44 43 def conf_edit(request, conf_id):
45 44
46 45 conf = get_object_or_404(RCConfiguration, pk=conf_id)
47 46
48 47 lines = RCLine.objects.filter(rc_configuration=conf).order_by('channel')
49 48
50 49 for line in lines:
51 50 params = json.loads(line.params)
52 51 line.form = RCLineEditForm(conf=conf, line=line, extra_fields=params)
53 52 line.subform = False
54 53
55 54 if 'params' in params:
56 55 line.subforms = [RCLineEditForm(extra_fields=fields, line=line, subform=i) for i, fields in enumerate(params['params'])]
57 56 line.subform = True
58 57
59 58 if request.method=='GET':
60 59
61 60 form = RCConfigurationForm(instance=conf)
62 61
63 62 elif request.method=='POST':
64 63
65 64 line_data = {}
66 65 conf_data = {}
67 66 extras = []
68 67
69 68 #classified post fields
70 69 for label,value in request.POST.items():
71 70 if label=='csrfmiddlewaretoken':
72 71 continue
73 72
74 73 if label.count('|')==0:
75 74 conf_data[label] = value
76 75 continue
77 76
78 77 elif label.split('|')[0]<>'-1':
79 78 extras.append(label)
80 79 continue
81 80
82 81 x, pk, name = label.split('|')
83 82
84 83 if name=='codes':
85 84 value = [s for s in value.split('\r\n') if s]
86 85
87 86 if pk in line_data:
88 87 line_data[pk][name] = value
89 88 else:
90 89 line_data[pk] = {name:value}
91 90
92 91 #update conf
93 92 form = RCConfigurationForm(conf_data, instance=conf)
94 93
95 94 if form.is_valid():
96 95
97 96 form.save()
98 97
99 98 #update lines fields
100 99 extras.sort()
101 100 for label in extras:
102 101 x, pk, name = label.split('|')
103 102 if pk not in line_data:
104 103 line_data[pk] = {}
105 104 if 'params' not in line_data[pk]:
106 105 line_data[pk]['params'] = []
107 106 if len(line_data[pk]['params'])<int(x)+1:
108 107 line_data[pk]['params'].append({})
109 108 line_data[pk]['params'][int(x)][name] = float(request.POST[label])
110 109
111 110 for pk, params in line_data.items():
112 111 line = RCLine.objects.get(pk=pk)
113 112 if line.line_type.name in ('windows', 'prog_pulses'):
114 113 if 'params' not in params:
115 114 params['params'] = []
116 115 line.params = json.dumps(params)
117 116 line.save()
118 117
119 118 #update pulses field
120 119 conf.update_pulses()
121 120
122 121 messages.success(request, 'RC Configuration successfully updated')
123 122
124 123 return redirect(conf.get_absolute_url())
125 124
126 125 kwargs = {}
127 126 kwargs['dev_conf'] = conf
128 127 kwargs['form'] = form
129 128 kwargs['rc_lines'] = lines
130 129 kwargs['edit'] = True
131 130
132 131 kwargs['title'] = 'RC Configuration'
133 132 kwargs['suptitle'] = 'Edit'
134 133 kwargs['button'] = 'Update'
135 134 kwargs['previous'] = conf.get_absolute_url()
136 135
137 136 return render(request, 'rc_conf_edit.html', kwargs)
138 137
139 138
140 139 def add_line(request, conf_id, line_type_id=None, code_id=None):
141 140
142 141 conf = get_object_or_404(RCConfiguration, pk=conf_id)
143 142
144 143 if request.method=='GET':
145 144 if line_type_id:
146 145 line_type = get_object_or_404(RCLineType, pk=line_type_id)
147 146
148 147 if code_id:
149 148 form = RCLineForm(initial={'rc_configuration':conf_id, 'line_type': line_type_id, 'code_id': code_id},
150 149 extra_fields=json.loads(line_type.params))
151 150 else:
152 151 form = RCLineForm(initial={'rc_configuration':conf_id, 'line_type': line_type_id},
153 152 extra_fields=json.loads(line_type.params))
154 153 else:
155 154 line_type = {'id':0}
156 155 form = RCLineForm(initial={'rc_configuration':conf_id})
157 156
158 157 if request.method=='POST':
159 158
160 159 line_type = get_object_or_404(RCLineType, pk=line_type_id)
161 160 form = RCLineForm(request.POST,
162 161 extra_fields=json.loads(line_type.params))
163 162
164 163 if form.is_valid():
165 164 form.save()
166 165 form.instance.update_pulses()
167 166 return redirect('url_edit_rc_conf', conf.id)
168 167
169 168 kwargs = {}
170 169 kwargs['form'] = form
171 170 kwargs['title'] = 'RC Configuration'
172 171 kwargs['suptitle'] = 'Add Line'
173 172 kwargs['button'] = 'Add'
174 173 kwargs['previous'] = conf.get_absolute_url_edit()
175 174 kwargs['dev_conf'] = conf
176 175 kwargs['line_type'] = line_type
177 176
178 177 return render(request, 'rc_add_line.html', kwargs)
179 178
180 179 def edit_codes(request, conf_id, line_id, code_id=None):
181 180
182 181 conf = get_object_or_404(RCConfiguration, pk=conf_id)
183 182 line = get_object_or_404(RCLine, pk=line_id)
184 183 params = json.loads(line.params)
185 184
186 185 if request.method=='GET':
187 186 if code_id:
188 187 code = get_object_or_404(RCLineCode, pk=code_id)
189 188 form = RCLineCodesForm(instance=code)
190 189 else:
191 190 initial = {'code': params['code'],
192 191 'codes': params['codes'] if 'codes' in params else [],
193 192 'number_of_codes': len(params['codes']) if 'codes' in params else 0,
194 193 'bits_per_code': len(params['codes'][0]) if 'codes' in params else 0,
195 194 }
196 195 form = RCLineCodesForm(initial=initial)
197 196
198 197 if request.method=='POST':
199 198 form = RCLineCodesForm(request.POST)
200 199 if form.is_valid():
201 200 params['code'] = request.POST['code']
202 201 params['codes'] = [s for s in request.POST['codes'].split('\r\n') if s]
203 202 line.params = json.dumps(params)
204 203 line.save()
205 204 messages.success(request, 'Line: "%s" has been updated.' % line)
206 205 return redirect('url_edit_rc_conf', conf.id)
207 206
208 207 kwargs = {}
209 208 kwargs['form'] = form
210 209 kwargs['title'] = line
211 210 kwargs['suptitle'] = 'Edit'
212 211 kwargs['button'] = 'Update'
213 212 kwargs['dev_conf'] = conf
214 213 kwargs['previous'] = conf.get_absolute_url_edit()
215 214 kwargs['line'] = line
216 215
217 216 return render(request, 'rc_edit_codes.html', kwargs)
218 217
219 218 def add_subline(request, conf_id, line_id):
220 219
221 220 conf = get_object_or_404(RCConfiguration, pk=conf_id)
222 221 line = get_object_or_404(RCLine, pk=line_id)
223 222
224 223 if request.method == 'POST':
225 224 if line:
226 225 params = json.loads(line.params)
227 226 subparams = json.loads(line.line_type.params)
228 227 if 'params' in subparams:
229 228 dum = {}
230 229 for key, value in subparams['params'].items():
231 230 dum[key] = value['value']
232 231 params['params'].append(dum)
233 232 line.params = json.dumps(params)
234 233 line.save()
235 234 return redirect('url_edit_rc_conf', conf.id)
236 235
237 236 kwargs = {}
238 237
239 238 kwargs['title'] = 'Add new'
240 239 kwargs['suptitle'] = '%s to %s' % (line.line_type.name, line)
241 240
242 241 return render(request, 'confirm.html', kwargs)
243 242
244 243 def remove_line(request, conf_id, line_id):
245 244
246 245 conf = get_object_or_404(RCConfiguration, pk=conf_id)
247 246 line = get_object_or_404(RCLine, pk=line_id)
248 247
249 248 if request.method == 'POST':
250 249 if line:
251 250 try:
252 251 channel = line.channel
253 252 line.delete()
254 253 for ch in range(channel+1, RCLine.objects.filter(rc_configuration=conf).count()+1):
255 254 l = RCLine.objects.get(rc_configuration=conf, channel=ch)
256 255 l.channel = l.channel-1
257 256 l.save()
258 257 messages.success(request, 'Line: "%s" has been deleted.' % line)
259 258 except:
260 259 messages.error(request, 'Unable to delete line: "%s".' % line)
261 260
262 261 return redirect('url_edit_rc_conf', conf.id)
263 262
264 263 kwargs = {}
265 264
266 265 kwargs['object'] = line
267 266 kwargs['delete_view'] = True
268 267 kwargs['title'] = 'Confirm delete'
269 268 kwargs['previous'] = conf.get_absolute_url_edit()
270 269 return render(request, 'confirm.html', kwargs)
271 270
272 271
273 272 def remove_subline(request, conf_id, line_id, subline_id):
274 273
275 274 conf = get_object_or_404(RCConfiguration, pk=conf_id)
276 275 line = get_object_or_404(RCLine, pk=line_id)
277 276
278 277 if request.method == 'POST':
279 278 if line:
280 279 params = json.loads(line.params)
281 280 params['params'].remove(params['params'][int(subline_id)-1])
282 281 line.params = json.dumps(params)
283 282 line.save()
284 283
285 284 return redirect('url_edit_rc_conf', conf.id)
286 285
287 286 kwargs = {}
288 287
289 288 kwargs['object'] = line
290 289 kwargs['object_name'] = line.line_type.name
291 290 kwargs['delete_view'] = True
292 291 kwargs['title'] = 'Confirm delete'
293 292
294 293 return render(request, 'confirm.html', kwargs)
295 294
296 295
297 296 def update_lines_position(request, conf_id):
298 297
299 298 conf = get_object_or_404(RCConfiguration, pk=conf_id)
300 299
301 300 if request.method=='POST':
302 301 ch = 0
303 302 for item in request.POST['items'].split('&'):
304 303 line = RCLine.objects.get(pk=item.split('=')[-1])
305 304 line.channel = ch
306 305 line.save()
307 306 ch += 1
308 307
309 308 lines = RCLine.objects.filter(rc_configuration=conf).order_by('channel')
310 309
311 310 for line in lines:
312 311 params = json.loads(line.params)
313 312 line.form = RCLineEditForm(conf=conf, line=line, extra_fields=params)
314 313
315 314 if 'params' in params:
316 315 line.subform = True
317 316 line.subforms = [RCLineEditForm(extra_fields=fields, line=line, subform=i) for i, fields in enumerate(params['params'])]
318 317
319 318 html = render(request, 'rc_lines.html', {'dev_conf':conf, 'rc_lines':lines, 'edit':True})
320 319 data = {'html': html.content}
321 320
322 321 return HttpResponse(json.dumps(data), content_type="application/json")
323 322 return redirect('url_edit_rc_conf', conf.id)
324 323
325 324
326 325 def import_file(request, conf_id):
327 326
328 327 conf = get_object_or_404(RCConfiguration, pk=conf_id)
329 328 if request.method=='POST':
330 329 form = RCImportForm(request.POST, request.FILES)
331 330 if form.is_valid():
332 #try:
333 if True:
334
331 try:
335 332 conf.update_from_file(request.FILES['file_name'])
336 conf.save()
337
338 for line in conf.get_lines():
339 if line.line_type.name=='tr':
340 continue
341 line.update_pulses()
342
343 for tr in conf.get_lines('tr'):
344 tr.update_pulses()
345
346 333 messages.success(request, 'Configuration "%s" loaded succesfully' % request.FILES['file_name'])
347 return redirect(conf.get_absolute_url())
334 return redirect(conf.get_absolute_url_edit())
348 335
349 #except Exception as e:
350 # messages.error(request, 'Error parsing file: "%s" - %s' % (request.FILES['file_name'], e))
336 except Exception as e:
337 messages.error(request, 'Error parsing file: "%s" - %s' % (request.FILES['file_name'], e))
351 338
352 339 else:
353 340 messages.warning(request, 'Your current configuration will be replaced')
354 341 form = RCImportForm()
355 342
356 343 kwargs = {}
357 344 kwargs['form'] = form
358 345 kwargs['title'] = 'RC Configuration'
359 346 kwargs['suptitle'] = 'Import file'
360 347 kwargs['button'] = 'Upload'
361 348 kwargs['previous'] = conf.get_absolute_url()
362 349
363 350 return render(request, 'rc_import.html', kwargs)
364 351
365 352
366 def view_pulses(request, conf_id):
353 def plot_pulses(request, conf_id):
367 354
368 conf = get_object_or_404(RCConfiguration, pk=conf_id)
369 lines = RCLine.objects.filter(rc_configuration=conf)
370
371 unit = (conf.clock/conf.clock_divider)*3./20
372
373 N = conf.ipp*conf.km2unit*conf.ntx
355 conf = get_object_or_404(RCConfiguration, pk=conf_id)
374 356
375 script, div = plot_pulses(unit, N, lines)
357 script, div = conf.plot_pulses()
376 358
377 359 kwargs = {}
378 360
379 361 kwargs['title'] = 'RC Pulses'
380 362 kwargs['suptitle'] = conf.name
381 363 kwargs['div'] = mark_safe(div)
382 364 kwargs['script'] = mark_safe(script)
383
384 return render(request, 'rc_pulses.html', kwargs)
365
366 if 'json' in request.GET:
367 return HttpResponse(json.dumps({'div':mark_safe(div), 'script':mark_safe(script)}), content_type="application/json")
368 else:
369 return render(request, 'rc_pulses.html', kwargs)
385 370
General Comments 0
You need to be logged in to leave comments. Login now