##// END OF EJS Templates
last changes
jespinoza -
r334:ff9b4f433b43
parent child
Show More
@@ -1,12 +1,12
1 1 REDIS_HOST=radarsys-redis
2 2 REDIS_PORT=6379
3 3 POSTGRES_PORT_5432_TCP_ADDR=radarsys-postgres
4 4 POSTGRES_PORT_5432_TCP_PORT=5432
5 5 DB_NAME=radarsys
6 6 DB_USER=docker
7 7 DB_PASSWORD=docker
8 8 PGDATA=/var/lib/postgresql/data
9 9 LC_ALL=C.UTF-8
10 10 TZ=America/Lima
11 DOCKER_DATA=/Volumes/dockers/radarsys/
11 DOCKER_DATA=/data/dockers/radarsys/
12 12 LOCAL_IP=192.168.1.128
@@ -1,194 +1,193
1 1 from django.shortcuts import render_to_response
2 2 from django.template import RequestContext
3 3 from django.shortcuts import redirect, render, get_object_or_404
4 4 from django.contrib import messages
5 5 from django.http import HttpResponse
6 6
7 7 from apps.main.models import Device
8 8 from apps.main.views import sidebar
9 9
10 10 from .models import JARSConfiguration, JARSFilter
11 11 from .forms import JARSConfigurationForm, JARSFilterForm, JARSImportForm
12 12
13 13 import json
14 14 # Create your views here.
15 15
16 16 def jars_conf(request, id_conf):
17 17
18 18 conf = get_object_or_404(JARSConfiguration, pk=id_conf)
19 19
20 20 filter_parms = json.loads(conf.filter_parms)
21 21
22 22 kwargs = {}
23 23 kwargs['filter'] = filter_parms
24 24 kwargs['filter_obj'] = JARSFilter.objects.get(pk=1)
25 25 kwargs['filter_keys'] = ['clock', 'multiplier', 'frequency', 'f_decimal',
26 26 'cic_2', 'scale_cic_2', 'cic_5', 'scale_cic_5', 'fir',
27 27 'scale_fir', 'number_taps', 'taps']
28 28
29 29 filter_resolution = conf.filter_resolution()
30 30 kwargs['resolution'] = '{} (MHz)'.format(filter_resolution)
31 31 if filter_resolution < 1:
32 32 kwargs['resolution'] = '{} (kHz)'.format(filter_resolution*1000)
33 33
34 34 kwargs['status'] = conf.device.get_status_display()
35 35 kwargs['dev_conf'] = conf
36 36 kwargs['dev_conf_keys'] = ['cards_number', 'channels_number', 'channels',
37 37 'ftp_interval', 'data_type','acq_profiles',
38 38 'profiles_block', 'raw_data_blocks', 'ftp_interval',
39 39 'cohe_integr_str', 'cohe_integr', 'decode_data', 'post_coh_int',
40 40 'incohe_integr', 'fftpoints', 'spectral_number',
41 41 'spectral', 'create_directory', 'include_expname',
42 42 'save_ch_dc', 'save_data']
43 43
44 44 if conf.exp_type == 0:
45 45 for field in ['incohe_integr','fftpoints','spectral_number', 'spectral', 'save_ch_dc']:
46 46 kwargs['dev_conf_keys'].remove(field)
47 47
48 48 if conf.decode_data == 0:
49 49 kwargs['dev_conf_keys'].remove('decode_data')
50 50 kwargs['dev_conf_keys'].remove('post_coh_int')
51 51
52 52 kwargs['title'] = 'JARS Configuration'
53 53 kwargs['suptitle'] = 'Details'
54 54
55 55 ###### SIDEBAR ######
56 56 kwargs.update(sidebar(conf=conf))
57 57
58 58 return render(request, 'jars_conf.html', kwargs)
59 59
60 60 def jars_conf_edit(request, id_conf):
61 61
62 62 conf = get_object_or_404(JARSConfiguration, pk=id_conf)
63 63
64 64 filter_parms = json.loads(conf.filter_parms)
65 65
66 66 if request.method=='GET':
67 67 form = JARSConfigurationForm(instance=conf)
68 68 filter_form = JARSFilterForm(initial=filter_parms)
69 69
70 70 if request.method=='POST':
71 71 form = JARSConfigurationForm(request.POST, instance=conf)
72 72 filter_form = JARSFilterForm(request.POST)
73 73
74 74 if filter_form.is_valid():
75 75 jars_filter = filter_form.cleaned_data
76 76 jars_filter['id'] = request.POST['filter_template']
77 if form.is_valid():
78 conf = form.save(commit=False)
79 conf.filter_parms = json.dumps(jars_filter)
80 conf.save()
81 return redirect('url_jars_conf', id_conf=conf.id)
77 82 else:
78 83 messages.error(request, filter_form.errors)
79 84
80 if form.is_valid():
81 conf = form.save(commit=False)
82 conf.filter_parms = json.dumps(jars_filter)
83 conf.save()
84 return redirect('url_jars_conf', id_conf=conf.id)
85
86 85 kwargs = {}
87 86
88 87 kwargs['id_dev'] = conf.id
89 88 kwargs['form'] = form
90 89 kwargs['filter_form'] = filter_form
91 90 kwargs['filter_name'] = JARSFilter.objects.get(pk=filter_parms['id']).name
92 91 kwargs['title'] = 'Device Configuration'
93 92 kwargs['suptitle'] = 'Edit'
94 93 kwargs['button'] = 'Save'
95 94
96 95 return render(request, 'jars_conf_edit.html', kwargs)
97 96
98 97 def import_file(request, conf_id):
99 98
100 99 conf = get_object_or_404(JARSConfiguration, pk=conf_id)
101 100 if request.method=='POST':
102 101 form = JARSImportForm(request.POST, request.FILES)
103 102 if form.is_valid():
104 103 try:
105 104 data = conf.import_from_file(request.FILES['file_name'])
106 105 conf.dict_to_parms(data)
107 106 messages.success(request, 'Configuration "%s" loaded succesfully' % request.FILES['file_name'])
108 107 return redirect(conf.get_absolute_url_edit())
109 108
110 109 except Exception as e:
111 110 messages.error(request, 'Error parsing file: "%s" - %s' % (request.FILES['file_name'], repr(e)))
112 111 else:
113 112 messages.warning(request, 'Your current configuration will be replaced')
114 113 form = JARSImportForm()
115 114
116 115 kwargs = {}
117 116 kwargs['form'] = form
118 117 kwargs['title'] = 'JARS Configuration'
119 118 kwargs['suptitle'] = 'Import file'
120 119 kwargs['button'] = 'Upload'
121 120 kwargs['previous'] = conf.get_absolute_url()
122 121
123 122 return render(request, 'jars_import.html', kwargs)
124 123
125 124 def read_conf(request, conf_id):
126 125
127 126 conf = get_object_or_404(JARSConfiguration, pk=conf_id)
128 127 #filter = get_object_or_404(JARSfilter, pk=filter_id)
129 128
130 129 if request.method=='GET':
131 130
132 131 parms = conf.read_device()
133 132 conf.status_device()
134 133
135 134 if not parms:
136 135 messages.error(request, conf.message)
137 136 return redirect(conf.get_absolute_url())
138 137
139 138 form = JARSConfigurationForm(initial=parms, instance=conf)
140 139
141 140 if request.method=='POST':
142 141 form = JARSConfigurationForm(request.POST, instance=conf)
143 142
144 143 if form.is_valid():
145 144 form.save()
146 145 return redirect(conf.get_absolute_url())
147 146
148 147 messages.error(request, "Parameters could not be saved")
149 148
150 149 kwargs = {}
151 150 kwargs['id_dev'] = conf.id
152 151 kwargs['filter_id'] = conf.filter.id
153 152 kwargs['form'] = form
154 153 kwargs['title'] = 'Device Configuration'
155 154 kwargs['suptitle'] = 'Parameters read from device'
156 155 kwargs['button'] = 'Save'
157 156
158 157 ###### SIDEBAR ######
159 158 kwargs.update(sidebar(conf=conf))
160 159
161 160 return render(request, 'jars_conf_edit.html', kwargs)
162 161
163 162 def change_filter(request, conf_id, filter_id):
164 163
165 164 conf = get_object_or_404(JARSConfiguration, pk=conf_id)
166 165 filter = get_object_or_404(JARSFilter, pk=filter_id)
167 166 conf.filter_parms = json.dumps(filter.jsonify())
168 167 conf.save()
169 168
170 169 return redirect('url_edit_jars_conf', id_conf=conf.id)
171 170
172 171 def get_log(request, conf_id):
173 172
174 173 conf = get_object_or_404(JARSConfiguration, pk=conf_id)
175 174 response = conf.get_log()
176 175
177 176 if not response:
178 177 message = conf.message
179 178 messages.error(request, message)
180 179 return redirect('url_jars_conf', id_conf=conf.id)
181 180
182 181 try:
183 182 message = response.json()['message']
184 183 messages.error(request, message)
185 184 return redirect('url_jars_conf', id_conf=conf.id)
186 185 except Exception as e:
187 186 message = 'Restarting Report.txt has been downloaded successfully.'
188 187
189 188 content = response
190 189 filename = 'Log_%s_%s.txt' %(conf.experiment.name, conf.experiment.id)
191 190 response = HttpResponse(content,content_type='text/plain')
192 191 response['Content-Disposition'] = 'attachment; filename="%s"' %filename
193 192
194 193 return response
@@ -1,418 +1,420
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, RCClock
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', 'author', 'hash', 'clock_in')
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 def save(self, *args, **kwargs):
96 96 conf = super(RCConfigurationForm, self).save(*args, **kwargs)
97 97 clk = RCClock.objects.filter(rc_configuration=conf).first()
98 98 if clk:
99 99 conf.clock_in = clk.frequency
100 100 conf.total_units = conf.ipp*conf.ntx*conf.km2unit
101 101 conf.save()
102 102 return conf
103 103
104 104
105 105 class RCMixConfigurationForm(forms.Form):
106 106
107 107 clock_in = forms.CharField(widget=forms.HiddenInput())
108 frequency = forms.CharField(widget=forms.HiddenInput())
108 109 clock_divider = forms.CharField(widget=forms.HiddenInput())
109 110 name = forms.CharField()
110 111 experiment = forms.ChoiceField()
111 112 mode = forms.ChoiceField(widget=forms.RadioSelect(),
112 113 choices=[(0, 'Parallel'), (1, 'Sequence')],
113 114 initial=0)
114 115 operation = forms.ChoiceField(widget=forms.RadioSelect(),
115 116 choices=[(0, 'OR'), (1, 'XOR'), (2, 'AND'), (3, 'NAND')],
116 117 initial=1)
117 118 delay = forms.CharField()
118 119 mask = forms.MultipleChoiceField(
119 120 choices=[(0, 'L1'),(1, 'L2'),(2, 'L3'),(3, 'L4'),(4, 'L5'),(5, 'L6'),(6, 'L7'),(7, 'L8'),
120 121 (8, 'L9'),(9, 'L10'),(10, 'L11'),(11, 'L12'),(12, 'L13'),(13, 'L14'),(14, 'L15'),(15, 'L16')],
121 122 widget=HCheckboxSelectMultiple())
122 123 result = forms.CharField(required=False,
123 124 widget=forms.Textarea(attrs={'readonly':True, 'rows':5, 'class':'tabuled'}))
124 125
125 126 def __init__(self, *args, **kwargs):
126 127 confs = kwargs.pop('confs', [])
127 128 if confs:
128 129 km2unit = confs[0].km2unit
129 130 clock_in = confs[0].clock_in
130 131 clock_divider = confs[0].clock_divider
131 132 else:
132 133 km2unit = clock_in = clock_divider = 0
133 134 super(RCMixConfigurationForm, self).__init__(*args, **kwargs)
134 135 self.fields['experiment'].choices = [(conf.pk, '{} | {}'.format(conf.pk, conf.name)) for conf in confs]
135 136 self.fields['delay'].widget = KmUnitWidget(attrs = {'km2unit':km2unit})
136 137 self.fields['clock_in'].initial = clock_in
138 self.fields['frequency'].initial = clock_in
137 139 self.fields['clock_divider'].initial = clock_divider
138 140
139 141
140 142 class RCLineForm(forms.ModelForm):
141 143
142 144 def __init__(self, *args, **kwargs):
143 145 self.extra_fields = kwargs.pop('extra_fields', [])
144 146 super(RCLineForm, self).__init__(*args, **kwargs)
145 147
146 148 if 'initial' in kwargs and 'line_type' in kwargs['initial']:
147 149 line_type = RCLineType.objects.get(pk=kwargs['initial']['line_type'])
148 150
149 151 if 'code_id' in kwargs['initial']:
150 152 model_initial = kwargs['initial']['code_id']
151 153 else:
152 154 model_initial = 0
153 155
154 156 params = json.loads(line_type.params)
155 157
156 158 for label, value in self.extra_fields.items():
157 159 if label=='params':
158 160 continue
159 161
160 162 if 'model' in params[label]:
161 163 self.fields[label] = forms.ChoiceField(choices=create_choices_from_model(params[label]['model'],
162 164 kwargs['initial']['rc_configuration']),
163 165 initial=model_initial)
164 166
165 167
166 168 else:
167 169 if label=='codes' and 'code_id' in kwargs['initial']:
168 170 self.fields[label] = forms.CharField(initial=RCLineCode.objects.get(pk=kwargs['initial']['code_id']).codes)
169 171 else:
170 172 self.fields[label] = forms.CharField(initial=value['value'])
171 173
172 174 if label=='codes':
173 175 self.fields[label].widget = CodesWidget()
174 176
175 177 if self.data:
176 178 line_type = RCLineType.objects.get(pk=self.data['line_type'])
177 179
178 180 if 'code_id' in self.data:
179 181 model_initial = self.data['code_id']
180 182 else:
181 183 model_initial = 0
182 184
183 185 params = json.loads(line_type.params)
184 186
185 187 for label, value in self.extra_fields.items():
186 188 if label=='params':
187 189 continue
188 190
189 191 if 'model' in params[label]:
190 192 self.fields[label] = forms.ChoiceField(choices=create_choices_from_model(params[label]['model'],
191 193 self.data['rc_configuration']),
192 194 initial=model_initial)
193 195
194 196
195 197 else:
196 198 if label=='codes' and 'code' in self.data:
197 199 self.fields[label] = forms.CharField(initial=self.data['codes'])
198 200 else:
199 201 self.fields[label] = forms.CharField(initial=self.data[label])
200 202
201 203 if label=='codes':
202 204 self.fields[label].widget = CodesWidget()
203 205
204 206
205 207 class Meta:
206 208 model = RCLine
207 209 fields = ('rc_configuration', 'line_type', 'channel')
208 210 widgets = {
209 211 'channel': forms.HiddenInput(),
210 212 }
211 213
212 214
213 215 def clean(self):
214 216
215 217 form_data = self.cleaned_data
216 218 if 'code' in self.data and self.data['TX_ref']=="0":
217 219 self.add_error('TX_ref', 'Choose a valid TX reference')
218 220
219 221 if RCLineType.objects.get(pk=self.data['line_type']).name=='mix':
220 222 self.add_error('line_type', 'Invalid Line type')
221 223
222 224 return form_data
223 225
224 226
225 227 def save(self):
226 228 line = super(RCLineForm, self).save()
227 229
228 230 #auto add channel
229 231 line.channel = RCLine.objects.filter(rc_configuration=line.rc_configuration).count()-1
230 232
231 233 #auto add position for TX, TR & CODE
232 234 if line.line_type.name in ('tx', ):
233 235 line.position = RCLine.objects.filter(rc_configuration=line.rc_configuration, line_type=line.line_type).count()-1
234 236
235 237 #save extra fields in params
236 238 params = {}
237 239 for label, value in self.extra_fields.items():
238 240 if label=='params':
239 241 params['params'] = []
240 242 elif label=='codes':
241 243 params[label] = [s for s in self.data[label].split('\r\n') if s]
242 244 else:
243 245 params[label] = self.data[label]
244 246 line.params = json.dumps(params)
245 247 line.save()
246 248 return
247 249
248 250
249 251 class RCLineViewForm(forms.Form):
250 252
251 253 def __init__(self, *args, **kwargs):
252 254
253 255 extra_fields = kwargs.pop('extra_fields')
254 256 line = kwargs.pop('line')
255 257 subform = kwargs.pop('subform', False)
256 258 super(RCLineViewForm, self).__init__(*args, **kwargs)
257 259
258 260 if subform:
259 261 params = json.loads(line.line_type.params)['params']
260 262 else:
261 263 params = json.loads(line.line_type.params)
262 264
263 265 for label, value in extra_fields.items():
264 266
265 267 if label=='params':
266 268 continue
267 269 if 'ref' in label:
268 270 if value in (0, '0'):
269 271 value = 'All'
270 272 else:
271 273 value = RCLine.objects.get(pk=value).get_name()
272 274 elif label=='code':
273 275 value = RCLineCode.objects.get(pk=value).name
274 276
275 277 self.fields[label] = forms.CharField(initial=value)
276 278
277 279 if 'widget' in params[label]:
278 280 km2unit = line.rc_configuration.km2unit
279 281 if params[label]['widget']=='km':
280 282 self.fields[label].widget = KmUnitWidget(attrs={'line':line, 'km2unit':km2unit, 'disabled':True})
281 283 elif params[label]['widget']=='unit':
282 284 self.fields[label].widget = UnitKmWidget(attrs={'line':line, 'km2unit':km2unit, 'disabled':True})
283 285 elif params[label]['widget']=='dc':
284 286 self.fields[label].widget = KmUnitDcWidget(attrs={'line':line, 'km2unit':km2unit, 'disabled':True})
285 287 elif params[label]['widget']=='codes':
286 288 self.fields[label].widget = CodesWidget(attrs={'line':line, 'km2unit':km2unit, 'disabled':True})
287 289 else:
288 290 self.fields[label].widget = DefaultWidget(attrs={'disabled':True})
289 291
290 292
291 293 class RCLineEditForm(forms.ModelForm):
292 294
293 295 def __init__(self, *args, **kwargs):
294 296
295 297 extra_fields = kwargs.pop('extra_fields', [])
296 298 conf = kwargs.pop('conf', False)
297 299 line = kwargs.pop('line')
298 300 subform = kwargs.pop('subform', False)
299 301
300 302 super(RCLineEditForm, self).__init__(*args, **kwargs)
301 303
302 304 if subform is not False:
303 305 params = json.loads(line.line_type.params)['params']
304 306 count = subform
305 307 else:
306 308 params = json.loads(line.line_type.params)
307 309 count = -1
308 310
309 311 for label, value in extra_fields.items():
310 312
311 313 if label in ('params',):
312 314 continue
313 315 if 'help' in params[label]:
314 316 help_text = params[label]['help']
315 317 else:
316 318 help_text = ''
317 319
318 320 if 'model' in params[label]:
319 321 if line.line_type.name=='tr':
320 322 all_choice = True
321 323 else:
322 324 all_choice = False
323 325 self.fields[label] = forms.ChoiceField(choices=create_choices_from_model(params[label]['model'], conf.id, all_choice=all_choice),
324 326 initial=value,
325 327 widget=forms.Select(attrs={'name':'%s|%s|%s' % (count, line.id, label)}),
326 328 help_text=help_text)
327 329
328 330 else:
329 331 self.fields[label] = forms.CharField(initial=value, help_text=help_text)
330 332
331 333 if label in ('code', ):
332 334 self.fields[label].widget = HiddenWidget(attrs={'name':'%s|%s|%s' % (count, line.id, label)})
333 335
334 336 elif 'widget' in params[label]:
335 337 km2unit = line.rc_configuration.km2unit
336 338 if params[label]['widget']=='km':
337 339 self.fields[label].widget = KmUnitWidget(attrs={'line':line, 'km2unit':km2unit, 'name':'%s|%s|%s' % (count, line.id, label)})
338 340 elif params[label]['widget']=='unit':
339 341 self.fields[label].widget = UnitKmWidget(attrs={'line':line, 'km2unit':km2unit, 'name':'%s|%s|%s' % (count, line.id, label)})
340 342 elif params[label]['widget']=='dc':
341 343 self.fields[label].widget = KmUnitDcWidget(attrs={'line':line, 'km2unit':km2unit, 'name':'%s|%s|%s' % (count, line.id, label)})
342 344 elif params[label]['widget']=='codes':
343 345 self.fields[label].widget = CodesWidget(attrs={'line':line, 'km2unit':km2unit, 'name':'%s|%s|%s' % (count, line.id, label)})
344 346 else:
345 347 self.fields[label].widget = DefaultWidget(attrs={'line':line, 'name':'%s|%s|%s' % (count, line.id, label)})
346 348
347 349
348 350 class Meta:
349 351 model = RCLine
350 352 exclude = ('rc_configuration', 'line_type', 'channel', 'position', 'params', 'pulses')
351 353
352 354
353 355 class RCSubLineEditForm(forms.Form):
354 356
355 357 def __init__(self, *args, **kwargs):
356 358 extra_fields = kwargs.pop('extra_fields')
357 359 count = kwargs.pop('count')
358 360 line = kwargs.pop('line')
359 361 super(RCSubLineEditForm, self).__init__(*args, **kwargs)
360 362 for label, value in extra_fields.items():
361 363 self.fields[label] = forms.CharField(initial=value,
362 364 widget=forms.TextInput(attrs={'name':'%s|%s|%s' % (count, line, label)}))
363 365
364 366
365 367 class RCImportForm(forms.Form):
366 368
367 369 file_name = ExtFileField(extensions=['.racp', '.json', '.dat'])
368 370
369 371
370 372 class RCLineCodesForm(forms.ModelForm):
371 373
372 374 def __init__(self, *args, **kwargs):
373 375 super(RCLineCodesForm, self).__init__(*args, **kwargs)
374 376
375 377 if 'initial' in kwargs:
376 378 self.fields['code'] = forms.ChoiceField(choices=RCLineCode.objects.all().values_list('pk', 'name'),
377 379 initial=kwargs['initial']['code'])
378 380 if 'instance' in kwargs:
379 381 self.fields['code'] = forms.ChoiceField(choices=RCLineCode.objects.all().values_list('pk', 'name'),
380 382 initial=kwargs['instance'].pk)
381 383
382 384 self.fields['codes'].widget = CodesWidget()
383 385
384 386
385 387 class Meta:
386 388 model = RCLineCode
387 389 exclude = ('name',)
388 390
389 391 class RCClockForm(forms.ModelForm):
390 392
391 393 def __init__(self, *args, **kwargs):
392 394 super(RCClockForm, self).__init__(*args, **kwargs)
393 395
394 396 instance = getattr(self, 'instance', None)
395 397
396 398 if instance is not None and instance.mode:
397 399 self.fields['multiplier'].widget.attrs['readonly'] = True
398 400 self.fields['divisor'].widget.attrs['readonly'] = True
399 401 self.fields['reference'].widget.attrs['readonly'] = True
400 402
401 403
402 404 class Meta:
403 405 model = RCClock
404 406 exclude = ('rc_configuration',)
405 407
406 408 def clean(self):
407 409
408 410 form_data = self.cleaned_data
409 411
410 412 if form_data['mode'] is True and float(form_data['frequency']) not in (60., 55.):
411 413 self.add_error('frequency', 'Only 60 and 55 are valid values in auto mode')
412 414 elif form_data['mode'] is False:
413 415 if form_data['reference']==0 and not 24<=form_data['multiplier']<=36:
414 416 self.add_error('multiplier', 'For 25MHz, valid values are between 24 and 36')
415 417 elif form_data['reference']==1 and not 60<=form_data['multiplier']<=90:
416 418 self.add_error('multiplier', 'For 10MHz, valid values are between 60 and 90')
417 419
418 return form_data No newline at end of file
420 return form_data
@@ -1,1027 +1,1030
1 1
2 2
3 3 import ast
4 4 import json
5 5 import requests
6 6 import numpy as np
7 7 from base64 import b64encode
8 8 from struct import pack
9 9
10 10 from django.db import models
11 11 from django.core.urlresolvers import reverse
12 12 from django.core.validators import MinValueValidator, MaxValueValidator
13 13
14 14 from apps.main.models import Configuration
15 15 from apps.main.utils import Params
16 16 from devices.rc import api
17 17 from apps.rc.utils import RCFile
18 18
19 19
20 20 LINE_TYPES = (
21 21 ('none', 'Not used'),
22 22 ('tr', 'Transmission/reception selector signal'),
23 23 ('tx', 'A modulating signal (Transmission pulse)'),
24 24 ('codes', 'BPSK modulating signal'),
25 25 ('windows', 'Sample window signal'),
26 26 ('sync', 'Synchronizing signal'),
27 27 ('flip', 'IPP related periodic signal'),
28 28 ('prog_pulses', 'Programmable pulse'),
29 29 ('mix', 'Mixed line'),
30 30 )
31 31
32 32
33 33 SAMPLING_REFS = (
34 34 ('none', 'No Reference'),
35 35 ('begin_baud', 'Begin of the first baud'),
36 36 ('first_baud', 'Middle of the first baud'),
37 37 ('sub_baud', 'Middle of the sub-baud')
38 38 )
39 39
40 40 DAT_CMDS = {
41 41 # Pulse Design commands
42 42 'DISABLE' : 0, # Disables pulse generation
43 43 'ENABLE' : 24, # Enables pulse generation
44 44 'DELAY_START' : 40, # Write delay status to memory
45 45 'FLIP_START' : 48, # Write flip status to memory
46 46 'SAMPLING_PERIOD' : 64, # Establish Sampling Period
47 47 'TX_ONE' : 72, # Output '0' in line TX
48 48 'TX_ZERO' : 88, # Output '0' in line TX
49 49 'SW_ONE' : 104, # Output '0' in line SW
50 50 'SW_ZERO' : 112, # Output '1' in line SW
51 51 'RESTART': 120, # Restarts CR8 Firmware
52 52 'CONTINUE' : 253, # Function Unknown
53 53 # Commands available to new controllers
54 54 # In Pulse Design Executable, the clock divisor code is written as 12 at the start, but it should be written as code 22(below) just before the final enable.
55 55 'CLOCK_DIVISOR_INIT' : 12, # Specifies Clock Divisor. Legacy command, ignored in the actual .dat conversion
56 56 'CLOCK_DIVISOR_LAST' : 22, # Specifies Clock Divisor (default 60 if not included) syntax: 255,22 254,N-1.
57 57 'CLOCK_DIVIDER' : 8,
58 58 }
59 59
60 60 MAX_BITS = 8
61 61
62 62 # Rotate left: 0b1001 --> 0b0011
63 63 rol = lambda val, r_bits: \
64 64 (val << r_bits%MAX_BITS) & (2**MAX_BITS-1) | \
65 65 ((val & (2**MAX_BITS-1)) >> (MAX_BITS-(r_bits%MAX_BITS)))
66 66
67 67 # Rotate right: 0b1001 --> 0b1100
68 68 ror = lambda val, r_bits: \
69 69 ((val & (2**MAX_BITS-1)) >> r_bits%MAX_BITS) | \
70 70 (val << (MAX_BITS-(r_bits%MAX_BITS)) & (2**MAX_BITS-1))
71 71
72 72
73 73 class RCConfiguration(Configuration):
74 74
75 75 ipp = models.FloatField(verbose_name='IPP [Km]', validators=[MinValueValidator(1)], default=300)
76 76 ntx = models.PositiveIntegerField(verbose_name='Number of TX', validators=[MinValueValidator(1)], default=1)
77 77 clock_in = models.FloatField(verbose_name='Clock in [MHz]', validators=[MinValueValidator(1), MaxValueValidator(80)], default=1)
78 78 clock_divider = models.PositiveIntegerField(verbose_name='Clock divider', validators=[MinValueValidator(1), MaxValueValidator(256)], default=1)
79 79 clock = models.FloatField(verbose_name='Clock Master [MHz]', blank=True, default=1)
80 80 time_before = models.PositiveIntegerField(verbose_name='Time before [&mu;S]', default=12)
81 81 time_after = models.PositiveIntegerField(verbose_name='Time after [&mu;S]', default=1)
82 82 sync = models.PositiveIntegerField(verbose_name='Synchro delay', default=0)
83 83 sampling_reference = models.CharField(verbose_name='Sampling Reference', choices=SAMPLING_REFS, default='none', max_length=40)
84 84 control_tx = models.BooleanField(verbose_name='Control Switch TX', default=False)
85 85 control_sw = models.BooleanField(verbose_name='Control Switch SW', default=False)
86 86 total_units = models.PositiveIntegerField(default=0)
87 87 mix = models.BooleanField(default=False)
88 88
89 89 class Meta:
90 90 db_table = 'rc_configurations'
91 91
92 92 def get_absolute_url_plot(self):
93 93 return reverse('url_plot_rc_pulses', args=[str(self.id)])
94 94
95 95 @property
96 96 def ipp_unit(self):
97 97
98 98 return '{} ({})'.format(self.ipp, int(self.ipp*self.km2unit))
99 99
100 100 @property
101 101 def us2unit(self):
102 102
103 103 return self.clock_in/self.clock_divider
104 104
105 105 @property
106 106 def km2unit(self):
107 107
108 108 return 20./3*(self.clock_in/self.clock_divider)
109 109
110 110 def clone(self, **kwargs):
111 111
112 112 lines = self.get_lines()
113 113 self.pk = None
114 114 self.id = None
115 115 for attr, value in kwargs.items():
116 116 setattr(self, attr, value)
117 117 self.save()
118 118
119 119 for line in lines:
120 120 line.clone(rc_configuration=self)
121 121
122 122 new_lines = self.get_lines()
123 123 for line in new_lines:
124 124 line_params = json.loads(line.params)
125 125 if 'TX_ref' in line_params and (line_params['TX_ref'] != '0'):
126 126 ref_line = RCLine.objects.get(pk=line_params['TX_ref'])
127 127 line_params['TX_ref'] = ['{}'.format(l.pk) for l in new_lines if l.get_name()==ref_line.get_name()][0]
128 128 line.params = json.dumps(line_params)
129 129 line.save()
130 130
131 131 return self
132 132
133 133 def get_lines(self, **kwargs):
134 134 '''
135 135 Retrieve configuration lines
136 136 '''
137 137
138 138 return RCLine.objects.filter(rc_configuration=self.pk, **kwargs)
139 139
140 140
141 141 def clean_lines(self):
142 142 '''
143 143 '''
144 144
145 145 empty_line = RCLineType.objects.get(name='none')
146 146
147 147 for line in self.get_lines():
148 148 line.line_type = empty_line
149 149 line.params = '{}'
150 150 line.save()
151 151
152 152 def dict_to_parms(self, params, id=None):
153 153 '''
154 154 '''
155 155
156 156 if id:
157 157 data = Params(params).get_conf(id_conf=id)
158 158 else:
159 159 data = Params(params).get_conf(dtype='rc')
160 160
161 161 # self.name = data['name']
162 162 self.ipp = data['ipp']
163 163 self.ntx = data['ntx']
164 164 self.clock_in = data['clock_in']
165 165 self.clock_divider = data['clock_divider']
166 166 self.clock = data['clock']
167 167 self.time_before = data['time_before']
168 168 self.time_after = data['time_after']
169 169 self.sync = data['sync']
170 170 self.sampling_reference = data['sampling_reference']
171 171 self.total_units = self.ipp*self.ntx*self.km2unit
172 172 self.save()
173 173 self.clean_lines()
174 174
175 175 positions = {'tx':0, 'tr':0}
176 176 for i, id in enumerate(data['lines']):
177 177 line_data = params['lines']['byId'][id]
178 178 line_type = RCLineType.objects.get(name=line_data['line_type'])
179 179 if line_type.name == 'codes':
180 180 code = RCLineCode.objects.get(name=line_data['params']['code'])
181 181 line_data['params']['code'] = code.pk
182 182 if line_type.name == 'tx':
183 183 position = positions['tx']
184 184 positions['tx'] += 1
185 185 elif line_type.name == 'tr':
186 186 position = positions['tr']
187 187 positions['tr'] += 1
188 188 else:
189 189 position = 0
190 190 line, dum = RCLine.objects.update_or_create(
191 191 rc_configuration=self,
192 192 channel=i,
193 193 position=position,
194 194 defaults={
195 195 'line_type': line_type,
196 196 'params': json.dumps(line_data['params'])
197 197 }
198 198 )
199 199
200 200 for i, line in enumerate(self.get_lines()):
201 201 line_params = json.loads(line.params)
202 202 if 'TX_ref' in line_params:
203 203 if line_params['TX_ref'] in (0, '0'):
204 204 line_params['TX_ref'] = '0'
205 205 else:
206 206 ref_id = '{}'.format(line_params['TX_ref'])
207 207 ref_line = params['lines']['byId'][ref_id]
208 208 line_params['TX_ref'] = RCLine.objects.get(
209 209 rc_configuration=self,
210 210 params=json.dumps(ref_line['params'])
211 211 ).pk
212 212 line.params = json.dumps(line_params)
213 213 line.save()
214 214
215 215
216 216 def get_delays(self):
217 217
218 218 pulses = [line.pulses_as_points() for line in self.get_lines()]
219 219 points = [tup for tups in pulses for tup in tups]
220 220 points = set([x for tup in points for x in tup])
221 221 points = list(points)
222 222 points.sort()
223 223
224 224 if points[0]!=0:
225 225 points.insert(0, 0)
226 226
227 227 return [points[i+1]-points[i] for i in range(len(points)-1)]
228 228
229 229
230 230 def get_pulses(self, binary=True):
231 231
232 232 pulses = [line.pulses_as_points() for line in self.get_lines()]
233 233 tuples = [tup for tups in pulses for tup in tups]
234 234 points = set([x for tup in tuples for x in tup])
235 235 points = list(points)
236 236 points.sort()
237 237 states = []
238 238 last = [0 for x in pulses]
239 239
240 240 for x in points:
241 241 dum = []
242 242 for i, tups in enumerate(pulses):
243 243 ups = [tup[0] for tup in tups if tup!=(0,0)]
244 244 dws = [tup[1] for tup in tups if tup!=(0,0)]
245 245 if x in ups:
246 246 dum.append(1)
247 247 elif x in dws:
248 248 dum.append(0)
249 249 else:
250 250 dum.append(last[i])
251 251 states.append(dum)
252 252 last = dum
253 253
254 254 if binary:
255 255 ret = []
256 256 for flips in states:
257 257 flips.reverse()
258 258 ret.append(int(''.join([str(x) for x in flips]), 2))
259 259 states = ret
260 260
261 261 return states[:-1]
262 262
263 263 def add_cmd(self, cmd):
264 264
265 265 if cmd in DAT_CMDS:
266 266 return (255, DAT_CMDS[cmd])
267 267
268 268 def add_data(self, value):
269 269
270 270 return (254, value-1)
271 271
272 272 def parms_to_binary(self, dat=True):
273 273 '''
274 274 Create "dat" stream to be send to CR
275 275 '''
276 276
277 277 data = bytearray()
278 278 # create header
279 279 data.extend(self.add_cmd('DISABLE'))
280 280 data.extend(self.add_cmd('CONTINUE'))
281 281 data.extend(self.add_cmd('RESTART'))
282 282
283 283 if self.control_sw:
284 284 data.extend(self.add_cmd('SW_ONE'))
285 285 else:
286 286 data.extend(self.add_cmd('SW_ZERO'))
287 287
288 288 if self.control_tx:
289 289 data.extend(self.add_cmd('TX_ONE'))
290 290 else:
291 291 data.extend(self.add_cmd('TX_ZERO'))
292 292
293 293 # write divider
294 294 data.extend(self.add_cmd('CLOCK_DIVIDER'))
295 295 data.extend(self.add_data(self.clock_divider))
296 296
297 297 # write delays
298 298 data.extend(self.add_cmd('DELAY_START'))
299 299 # first delay is always zero
300 300 data.extend(self.add_data(1))
301 301
302 302 delays = self.get_delays()
303 303
304 304 for delay in delays:
305 305 while delay>252:
306 306 data.extend(self.add_data(253))
307 307 delay -= 253
308 308 data.extend(self.add_data(int(delay)))
309 309
310 310 # write flips
311 311 data.extend(self.add_cmd('FLIP_START'))
312 312
313 313 states = self.get_pulses(binary=True)
314 314
315 315
316 316 last = 0
317 317 for flip, delay in zip(states, delays):
318 318 data.extend(self.add_data((flip^last)+1))
319 319 last = flip
320 320 while delay>252:
321 321 data.extend(self.add_data(1))
322 322 delay -= 253
323 323
324 324 # write sampling period
325 325 data.extend(self.add_cmd('SAMPLING_PERIOD'))
326 326 wins = self.get_lines(line_type__name='windows')
327 327 if wins:
328 328 win_params = json.loads(wins[0].params)['params']
329 329 if win_params:
330 330 dh = int(win_params[0]['resolution']*self.km2unit)
331 331 else:
332 332 dh = 1
333 333 else:
334 334 dh = 1
335 335 data.extend(self.add_data(dh))
336 336
337 337 # write enable
338 338 data.extend(self.add_cmd('ENABLE'))
339 339
340 340 if not dat:
341 341 return data
342 342
343 343 return '\n'.join(['{}'.format(x) for x in data])
344 344
345 345 def update_pulses(self):
346 346
347 347 for line in self.get_lines():
348 348 line.update_pulses()
349 349
350 350 def plot_pulses2(self, km=False):
351 351
352 352 import matplotlib
353 353 matplotlib.use('Agg')
354 354 import matplotlib.pyplot as plt
355 355 from bokeh.resources import CDN
356 356 from bokeh.embed import components
357 357 from bokeh.mpl import to_bokeh
358 358 from bokeh.models.tools import WheelZoomTool, ResetTool, PanTool, HoverTool, SaveTool
359 359
360 360 lines = self.get_lines()
361 361
362 362 N = len(lines)
363 363 npoints = self.total_units/self.km2unit if km else self.total_units
364 364 fig = plt.figure(figsize=(12, 2+N*0.5))
365 365 ax = fig.add_subplot(111)
366 366 labels = ['IPP']
367 367
368 368 for i, line in enumerate(lines):
369 369 labels.append(line.get_name(channel=True))
370 370 l = ax.plot((0, npoints),(N-i-1, N-i-1))
371 371 points = [(tup[0], tup[1]-tup[0]) for tup in line.pulses_as_points(km=km) if tup!=(0,0)]
372 372 ax.broken_barh(points, (N-i-1, 0.5),
373 373 edgecolor=l[0].get_color(), facecolor='none')
374 374
375 375 n = 0
376 376 f = ((self.ntx+50)/100)*5 if ((self.ntx+50)/100)*10>0 else 2
377 377 for x in np.arange(0, npoints, self.ipp if km else self.ipp*self.km2unit):
378 378 if n%f==0:
379 379 ax.text(x, N, '%s' % n, size=10)
380 380 n += 1
381 381
382 382 labels.reverse()
383 383 ax.set_yticks(range(len(labels)))
384 384 ax.set_yticklabels(labels)
385 385 ax.set_xlabel = 'Units'
386 386 plot = to_bokeh(fig, use_pandas=False)
387 387 plot.tools = [PanTool(dimensions=['width']), WheelZoomTool(dimensions=['width']), ResetTool(), SaveTool()]
388 388 plot.toolbar_location="above"
389 389
390 390 return components(plot, CDN)
391 391
392 392 def plot_pulses(self, km=False):
393 393
394 394 from bokeh.plotting import figure
395 395 from bokeh.resources import CDN
396 396 from bokeh.embed import components
397 397 from bokeh.models import FixedTicker, PrintfTickFormatter
398 398 from bokeh.models.tools import WheelZoomTool, ResetTool, PanTool, HoverTool, SaveTool
399 399 from bokeh.models.sources import ColumnDataSource
400 400
401 401 lines = self.get_lines().reverse()
402 402
403 403 N = len(lines)
404 404 npoints = self.total_units/self.km2unit if km else self.total_units
405 405 ipp = self.ipp if km else self.ipp*self.km2unit
406 406
407 407 hover = HoverTool(tooltips=[("Line", "@name"),
408 408 ("IPP", "@ipp"),
409 409 ("X", "@left")])
410 410
411 411 tools = [PanTool(dimensions=['width']),
412 412 WheelZoomTool(dimensions=['width']),
413 413 hover, SaveTool()]
414 414
415 415 plot = figure(width=1000,
416 416 height=40+N*50,
417 417 y_range = (0, N),
418 418 tools=tools,
419 419 toolbar_location='above',
420 420 toolbar_sticky=False,)
421 421
422 422 plot.xaxis.axis_label = 'Km' if km else 'Units'
423 423 plot.xaxis[0].formatter = PrintfTickFormatter(format='%d')
424 424 plot.yaxis.axis_label = 'Pulses'
425 425 plot.yaxis[0].ticker=FixedTicker(ticks=list(range(N)))
426 426 plot.yaxis[0].formatter = PrintfTickFormatter(format='Line %d')
427 427
428 428 for i, line in enumerate(lines):
429 429
430 430 points = [tup for tup in line.pulses_as_points(km=km) if tup!=(0,0)]
431 431
432 432 source = ColumnDataSource(data = dict(
433 433 bottom = [i for tup in points],
434 434 top = [i+0.5 for tup in points],
435 435 left = [tup[0] for tup in points],
436 436 right = [tup[1] for tup in points],
437 437 ipp = [int(tup[0]/ipp) for tup in points],
438 438 name = [line.get_name() for tup in points]
439 439 ))
440 440
441 441 plot.quad(
442 442 bottom = 'bottom',
443 443 top = 'top',
444 444 left = 'left',
445 445 right = 'right',
446 446 source = source,
447 447 fill_alpha = 0,
448 448 #line_color = 'blue',
449 449 )
450 450
451 451 plot.line([0, npoints], [i, i])#, color='blue')
452 452
453 453 return components(plot, CDN)
454 454
455 455 def request(self, cmd, method='get', **kwargs):
456 456
457 457 req = getattr(requests, method)(self.device.url(cmd), **kwargs)
458 458 payload = req.json()
459 459
460 460 return payload
461 461
462 462 def status_device(self):
463 463
464 464 try:
465 465 self.device.status = 0
466 466 payload = self.request('status')
467 467 if payload['status']=='enable':
468 468 self.device.status = 3
469 469 elif payload['status']=='disable':
470 470 self.device.status = 2
471 471 else:
472 472 self.device.status = 1
473 473 self.device.save()
474 474 self.message = 'RC status: {}'.format(payload['status'])
475 475 return False
476 476 except Exception as e:
477 477 if 'No route to host' not in str(e):
478 478 self.device.status = 4
479 479 self.device.save()
480 480 self.message = 'RC status: {}'.format(str(e))
481 481 return False
482 482
483 483 self.device.save()
484 484 return True
485 485
486 486 def reset_device(self):
487 487
488 488 try:
489 489 payload = self.request('reset', 'post')
490 490 if payload['reset']=='ok':
491 491 self.message = 'RC restarted OK'
492 492 self.device.status = 2
493 493 self.device.save()
494 494 else:
495 495 self.message = 'RC restart fail'
496 496 self.device.status = 4
497 497 self.device.save()
498 498 except Exception as e:
499 499 self.message = 'RC reset: {}'.format(str(e))
500 500 return False
501 501
502 502 return True
503 503
504 504 def stop_device(self):
505 505
506 506 try:
507 507 payload = self.request('stop', 'post')
508 508 self.message = 'RC stop: {}'.format(payload['stop'])
509 509 if payload['stop']=='ok':
510 510 self.device.status = 2
511 511 self.device.save()
512 512 else:
513 513 self.device.status = 4
514 514 self.device.save()
515 515 return False
516 516 except Exception as e:
517 517 if 'No route to host' not in str(e):
518 518 self.device.status = 4
519 519 else:
520 520 self.device.status = 0
521 521 self.message = 'RC stop: {}'.format(str(e))
522 522 self.device.save()
523 523 return False
524 524
525 525 return True
526 526
527 527 def start_device(self):
528 528
529 529 try:
530 530 payload = self.request('start', 'post')
531 531 self.message = 'RC start: {}'.format(payload['start'])
532 532 if payload['start']=='ok':
533 533 self.device.status = 3
534 534 self.device.save()
535 535 else:
536 536 return False
537 537 except Exception as e:
538 538 if 'No route to host' not in str(e):
539 539 self.device.status = 4
540 540 else:
541 541 self.device.status = 0
542 542 self.message = 'RC start: {}'.format(str(e))
543 543 self.device.save()
544 544 return False
545 545
546 546 return True
547 547
548 548 def write_device(self, raw=False):
549 549
550 550 if not raw:
551 551 clock = RCClock.objects.get(rc_configuration=self)
552 552 if clock.mode:
553 553 data = {'default': clock.frequency}
554 554 else:
555 555 data = {'manual': [clock.multiplier, clock.divisor, clock.reference]}
556 payload = self.request('setfreq', 'post', data=json.dumps(data))
557 if payload['command'] <> 'ok':
558 self.message = 'RC write: {}'.format(payload['command'])
559 else:
560 self.message = payload['programming']
561 if payload['programming'] == 'fail':
562 self.message = 'RC write: error programming CGS chip'
563
556 try:
557 payload = self.request('setfreq', 'post', data=json.dumps(data))
558 if payload['command'] <> 'ok':
559 self.message = 'RC write: {}'.format(payload['command'])
560 else:
561 self.message = payload['programming']
562 if payload['programming'] == 'fail':
563 self.message = 'RC write: error programming CGS chip'
564 except Exception as e:
565 self.message = 'RC Write: No CGS found {}'.format(e)
566 # return False
564 567 values = []
565 568 for pulse, delay in zip(self.get_pulses(), self.get_delays()):
566 569 while delay>65536:
567 570 values.append((pulse, 65535))
568 571 delay -= 65536
569 572 values.append((pulse, delay-1))
570 573 data = bytearray()
571 574 #reset
572 575 data.extend((128, 0))
573 576 #disable
574 577 data.extend((129, 0))
575 578 #SW switch
576 579 if self.control_sw:
577 580 data.extend((130, 2))
578 581 else:
579 582 data.extend((130, 0))
580 583 #divider
581 584 data.extend((131, self.clock_divider-1))
582 585 #enable writing
583 586 data.extend((139, 62))
584 587
585 588 last = 0
586 589 for tup in values:
587 590 vals = pack('<HH', last^tup[0], tup[1])
588 591 last = tup[0]
589 592 data.extend((133, vals[1], 132, vals[0], 133, vals[3], 132, vals[2]))
590 593
591 594 #enable
592 595 data.extend((129, 1))
593 596
594 597 if raw:
595 598 return b64encode(data)
596 599
597 600 try:
598 601 payload = self.request('stop', 'post')
599 602 payload = self.request('reset', 'post')
600 603 #payload = self.request('divider', 'post', data={'divider': self.clock_divider-1})
601 604 #payload = self.request('write', 'post', data=b64encode(bytearray((139, 62))), timeout=20)
602 605 n = len(data)
603 606 x = 0
604 607 #while x < n:
605 608 payload = self.request('write', 'post', data=b64encode(data))
606 609 # x += 1024
607 610
608 611 if payload['write']=='ok':
609 612 self.device.status = 3
610 613 self.device.save()
611 614 self.message = 'RC configured and started'
612 615 else:
613 616 self.device.status = 1
614 617 self.device.save()
615 618 self.message = 'RC write: {}'.format(payload['write'])
616 619 return False
617 620
618 621 #payload = self.request('start', 'post')
619 622
620 623 except Exception as e:
621 624 if 'No route to host' not in str(e):
622 625 self.device.status = 4
623 626 else:
624 627 self.device.status = 0
625 628 self.message = 'RC write: {}'.format(str(e))
626 629 self.device.save()
627 630 return False
628 631
629 632 return True
630 633
631 634
632 635 def get_absolute_url_import(self):
633 636 return reverse('url_import_rc_conf', args=[str(self.id)])
634 637
635 638
636 639 class RCLineCode(models.Model):
637 640
638 641 name = models.CharField(max_length=40)
639 642 bits_per_code = models.PositiveIntegerField(default=0)
640 643 number_of_codes = models.PositiveIntegerField(default=0)
641 644 codes = models.TextField(blank=True, null=True)
642 645
643 646 class Meta:
644 647 db_table = 'rc_line_codes'
645 648 ordering = ('name',)
646 649
647 650 def __str__(self):
648 651 return u'%s' % self.name
649 652
650 653
651 654 class RCLineType(models.Model):
652 655
653 656 name = models.CharField(choices=LINE_TYPES, max_length=40)
654 657 description = models.TextField(blank=True, null=True)
655 658 params = models.TextField(default='[]')
656 659
657 660 class Meta:
658 661 db_table = 'rc_line_types'
659 662
660 663 def __str__(self):
661 664 return u'%s - %s' % (self.name.upper(), self.get_name_display())
662 665
663 666
664 667 class RCLine(models.Model):
665 668
666 669 rc_configuration = models.ForeignKey(RCConfiguration, on_delete=models.CASCADE)
667 670 line_type = models.ForeignKey(RCLineType)
668 671 channel = models.PositiveIntegerField(default=0)
669 672 position = models.PositiveIntegerField(default=0)
670 673 params = models.TextField(default='{}')
671 674 pulses = models.TextField(default='')
672 675
673 676 class Meta:
674 677 db_table = 'rc_lines'
675 678 ordering = ['channel']
676 679
677 680 def __str__(self):
678 681 if self.rc_configuration:
679 682 return u'{}|{} - {}'.format(self.pk, self.get_name(), self.rc_configuration.name)
680 683
681 684 def jsonify(self):
682 685
683 686 data = {}
684 687 data['params'] = json.loads(self.params)
685 688 data['id'] = '{}'.format(self.pk)
686 689 data['line_type'] = self.line_type.name
687 690 data['name'] = self.get_name()
688 691 if data['line_type']=='codes':
689 692 data['params']['code'] = RCLineCode.objects.get(pk=data['params']['code']).name
690 693
691 694 return data
692 695
693 696
694 697 def clone(self, **kwargs):
695 698
696 699 self.pk = None
697 700 self.id = None
698 701
699 702 for attr, value in kwargs.items():
700 703 setattr(self, attr, value)
701 704
702 705 self.save()
703 706
704 707 return self
705 708
706 709 def get_name(self, channel=False):
707 710
708 711 chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
709 712 s = ''
710 713
711 714 if self.line_type.name in ('tx',):
712 715 s = chars[self.position]
713 716 elif self.line_type.name in ('codes', 'windows', 'tr'):
714 717 if 'TX_ref' in json.loads(self.params):
715 718 pk = json.loads(self.params)['TX_ref']
716 719 if pk in (0, '0'):
717 720 s = ','.join(chars[l.position] for l in self.rc_configuration.get_lines(line_type__name='tx'))
718 721 else:
719 722 ref = RCLine.objects.get(pk=pk)
720 723 s = chars[ref.position]
721 724 s = '({})'.format(s)
722 725
723 726 s = '{}{}'.format(self.line_type.name.upper(), s)
724 727
725 728 if channel:
726 729 return '{} {}'.format(s, self.channel)
727 730 else:
728 731 return s
729 732
730 733 def get_lines(self, **kwargs):
731 734
732 735 return RCLine.objects.filter(rc_configuration=self.rc_configuration, **kwargs)
733 736
734 737 def pulses_as_array(self):
735 738
736 739 y = np.zeros(self.rc_configuration.total_units)
737 740
738 741 for tup in ast.literal_eval(self.pulses):
739 742 y[tup[0]:tup[1]] = 1
740 743
741 744 return y.astype(np.int8)
742 745
743 746 def pulses_as_points(self, km=False):
744 747
745 748 if km:
746 749 unit2km = 1/self.rc_configuration.km2unit
747 750 return [(tup[0]*unit2km, tup[1]*unit2km) for tup in ast.literal_eval(self.pulses)]
748 751 else:
749 752 return ast.literal_eval(self.pulses)
750 753
751 754 def get_win_ref(self, params, tx_id, km2unit):
752 755
753 756 ref = self.rc_configuration.sampling_reference
754 757 codes = [line for line in self.get_lines(line_type__name='codes') if int(json.loads(line.params)['TX_ref'])==int(tx_id)]
755 758
756 759 if codes:
757 760 tx_width = float(json.loads(RCLine.objects.get(pk=tx_id).params)['pulse_width'])*km2unit/len(json.loads(codes[0].params)['codes'][0])
758 761 else:
759 762 tx_width = float(json.loads(RCLine.objects.get(pk=tx_id).params)['pulse_width'])*km2unit
760 763
761 764 if ref=='first_baud':
762 765 return int(1 + round((tx_width + 1)/2 + params['first_height']*km2unit - params['resolution']*km2unit))
763 766 elif ref=='sub_baud':
764 767 return np.ceil(1 + params['first_height']*km2unit - params['resolution']*km2unit/2)
765 768 else:
766 769 return 0
767 770
768 771 def update_pulses(self):
769 772 '''
770 773 Update pulses field
771 774 '''
772 775
773 776 km2unit = self.rc_configuration.km2unit
774 777 us2unit = self.rc_configuration.us2unit
775 778 ipp = self.rc_configuration.ipp
776 779 ntx = int(self.rc_configuration.ntx)
777 780 ipp_u = int(ipp*km2unit)
778 781 total = ipp_u*ntx if self.rc_configuration.total_units==0 else self.rc_configuration.total_units
779 782 y = []
780 783
781 784 if self.line_type.name=='tr':
782 785 tr_params = json.loads(self.params)
783 786
784 787 if tr_params['TX_ref'] in ('0', 0):
785 788 txs = self.get_lines(line_type__name='tx')
786 789 else:
787 790 txs = RCLine.objects.filter(pk=tr_params['TX_ref'])
788 791
789 792 for tx in txs:
790 793 params = json.loads(tx.params)
791 794
792 795 if float(params['pulse_width'])==0:
793 796 continue
794 797 delays = [float(d)*km2unit for d in params['delays'].split(',') if d]
795 798 width = float(params['pulse_width'])*km2unit+int(self.rc_configuration.time_before*us2unit)
796 799 before = 0
797 800 after = int(self.rc_configuration.time_after*us2unit)
798 801
799 802 y_tx = self.points(ntx, ipp_u, width,
800 803 delay=delays,
801 804 before=before,
802 805 after=after,
803 806 sync=self.rc_configuration.sync)
804 807
805 808 ranges = params['range'].split(',')
806 809
807 810 if len(ranges)>0 and ranges[0]!='0':
808 811 y_tx = self.mask_ranges(y_tx, ranges)
809 812
810 813 tr_ranges = tr_params['range'].split(',')
811 814
812 815 if len(tr_ranges)>0 and tr_ranges[0]!='0':
813 816 y_tx = self.mask_ranges(y_tx, tr_ranges)
814 817
815 818 y.extend(y_tx)
816 819
817 820 self.pulses = str(y)
818 821 y = self.array_to_points(self.pulses_as_array())
819 822
820 823 elif self.line_type.name=='tx':
821 824 params = json.loads(self.params)
822 825 delays = [float(d)*km2unit for d in params['delays'].split(',') if d]
823 826 width = float(params['pulse_width'])*km2unit
824 827
825 828 if width>0:
826 829 before = int(self.rc_configuration.time_before*us2unit)
827 830 after = 0
828 831
829 832 y = self.points(ntx, ipp_u, width,
830 833 delay=delays,
831 834 before=before,
832 835 after=after,
833 836 sync=self.rc_configuration.sync)
834 837
835 838 ranges = params['range'].split(',')
836 839
837 840 if len(ranges)>0 and ranges[0]!='0':
838 841 y = self.mask_ranges(y, ranges)
839 842
840 843 elif self.line_type.name=='flip':
841 844 n = float(json.loads(self.params)['number_of_flips'])
842 845 width = n*ipp*km2unit
843 846 y = self.points(int((ntx+1)/(2*n)), ipp_u*n*2, width)
844 847
845 848 elif self.line_type.name=='codes':
846 849 params = json.loads(self.params)
847 850 tx = RCLine.objects.get(pk=params['TX_ref'])
848 851 tx_params = json.loads(tx.params)
849 852 delays = [float(d)*km2unit for d in tx_params['delays'].split(',') if d]
850 853 f = int(float(tx_params['pulse_width'])*km2unit/len(params['codes'][0]))
851 854 codes = [(np.fromstring(''.join([s*f for s in code]), dtype=np.uint8)-48).astype(np.int8) for code in params['codes']]
852 855 codes = [self.array_to_points(code) for code in codes]
853 856 n = len(codes)
854 857
855 858 ranges = tx_params['range'].split(',')
856 859 if len(ranges)>0 and ranges[0]!='0':
857 860 dum = self.mask_ranges(tx.pulses_as_points(), ranges)
858 861 else:
859 862 dum = tx.pulses_as_points()
860 863
861 864 for i, tup in enumerate(dum):
862 865 if tup==(0,0): continue
863 866 code = codes[i%n]
864 867 y.extend([(c[0]+tup[0], c[1]+tup[0]) for c in code])
865 868
866 869 elif self.line_type.name=='sync':
867 870 params = json.loads(self.params)
868 871 n = ipp_u*ntx
869 872 if params['invert'] in ('1', 1):
870 y = [(n-1, n)]
873 y = [(n-2, n)]
871 874 else:
872 875 y = [(0, 1)]
873 876
874 877 elif self.line_type.name=='prog_pulses':
875 878 params = json.loads(self.params)
876 879 if int(params['periodic'])==0:
877 880 nntx = 1
878 881 nipp = ipp_u*ntx
879 882 else:
880 883 nntx = ntx
881 884 nipp = ipp_u
882 885
883 886 if 'params' in params and len(params['params'])>0:
884 887 for p in params['params']:
885 888 y_pp = self.points(nntx, nipp,
886 889 p['end']-p['begin'],
887 890 before=p['begin'])
888 891
889 892 y.extend(y_pp)
890 893
891 894 elif self.line_type.name=='windows':
892 895 params = json.loads(self.params)
893 896 if 'params' in params and len(params['params'])>0:
894 897 tx = RCLine.objects.get(pk=params['TX_ref'])
895 898 tx_params = json.loads(tx.params)
896 899 ranges = tx_params['range'].split(',')
897 900 for p in params['params']:
898 901 y_win = self.points(ntx, ipp_u,
899 902 p['resolution']*p['number_of_samples']*km2unit,
900 903 before=int(self.rc_configuration.time_before*us2unit)+p['first_height']*km2unit,
901 904 sync=self.rc_configuration.sync+self.get_win_ref(p, params['TX_ref'], km2unit))
902 905
903 906
904 907 if len(ranges)>0 and ranges[0]!='0':
905 908 y_win = self.mask_ranges(y_win, ranges)
906 909
907 910 y.extend(y_win)
908 911
909 912 elif self.line_type.name=='mix':
910 913 values = self.rc_configuration.parameters.split('-')
911 914 confs = [RCConfiguration.objects.get(pk=value.split('|')[0]) for value in values]
912 915 modes = [value.split('|')[1] for value in values]
913 916 ops = [value.split('|')[2] for value in values]
914 917 delays = [value.split('|')[3] for value in values]
915 918 masks = [value.split('|')[4] for value in values]
916 919 mask = list('{:8b}'.format(int(masks[0])))
917 920 mask.reverse()
918 921 if mask[self.channel] in ('0', '', ' '):
919 922 y = np.zeros(confs[0].total_units, dtype=np.int8)
920 923 else:
921 924 y = confs[0].get_lines(channel=self.channel)[0].pulses_as_array()
922 925
923 926 for i in range(1, len(values)):
924 927 mask = list('{:8b}'.format(int(masks[i])))
925 928 mask.reverse()
926 929
927 930 if mask[self.channel] in ('0', '', ' '):
928 931 continue
929 932 Y = confs[i].get_lines(channel=self.channel)[0].pulses_as_array()
930 delay = float(delays[i])*km2unit
933 delay = int(float(delays[i])*km2unit)
931 934
932 935 if modes[i]=='P':
933 936 if delay>0:
934 937 if delay<self.rc_configuration.ipp*km2unit and len(Y)==len(y):
935 938 y_temp = np.empty_like(Y)
936 939 y_temp[:delay] = 0
937 940 y_temp[delay:] = Y[:-delay]
938 941 elif delay+len(Y)>len(y):
939 942 y_new = np.zeros(delay+len(Y), dtype=np.int8)
940 943 y_new[:len(y)] = y
941 944 y = y_new
942 945 y_temp = np.zeros(delay+len(Y), dtype=np.int8)
943 946 y_temp[-len(Y):] = Y
944 947 elif delay+len(Y)==len(y):
945 948 y_temp = np.zeros(delay+len(Y))
946 949 y_temp[-len(Y):] = Y
947 950 elif delay+len(Y)<len(y):
948 951 y_temp = np.zeros(len(y), dtype=np.int8)
949 952 y_temp[delay:delay+len(Y)] = Y
950 953 else:
951 954 y_temp = Y.copy()
952 955
953 956 if ops[i]=='OR':
954 957 y = y | y_temp
955 958 elif ops[i]=='XOR':
956 959 y = y ^ y_temp
957 960 elif ops[i]=='AND':
958 961 y = y & y_temp
959 962 elif ops[i]=='NAND':
960 963 y = y & ~y_temp
961 964 else:
962 965 y = np.concatenate([y, Y])
963 966
964 967 total = len(y)
965 968 y = self.array_to_points(y)
966 969
967 970 else:
968 971 y = []
969 972
970 973 if self.rc_configuration.total_units != total:
971 974 self.rc_configuration.total_units = total
972 975 self.rc_configuration.save()
973 976
974 977 self.pulses = str(y)
975 978 self.save()
976 979
977 980 @staticmethod
978 981 def array_to_points(X):
979 982
980 983 if X.size==0:
981 984 return []
982 985
983 986 d = X[1:]-X[:-1]
984 987
985 988 up = np.where(d==1)[0]
986 989 if X[0]==1:
987 990 up = np.concatenate((np.array([-1]), up))
988 991 up += 1
989 992
990 993 dw = np.where(d==-1)[0]
991 994 if X[-1]==1:
992 995 dw = np.concatenate((dw, np.array([len(X)-1])))
993 996 dw += 1
994 997
995 998 return [(tup[0], tup[1]) for tup in zip(up, dw)]
996 999
997 1000 @staticmethod
998 1001 def mask_ranges(Y, ranges):
999 1002
1000 1003 y = [(0, 0) for __ in Y]
1001 1004
1002 1005 for index in ranges:
1003 1006 if '-' in index:
1004 1007 args = [int(a) for a in index.split('-')]
1005 1008 y[args[0]-1:args[1]] = Y[args[0]-1:args[1]]
1006 1009 else:
1007 1010 y[int(index)-1] = Y[int(index)-1]
1008 1011
1009 1012 return y
1010 1013
1011 1014 @staticmethod
1012 1015 def points(ntx, ipp, width, delay=[0], before=0, after=0, sync=0):
1013 1016
1014 1017 delays = len(delay)
1015 1018
1016 1019 Y = [(int(ipp*x+before+delay[x%delays]+sync), int(ipp*x+width+before+delay[x%delays]+after+sync)) for x in range(ntx)]
1017 1020
1018 1021 return Y
1019 1022
1020 1023 class RCClock(models.Model):
1021 1024
1022 1025 rc_configuration = models.ForeignKey(RCConfiguration, on_delete=models.CASCADE)
1023 1026 mode = models.BooleanField(default=True, choices=((True, 'Auto'), (False, 'Manual')))
1024 1027 multiplier = models.PositiveIntegerField(default=60)
1025 1028 divisor = models.PositiveIntegerField(default=10)
1026 1029 reference = models.PositiveSmallIntegerField(default=1, choices=((0, 'Internal (25MHz)'), (1, 'External (10MHz)')))
1027 frequency = models.FloatField(default=60.0) No newline at end of file
1030 frequency = models.FloatField(default=60.0)
@@ -1,420 +1,425
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 from django.contrib.auth.decorators import login_required
8 8
9 9 from apps.main.models import Experiment, Device
10 10 from apps.main.views import sidebar
11 11
12 12 from .models import RCConfiguration, RCLine, RCLineType, RCLineCode, RCClock
13 13 from .forms import RCConfigurationForm, RCLineForm, RCLineViewForm, RCLineEditForm, RCImportForm, RCLineCodesForm, RCClockForm
14 14
15 15
16 16 def conf(request, conf_id):
17 17
18 18 conf = get_object_or_404(RCConfiguration, pk=conf_id)
19 19
20 20 lines = RCLine.objects.filter(rc_configuration=conf).order_by('channel')
21 21 clk = RCClock.objects.filter(rc_configuration=conf).first()
22 22 if clk is None:
23 23 clk = RCClock(rc_configuration=conf)
24 24 clk.save()
25 25
26 26 for line in lines:
27 27 params = json.loads(line.params)
28 28 line.form = RCLineViewForm(extra_fields=params, line=line)
29 29 if 'params' in params:
30 30 line.subforms = [RCLineViewForm(extra_fields=fields, line=line, subform=True) for fields in params['params']]
31 31
32 32 kwargs = {}
33 33 kwargs['clock'] = clk
34 34 kwargs['dev_conf'] = conf
35 35 kwargs['rc_lines'] = lines
36 36 kwargs['dev_conf_keys'] = ['ipp_unit', 'ntx', 'clock_divider', 'clock',
37 37 'time_before', 'time_after', 'sync', 'sampling_reference',
38 38 'control_tx', 'control_sw']
39 39
40 40 kwargs['title'] = 'Configuration'
41 41 kwargs['suptitle'] = 'Detail'
42 42
43 43 kwargs['button'] = 'Edit Configuration'
44 44 ###### SIDEBAR ######
45 45 kwargs.update(sidebar(conf=conf))
46 46
47 47 return render(request, 'rc_conf.html', kwargs)
48 48
49 49 @login_required
50 50 def conf_edit(request, conf_id):
51 51
52 52 conf = get_object_or_404(RCConfiguration, pk=conf_id)
53 53 clock = RCClock.objects.get(rc_configuration=conf)
54 54 lines = RCLine.objects.filter(rc_configuration=conf).order_by('channel')
55 55
56 56 for line in lines:
57 57 params = json.loads(line.params)
58 58 line.form = RCLineEditForm(conf=conf, line=line, extra_fields=params)
59 59 line.subform = False
60 60
61 61 if 'params' in params:
62 62 line.subforms = [RCLineEditForm(extra_fields=fields, line=line, subform=i) for i, fields in enumerate(params['params'])]
63 63 line.subform = True
64 64
65 65 if request.method=='GET':
66 66
67 67 form = RCConfigurationForm(instance=conf)
68 68 form_clock = RCClockForm(instance=clock)
69 69
70 70 elif request.method=='POST':
71 71
72 72 line_data = {}
73 73 conf_data = {}
74 74 clock_data = {}
75 75 extras = []
76 76
77 77 #classified post fields
78 78 for label,value in request.POST.items():
79 79 if label=='csrfmiddlewaretoken':
80 80 continue
81 81
82 82 if label.count('|')==0:
83 83 if label in ('mode', 'multiplier', 'divisor', 'reference', 'frequency'):
84 84 clock_data[label] = value
85 85 else:
86 86 conf_data[label] = value
87 87 continue
88 88
89 89 elif label.split('|')[0]!='-1':
90 90 extras.append(label)
91 91 continue
92 92
93 93 x, pk, name = label.split('|')
94 94
95 95 if name=='codes':
96 96 value = [s for s in value.split('\r\n') if s]
97 97
98 98 if pk in line_data:
99 99 line_data[pk][name] = value
100 100 else:
101 101 line_data[pk] = {name:value}
102 102
103 103 #update conf
104 104
105 105 form_clock = RCClockForm(clock_data, instance=clock)
106 106 form = RCConfigurationForm(conf_data, instance=conf)
107 107
108 108 if form_clock.is_valid() and form.is_valid():
109 109 form_clock.save()
110 110 form.save()
111 111
112 112 #update lines fields
113 113 extras.sort()
114 xxs = {}
114 115 for label in extras:
115 116 x, pk, name = label.split('|')
116 117 if pk not in line_data:
117 118 line_data[pk] = {}
118 119 if 'params' not in line_data[pk]:
119 120 line_data[pk]['params'] = []
120 if len(line_data[pk]['params'])<int(x)+1:
121 xxs[pk] = []
122 if x not in xxs[pk]:
121 123 line_data[pk]['params'].append({})
124 xxs[pk].append(x)
125 for label in extras:
126 x, pk, name = label.split('|')
122 127 line_data[pk]['params'][int(x)][name] = float(request.POST[label])
123 128
124 129 for pk, params in line_data.items():
125 130 line = RCLine.objects.get(pk=pk)
126 131 if line.line_type.name in ('windows', 'prog_pulses'):
127 132 if 'params' not in params:
128 133 params['params'] = []
129 134 line.params = json.dumps(params)
130 135 line.save()
131 136
132 137 #update pulses field
133 138 conf.update_pulses()
134 139
135 140 messages.success(request, 'RC Configuration successfully updated')
136 141
137 142 return redirect(conf.get_absolute_url())
138 143
139 144 kwargs = {}
140 145 kwargs['dev_conf'] = conf
141 146 kwargs['form'] = form
142 147 kwargs['form_clock'] = form_clock
143 148 kwargs['rc_lines'] = lines
144 149 kwargs['edit'] = True
145 150
146 151 kwargs['title'] = 'RC Configuration'
147 152 kwargs['suptitle'] = 'Edit'
148 153 kwargs['button'] = 'Update'
149 154
150 155 return render(request, 'rc_conf_edit.html', kwargs)
151 156
152 157
153 158 def add_line(request, conf_id, line_type_id=None, code_id=None):
154 159
155 160 conf = get_object_or_404(RCConfiguration, pk=conf_id)
156 161
157 162 if request.method=='GET':
158 163 if line_type_id:
159 164 line_type = get_object_or_404(RCLineType, pk=line_type_id)
160 165
161 166 if code_id:
162 167 form = RCLineForm(initial={'rc_configuration':conf_id, 'line_type': line_type_id, 'code_id': code_id},
163 168 extra_fields=json.loads(line_type.params))
164 169 else:
165 170 form = RCLineForm(initial={'rc_configuration':conf_id, 'line_type': line_type_id},
166 171 extra_fields=json.loads(line_type.params))
167 172 else:
168 173 line_type = {'id':0}
169 174 form = RCLineForm(initial={'rc_configuration':conf_id})
170 175
171 176 if request.method=='POST':
172 177
173 178 line_type = get_object_or_404(RCLineType, pk=line_type_id)
174 179 form = RCLineForm(request.POST,
175 180 extra_fields=json.loads(line_type.params))
176 181
177 182 if form.is_valid():
178 183 form.save()
179 184 form.instance.update_pulses()
180 185 return redirect('url_edit_rc_conf', conf.id)
181 186
182 187 kwargs = {}
183 188 kwargs['form'] = form
184 189 kwargs['title'] = 'RC Configuration'
185 190 kwargs['suptitle'] = 'Add Line'
186 191 kwargs['button'] = 'Add'
187 192 kwargs['previous'] = conf.get_absolute_url_edit()
188 193 kwargs['dev_conf'] = conf
189 194 kwargs['line_type'] = line_type
190 195
191 196 return render(request, 'rc_add_line.html', kwargs)
192 197
193 198 def edit_codes(request, conf_id, line_id, code_id=None):
194 199
195 200 conf = get_object_or_404(RCConfiguration, pk=conf_id)
196 201 line = get_object_or_404(RCLine, pk=line_id)
197 202 params = json.loads(line.params)
198 203
199 204 if request.method=='GET':
200 205 if code_id:
201 206 code = get_object_or_404(RCLineCode, pk=code_id)
202 207 form = RCLineCodesForm(instance=code)
203 208 else:
204 209 initial = {'code': params['code'],
205 210 'codes': params['codes'] if 'codes' in params else [],
206 211 'number_of_codes': len(params['codes']) if 'codes' in params else 0,
207 212 'bits_per_code': len(params['codes'][0]) if 'codes' in params else 0,
208 213 }
209 214 form = RCLineCodesForm(initial=initial)
210 215
211 216 if request.method=='POST':
212 217 form = RCLineCodesForm(request.POST)
213 218 if form.is_valid():
214 219 params['code'] = request.POST['code']
215 220 params['codes'] = [s for s in request.POST['codes'].split('\r\n') if s]
216 221 line.params = json.dumps(params)
217 222 line.save()
218 223 messages.success(request, 'Line: "%s" has been updated.' % line)
219 224 return redirect('url_edit_rc_conf', conf.id)
220 225
221 226 kwargs = {}
222 227 kwargs['form'] = form
223 228 kwargs['title'] = line
224 229 kwargs['suptitle'] = 'Edit'
225 230 kwargs['button'] = 'Update'
226 231 kwargs['dev_conf'] = conf
227 232 kwargs['previous'] = conf.get_absolute_url_edit()
228 233 kwargs['line'] = line
229 234
230 235 return render(request, 'rc_edit_codes.html', kwargs)
231 236
232 237 def add_subline(request, conf_id, line_id):
233 238
234 239 conf = get_object_or_404(RCConfiguration, pk=conf_id)
235 240 line = get_object_or_404(RCLine, pk=line_id)
236 241
237 242 if request.method == 'POST':
238 243 if line:
239 244 params = json.loads(line.params)
240 245 subparams = json.loads(line.line_type.params)
241 246 if 'params' in subparams:
242 247 dum = {}
243 248 for key, value in subparams['params'].items():
244 249 dum[key] = value['value']
245 250 params['params'].append(dum)
246 251 line.params = json.dumps(params)
247 252 line.save()
248 253 return redirect('url_edit_rc_conf', conf.id)
249 254
250 255 kwargs = {}
251 256
252 257 kwargs['title'] = 'Add new'
253 258 kwargs['suptitle'] = '%s to %s' % (line.line_type.name, line)
254 259
255 260 return render(request, 'confirm.html', kwargs)
256 261
257 262 def remove_line(request, conf_id, line_id):
258 263
259 264 conf = get_object_or_404(RCConfiguration, pk=conf_id)
260 265 line = get_object_or_404(RCLine, pk=line_id)
261 266
262 267 if request.method == 'POST':
263 268 if line:
264 269 try:
265 270 channel = line.channel
266 271 line.delete()
267 272 for ch in range(channel+1, RCLine.objects.filter(rc_configuration=conf).count()+1):
268 273 l = RCLine.objects.get(rc_configuration=conf, channel=ch)
269 274 l.channel = l.channel-1
270 275 l.save()
271 276 messages.success(request, 'Line: "%s" has been deleted.' % line)
272 277 except:
273 278 messages.error(request, 'Unable to delete line: "%s".' % line)
274 279
275 280 return redirect('url_edit_rc_conf', conf.id)
276 281
277 282 kwargs = {}
278 283
279 284 kwargs['object'] = line
280 285 kwargs['delete'] = True
281 286 kwargs['title'] = 'Delete'
282 287 kwargs['suptitle'] = 'Line'
283 288 kwargs['previous'] = conf.get_absolute_url_edit()
284 289 return render(request, 'confirm.html', kwargs)
285 290
286 291
287 292 def remove_subline(request, conf_id, line_id, subline_id):
288 293
289 294 conf = get_object_or_404(RCConfiguration, pk=conf_id)
290 295 line = get_object_or_404(RCLine, pk=line_id)
291 296
292 297 if request.method == 'POST':
293 298 if line:
294 299 params = json.loads(line.params)
295 300 params['params'].remove(params['params'][int(subline_id)-1])
296 301 line.params = json.dumps(params)
297 302 line.save()
298 303
299 304 return redirect('url_edit_rc_conf', conf.id)
300 305
301 306 kwargs = {}
302 307
303 308 kwargs['object'] = line
304 309 kwargs['object_name'] = line.line_type.name
305 310 kwargs['delete_view'] = True
306 311 kwargs['title'] = 'Confirm delete'
307 312
308 313 return render(request, 'confirm.html', kwargs)
309 314
310 315
311 316 def update_lines_position(request, conf_id):
312 317
313 318 conf = get_object_or_404(RCConfiguration, pk=conf_id)
314 319
315 320 if request.method=='POST':
316 321 ch = 0
317 322 for item in request.POST['items'].split('&'):
318 323 line = RCLine.objects.get(pk=item.split('=')[-1])
319 324 line.channel = ch
320 325 line.save()
321 326 ch += 1
322 327
323 328 lines = RCLine.objects.filter(rc_configuration=conf).order_by('channel')
324 329
325 330 for line in lines:
326 331 params = json.loads(line.params)
327 332 line.form = RCLineEditForm(conf=conf, line=line, extra_fields=params)
328 333
329 334 if 'params' in params:
330 335 line.subform = True
331 336 line.subforms = [RCLineEditForm(extra_fields=fields, line=line, subform=i) for i, fields in enumerate(params['params'])]
332 337
333 338 html = render(request, 'rc_lines.html', {'dev_conf':conf, 'rc_lines':lines, 'edit':True})
334 339 data = {'html': html.content.decode('utf8')}
335 340
336 341 return HttpResponse(json.dumps(data), content_type="application/json")
337 342 return redirect('url_edit_rc_conf', conf.id)
338 343
339 344
340 345 def import_file(request, conf_id):
341 346
342 347 conf = get_object_or_404(RCConfiguration, pk=conf_id)
343 348 if request.method=='POST':
344 349 form = RCImportForm(request.POST, request.FILES)
345 350 if form.is_valid():
346 351 try:
347 352 data = conf.import_from_file(request.FILES['file_name'])
348 353 conf.dict_to_parms(data)
349 354 conf.update_pulses()
350 355 messages.success(request, 'Configuration "%s" loaded succesfully' % request.FILES['file_name'])
351 356 return redirect(conf.get_absolute_url_edit())
352 357
353 358 except Exception as e:
354 359 messages.error(request, 'Error parsing file: "%s" - %s' % (request.FILES['file_name'], repr(e)))
355 360 else:
356 361 messages.warning(request, 'Your current configuration will be replaced')
357 362 form = RCImportForm()
358 363
359 364 kwargs = {}
360 365 kwargs['form'] = form
361 366 kwargs['title'] = 'RC Configuration'
362 367 kwargs['suptitle'] = 'Import file'
363 368 kwargs['button'] = 'Upload'
364 369 kwargs['previous'] = conf.get_absolute_url()
365 370
366 371 return render(request, 'rc_import.html', kwargs)
367 372
368 373
369 374 def plot_pulses(request, conf_id):
370 375
371 376 conf = get_object_or_404(RCConfiguration, pk=conf_id)
372 377 km = True if 'km' in request.GET else False
373 378
374 379 script, div = conf.plot_pulses(km=km)
375 380
376 381 kwargs = {}
377 382 kwargs['no_sidebar'] = True
378 383 kwargs['title'] = 'RC Pulses'
379 384 kwargs['suptitle'] = conf.name
380 385 kwargs['div'] = mark_safe(div)
381 386 kwargs['script'] = mark_safe(script)
382 387 kwargs['units'] = conf.km2unit
383 388 kwargs['kms'] = 1/conf.km2unit
384 389
385 390 if km:
386 391 kwargs['km_selected'] = True
387 392
388 393 if 'json' in request.GET:
389 394 return HttpResponse(json.dumps({'div':mark_safe(div), 'script':mark_safe(script)}), content_type="application/json")
390 395 else:
391 396 return render(request, 'rc_pulses.html', kwargs)
392 397
393 398 def plot_pulses2(request, conf_id):
394 399
395 400 conf = get_object_or_404(RCConfiguration, pk=conf_id)
396 401 km = True if 'km' in request.GET else False
397 402
398 403 script, div = conf.plot_pulses2(km=km)
399 404
400 405 kwargs = {}
401 406 kwargs['no_sidebar'] = True
402 407 kwargs['title'] = 'RC Pulses'
403 408 kwargs['suptitle'] = conf.name
404 409 kwargs['div'] = mark_safe(div)
405 410 kwargs['script'] = mark_safe(script)
406 411 kwargs['units'] = conf.km2unit
407 412 kwargs['kms'] = 1/conf.km2unit
408 413
409 414 if km:
410 415 kwargs['km_selected'] = True
411 416
412 417 if 'json' in request.GET:
413 418 return HttpResponse(json.dumps({'div':mark_safe(div), 'script':mark_safe(script)}), content_type="application/json")
414 419 else:
415 420 return render(request, 'rc_pulses.html', kwargs)
416 421
417 422 def conf_raw(request, conf_id):
418 423 conf = get_object_or_404(RCConfiguration, pk=conf_id)
419 424 raw = conf.write_device(raw=True)
420 return HttpResponse(raw, content_type='application/json') No newline at end of file
425 return HttpResponse(raw, content_type='application/json')
@@ -1,68 +1,70
1 1 version: '2'
2 2 services:
3 3 # Django app
4 web:
5 container_name: 'radarsys'
6 build: .
7 restart: always
8 image: radarsys
9 command: gunicorn radarsys.wsgi:application -w 2 -b :8000
10 # command: python manage.py runserver 0.0.0.0:8030
11 # ports:
12 # - 8030:8030
13 env_file: .env
4 # web:
5 # container_name: 'radarsys'
6 # build: .
7 # restart: always
8 # image: radarsys
9 # command: gunicorn radarsys.wsgi:application -w 2 -b :8000
10 # # command: python manage.py runserver 0.0.0.0:8030
11 # # ports:
12 # # - 8030:8030
13 # env_file: .env
14 14
15 links:
16 - redis
17 - postgres
18 volumes:
19 - './:/radarsys'
20 - '${DOCKER_DATA}/static:/radarsys/static'
21 depends_on:
22 - redis
23 - postgres
15 # links:
16 # - redis
17 # - postgres
18 # volumes:
19 # - './:/radarsys'
20 # - '${DOCKER_DATA}/static:/radarsys/static'
21 # depends_on:
22 # - redis
23 # - postgres
24 24
25 25 redis:
26 26 container_name: 'radarsys-redis'
27 27 image: 'redis:3.2-alpine'
28 28 volumes:
29 29 - '${DOCKER_DATA}/redis:/data'
30 ports:
31 - 6300:6379
30 32
31 33 celery_worker:
32 34 container_name: 'radarsys-celery'
33 35 image: radarsys
34 36 env_file: .env
35 37 command: celery -A radarsys worker -l info
36 volumes_from:
37 - web
38 depends_on:
39 - web
38 # volumes_from:
39 # - web
40 # depends_on:
41 # - web
40 42
41 43 # PostgreSQL
42 44 postgres:
43 45 container_name: 'radarsys-postgres'
44 46 build: ./postgres/
45 47 volumes:
46 48 - ./postgres/docker-entrypoint-initdb.d:/docker-entrypoint-initdb.d
47 49 - pgdata:/var/lib/postgresql/data
48 # ports:
49 # - 5432:5432
50 ports:
51 - 5400:5432
50 52 env_file: .env
51 53
52 54 # Web Server
53 nginx:
54 container_name: 'radarsys-nginx'
55 restart: always
56 build: ./nginx/
57 ports:
58 - '8030:8030'
59 volumes_from:
60 - web
61 links:
62 - web:web
63 depends_on:
64 - web
55 # nginx:
56 # container_name: 'radarsys-nginx'
57 # restart: always
58 # build: ./nginx/
59 # ports:
60 # - '8030:8030'
61 # volumes_from:
62 # - web
63 # links:
64 # - web:web
65 # depends_on:
66 # - web
65 67
66 68 volumes:
67 69 pgdata:
68 70 driver: local
General Comments 0
You need to be logged in to leave comments. Login now