##// END OF EJS Templates
App JARS funcional
gonzalesluisfrancisco -
r345:cf456d2fb627
parent child
Show More
@@ -0,0 +1,2
1 {% extends "base_edit.html" %}
2
@@ -1,47 +1,46
1 1 # Integrated Radar System (SIR)
2 2
3 3 The Integrated Radar System (SIR) is a web application that allows the configuration of the radar devices as required by the experiment,
4 4 This app allows the creation of Campaigns, Experiment and Device Configurations.
5 For the python3.0 update please check the requeriments vrsion for each package. It depends on the python 3.7 or 3.8 version.
6 Special attention with the bokeh version.
5 For the python3.0 update please check the requeriments vrsion for each package. It depends on the python 3.7 or 3.8 version. Special attention with the bokeh version.
7 6 For more information visit: http://jro-dev.igp.gob.pe:3000/projects/sistema-integrado-de-radar/wiki
8 7
9 8 ## Installation
10 9
11 10 We recommend use docker/docker-compose for test/production but you can install the aplication as a normal django app.
12 11
13 12 ### 1. Download
14 13
15 14 Download the application *radarsys* to your workspace
16 15
17 16 $ cd /path/to/your/workspace
18 17 $ git clone http://jro-dev.igp.gob.pe/rhodecode/radarsys && cd radarsys
19 18
20 19 ### 2. Config app
21 20
22 21 Update enviroment vars (/path/to/radarsys/.env)
23 22
24 23 REDIS_HOST=radarsys-redis
25 24 REDIS_PORT=6300
26 25 POSTGRES_DB_NAME=radarsys
27 26 POSTGRES_PORT_5432_TCP_ADDR=radarsys-postgres
28 27 POSTGRES_PORT_5432_TCP_PORT=5400
29 28 POSTGRES_USER=docker
30 29 POSTGRES_PASSWORD=****
31 30 PGDATA=/var/lib/postgresql/data
32 31 LC_ALL=C.UTF-8
33 32
34 33 ### 3. Build application & make migrations (only once at installation)
35 34
36 35 $ cd /path/to/radarsys
37 36 $ docker-compose build
38 37 $ docker-compose run web python manage.py makemigrations
39 38 $ docker-compose run web python manage.py migrate
40 39 $ docker-compose run web python manage.py loaddata apps/main/fixtures/main_initial_data.json
41 40 $ docker-compose run web python manage.py loaddata apps/rc/fixtures/rc_initial_data.json
42 41 $ docker-compose run web python manage.py loaddata apps/jars/fixtures/initial_filters_data.json
43 42 $ docker-compose run web python manage.py collectstatic
44 43
45 44 ### 4. Run containers
46 45
47 46 $ docker-compose up -d
@@ -1,446 +1,445
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.conf import settings
6 6 from django.http import HttpResponse
7 7 from django.urls import reverse
8 8 from django.views.decorators.csrf import csrf_exempt
9 9 from django.utils.safestring import mark_safe
10 10
11 11 from datetime import datetime
12 12 from time import sleep
13 13 import os
14 14 import io
15 15
16 16 from apps.main.models import Device, Configuration, Experiment
17 17 from apps.main.views import sidebar
18 18
19 19 from .models import ABSConfiguration, ABSBeam
20 20 from .forms import ABSConfigurationForm, ABSBeamEditForm, ABSBeamAddForm, ABSImportForm
21 21
22 22 from .utils.overJroShow import overJroShow
23 23 #from .utils.OverJRO import OverJRO
24 24 # Create your views here.
25 25 import json, ast
26 26
27 27
28 28 def get_values_from_form(form_data):
29 29
30 30 sublistup = []
31 31 sublistdown = []
32 32 subtxlistup = []
33 33 subtxlistdown = []
34 34 subrxlistup = []
35 35 subrxlistdown = []
36 36
37 37 up_values_list = []
38 38 down_values_list = []
39 39 up_txvalues_list = []
40 40 down_txvalues_list = []
41 41 up_rxvalues_list = []
42 42 down_rxvalues_list = []
43 43
44 44 values_list = {}
45 45 cont = 1
46 46
47 47 for i in range(1,65):
48 48 x = float(form_data['abs_up'+str(i)])
49 49 y = float(form_data['abs_down'+str(i)])
50 50 sublistup.append(x)
51 51 sublistdown.append(y)
52 52
53 53 if str(i) in form_data.getlist('uptx_checks'):
54 54 subtxlistup.append(1)
55 55 else:
56 56 subtxlistup.append(0)
57 57 if str(i) in form_data.getlist('downtx_checks'):
58 58 subtxlistdown.append(1)
59 59 else:
60 60 subtxlistdown.append(0)
61 61
62 62 if str(i) in form_data.getlist('uprx_checks'):
63 63 subrxlistup.append(1)
64 64 else:
65 65 subrxlistup.append(0)
66 66 if str(i) in form_data.getlist('downrx_checks'):
67 67 subrxlistdown.append(1)
68 68 else:
69 69 subrxlistdown.append(0)
70 70
71 71 cont = cont+1
72 72
73 73 if cont == 9:
74 74 up_values_list.append(sublistup)
75 75 down_values_list.append(sublistdown)
76 76 sublistup = []
77 77 sublistdown = []
78 78
79 79 up_txvalues_list.append(subtxlistup)
80 80 down_txvalues_list.append(subtxlistdown)
81 81 subtxlistup = []
82 82 subtxlistdown = []
83 83 up_rxvalues_list.append(subrxlistup)
84 84 down_rxvalues_list.append(subrxlistdown)
85 85 subrxlistup = []
86 86 subrxlistdown = []
87 87 cont = 1
88 88
89 89
90 90 list_uesup = []
91 91 list_uesdown = []
92 92 for i in range(1,5):
93 93 if form_data['ues_up'+str(i)] == '':
94 94 list_uesup.append(0.0)
95 95 else:
96 96 list_uesup.append(float(form_data['ues_up'+str(i)]))
97 97
98 98 if form_data['ues_down'+str(i)] == '':
99 99 list_uesdown.append(0.0)
100 100 else:
101 101 list_uesdown.append(float(form_data['ues_down'+str(i)]))
102 102
103 103 onlyrx_list = form_data.getlist('onlyrx')
104 104 only_rx = {}
105 105 if '1' in onlyrx_list:
106 106 only_rx['up'] = True
107 107 else:
108 108 only_rx['up'] = False
109 109 if '2' in onlyrx_list:
110 110 only_rx['down'] = True
111 111 else:
112 112 only_rx['down'] = False
113 113
114 114 antenna = {'antenna_up': up_values_list, 'antenna_down': down_values_list}
115 115 tx = {'up': up_txvalues_list, 'down': down_txvalues_list}
116 116 rx = {'up': up_rxvalues_list, 'down': down_rxvalues_list}
117 117 ues = {'up': list_uesup, 'down': list_uesdown}
118 118 name = str(form_data['beam_name'])
119 119
120 120 beam_data = {'name': name, 'antenna': antenna, 'tx': tx, 'rx': rx, 'ues': ues, 'only_rx': only_rx}
121 121
122 122 return beam_data
123 123
124 124
125 125 def abs_conf(request, id_conf):
126 126
127 127 conf = get_object_or_404(ABSConfiguration, pk=id_conf)
128 128 beams = ABSBeam.objects.filter(abs_conf=conf)
129 129 #------------Colors for Active Beam:-------------
130 130 all_status = {}
131 131 module_messages = json.loads(conf.module_messages)
132 132
133 133 color_status = {}
134 134 for i, status in enumerate(conf.module_status):
135 135 if status == '3': #Running background-color: #00cc00;
136 136 all_status['{}'.format(i+1)] = 2
137 137 color_status['{}'.format(i+1)] = 'class=text-success'#'bgcolor=#00cc00'
138 138 elif status == '2':
139 139 all_status['{}'.format(i+1)] = 1
140 140 color_status['{}'.format(i+1)] = 'class=text-info'
141 141 elif status == '1': #Connected background-color: #ee902c;
142 142 all_status['{}'.format(i+1)] = 1
143 143 color_status['{}'.format(i+1)] = 'class=text-warning'#'bgcolor=#ee902c'
144 144 else: #Disconnected background-color: #ff0000;
145 145 all_status['{}'.format(i+1)] = 0
146 146 color_status['{}'.format(i+1)] = 'class=text-danger'#'bgcolor=#FF0000'
147 147 #------------------------------------------------
148 148
149 149 kwargs = {}
150 150 kwargs['connected_modules'] = str(conf.connected_modules())+'/64'
151 151 kwargs['dev_conf'] = conf
152 152
153 153 if conf.operation_mode == 0:
154 154 kwargs['dev_conf_keys'] = ['label', 'operation_mode']
155 155 else:
156 156 kwargs['dev_conf_keys'] = ['label', 'operation_mode', 'operation_value']
157 157
158 158 kwargs['title'] = 'ABS Configuration'
159 159 kwargs['suptitle'] = 'Details'
160 160 kwargs['button'] = 'Edit Configuration'
161 161
162 162 if conf.active_beam != 0:
163 163 kwargs['active_beam'] = int(conf.active_beam)
164 164
165 165 kwargs['beams'] = beams
166 166 kwargs['modules_status'] = all_status
167 167 kwargs['color_status'] = color_status
168 168 kwargs['module_messages'] = module_messages
169 169 ###### SIDEBAR ######
170 170 kwargs.update(sidebar(conf=conf))
171 171
172 172 return render(request, 'abs_conf.html', kwargs)
173 173
174 174
175 175 def abs_conf_edit(request, id_conf):
176 176
177 177 conf = get_object_or_404(ABSConfiguration, pk=id_conf)
178 178
179 179 beams = ABSBeam.objects.filter(abs_conf=conf)
180 180
181 181 if request.method=='GET':
182 182 form = ABSConfigurationForm(instance=conf)
183 183
184 184 if request.method=='POST':
185 185 form = ABSConfigurationForm(request.POST, instance=conf)
186 186
187 187 if form.is_valid():
188 188 conf = form.save(commit=False)
189 189 conf.save()
190 190 return redirect('url_abs_conf', id_conf=conf.id)
191 191
192 192 ###### SIDEBAR ######
193 193 kwargs = {}
194 194
195 195 kwargs['dev_conf'] = conf
196 196 #kwargs['id_dev'] = conf.id
197 197 kwargs['id_conf'] = conf.id
198 198 kwargs['form'] = form
199 199 kwargs['abs_beams'] = beams
200 200 kwargs['title'] = 'Device Configuration'
201 201 kwargs['suptitle'] = 'Edit'
202 202 kwargs['button'] = 'Save'
203 203
204 204 kwargs['edit'] = True
205 205
206 206 return render(request, 'abs_conf_edit.html', kwargs)
207 207
208 208 @csrf_exempt
209 209 def abs_conf_alert(request):
210 210
211 211 if request.method == 'POST':
212 212 print (request.POST)
213 213 return HttpResponse(json.dumps({'result':1}), content_type='application/json')
214 214 else:
215 215 return redirect('index')
216 216
217 217
218 218 def import_file(request, id_conf):
219 219
220 220 conf = get_object_or_404(ABSConfiguration, pk=id_conf)
221 221 if request.method=='POST':
222 222 form = ABSImportForm(request.POST, request.FILES)
223 223 if form.is_valid():
224 224 try:
225 225 parms = conf.import_from_file(request.FILES['file_name'])
226 226
227 227 if parms:
228 228 conf.update_from_file(parms)
229 229 messages.success(request, 'Configuration "%s" loaded succesfully' % request.FILES['file_name'])
230 230 return redirect(conf.get_absolute_url_edit())
231 231
232 232 except Exception as e:
233 233 messages.error(request, 'Error parsing file: "%s" - %s' % (request.FILES['file_name'], e))
234 234
235 235 else:
236 236 messages.warning(request, 'Your current configuration will be replaced')
237 237 form = ABSImportForm()
238 238
239 239 kwargs = {}
240 240 kwargs['form'] = form
241 241 kwargs['title'] = 'ABS Configuration'
242 242 kwargs['suptitle'] = 'Import file'
243 243 kwargs['button'] = 'Upload'
244 244 kwargs['previous'] = conf.get_absolute_url()
245 245
246 246 return render(request, 'abs_import.html', kwargs)
247 247
248 248
249 249 def send_beam(request, id_conf, id_beam):
250 250
251 251 conf = get_object_or_404(ABSConfiguration, pk=id_conf)
252 252
253 253 abs = Configuration.objects.filter(pk=conf.device.conf_active).first()
254 254 if abs!=conf:
255 255 url = '#' if abs is None else abs.get_absolute_url()
256 256 label = 'None' if abs is None else abs.label
257 257 messages.warning(
258 258 request,
259 259 mark_safe('The current configuration has not been written in the modules, the active configuration is <a href="{}">{}</a>'.format(
260 260 url,
261 261 label
262 262 ))
263 263 )
264 264 return redirect(conf.get_absolute_url())
265 265
266 266 beam = get_object_or_404(ABSBeam, pk=id_beam)
267 267
268 268 if request.method == 'POST':
269 269
270 270 beams_list = ABSBeam.objects.filter(abs_conf=conf)
271 271 conf.active_beam = id_beam
272 272
273 273 i = 0
274 274 for b in beams_list:
275 275 if b.id == int(id_beam):
276 276 break
277 277 else:
278 278 i += 1
279 279 beam_pos = i + 1 #Estandarizar
280 280 print ('%s Position: %s') % (beam.name, str(beam_pos))
281 281 conf.send_beam(beam_pos)
282 282
283 283 return redirect('url_abs_conf', conf.id)
284 284
285 285 kwargs = {
286 286 'title': 'ABS',
287 287 'suptitle': conf.label,
288 288 'message': 'Are you sure you want to change ABS Beam to: {}?'.format(beam.name),
289 289 'delete': False
290 290 }
291 291 kwargs['menu_configurations'] = 'active'
292 292
293 293 return render(request, 'confirm.html', kwargs)
294 294
295 295
296 296 def add_beam(request, id_conf):
297 297
298 298 conf = get_object_or_404(ABSConfiguration, pk=id_conf)
299 299 confs = Configuration.objects.all()
300 300
301 301 if request.method=='GET':
302 302 form = ABSBeamAddForm()
303 303
304 304 if request.method=='POST':
305 305 form = ABSBeamAddForm(request.POST)
306 306
307 307 beam_data = get_values_from_form(request.POST)
308 308
309 309 new_beam = ABSBeam(
310 310 name = beam_data['name'],
311 311 antenna = json.dumps(beam_data['antenna']),
312 312 abs_conf = conf,
313 313 tx = json.dumps(beam_data['tx']),
314 314 rx = json.dumps(beam_data['rx']),
315 315 ues = json.dumps(beam_data['ues']),
316 316 only_rx = json.dumps(beam_data['only_rx'])
317 317 )
318 318 new_beam.save()
319 319 messages.success(request, 'Beam: "%s" has been added.' % new_beam.name)
320 320
321 321 return redirect('url_edit_abs_conf', conf.id)
322 322
323 323 ###### SIDEBAR ######
324 324 kwargs = {}
325 325
326 326 #kwargs['dev_conf'] = conf.device
327 327 #kwargs['id_dev'] = conf.device
328 #kwargs['previous'] = conf.get_absolute_url_edit()
328 329 kwargs['id_conf'] = conf.id
329 330 kwargs['form'] = form
330 331 kwargs['title'] = 'ABS Beams'
331 332 kwargs['suptitle'] = 'Add Beam'
332 333 kwargs['button'] = 'Add'
333 334 kwargs['no_sidebar'] = True
334
335 #kwargs['previous'] = conf.get_absolute_url_edit()
336 335 kwargs['edit'] = True
337 336
338 337 return render(request, 'abs_add_beam.html', kwargs)
339 338
340 339
341 340 def edit_beam(request, id_conf, id_beam):
342 341
343 342 conf = get_object_or_404(ABSConfiguration, pk=id_conf)
344 343 beam = get_object_or_404(ABSBeam, pk=id_beam)
345 344
346 345 if request.method=='GET':
347 346 form = ABSBeamEditForm(initial={'beam': beam})
348 347
349 348 if request.method=='POST':
350 349 form = ABSBeamEditForm(request.POST)
351 350
352 351 beam_data = get_values_from_form(request.POST)
353 352
354 353 beam.dict_to_parms(beam_data)
355 354 beam.save()
356 355
357 356 messages.success(request, 'Beam: "%s" has been updated.' % beam.name)
358 357
359 358 return redirect('url_edit_abs_conf', conf.id)
360 359
361 360 ###### SIDEBAR ######
362 361 kwargs = {}
363 362
364 363 kwargs['id_conf'] = conf.id
365 364 kwargs['form'] = form
366 365 kwargs['title'] = 'ABS Beams'
367 366 kwargs['suptitle'] = 'Edit Beam'
368 367 kwargs['button'] = 'Save'
369 368 kwargs['no_sidebar'] = True
370 369
371 370 #kwargs['previous'] = conf.get_absolute_url_edit()
372 371 kwargs['edit'] = True
373 372
374 373 return render(request, 'abs_edit_beam.html', kwargs)
375 374
376 375
377 376
378 377 def remove_beam(request, id_conf, id_beam):
379 378
380 379 conf = get_object_or_404(ABSConfiguration, pk=id_conf)
381 380 beam = get_object_or_404(ABSBeam, pk=id_beam)
382 381
383 382 if request.method=='POST':
384 383 if beam:
385 384 try:
386 385 beam.delete()
387 386 messages.success(request, 'Beam: "%s" has been deleted.' % beam)
388 387 except:
389 388 messages.error(request, 'Unable to delete beam: "%s".' % beam)
390 389
391 390 return redirect('url_edit_abs_conf', conf.id)
392 391
393 392 ###### SIDEBAR ######
394 393 kwargs = {}
395 394
396 395 kwargs['object'] = beam
397 396 kwargs['delete'] = True
398 397 kwargs['title'] = 'Delete'
399 398 kwargs['suptitle'] = 'Beam'
400 399 kwargs['previous'] = conf.get_absolute_url_edit()
401 400 return render(request, 'confirm.html', kwargs)
402 401
403 402
404 403
405 404 def plot_patterns(request, id_conf, id_beam=None):
406 405
407 406 kwargs = {}
408 407 conf = get_object_or_404(ABSConfiguration, pk=id_conf)
409 408 beams = ABSBeam.objects.filter(abs_conf=conf)
410 409
411 410 if id_beam:
412 411 beam = get_object_or_404(ABSBeam, pk=id_beam)
413 412 kwargs['beam'] = beam
414 413
415 414 ###### SIDEBAR ######
416 415
417 416 kwargs['dev_conf'] = conf.device
418 417 kwargs['id_dev'] = conf.device
419 418 kwargs['id_conf'] = conf.id
420 419 kwargs['abs_beams'] = beams
421 420 kwargs['title'] = 'ABS Patterns'
422 421 kwargs['suptitle'] = conf.name
423 422 kwargs['no_sidebar'] = True
424 423
425 424 return render(request, 'abs_patterns.html', kwargs)
426 425
427 426
428 427 def plot_pattern(request, id_conf, id_beam, antenna):
429 428
430 429 if antenna=='down':
431 430 sleep(3)
432 431
433 432 conf = get_object_or_404(ABSConfiguration, pk=id_conf)
434 433 beam = get_object_or_404(ABSBeam, pk=id_beam)
435 434 just_rx = 1 if json.loads(beam.only_rx)[antenna] else 0
436 435 phases = json.loads(beam.antenna)['antenna_{}'.format(antenna)]
437 436 gain_tx = json.loads(beam.tx)[antenna]
438 437 gain_rx = json.loads(beam.rx)[antenna]
439 438 ues = json.loads(beam.ues)[antenna]
440 439 newOverJro = overJroShow(beam.name)
441 440 fig = newOverJro.plotPattern2(datetime.today(), phases, gain_tx, gain_rx, ues, just_rx)
442 441 buf = io.BytesIO()
443 442 fig.savefig(buf, format='png')
444 443 response = HttpResponse(buf.getvalue(), content_type='image/png')
445 444 return response
446 445
@@ -1,102 +1,111
1 1 import os
2 2
3 3 from django import forms
4 4 from apps.main.models import Device, Experiment
5 5 from .models import JARSConfiguration, JARSFilter
6 6 from .widgets import SpectralWidget
7 7 from apps.main.forms import add_empty_choice
8 8
9 9 def create_choices_from_model(model, filter_id=None):
10 10
11 11 #instance = globals()[model]
12 12 choices = model.objects.all().values_list('pk', 'name')
13 choices = add_empty_choice(choices)
13 choices = add_empty_choice(choices,label="New Choice")
14 14 return choices
15 15
16 16 class JARSConfigurationForm(forms.ModelForm):
17 17 def __init__(self, *args, **kwargs):
18 18 super(JARSConfigurationForm, self).__init__(*args, **kwargs)
19 19 instance = getattr(self, 'instance', None)
20 20
21 21 if instance and instance.pk:
22 22 devices = Device.objects.filter(device_type__name='jars')
23 23 self.fields['device'].widget.choices = [(device.id, device) for device in devices]
24 24 self.fields['spectral_number'].widget.attrs['readonly'] = True
25 25 self.fields['spectral'].widget = SpectralWidget()
26 26
27 27 class Meta:
28 28 model = JARSConfiguration
29 29 exclude = ('type', 'parameters', 'status', 'filter_parms', 'author', 'hash', 'filter')
30 30
31 31 class JARSFilterForm(forms.ModelForm):
32 32 def __init__(self, *args, **kwargs):
33 33 super(JARSFilterForm, self).__init__(*args, **kwargs)
34 34 instance = getattr(self, 'instance', None)
35 35
36 36 self.fields['f_decimal'].widget.attrs['readonly'] = True
37 37
38 38 if 'initial' in kwargs:
39 39 self.fields['filter_template'] = forms.ChoiceField(
40 40 choices=create_choices_from_model(JARSFilter),
41 41 initial = kwargs['initial']['id']
42 42 )
43 43 # self.fields['name'].initial = kwargs['initial']['id']
44 44
45 45 # filter_id = kwargs['initial']['filter_id']
46 46
47 47 # if filter_id == 0:
48 48 # for value in self.fields:
49 49 # if value != 'name':
50 50 # self.fields.pop(value)
51 51 # self.fields['name'].label = "Filter Template Name"
52 52 # else:
53 53 # self.fields['name'] = forms.ChoiceField(choices=create_choices_from_model(JARSFilter, kwargs['initial']['filter_id']))
54 54 # jars_filter = JARSFilter.objects.get(pk=kwargs['initial']['filter_id'])
55 55 # labels = [f.name for f in jars_filter._meta.get_fields()]
56 56
57 57 # for label in ['id']:
58 58 # labels.remove(label)
59 59 # for label in labels:
60 60 # self.fields['name'].initial = kwargs['initial']['filter_id']
61 61 # self.fields[label].initial = getattr(jars_filter,label)
62 62 # self.fields['name'].label = "Filter Template Name"
63 63
64 64 class Meta:
65 65 model = JARSFilter
66 66 exclude = ('name', )
67 67
68 class JARSFilterFormNew(forms.ModelForm):
69 def __init__(self, *args, **kwargs):
70 super(JARSFilterFormNew, self).__init__(*args, **kwargs)
71
72 self.fields['f_decimal'].widget.attrs['readonly'] = True
73
74 class Meta:
75 model = JARSFilter
76 exclude = ()
68 77
69 78 class ExtFileField(forms.FileField):
70 79 """
71 80 Same as forms.FileField, but you can specify a file extension whitelist.
72 81
73 82 >>> from django.core.files.uploadedfile import SimpleUploadedFile
74 83 >>>
75 84 >>> t = ExtFileField(ext_whitelist=(".pdf", ".txt"))
76 85 >>>
77 86 >>> t.clean(SimpleUploadedFile('filename.pdf', 'Some File Content'))
78 87 >>> t.clean(SimpleUploadedFile('filename.txt', 'Some File Content'))
79 88 >>>
80 89 >>> t.clean(SimpleUploadedFile('filename.exe', 'Some File Content'))
81 90 Traceback (most recent call last):
82 91 ...
83 92 ValidationError: [u'Not allowed filetype!']
84 93 """
85 94 def __init__(self, *args, **kwargs):
86 95 extensions = kwargs.pop("extensions")
87 96 self.extensions = [i.lower() for i in extensions]
88 97
89 98 super(ExtFileField, self).__init__(*args, **kwargs)
90 99
91 100 def clean(self, *args, **kwargs):
92 101 data = super(ExtFileField, self).clean(*args, **kwargs)
93 102 filename = data.name
94 103 ext = os.path.splitext(filename)[1]
95 104 ext = ext.lower()
96 105 if ext not in self.extensions:
97 106 raise forms.ValidationError('Not allowed file type: %s' % ext)
98 107
99 108
100 109 class JARSImportForm(forms.Form):
101 110
102 111 file_name = ExtFileField(extensions=['.racp','.json'])
@@ -1,389 +1,404
1 1 import json
2 2 import requests
3 3
4 4 from django.db import models
5 5 from django.core.validators import MinValueValidator, MaxValueValidator
6 6 from django.urls import reverse
7 7
8 8 from apps.main.models import Configuration
9 9 from apps.main.utils import Params
10 10 from .utils import create_jarsfiles
11 11
12 12 # Create your models here.
13 13
14 14 EXPERIMENT_TYPE = (
15 15 (0, 'RAW_DATA'),
16 16 (1, 'PDATA'),
17 17 )
18 18
19 19 DATA_TYPE = (
20 20 (0, 'SHORT'),
21 21 (1, 'FLOAT'),
22 22 )
23 23
24 24 DECODE_TYPE = (
25 25 (0, 'None'),
26 26 (1, 'TimeDomain'),
27 27 (2, 'FreqDomain'),
28 28 (3, 'InvFreqDomain'),
29 29 )
30 30
31 31 FILTER = '{"id":1, "clock": 60, "multiplier": 5, "frequency": 49.92, "f_decimal": 721554506, "fir": 2, "cic_2": 12, "cic_5": 25}'
32 32
33 33 class JARSFilter(models.Model):
34 34
35 35 JARS_NBITS = 32
36 36
37 37 name = models.CharField(verbose_name='Name', max_length=60, unique=True, default='')
38 38 clock = models.FloatField(verbose_name='Clock In (MHz)', validators=[
39 39 MinValueValidator(5), MaxValueValidator(75)], null=True, default=60)
40 40 multiplier = models.PositiveIntegerField(verbose_name='Multiplier', validators=[
41 41 MinValueValidator(1), MaxValueValidator(20)], default=5)
42 42 frequency = models.FloatField(verbose_name='Frequency (MHz)', validators=[
43 43 MaxValueValidator(150)], null=True, default=49.9200)
44 44 f_decimal = models.BigIntegerField(verbose_name='Frequency (Decimal)', validators=[
45 45 MinValueValidator(-9223372036854775808), MaxValueValidator(2**JARS_NBITS-1)], null=True, default=721554505)
46 46 cic_2 = models.PositiveIntegerField(verbose_name='CIC2', validators=[
47 47 MinValueValidator(2), MaxValueValidator(100)], default=10)
48 48 scale_cic_2 = models.PositiveIntegerField(verbose_name='Scale CIC2', validators=[
49 49 MinValueValidator(0), MaxValueValidator(6)], default=1)
50 50 cic_5 = models.PositiveIntegerField(verbose_name='CIC5', validators=[
51 51 MinValueValidator(1), MaxValueValidator(100)], default=1)
52 52 scale_cic_5 = models.PositiveIntegerField(verbose_name='Scale CIC5', validators=[
53 53 MinValueValidator(0), MaxValueValidator(20)], default=5)
54 54 fir = models.PositiveIntegerField(verbose_name='FIR', validators=[
55 55 MinValueValidator(1), MaxValueValidator(100)], default=6)
56 56 scale_fir = models.PositiveIntegerField(verbose_name='Scale FIR', validators=[
57 57 MinValueValidator(0), MaxValueValidator(7)], default=3)
58 58 number_taps = models.PositiveIntegerField(verbose_name='Number of taps', validators=[
59 59 MinValueValidator(1), MaxValueValidator(256)], default=4)
60 60 taps = models.CharField(verbose_name='Taps', max_length=1600, default='0')
61 61
62 62 class Meta:
63 63 db_table = 'jars_filters'
64 64
65 65 def __unicode__(self):
66 66 return u'%s' % (self.name)
67 67
68 68 def jsonify(self):
69 69
70 70 data = {}
71 71 ignored = ()
72 72
73 73 for field in self._meta.fields:
74 74 if field.name in ignored:
75 75 continue
76 76 data[field.name] = field.value_from_object(self)
77 77
78 78 return data
79 79
80 80 def parms_to_dict(self):
81 81
82 82 parameters = {}
83 83
84 84 parameters['name'] = self.name
85 85 parameters['clock'] = float(self.clock)
86 86 parameters['multiplier'] = int(self.multiplier)
87 87 parameters['frequency'] = float(self.frequency)
88 88 parameters['f_decimal'] = int(self.frequency)
89 89 parameters['fir'] = int(self.fir)
90 90 parameters['cic_2'] = int(self.cic_2)
91 91 parameters['cic_5'] = int(self.cic_5)
92 92
93 93 return parameters
94 94
95 95 def dict_to_parms(self, parameters):
96 96
97 97 self.name = parameters['name']
98 98 self.clock = parameters['clock']
99 99 self.multiplier = parameters['multiplier']
100 100 self.frequency = parameters['frequency']
101 101 self.f_decimal = parameters['f_decimal']
102 102 self.fir = parameters['fir']
103 103 self.cic_2 = parameters['cic_2']
104 104 self.cic_5 = parameters['cic_5']
105 105
106 def dict_to_parms_new(self, parameters):
107
108 self.name = parameters['name']
109 self.clock = parameters['clock']
110 self.multiplier = parameters['multiplier']
111 self.frequency = parameters['frequency']
112 self.f_decimal = parameters['f_decimal']
113 self.fir = parameters['fir']
114 self.cic_2 = parameters['cic_2']
115 self.cic_5 = parameters['cic_5']
116 self.scale_fir = parameters['scale_fir']
117 self.scale_cic_2 = parameters['scale_cic_2']
118 self.scale_cic_5 = parameters['scale_cic_5']
119 self.number_taps = parameters['number_taps']
120 self.taps = parameters['taps']
106 121
107 122 class JARSConfiguration(Configuration):
108 123
109 124 ADC_RESOLUTION = 8
110 125 PCI_DIO_BUSWIDTH = 32
111 126 HEADER_VERSION = 1103
112 127 BEGIN_ON_START = True
113 128 REFRESH_RATE = 1
114 129
115 130 exp_type = models.PositiveIntegerField(
116 131 verbose_name='Experiment Type', choices=EXPERIMENT_TYPE, default=0)
117 132 cards_number = models.PositiveIntegerField(verbose_name='Number of Cards', validators=[
118 133 MinValueValidator(1), MaxValueValidator(4)], default=1)
119 134 channels_number = models.PositiveIntegerField(verbose_name='Number of Channels', validators=[
120 135 MinValueValidator(1), MaxValueValidator(8)], default=5)
121 136 channels = models.CharField(
122 137 verbose_name='Channels', max_length=15, default='1,2,3,4,5')
123 138 data_type = models.PositiveIntegerField(
124 139 verbose_name='Data Type', choices=DATA_TYPE, default=0)
125 140 raw_data_blocks = models.PositiveIntegerField(
126 141 verbose_name='Raw Data Blocks', validators=[MaxValueValidator(5000)], default=60)
127 142 profiles_block = models.PositiveIntegerField(
128 143 verbose_name='Profiles Per Block', default=400)
129 144 acq_profiles = models.PositiveIntegerField(
130 145 verbose_name='Acquired Profiles', default=400)
131 146 ftp_interval = models.PositiveIntegerField(
132 147 verbose_name='FTP Interval', default=60)
133 148 fftpoints = models.PositiveIntegerField(
134 149 verbose_name='FFT Points', default=16)
135 150 cohe_integr_str = models.PositiveIntegerField(
136 151 verbose_name='Coh. Int. Stride', validators=[MinValueValidator(1)], default=30)
137 152 cohe_integr = models.PositiveIntegerField(
138 153 verbose_name='Coherent Integrations', validators=[MinValueValidator(1)], default=30)
139 154 incohe_integr = models.PositiveIntegerField(
140 155 verbose_name='Incoherent Integrations', validators=[MinValueValidator(1)], default=30)
141 156 decode_data = models.PositiveIntegerField(
142 157 verbose_name='Decode Data', choices=DECODE_TYPE, default=0)
143 158 post_coh_int = models.BooleanField(
144 159 verbose_name='Post Coherent Integration', default=False)
145 160 spectral_number = models.PositiveIntegerField(
146 161 verbose_name='# Spectral Combinations', validators=[MinValueValidator(1)], default=1)
147 162 spectral = models.CharField(
148 163 verbose_name='Combinations', max_length=5000, default='[0, 0],')
149 164 create_directory = models.BooleanField(
150 165 verbose_name='Create Directory Per Day', default=True)
151 166 include_expname = models.BooleanField(
152 167 verbose_name='Experiment Name in Directory', default=False)
153 168 #view_raw_data = models.BooleanField(verbose_name='View Raw Data', default=True)
154 169 save_ch_dc = models.BooleanField(
155 170 verbose_name='Save Channels DC', default=True)
156 171 save_data = models.BooleanField(verbose_name='Save Data', default=True)
157 172 filter_parms = models.CharField(
158 173 max_length=10000, default=FILTER)
159 174 filter = models.ForeignKey(
160 175 'JARSFilter', verbose_name='Filter', null=True, blank=True, on_delete=models.CASCADE)
161 176
162 177 class Meta:
163 178 db_table = 'jars_configurations'
164 179
165 180 def filter_resolution(self):
166 181 filter_parms = json.loads(self.filter_parms)
167 182 clock = float(filter_parms['clock'])
168 183 cic_2 = filter_parms['cic_2']
169 184 cic_5 = filter_parms['cic_5']
170 185 fir = filter_parms['fir']
171 186 resolution = round((clock/(cic_2*cic_5*fir)), 2)
172 187 return resolution
173 188
174 189 def dict_to_parms(self, params, id=None):
175 190
176 191 if id is not None:
177 192 data = Params(params).get_conf(id_conf=id)
178 193 else:
179 194 data = Params(params).get_conf(dtype='jars')
180 195 data['filter_parms'] = params['filter_parms']
181 196
182 197 # self.name = data['name']
183 198 self.exp_type = data['exp_type']
184 199 #----PDATA----
185 200 if self.exp_type == 1:
186 201 self.incohe_integr = data['incohe_integr']
187 202 self.spectral_number = data['spectral_number']
188 203 self.spectral = data['spectral']
189 204 self.fftpoints = data['fftpoints']
190 205 self.save_ch_dc = data['save_ch_dc']
191 206 else:
192 207 self.raw_data_blocks = data['raw_data_blocks']
193 208 #----PDATA----
194 209 self.cards_number = data['cards_number']
195 210 self.channels_number = data['channels_number']
196 211 self.channels = data['channels']
197 212 self.data_type = data['data_type']
198 213 self.profiles_block = data['profiles_block']
199 214 self.acq_profiles = data['acq_profiles']
200 215 self.ftp_interval = data['ftp_interval']
201 216 self.cohe_integr_str = data['cohe_integr_str']
202 217 self.cohe_integr = data['cohe_integr']
203 218 #----DECODE----
204 219 self.decode_data = data['decode_data']
205 220 self.post_coh_int = data['post_coh_int']
206 221 #----DECODE----
207 222 self.create_directory = data['create_directory']
208 223 self.include_expname = data['include_expname']
209 224 self.save_data = data['save_data']
210 225 self.filter_parms = json.dumps(data['filter_parms'])
211 226
212 227 self.save()
213 228
214 229 def parms_to_text(self, file_format='jars'):
215 230
216 231 data = self.experiment.parms_to_dict()
217 232
218 233 for key in data['configurations']['allIds']:
219 234 if data['configurations']['byId'][key]['device_type'] in ('dds', 'cgs'):
220 235 data['configurations']['allIds'].remove(key)
221 236 data['configurations']['byId'].pop(key)
222 237 elif data['configurations']['byId'][key]['device_type'] == 'jars':
223 238 data['configurations']['byId'][key] = self.parms_to_dict(
224 239 )['configurations']['byId'][str(self.pk)]
225 240 elif data['configurations']['byId'][key]['device_type'] == 'rc':
226 241 data['configurations']['byId'][key]['pulses'] = ''
227 242 data['configurations']['byId'][key]['delays'] = ''
228 243 rc_ids = [pk for pk in data['configurations']['allIds']
229 244 if data['configurations']['byId'][pk]['device_type'] == 'rc']
230 245 mix_ids = [pk for pk in rc_ids if data['configurations']
231 246 ['byId'][pk]['mix']]
232 247
233 248 if mix_ids:
234 249 params = data['configurations']['byId'][mix_ids[0]]['parameters']
235 250 rc = data['configurations']['byId'][params.split(
236 251 '-')[0].split('|')[0]]
237 252 rc['mix'] = True
238 253 data['configurations']['byId'][rc['id']] = rc
239 254 elif len(rc_ids) == 0:
240 255 self.message = 'File needs RC configuration'
241 256 return ''
242 257
243 258 json_data = json.dumps(data)
244 259 racp_file, filter_file = create_jarsfiles(json_data)
245 260 if file_format == 'racp':
246 261 return racp_file
247 262
248 263 return filter_file
249 264
250 265 def request(self, cmd, method='get', **kwargs):
251 266
252 267 req = getattr(requests, method)(self.device.url(cmd), **kwargs)
253 268 payload = req.json()
254 269 return payload
255 270
256 271 def status_device(self):
257 272
258 273 try:
259 274 payload = self.request('status',
260 275 params={'name': self.experiment.name})
261 276 self.device.status = payload['status']
262 277 self.device.save()
263 278 self.message = payload['message']
264 279 except Exception as e:
265 280 self.device.status = 0
266 281 self.message = str(e)
267 282 self.device.save()
268 283 return False
269 284
270 285 return True
271 286
272 287 def stop_device(self):
273 288
274 289 try:
275 290 payload = self.request('stop', 'post')
276 291 self.device.status = payload['status']
277 292 self.device.save()
278 293 self.message = payload['message']
279 294 except Exception as e:
280 295 self.device.status = 0
281 296 self.message = str(e)
282 297 self.device.save()
283 298 return False
284 299
285 300 return True
286 301
287 302 def read_device(self):
288 303
289 304 try:
290 305 payload = self.request(
291 306 'read', params={'name': self.experiment.name})
292 307 self.message = 'Configuration loaded'
293 308 except:
294 309 self.device.status = 0
295 310 self.device.save()
296 311 self.message = 'Could not read JARS configuration.'
297 312 return False
298 313
299 314 return payload
300 315
301 316 def write_device(self):
302 317
303 318 if self.device.status == 3:
304 319 self.message = 'Could not configure device. Software Acquisition is running'
305 320 return False
306 321
307 322 data = self.experiment.parms_to_dict()
308
323 #print(data)
309 324 for key in data['configurations']['allIds']:
310 325 if data['configurations']['byId'][key]['device_type'] in ('dds', 'cgs'):
311 326 data['configurations']['allIds'].remove(key)
312 327 data['configurations']['byId'].pop(key)
313 328 elif data['configurations']['byId'][key]['device_type'] == 'rc':
314 329 data['configurations']['byId'][key]['pulses'] = ''
315 330 data['configurations']['byId'][key]['delays'] = ''
316 331 rc_ids = [pk for pk in data['configurations']['allIds']
317 332 if data['configurations']['byId'][pk]['device_type'] == 'rc']
318 333 if len(rc_ids) == 0:
319 334 self.message = 'Missing RC configuration'
320 335 return False
321 336
322 337 json_data = json.dumps(data)
323 338
324 339 try:
325 340 payload = self.request('write', 'post', json=json_data)
326 341 self.device.status = payload['status']
327 342 self.message = payload['message']
328 343 self.device.save()
329 344 if self.device.status == 1:
330 345 return False
331 346
332 347 except Exception as e:
333 348 self.device.status = 0
334 349 self.message = str(e)
335 350 self.device.save()
336 351 return False
337 352
338 353 return True
339 354
340 355 def start_device(self):
341 356
342 357 try:
343 358 payload = self.request('start', 'post',
344 359 json={'name': self.experiment.name})
345 360 self.device.status = payload['status']
346 361 self.message = payload['message']
347 362 self.device.save()
348 363 if self.device.status == 1:
349 364 return False
350 365
351 366 except Exception as e:
352 367 self.device.status = 0
353 368 self.message = str(e)
354 369 self.device.save()
355 370 return False
356 371
357 372 return True
358 373
359 374 def get_log(self):
360 375
361 376 payload = None
362 377
363 378 try:
364 379 payload = requests.get(self.device.url('get_log'), params={
365 380 'name': self.experiment.name})
366 381 except:
367 382 self.device.status = 0
368 383 self.device.save()
369 384 self.message = 'Jars API is not running.'
370 385 return False
371 386
372 387 self.message = 'Jars API is running'
373 388
374 389 return payload
375 390
376 391 def update_from_file(self, filename):
377 392
378 393 f = JARSFile(filename)
379 394 self.dict_to_parms(f.data)
380 395 self.save()
381 396
382 397 def get_absolute_url_import(self):
383 398 return reverse('url_import_jars_conf', args=[str(self.id)])
384 399
385 400 def get_absolute_url_read(self):
386 401 return reverse('url_read_jars_conf', args=[str(self.id)])
387 402
388 403 def get_absolute_url_log(self):
389 404 return reverse('url_get_jars_log', args=[str(self.id)])
@@ -1,20 +1,20
1 1 {% extends "base.html" %}
2 {% load bootstrap3 %}
2 {% load bootstrap4 %}
3 3 {% block mainactive %}active{% endblock %}
4 4
5 5 {% block content-title %}Acquisition System{% endblock %}
6 6 {% block content-suptitle %}JARS{% endblock %}
7 7
8 8 {% block content %}
9 9 <form class="form" method="post" action="">
10 10 {% csrf_token %}
11 11 {% bootstrap_form form layout='horizontal' size='medium' %}
12 12 <div style="clear: both;"></div>
13 13 <br>
14 14 <button type="submit" class="btn btn-primary pull-right" id="bt_update">Update</button>
15 15 </form>
16 16 {% endblock %}
17 17
18 18 {% block sidebar%}
19 19 {% include "sidebar_devices.html" %}
20 20 {% endblock %}
@@ -1,25 +1,25
1 1 {% extends "dev_conf.html" %}
2 2 {% load static %}
3 {% load bootstrap3 %}
3 {% load bootstrap4 %}
4 4 {% load main_tags %}
5 5
6 6 {% block extra-menu-actions %}
7 7 <li><a href="{{ dev_conf.get_absolute_url_log }}"><span class="fas fa-save" aria-hidden="true"></span>
8 8 Get Log File</a></li>
9 9 {% endblock %}
10 10
11 11 {% block extra-content %}
12 12
13 13 <div class="clearfix"></div>
14 14 <h2>Filter: {{resolution}}</h2>
15 15 <br>
16 16 <table class="table table-bordered">
17 17 {% for key in filter_keys %}
18 18 <tr>
19 19 <th>{% get_verbose_field_name filter_obj key %}</th>
20 20 <td>{{filter|attr:key}}</td>
21 21 </tr>
22 22 {% endfor %}
23 23 </table>
24 24
25 25 {% endblock extra-content%} No newline at end of file
@@ -1,40 +1,43
1 1 {% extends "dev_conf_edit.html" %}
2 {% load bootstrap3 %}
2 {% load bootstrap4 %}
3 3 {% load static %}
4 4 {% load main_tags %}
5 5
6 6 {% block content %}
7 7 <form class="form" method="post">
8 8 {% csrf_token %}
9 9 {% bootstrap_form form layout='horizontal' size='medium' %}
10 10 <div style="clear: both;"></div>
11 11 <h2>Filter <small>{{filter_name}}</small></h2>
12 12 <br>
13 13 {% bootstrap_form filter_form layout='horizontal' size='medium' %}
14 14 <div style="clear: both;"></div>
15 15 <br>
16 16 <div class="pull-right">
17 17 <button type="button" class="btn btn-primary" onclick="{% if previous %}window.location.replace('{{ previous }}');{% else %}history.go(-1);{% endif %}">Cancel</button>
18 18 <button type="submit" class="btn btn-primary">{{button}}</button>
19 19 </div>
20 20
21 21 <div style="clear: both;"></div>
22 22 <br>
23 23 </form>
24 24 {% endblock %}
25 25
26 26 {% block extra-js%}
27 27 <script src="{% static 'js/jars.js' %}"></script>
28 28 <script src="{% static 'js/filters.js' %}"></script>
29 29 <script type="text/javascript">
30 30
31 31 $("#bt_cancel").click(function () {
32 32 document.location = "{% url 'url_jars_conf' id_dev %}";
33 33 });
34 34
35 35 $("#id_filter_template").change(function () {
36 if($("#id_filter_template").val()!=0)
36 37 document.location = "{% url 'url_change_jars_filter' id_dev %}" + $("#id_filter_template").val();
38 else
39 document.location = "{% url 'url_new_jars_filter' id_dev %}"
37 40 });
38 41
39 42 </script>
40 43 {% endblock %} No newline at end of file
@@ -1,13 +1,14
1 1 from django.urls import path
2 2
3 3 from . import views
4 4
5 5 urlpatterns = (
6 6 path('<int:id_conf>/', views.jars_conf, name='url_jars_conf'),
7 7 path('<int:id_conf>/edit/', views.jars_conf_edit, name='url_edit_jars_conf'),
8 8 path('<int:conf_id>/change_filter/', views.change_filter, name='url_change_jars_filter'),
9 9 path('<int:conf_id>/change_filter/<int:filter_id>/', views.change_filter, name='url_change_jars_filter'),
10 path('<int:conf_id>/new_filter/', views.new_filter, name='url_new_jars_filter'),
10 11 path('<int:conf_id>/import/', views.import_file, name='url_import_jars_conf'),
11 12 path('<int:conf_id>/read/', views.read_conf, name='url_read_jars_conf'),
12 13 path('<int:conf_id>/get_log/', views.get_log, name='url_get_jars_log'),
13 14 )
@@ -1,194 +1,221
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 from .forms import JARSConfigurationForm, JARSFilterForm, JARSImportForm
11 from .forms import JARSConfigurationForm, JARSFilterForm, JARSImportForm,JARSFilterFormNew
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
64 63 filter_parms = json.loads(conf.filter_parms)
65 64
66 65 if request.method=='GET':
67 66 form = JARSConfigurationForm(instance=conf)
68 67 filter_form = JARSFilterForm(initial=filter_parms)
69 68
70 69 if request.method=='POST':
71 70 form = JARSConfigurationForm(request.POST, instance=conf)
72 71 filter_form = JARSFilterForm(request.POST)
73 72
74 73 if filter_form.is_valid():
75 74 jars_filter = filter_form.cleaned_data
76 75 jars_filter['id'] = request.POST['filter_template']
77 76 else:
78 77 messages.error(request, filter_form.errors)
79 78
80 79 if form.is_valid():
81 80 conf = form.save(commit=False)
82 81 conf.filter_parms = json.dumps(jars_filter)
83 82 conf.save()
84 83 return redirect('url_jars_conf', id_conf=conf.id)
85 84
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
162 def new_filter(request, conf_id):
163 conf = get_object_or_404(JARSConfiguration, pk=conf_id)
164 form = JARSFilterFormNew()
165
166 if request.method=='POST':
167 filter_form = JARSFilterFormNew(request.POST)
168
169 if filter_form.is_valid():
170 jars_filter = filter_form.cleaned_data
171 jars_filter['id'] = request.POST['name']
172 else:
173 messages.error(request, filter_form.errors)
174
175 #print(json.dumps(jars_filter))
176 jars_filter_obj = JARSFilter()
177 jars_filter_obj.dict_to_parms_new(request.POST)
178 jars_filter_obj.save()
179 return redirect('url_edit_jars_conf', id_conf=conf.id)
180
181 kwargs = {}
182 kwargs['id_dev'] = conf.id
183 kwargs['form'] = form
184 kwargs['title'] = 'New JARS Filter'
185 kwargs['suptitle'] = 'Parameters'
186 kwargs['button'] = 'Save'
187
188 return render(request, 'jars_new_filter.html', kwargs)
189
163 190 def change_filter(request, conf_id, filter_id):
164 191
165 192 conf = get_object_or_404(JARSConfiguration, pk=conf_id)
166 193 filter = get_object_or_404(JARSFilter, pk=filter_id)
167 194 conf.filter_parms = json.dumps(filter.jsonify())
168 195 conf.save()
169 196
170 197 return redirect('url_edit_jars_conf', id_conf=conf.id)
171 198
172 199 def get_log(request, conf_id):
173 200
174 201 conf = get_object_or_404(JARSConfiguration, pk=conf_id)
175 202 response = conf.get_log()
176 203
177 204 if not response:
178 205 message = conf.message
179 206 messages.error(request, message)
180 207 return redirect('url_jars_conf', id_conf=conf.id)
181 208
182 209 try:
183 210 message = response.json()['message']
184 211 messages.error(request, message)
185 212 return redirect('url_jars_conf', id_conf=conf.id)
186 213 except Exception as e:
187 message = 'Restarting Report.txt has been downloaded successfully.'
214 message = 'Restarting Report.txt has been downloaded successfully.'+e
188 215
189 216 content = response
190 217 filename = 'Log_%s_%s.txt' %(conf.experiment.name, conf.experiment.id)
191 218 response = HttpResponse(content,content_type='text/plain')
192 219 response['Content-Disposition'] = 'attachment; filename="%s"' %filename
193 220
194 221 return response
@@ -1,165 +1,165
1 1
2 2 import ast
3 3 import json
4 4 from itertools import chain
5 5
6 6 from django import forms
7 7 from django.utils.safestring import mark_safe
8 8 from django.utils.html import conditional_escape
9 9
10 10
11 11 class SpectralWidget(forms.widgets.TextInput):
12 12
13 def render(self, label, value, attrs=None):
14
13 def render(self, name, value, attrs=None, renderer=None):
14 label = name
15 15 readonly = 'readonly' if attrs.get('readonly', False) else ''
16 16 name = attrs.get('name', label)
17 17 if value == None:
18 18 value = '[0, 0],'
19 19 if '[' in value:
20 20 if value[len(value)-1] == ",":
21 21 value = ast.literal_eval(value)
22 22 else:
23 23 value = value + ","
24 24 value = ast.literal_eval(value)
25 25
26 26 codes = value
27 27 if not isinstance(value, list):
28 28 text=''
29 29 #lista = []
30 30 #if len(value) > 1:
31 31 for val in value:
32 32 text = text+str(val)+','
33 33 #lista.append(val)
34 34 codes=text
35 35 else:
36 36 codes=''
37 37
38 38 html = '''<textarea rows="5" {0} class="form-control" id="id_{1}" name="{2}" style="white-space:nowrap; overflow:scroll;">{3}</textarea>
39 39 <input type="text" class="col-md-1 col-no-padding" id="num1" value=0>
40 40 <input type="text" class="col-md-1 col-no-padding" id="num2" value=0>
41 41 <button type="button" class="button" id="add_spectral_button"> Add </button>
42 42 <button type="button" class="button" id="delete_spectral_button"> Delete </button>
43 43 <button type="button" class="button pull-right" id="cross_spectral_button"> Cross </button>
44 44 <button type="button" class="button pull-right" id="self_spectral_button"> Self </button>
45 45 <button type="button" class="button pull-right" id="all_spectral_button"> All </button>
46 46 '''.format(readonly, label, name, codes)
47 47
48 48 script = '''
49 49 <script type="text/javascript">
50 50 $(document).ready(function () {{
51 51
52 52 var spectral_number1 = $("#num1").val();
53 53 var spectral_number2 = $("#num2").val();
54 54
55 55
56 56 $("#all_spectral_button").click(function(){{
57 57 var sequence1 = selfSpectral()
58 58 var sequence2 = crossSpectral()
59 59 $("#id_spectral").val(sequence1+sequence2)
60 60 updateSpectralNumber()
61 61 }});
62 62
63 63
64 64 $("#add_spectral_button").click(function(){{
65 65 var spectral_comb = $("#id_spectral").val();
66 66 var spectral_number1 = $("#num1").val();
67 67 var spectral_number2 = $("#num2").val();
68 68 var str = spectral_number1+", "+spectral_number2;
69 69 //not to duplicate
70 70 var n = spectral_comb.search(str);
71 71 if (n==-1){
72 72 $("#id_spectral").val(spectral_comb+"["+$("#num1").val()+", "+$("#num2").val()+"],")
73 73 }
74 74 updateSpectralNumber()
75 75 }});
76 76
77 77
78 78 $("#self_spectral_button").click(function(){{
79 79 var sequence = selfSpectral()
80 80 $("#id_spectral").val(sequence)
81 81
82 82 updateSpectralNumber()
83 83 }});
84 84
85 85 $("#cross_spectral_button").click(function(){{
86 86 var sequence = crossSpectral()
87 87 $("#id_spectral").val(sequence)
88 88
89 89 updateSpectralNumber()
90 90 }});
91 91
92 92
93 93 function selfSpectral() {
94 94 var channels = $("#id_channels").val();
95 95 var n = (channels.length)-1;
96 96 var num = parseInt(channels[n]);
97 97 sequence = ""
98 98 for (i = 0; i < num; i++) {
99 99 sequence = sequence + "[" + i.toString() + ", " + i.toString() + "],"
100 100 }
101 101 return sequence
102 102 }
103 103
104 104
105 105 function crossSpectral() {
106 106 var channels = $("#id_channels").val();
107 107 var n = (channels.length)-1;
108 108 var num = parseInt(channels[n]);
109 109 sequence = ""
110 110 for (i = 0; i < num; i++) {
111 111 for (j = i+1; j < num; j++) {
112 112 sequence = sequence + "[" + i.toString() + ", " + j.toString() + "],"
113 113 }
114 114 }
115 115 return sequence
116 116 }
117 117
118 118
119 119 function updateSpectralNumber(){
120 120 var spectral_comb = $("#id_spectral").val();
121 121 var num = spectral_comb.length;
122 122 var cont = 0
123 123 for (i = 0; i < num; i++) {
124 124 if (spectral_comb[i] == "]"){
125 125 cont = cont + 1
126 126 }
127 127 }
128 128 $("#id_spectral_number").val(cont)
129 129 }
130 130
131 131
132 132 $("#delete_spectral_button").click(function(){{
133 133 var spectral_comb = $("#id_spectral").val();
134 134 var spectral_number1 = $("#num1").val();
135 135 var spectral_number2 = $("#num2").val();
136 136 var str = spectral_number1+", "+spectral_number2;
137 137 var n = spectral_comb.search(str);
138 138 if (n==-1){
139 139
140 140 }
141 141 else {
142 142 n= spectral_comb.length;
143 143 if (n<8){
144 144 var tuple = "["+$("#num1").val()+", "+$("#num2").val()+"],"
145 145 var txt = spectral_comb.replace(tuple,'');
146 146 }
147 147 else {
148 148 var tuple = ",["+$("#num1").val()+", "+$("#num2").val()+"]"
149 149 var txt = spectral_comb.replace(tuple,'');
150 150 }
151 151 $("#id_spectral").val(txt)
152 152
153 153 var tuple = "["+$("#num1").val()+", "+$("#num2").val()+"],"
154 154 var txt = spectral_comb.replace(tuple,'');
155 155 $("#id_spectral").val(txt)
156 156 }
157 157 updateSpectralNumber()
158 158 }});
159 159
160 160
161 161 }});
162 162 </script>
163 163 '''
164 164
165 165 return mark_safe(html+script)
@@ -1,808 +1,816
1 1
2 2 import os
3 3 import json
4 4 import requests
5 5 import time
6 6 from datetime import datetime
7 7
8 8 try:
9 9 from polymorphic.models import PolymorphicModel
10 10 except:
11 11 from polymorphic import PolymorphicModel
12 12
13 13 from django.template.base import kwarg_re
14 14 from django.db import models
15 15 from django.urls import reverse
16 16 from django.core.validators import MinValueValidator, MaxValueValidator
17 17 from django.shortcuts import get_object_or_404
18 18 from django.contrib.auth.models import User
19 19 from django.db.models.signals import post_save
20 20 from django.dispatch import receiver
21 21
22 22 from apps.main.utils import Params
23 23 from apps.rc.utils import RCFile
24 24 from apps.jars.utils import RacpFile
25 25 from devices.dds import api as dds_api
26 26 from devices.dds import data as dds_data
27 27
28 28
29 29 DEV_PORTS = {
30 30 'rc' : 2000,
31 31 'dds' : 2000,
32 32 'jars' : 2000,
33 33 'usrp' : 2000,
34 34 'cgs' : 8080,
35 35 'abs' : 8080,
36 36 'dds_rest': 80
37 37 }
38 38
39 39 RADAR_STATES = (
40 40 (0, 'No connected'),
41 41 (1, 'Connected'),
42 42 (2, 'Configured'),
43 43 (3, 'Running'),
44 44 (4, 'Scheduled'),
45 45 )
46 46
47 47 EXPERIMENT_TYPE = (
48 48 (0, 'RAW_DATA'),
49 49 (1, 'PDATA'),
50 50 )
51 51
52 52 DECODE_TYPE = (
53 53 (0, 'None'),
54 54 (1, 'TimeDomain'),
55 55 (2, 'FreqDomain'),
56 56 (3, 'InvFreqDomain'),
57 57 )
58 58
59 59 DEV_STATES = (
60 60 (0, 'No connected'),
61 61 (1, 'Connected'),
62 62 (2, 'Configured'),
63 63 (3, 'Running'),
64 64 (4, 'Unknown'),
65 65 )
66 66
67 67 DEV_TYPES = (
68 68 ('', 'Select a device type'),
69 69 ('rc', 'Radar Controller'),
70 70 ('dds', 'Direct Digital Synthesizer'),
71 71 ('jars', 'Jicamarca Radar Acquisition System'),
72 72 ('usrp', 'Universal Software Radio Peripheral'),
73 73 ('cgs', 'Clock Generator System'),
74 74 ('abs', 'Automatic Beam Switching'),
75 75 ('dds_rest', 'Direct Digital Synthesizer_REST'),
76 76 )
77 77
78 78 EXP_STATES = (
79 79 (0,'Error'), #RED
80 80 (1,'Cancelled'), #YELLOW
81 81 (2,'Running'), #GREEN
82 82 (3,'Scheduled'), #BLUE
83 83 (4,'Unknown'), #WHITE
84 84 )
85 85
86 86 CONF_TYPES = (
87 87 (0, 'Active'),
88 88 (1, 'Historical'),
89 89 )
90 90
91 91 class Profile(models.Model):
92 92 user = models.OneToOneField(User, on_delete=models.CASCADE)
93 93 theme = models.CharField(max_length=30, default='spacelab')
94 94
95 95
96 96 @receiver(post_save, sender=User)
97 97 def create_user_profile(sender, instance, created, **kwargs):
98 98 if created:
99 99 Profile.objects.create(user=instance)
100 100
101 101 @receiver(post_save, sender=User)
102 102 def save_user_profile(sender, instance, **kwargs):
103 103 instance.profile.save()
104 104
105 105
106 106 class Location(models.Model):
107 107
108 108 name = models.CharField(max_length = 30)
109 109 description = models.TextField(blank=True, null=True)
110 110
111 111 class Meta:
112 112 db_table = 'db_location'
113 113
114 114 def __str__(self):
115 115 return u'%s' % self.name
116 116
117 117 def get_absolute_url(self):
118 118 return reverse('url_location', args=[str(self.id)])
119 119
120 120
121 121 class DeviceType(models.Model):
122 122
123 123 name = models.CharField(max_length = 10, choices = DEV_TYPES, default = 'dds_rest')
124 124 sequence = models.PositiveSmallIntegerField(default=55)
125 125 description = models.TextField(blank=True, null=True)
126 126
127 127 class Meta:
128 128 db_table = 'db_device_types'
129 129
130 130 def __str__(self):
131 131 return u'%s' % self.get_name_display()
132 132
133 133 class Device(models.Model):
134 134
135 135 device_type = models.ForeignKey('DeviceType', on_delete=models.CASCADE)
136 136 location = models.ForeignKey('Location', on_delete=models.CASCADE)
137 137 ip_address = models.GenericIPAddressField(protocol='IPv4', default='0.0.0.0')
138 138 port_address = models.PositiveSmallIntegerField(default=2000)
139 139 description = models.TextField(blank=True, null=True)
140 140 status = models.PositiveSmallIntegerField(default=4, choices=DEV_STATES)
141 141 conf_active = models.PositiveIntegerField(default=0, verbose_name='Current configuration')
142 142
143 143 class Meta:
144 144 db_table = 'db_devices'
145 145
146 146 def __str__(self):
147 147 ret = u'{} [{}]'.format(self.device_type.name.upper(), self.location.name)
148 148
149 149 return ret
150 150
151 151 @property
152 152 def name(self):
153 153 return str(self)
154 154
155 155 def get_status(self):
156 156 return self.status
157 157
158 158 @property
159 159 def status_color(self):
160 160 color = 'muted'
161 161 if self.status == 0:
162 162 color = "danger"
163 163 elif self.status == 1:
164 164 color = "warning"
165 165 elif self.status == 2:
166 166 color = "info"
167 167 elif self.status == 3:
168 168 color = "success"
169 169
170 170 return color
171 171
172 172 def url(self, path=None):
173 173
174 174 if path:
175 175 return 'http://{}:{}/{}/'.format(self.ip_address, self.port_address, path)
176 176 else:
177 177 return 'http://{}:{}/'.format(self.ip_address, self.port_address)
178 178
179 179 def get_absolute_url(self):
180 180 return reverse('url_device', args=[str(self.id)])
181 181
182 182 def get_absolute_url_edit(self):
183 183 return reverse('url_edit_device', args=[str(self.id)])
184 184
185 185 def get_absolute_url_delete(self):
186 186 return reverse('url_delete_device', args=[str(self.id)])
187 187
188 188 def change_ip(self, ip_address, mask, gateway, dns, **kwargs):
189 189
190 190 if self.device_type.name=='dds':
191 191 try:
192 192 answer = dds_api.change_ip(ip = self.ip_address,
193 193 port = self.port_address,
194 194 new_ip = ip_address,
195 195 mask = mask,
196 196 gateway = gateway)
197 197 if answer[0]=='1':
198 198 self.message = '25|DDS - {}'.format(answer)
199 199 self.ip_address = ip_address
200 200 self.save()
201 201 else:
202 202 self.message = '30|DDS - {}'.format(answer)
203 203 return False
204 204 except Exception as e:
205 205 self.message = '40|{}'.format(str(e))
206 206 return False
207 207
208 208 elif self.device_type.name=='rc':
209 209 headers = {'content-type': "application/json",
210 210 'cache-control': "no-cache"}
211 211
212 212 ip = [int(x) for x in ip_address.split('.')]
213 213 dns = [int(x) for x in dns.split('.')]
214 214 gateway = [int(x) for x in gateway.split('.')]
215 215 subnet = [int(x) for x in mask.split('.')]
216 216
217 217 payload = {
218 218 "ip": ip,
219 219 "dns": dns,
220 220 "gateway": gateway,
221 221 "subnet": subnet
222 222 }
223 223
224 224 req = requests.post(self.url('changeip'), data=json.dumps(payload), headers=headers)
225 225 try:
226 226 answer = req.json()
227 227 if answer['changeip']=='ok':
228 228 self.message = '25|IP succesfully changed'
229 229 self.ip_address = ip_address
230 230 self.save()
231 231 else:
232 232 self.message = '30|An error ocuur when changing IP'
233 233 except Exception as e:
234 234 self.message = '40|{}'.format(str(e))
235 235 else:
236 236 self.message = 'Not implemented'
237 237 return False
238 238
239 239 return True
240 240
241 241
242 242 class Campaign(models.Model):
243 243
244 244 template = models.BooleanField(default=False)
245 245 name = models.CharField(max_length=60, unique=True)
246 246 start_date = models.DateTimeField(blank=True, null=True)
247 247 end_date = models.DateTimeField(blank=True, null=True)
248 248 tags = models.CharField(max_length=40, blank=True, null=True)
249 249 description = models.TextField(blank=True, null=True)
250 250 experiments = models.ManyToManyField('Experiment', blank=True)
251 251 author = models.ForeignKey(User, null=True, blank=True,on_delete=models.CASCADE)
252 252
253 253 class Meta:
254 254 db_table = 'db_campaigns'
255 255 ordering = ('name',)
256 256
257 257 def __str__(self):
258 258 if self.template:
259 259 return u'{} (template)'.format(self.name)
260 260 else:
261 261 return u'{}'.format(self.name)
262 262
263 263 def jsonify(self):
264 264
265 265 data = {}
266 266
267 267 ignored = ('template')
268 268
269 269 for field in self._meta.fields:
270 270 if field.name in ignored:
271 271 continue
272 272 data[field.name] = field.value_from_object(self)
273 273
274 274 data['start_date'] = data['start_date'].strftime('%Y-%m-%d')
275 275 data['end_date'] = data['end_date'].strftime('%Y-%m-%d')
276 276
277 277 return data
278 278
279 279 def parms_to_dict(self):
280 280
281 281 params = Params({})
282 282 params.add(self.jsonify(), 'campaigns')
283 283
284 284 for exp in Experiment.objects.filter(campaign = self):
285 285 params.add(exp.jsonify(), 'experiments')
286 286 configurations = Configuration.objects.filter(experiment=exp, type=0)
287 287
288 288 for conf in configurations:
289 289 params.add(conf.jsonify(), 'configurations')
290 290 if conf.device.device_type.name=='rc':
291 291 for line in conf.get_lines():
292 292 params.add(line.jsonify(), 'lines')
293 293
294 294 return params.data
295 295
296 296 def dict_to_parms(self, parms, CONF_MODELS):
297 297
298 298 experiments = Experiment.objects.filter(campaign = self)
299 299
300 300 if experiments:
301 301 for experiment in experiments:
302 302 experiment.delete()
303 303
304 304 for id_exp in parms['experiments']['allIds']:
305 305 exp_parms = parms['experiments']['byId'][id_exp]
306 306 dum = (datetime.now() - datetime(1970, 1, 1)).total_seconds()
307 307 exp = Experiment(name='{}'.format(dum))
308 308 exp.save()
309 309 exp.dict_to_parms(parms, CONF_MODELS, id_exp=id_exp)
310 310 self.experiments.add(exp)
311 311
312 312 camp_parms = parms['campaigns']['byId'][parms['campaigns']['allIds'][0]]
313 313
314 314 self.name = '{}-{}'.format(camp_parms['name'], datetime.now().strftime('%y%m%d'))
315 315 self.start_date = camp_parms['start_date']
316 316 self.end_date = camp_parms['end_date']
317 317 self.tags = camp_parms['tags']
318 318 self.save()
319 319
320 320 return self
321 321
322 322 def get_experiments_by_radar(self, radar=None):
323 323
324 324 ret = []
325 325 if radar:
326 326 locations = Location.objects.filter(pk=radar)
327 327 else:
328 328 locations = set([e.location for e in self.experiments.all()])
329 329
330 330 for loc in locations:
331 331 dum = {}
332 332 dum['name'] = loc.name
333 333 dum['id'] = loc.pk
334 334 dum['experiments'] = [e for e in self.experiments.all() if e.location==loc]
335 335 ret.append(dum)
336 336
337 337 return ret
338 338
339 339 def get_absolute_url(self):
340 340 return reverse('url_campaign', args=[str(self.id)])
341 341
342 342 def get_absolute_url_edit(self):
343 343 return reverse('url_edit_campaign', args=[str(self.id)])
344 344
345 345 def get_absolute_url_delete(self):
346 346 return reverse('url_delete_campaign', args=[str(self.id)])
347 347
348 348 def get_absolute_url_export(self):
349 349 return reverse('url_export_campaign', args=[str(self.id)])
350 350
351 351 def get_absolute_url_import(self):
352 352 return reverse('url_import_campaign', args=[str(self.id)])
353 353
354 354
355 355 class RunningExperiment(models.Model):
356 356 radar = models.OneToOneField('Location', on_delete=models.CASCADE)
357 357 running_experiment = models.ManyToManyField('Experiment', blank = True)
358 358 status = models.PositiveSmallIntegerField(default=0, choices=RADAR_STATES)
359 359
360 360
361 361 class Experiment(models.Model):
362 362
363 363 template = models.BooleanField(default=False)
364 364 name = models.CharField(max_length=40, default='', unique=True)
365 365 location = models.ForeignKey('Location', null=True, blank=True, on_delete=models.CASCADE)
366 366 freq = models.FloatField(verbose_name='Operating Freq. (MHz)', validators=[MinValueValidator(1), MaxValueValidator(10000)], default=49.9200)
367 367 start_time = models.TimeField(default='00:00:00')
368 368 end_time = models.TimeField(default='23:59:59')
369 369 task = models.CharField(max_length=36, default='', blank=True, null=True)
370 370 status = models.PositiveSmallIntegerField(default=4, choices=EXP_STATES)
371 371 author = models.ForeignKey(User, null=True, blank=True,on_delete=models.CASCADE)
372 372 hash = models.CharField(default='', max_length=64, null=True, blank=True)
373 373
374 374 class Meta:
375 375 db_table = 'db_experiments'
376 376 ordering = ('template', 'name')
377 377
378 378 def __str__(self):
379 379 if self.template:
380 380 return u'%s (template)' % (self.name)
381 381 else:
382 382 return u'%s' % (self.name)
383 383
384 384 def jsonify(self):
385 385
386 386 data = {}
387 387
388 388 ignored = ('template')
389 389
390 390 for field in self._meta.fields:
391 391 if field.name in ignored:
392 392 continue
393 393 data[field.name] = field.value_from_object(self)
394 394
395 395 data['start_time'] = data['start_time'].strftime('%H:%M:%S')
396 396 data['end_time'] = data['end_time'].strftime('%H:%M:%S')
397 397 data['location'] = self.location.name
398 398 data['configurations'] = ['{}'.format(conf.pk) for
399 399 conf in Configuration.objects.filter(experiment=self, type=0)]
400 400
401 401 return data
402 402
403 403 @property
404 404 def radar_system(self):
405 405 return self.location
406 406
407 407 def clone(self, **kwargs):
408 408
409 409 confs = Configuration.objects.filter(experiment=self, type=0)
410 410 self.pk = None
411 411 self.name = '{}_{:%y%m%d}'.format(self.name, datetime.now())
412 412 for attr, value in kwargs.items():
413 413 setattr(self, attr, value)
414 414
415 415 self.save()
416 416
417 417 for conf in confs:
418 418 conf.clone(experiment=self, template=False)
419 419
420 420 return self
421 421
422 422 def start(self):
423 423 '''
424 424 Configure and start experiments's devices
425 425 ABS-CGS-DDS-RC-JARS
426 426 '''
427 427
428 428 confs = []
429 429 allconfs = Configuration.objects.filter(experiment=self, type = 0).order_by('-device__device_type__sequence')
430 430 rc_mix = [conf for conf in allconfs if conf.device.device_type.name=='rc' and conf.mix]
431 431 if rc_mix:
432 432 for conf in allconfs:
433 433 if conf.device.device_type.name == 'rc' and not conf.mix:
434 434 continue
435 435 confs.append(conf)
436 436 else:
437 437 confs = allconfs
438 438
439 439 try:
440 440 for conf in confs:
441 441 conf.stop_device()
442 442 conf.write_device()
443 443 conf.device.conf_active = conf.pk
444 444 conf.device.save()
445 445 conf.start_device()
446 446 time.sleep(1)
447 447 except:
448 448 return 0
449 449 return 2
450 450
451 451
452 452 def stop(self):
453 453 '''
454 454 Stop experiments's devices
455 455 DDS-JARS-RC-CGS-ABS
456 456 '''
457 457
458 458 confs = Configuration.objects.filter(experiment=self, type = 0).order_by('device__device_type__sequence')
459 459 confs=confs.exclude(device__device_type__name='cgs')
460 460 try:
461 461 for conf in confs:
462 462 conf.stop_device()
463 463 except:
464 464 return 0
465 465 return 1
466 466
467 467 def get_status(self):
468 468
469 469 if self.status == 3:
470 470 return
471 471
472 472 confs = Configuration.objects.filter(experiment=self, type=0)
473 473
474 474 for conf in confs:
475 475 conf.status_device()
476 476
477 477 total = confs.aggregate(models.Sum('device__status'))['device__status__sum']
478 478
479 479 if total==2*confs.count():
480 480 status = 1
481 481 elif total == 3*confs.count():
482 482 status = 2
483 483 else:
484 484 status = 0
485 485
486 486 self.status = status
487 487 self.save()
488 488
489 489 def status_color(self):
490 490 color = 'muted'
491 491 if self.status == 0:
492 492 color = "danger"
493 493 elif self.status == 1:
494 494 color = "warning"
495 495 elif self.status == 2:
496 496 color = "success"
497 497 elif self.status == 3:
498 498 color = "info"
499 499
500 500 return color
501 501
502 502 def parms_to_dict(self):
503 503
504 504 params = Params({})
505 505 params.add(self.jsonify(), 'experiments')
506 506
507 507 configurations = Configuration.objects.filter(experiment=self, type=0)
508 508
509 509 for conf in configurations:
510 510 params.add(conf.jsonify(), 'configurations')
511 511 if conf.device.device_type.name=='rc':
512 512 for line in conf.get_lines():
513 513 params.add(line.jsonify(), 'lines')
514 514
515 515 return params.data
516 516
517 517 def dict_to_parms(self, parms, CONF_MODELS, id_exp=None):
518 518
519 519 configurations = Configuration.objects.filter(experiment=self)
520 520
521 521 if id_exp is not None:
522 522 exp_parms = parms['experiments']['byId'][id_exp]
523 523 else:
524 524 exp_parms = parms['experiments']['byId'][parms['experiments']['allIds'][0]]
525 525
526 526 if configurations:
527 527 for configuration in configurations:
528 528 configuration.delete()
529 529
530 530 for id_conf in exp_parms['configurations']:
531 531 conf_parms = parms['configurations']['byId'][id_conf]
532 532 device = Device.objects.filter(device_type__name=conf_parms['device_type'])[0]
533 533 model = CONF_MODELS[conf_parms['device_type']]
534 534 conf = model(
535 535 experiment = self,
536 536 device = device,
537 537 )
538 538 conf.dict_to_parms(parms, id=id_conf)
539 539
540 540
541 541 location, created = Location.objects.get_or_create(name=exp_parms['location'])
542 542 self.name = '{}-{}'.format(exp_parms['name'], datetime.now().strftime('%y%m%d'))
543 543 self.location = location
544 544 self.start_time = exp_parms['start_time']
545 545 self.end_time = exp_parms['end_time']
546 546 self.save()
547 547
548 548 return self
549 549
550 550 def get_absolute_url(self):
551 551 return reverse('url_experiment', args=[str(self.id)])
552 552
553 553 def get_absolute_url_edit(self):
554 554 return reverse('url_edit_experiment', args=[str(self.id)])
555 555
556 556 def get_absolute_url_delete(self):
557 557 return reverse('url_delete_experiment', args=[str(self.id)])
558 558
559 559 def get_absolute_url_import(self):
560 560 return reverse('url_import_experiment', args=[str(self.id)])
561 561
562 562 def get_absolute_url_export(self):
563 563 return reverse('url_export_experiment', args=[str(self.id)])
564 564
565 565 def get_absolute_url_start(self):
566 566 return reverse('url_start_experiment', args=[str(self.id)])
567 567
568 568 def get_absolute_url_stop(self):
569 569 return reverse('url_stop_experiment', args=[str(self.id)])
570 570
571 571
572 572 class Configuration(PolymorphicModel):
573 573
574 574 template = models.BooleanField(default=False)
575 575 # name = models.CharField(verbose_name="Configuration Name", max_length=40, default='')
576 576 device = models.ForeignKey('Device', verbose_name='Device', null=True, on_delete=models.CASCADE)
577 577 label = models.CharField(verbose_name="Label", max_length=40, default='', blank=True, null=True)
578 578 experiment = models.ForeignKey('Experiment', verbose_name='Experiment', null=True, blank=True, on_delete=models.CASCADE)
579 579 type = models.PositiveSmallIntegerField(default=0, choices=CONF_TYPES)
580 580 created_date = models.DateTimeField(auto_now_add=True)
581 581 programmed_date = models.DateTimeField(auto_now=True)
582 582 parameters = models.TextField(default='{}')
583 583 author = models.ForeignKey(User, null=True, blank=True,on_delete=models.CASCADE)
584 584 hash = models.CharField(default='', max_length=64, null=True, blank=True)
585 585 message = ""
586 586
587 587 class Meta:
588 588 db_table = 'db_configurations'
589 589 ordering = ('device__device_type__name',)
590 590
591 591 def __str__(self):
592 592
593 593 ret = u'{} '.format(self.device.device_type.name.upper())
594 594
595 595 if 'mix' in [f.name for f in self._meta.get_fields()]:
596 596 if self.mix:
597 597 ret = '{} MIX '.format(self.device.device_type.name.upper())
598 598
599 599 if 'label' in [f.name for f in self._meta.get_fields()]:
600 600 ret += '{}'.format(self.label)
601 601
602 602 if self.template:
603 603 ret += ' (template)'
604 604
605 605 return ret
606 606
607 607 @property
608 608 def name(self):
609 609
610 610 return str(self)
611 611
612 612 def jsonify(self):
613 613
614 614 data = {}
615 615
616 616 ignored = ('type', 'polymorphic_ctype', 'configuration_ptr',
617 617 'created_date', 'programmed_date', 'template', 'device',
618 618 'experiment')
619 619
620 620 for field in self._meta.fields:
621 621 if field.name in ignored:
622 622 continue
623 623 data[field.name] = field.value_from_object(self)
624 624
625 625 data['device_type'] = self.device.device_type.name
626 626
627 627 if self.device.device_type.name == 'rc':
628 628 data['lines'] = ['{}'.format(line.pk) for line in self.get_lines()]
629 629 data['delays'] = self.get_delays()
630 630 data['pulses'] = self.get_pulses()
631 631
632 632 elif self.device.device_type.name == 'jars':
633 633 data['decode_type'] = DECODE_TYPE[self.decode_data][1]
634 634
635 635 elif self.device.device_type.name == 'dds':
636 636 data['frequencyA_Mhz'] = float(data['frequencyA_Mhz'])
637 637 data['frequencyB_Mhz'] = float(data['frequencyB_Mhz'])
638 638 data['phaseA'] = dds_data.phase_to_binary(data['phaseA_degrees'])
639 639 data['phaseB'] = dds_data.phase_to_binary(data['phaseB_degrees'])
640 640
641 elif self.device.device_type.name == 'dds_rest':
642 data['frequencyA_Mhz'] = float(data['frequencyA_Mhz'])
643 data['frequencyB_Mhz'] = float(data['frequencyB_Mhz'])
644 data['phaseA'] = dds_data.phase_to_binary(data['phaseA_degrees'])
645 data['phaseB'] = dds_data.phase_to_binary(data['phaseB_degrees'])
646 data['delta_frequency_Mhz'] = float(data['delta_frequency_Mhz'] or 0.00)
647 data['update_clock_Mhz'] = float(data['update_clock_Mhz'] or 0.00)
648 data['ramp_rate_clock_Mhz'] = float(data['ramp_rate_clock_Mhz'] or 0.0)
641 649 return data
642 650
643 651 def clone(self, **kwargs):
644 652
645 653 self.pk = None
646 654 self.id = None
647 655 for attr, value in kwargs.items():
648 656 setattr(self, attr, value)
649 657
650 658 self.save()
651 659
652 660 return self
653 661
654 662 def parms_to_dict(self):
655 663
656 664 params = Params({})
657 665 params.add(self.jsonify(), 'configurations')
658 666
659 667 if self.device.device_type.name=='rc':
660 668 for line in self.get_lines():
661 669 params.add(line.jsonify(), 'lines')
662 670
663 671 return params.data
664 672
665 673 def parms_to_text(self):
666 674
667 675 raise NotImplementedError("This method should be implemented in %s Configuration model" %str(self.device.device_type.name).upper())
668 676
669 677
670 678 def parms_to_binary(self):
671 679
672 680 raise NotImplementedError("This method should be implemented in %s Configuration model" %str(self.device.device_type.name).upper())
673 681
674 682
675 683 def dict_to_parms(self, parameters, id=None):
676 684
677 685 params = Params(parameters)
678 686
679 687 if id:
680 688 data = params.get_conf(id_conf=id)
681 689 else:
682 690 data = params.get_conf(dtype=self.device.device_type.name)
683 691
684 692 if data['device_type']=='rc':
685 693 self.clean_lines()
686 694 lines = data.pop('lines', None)
687 695 for line_id in lines:
688 696 pass
689 697
690 698 for key, value in data.items():
691 699 if key not in ('id', 'device_type'):
692 700 setattr(self, key, value)
693 701
694 702 self.save()
695 703
696 704
697 705 def export_to_file(self, format="json"):
698 706
699 707 content_type = ''
700 708
701 709 if format == 'racp':
702 710 content_type = 'text/plain'
703 711 filename = '%s_%s.%s' %(self.device.device_type.name, self.name, 'racp')
704 712 content = self.parms_to_text(file_format = 'racp')
705 713
706 714 if format == 'text':
707 715 content_type = 'text/plain'
708 716 filename = '%s_%s.%s' %(self.device.device_type.name, self.name, self.device.device_type.name)
709 717 content = self.parms_to_text()
710 718
711 719 if format == 'binary':
712 720 content_type = 'application/octet-stream'
713 721 filename = '%s_%s.bin' %(self.device.device_type.name, self.name)
714 722 content = self.parms_to_binary()
715 723
716 724 if not content_type:
717 725 content_type = 'application/json'
718 726 filename = '%s_%s.json' %(self.device.device_type.name, self.name)
719 727 content = json.dumps(self.parms_to_dict(), indent=2)
720 728
721 729 fields = {'content_type':content_type,
722 730 'filename':filename,
723 731 'content':content
724 732 }
725 733
726 734 return fields
727 735
728 736 def import_from_file(self, fp):
729 737
730 738 parms = {}
731 739
732 740 path, ext = os.path.splitext(fp.name)
733 741
734 742 if ext == '.json':
735 743 parms = json.load(fp)
736 744
737 745 if ext == '.dds':
738 746 lines = fp.readlines()
739 747 parms = dds_data.text_to_dict(lines)
740 748
741 749 if ext == '.racp':
742 750 if self.device.device_type.name == 'jars':
743 751 parms = RacpFile(fp).to_dict()
744 752 parms['filter_parms'] = json.loads(self.filter_parms)
745 753 return parms
746 754 parms = RCFile(fp).to_dict()
747 755
748 756 return parms
749 757
750 758 def status_device(self):
751 759
752 760 self.message = 'Function not implemented'
753 761 return False
754 762
755 763
756 764 def stop_device(self):
757 765
758 766 self.message = 'Function not implemented'
759 767 return False
760 768
761 769
762 770 def start_device(self):
763 771
764 772 self.message = 'Function not implemented'
765 773 return False
766 774
767 775
768 776 def write_device(self, parms):
769 777
770 778 self.message = 'Function not implemented'
771 779 return False
772 780
773 781
774 782 def read_device(self):
775 783
776 784 self.message = 'Function not implemented'
777 785 return False
778 786
779 787
780 788 def get_absolute_url(self):
781 789 return reverse('url_%s_conf' % self.device.device_type.name, args=[str(self.id)])
782 790
783 791 def get_absolute_url_edit(self):
784 792 return reverse('url_edit_%s_conf' % self.device.device_type.name, args=[str(self.id)])
785 793
786 794 def get_absolute_url_delete(self):
787 795 return reverse('url_delete_dev_conf', args=[str(self.id)])
788 796
789 797 def get_absolute_url_import(self):
790 798 return reverse('url_import_dev_conf', args=[str(self.id)])
791 799
792 800 def get_absolute_url_export(self):
793 801 return reverse('url_export_dev_conf', args=[str(self.id)])
794 802
795 803 def get_absolute_url_write(self):
796 804 return reverse('url_write_dev_conf', args=[str(self.id)])
797 805
798 806 def get_absolute_url_read(self):
799 807 return reverse('url_read_dev_conf', args=[str(self.id)])
800 808
801 809 def get_absolute_url_start(self):
802 810 return reverse('url_start_dev_conf', args=[str(self.id)])
803 811
804 812 def get_absolute_url_stop(self):
805 813 return reverse('url_stop_dev_conf', args=[str(self.id)])
806 814
807 815 def get_absolute_url_status(self):
808 816 return reverse('url_status_dev_conf', args=[str(self.id)])
@@ -1,322 +1,320
1 1
2 2 import ast
3 3 import json
4 4 from itertools import chain
5 5
6 6 from django import forms
7 7 from django.utils.safestring import mark_safe
8 8 from django.utils.encoding import force_text
9 9 from django.utils.html import conditional_escape
10 10
11 11 try:
12 12 basestring # attempt to evaluate basestring
13 13 def isstr(s):
14 14 return isinstance(s, basestring)
15 15 except NameError:
16 16 def isstr(s):
17 17 return isinstance(s, str)
18 18
19 19 class KmUnitWidget(forms.widgets.TextInput):
20 20
21 21 def render(self, name, value, attrs=None,renderer=None):
22 22 label = name
23 23 if isinstance(value, (int, float)):
24 24 unit = int(value*attrs['km2unit'])
25 25 elif isstr(value):
26 26 units = []
27 27 values = [s for s in value.split(',') if s]
28 28 for val in values:
29 29 units.append('{0:.0f}'.format(float(val)*attrs['km2unit']))
30 30
31 31 unit = ','.join(units)
32 32
33 33 disabled = 'disabled' if attrs.get('disabled', False) else ''
34 34 name = attrs.get('name', label)
35 35 if attrs['id'] in ('id_delays',):
36 36 input_type = 'text'
37 37 else:
38 38 input_type = 'number'
39 39
40 40 if 'line' in attrs:
41 41 label += '_{0}_{1}'.format(attrs['line'].pk, name.split('|')[0])
42 42
43 43 html = '''<div class="col-md-12 col-no-padding">
44 44 <div class="col-md-5 col-no-padding"><input type="{0}" step="any" {1} class="form-control" id="id_{2}" name="{3}" value="{4}"></div>
45 45 <div class="col-md-1 col-no-padding">Km</div>
46 46 <div class="col-md-5 col-no-padding"><input type="{0}" step="any" {1} class="form-control" id="id_{2}_unit" value="{5}"></div>
47 47 <div class="col-md-1 col-no-padding">Units</div></div><br>'''.format(input_type, disabled, label, name, value, unit)
48 48
49 49 script = '''<script type="text/javascript">
50 50 $(document).ready(function () {{
51 51
52 52 km_fields.push("id_{label}");
53 53 unit_fields.push("id_{label}_unit");
54 54
55 55 $("#id_{label}").change(function() {{
56 56 $("#id_{label}_unit").val(str2unit($(this).val()));
57 57 $("#id_{label}").val(str2km($("#id_{label}_unit").val()));
58 58 updateWindows("#id_{label}");
59 59 }});
60 60 $("#id_{label}_unit").change(function() {{
61 61 $(this).val(str2int($(this).val()));
62 62 $("#id_{label}").val(str2km($(this).val()));
63 63 updateWindows("#id_{label}");
64 64 }});
65 65 }});
66 66 </script>'''.format(label=label)
67 67
68 68 if disabled:
69 69 return mark_safe(html)
70 70 else:
71 71 return mark_safe(html+script)
72 72
73 73
74 74 class UnitKmWidget(forms.widgets.TextInput):
75 75
76 76 def render(self, name, value, attrs=None,renderer=None):
77 77 label = name
78 78 if isinstance(value, (int, float)):
79 79 km = value/attrs['km2unit']
80 80 elif isinstance(value, basestring):
81 81 kms = []
82 82 values = [s for s in value.split(',') if s]
83 83 for val in values:
84 84 kms.append('{0:.0f}'.format(float(val)/attrs['km2unit']))
85 85
86 86 km = ','.join(kms)
87 87
88 88 disabled = 'disabled' if attrs.get('disabled', False) else ''
89 89 name = attrs.get('name', label)
90 90
91 91 if 'line' in attrs:
92 92 label += '_{0}_{1}'.format(attrs['line'].pk, name.split('|')[0])
93 93
94 94 html = '''<div class="col-md-12 col-no-padding">
95 95 <div class="col-md-5 col-no-padding"><input type="number" step="any" {0} class="form-control" id="id_{1}_unit" name="{2}" value="{3}"></div>
96 96 <div class="col-md-1 col-no-padding">Units</div>
97 97 <div class="col-md-5 col-no-padding"><input type="number" step="any" {4} class="form-control" id="id_{5}" value="{6}"></div>
98 98 <div class="col-md-1 col-no-padding">Km</div></div>'''.format(disabled, label, name, value, disabled, label, km)
99 99
100 100 script = '''<script type="text/javascript">
101 101 $(document).ready(function () {{
102 102
103 103 km_fields.push("id_{label}");
104 104 unit_fields.push("id_{label}_unit");
105 105
106 106 $("#id_{label}").change(function() {{
107 107 $("#id_{label}_unit").val(str2unit($(this).val()));
108 108 }});
109 109 $("#id_{label}_unit").change(function() {{
110 110 $("#id_{label}").val(str2km($(this).val()));
111 111 }});
112 112 }});
113 113 </script>'''.format(label=label)
114 114
115 115 if disabled:
116 116 return mark_safe(html)
117 117 else:
118 118 return mark_safe(html+script)
119 119
120 120
121 121 class KmUnitHzWidget(forms.widgets.TextInput):
122 122
123 123 def render(self, name, value, attrs=None,renderer=None):
124 124 label = name
125 125 unit = float(value)*attrs['km2unit']
126 126 if unit%10==0:
127 127 unit = int(unit)
128 128 hz = 150000*float(value)**-1
129 129
130 130 disabled = 'disabled' if attrs.get('disabled', False) else ''
131 131 name = attrs.get('name', label)
132 132
133 133 if 'line' in attrs:
134 134 label += '_{0}'.format(attrs['line'].pk)
135 135
136 136 html = '''<div class="col-md-12 col-no-padding">
137 137 <div class="col-md-3 col-no-padding"><input type="number" step="any" {0} class="form-control" id="id_{1}" name="{2}" value="{3}"></div>
138 138 <div class="col-md-1 col-no-padding">Km</div>
139 139 <div class="col-md-3 col-no-padding"><input type="number" step="any" {4} class="form-control" id="id_{1}_unit" value="{5}"></div>
140 140 <div class="col-md-1 col-no-padding">Units</div>
141 141 <div class="col-md-3 col-no-padding"><input type="number" step="any" {4} class="form-control" id="id_{1}_hz" value="{6}"></div>
142 142 <div class="col-md-1 col-no-padding">Hz</div>
143 143 </div>'''.format(disabled, label, name, value, disabled, unit, hz)
144 144
145 145 script = '''<script type="text/javascript">
146 146 $(document).ready(function () {{
147 147 km_fields.push("id_{label}");
148 148 unit_fields.push("id_{label}_unit");
149 149 $("#id_{label}").change(function() {{
150 150 $("#id_{label}_unit").val(str2unit($(this).val()));
151 151 $("#id_{label}").val(str2km($("#id_{label}_unit").val()));
152 152 $("#id_{label}_hz").val(str2hz($(this).val()));
153 153 updateDc();
154 154 }});
155 155 $("#id_{label}_unit").change(function() {{
156 156 $(this).val(Math.round(parseFloat($(this).val())/10)*10);
157 157 $("#id_{label}").val(str2km($(this).val()));
158 158 $("#id_{label}_hz").val(str2hz($("#id_{label}").val()));
159 159 updateDc();
160 160 }});
161 161 $("#id_{label}_hz").change(function() {{
162 162 $("#id_{label}").val(str2hz($(this).val()));
163 163 $("#id_{label}_unit").val(str2unit($("#id_{label}").val()));
164 164 updateDc();
165 165 }});
166 166 }});
167 167 </script>'''.format(label=label)
168 168
169 169 if disabled:
170 170 return mark_safe(html)
171 171 else:
172 172 return mark_safe(html+script)
173 173
174 174
175 175 class KmUnitDcWidget(forms.widgets.TextInput):
176 176
177 177 def render(self, name, value, attrs=None,renderer=None):
178 178 label = name
179 179 unit = int(float(value)*attrs['km2unit'])
180 180
181 181 disabled = 'disabled' if attrs.get('disabled', False) else ''
182 182 name = attrs.get('name', label)
183 183
184 184 label += '_{0}'.format(attrs['line'].pk)
185 185
186 186 dc = float(json.loads(attrs['line'].params)['pulse_width'])*100/attrs['line'].rc_configuration.ipp
187 187
188 188 html = '''<div class="col-md-12 col-no-padding">
189 189 <div class="col-md-3 col-no-padding"><input type="number" step="any" {0} class="form-control" id="id_{1}" name="{2}" value="{3}"></div>
190 190 <div class="col-md-1 col-no-padding">Km</div>
191 191 <div class="col-md-3 col-no-padding"><input type="number" step="any" {4} class="form-control" id="id_{1}_unit" value="{5}"></div>
192 192 <div class="col-md-1 col-no-padding">Units</div>
193 193 <div class="col-md-3 col-no-padding"><input type="number" step="any" {4} class="form-control" id="id_{1}_dc" value="{6}"></div>
194 194 <div class="col-md-1 col-no-padding">DC[%]</div>
195 195 </div>'''.format(disabled, label, name, value, disabled, unit, dc)
196 196
197 197 script = '''<script type="text/javascript">
198 198 $(document).ready(function () {{
199 199 km_fields.push("id_{label}");
200 200 unit_fields.push("id_{label}_unit");
201 201 dc_fields.push("id_{label}");
202 202 $("#id_{label}").change(function() {{
203 203 $("#id_{label}_unit").val(str2unit($(this).val()));
204 204 $("#id_{label}").val(str2km($("#id_{label}_unit").val()));
205 205 $("#id_{label}_dc").val(str2dc($("#id_{label}").val()));
206 206 }});
207 207 $("#id_{label}_unit").change(function() {{
208 208 $("#id_{label}").val(str2km($(this).val()));
209 209 $("#id_{label}_dc").val(str2dc($("#id_{label}").val()));
210 210 }});
211 211
212 212 $("#id_{label}_dc").change(function() {{
213 213 $("#id_{label}").val(parseFloat($(this).val())*100/parseFloat($("#id_ipp").val()));
214 214 $("#id_{label}_unit").val(str2unit($("#id_{label}").val()));
215 215 }});
216 216 }});
217 217 </script>'''.format(label=label)
218 218
219 219 if disabled:
220 220 return mark_safe(html)
221 221 else:
222 222 return mark_safe(html+script)
223 223
224 224
225 225 class DefaultWidget(forms.widgets.TextInput):
226 226
227 227 def render(self, name, value, attrs=None,renderer=None):
228 228 print("Default widget")
229 229 label = name
230 230 disabled = 'disabled' if attrs.get('disabled', False) else ''
231 231 itype = 'number' if label in ('number_of_samples', 'last_height') else 'text'
232 232 print(label)
233 233 name = attrs.get('name', label)
234 234 print(name)
235 235 if 'line' in attrs:
236 236 label += '_{0}_{1}'.format(attrs['line'].pk, name.split('|')[0])
237 237 print(label)
238 238 if itype=='number':
239 239 html = '<div class="col-md-12 col-no-padding"><div class="col-md-5 col-no-padding"><input {0} type="{1}" step="any" class="form-control" id="id_{2}" name="{3}" value="{4}"></div></div>'.format(disabled, itype, label, name, value)
240 240 else:
241 241 html = '<div class="col-md-12 col-no-padding"><div class="col-md-5 col-no-padding"><input {0} type="{1}" step="any" class="form-control" id="id_{2}" name="{3}" value="{4}"></div></div>'.format(disabled, itype, label, name, value)
242 242
243 243 if 'last_height' in label or 'number_of_samples' in label:
244 244 script = '''<script type="text/javascript">
245 245 $(document).ready(function () {{
246 246
247 247 $("#id_{label}").change(function() {{
248 248 updateWindows("#id_{label}");
249 249 }});
250 250
251 251 }});
252 252 </script>'''.format(label=label)
253 253 else:
254 254 script = ''
255 255
256 256 if disabled:
257 257 return mark_safe(html)
258 258 else:
259 259 return mark_safe(html+script)
260 260
261
262
263 261 return mark_safe(html)
264 262
265 263
266 264 class HiddenWidget(forms.widgets.HiddenInput):
267 265
268 266 def render(self, name, value, attrs=None,renderer=None):
269 267 label = name
270 268 disabled = 'disabled' if attrs.get('disabled', False) else ''
271 269 name = self.attrs.get('name', label)
272 270
273 271 html = '<input {0} type="hidden" class="form-control" id="id_{1}" name="{2}" value="{3}">'.format(disabled, label, name, value)
274 272
275 273 return mark_safe(html)
276 274
277 275
278 276 class CodesWidget(forms.widgets.Textarea):
279 277
280 278 def render(self, name, value, attrs=None,renderer=None):
281 279 label = name
282 280 disabled = 'disabled' if attrs.get('disabled', False) else ''
283 281 name = attrs.get('name', label)
284 282
285 283 if '[' in value:
286 284 value = ast.literal_eval(value)
287 285
288 286 if isinstance(value, list):
289 287 codes = '\r\n'.join(value)
290 288 else:
291 289 codes = value
292 290
293 291 html = '<textarea rows="5" {0} class="form-control" id="id_{1}" name="{2}" style="white-space:nowrap; overflow:scroll;">{3}</textarea>'.format(disabled, label, name, codes)
294 292
295 293 return mark_safe(html)
296 294
297 295 class HCheckboxSelectMultiple(forms.CheckboxSelectMultiple):
298 296
299 297 def render(self, name, value, attrs=None, choices=(),renderer=None):
300 298
301 299 if value is None: value = []
302 300 has_id = attrs and 'id' in attrs
303 301 final_attrs = self.build_attrs(attrs, {'name': name})
304 302 output = [u'<br><ul>']
305 303 # Normalize to strings
306 304 str_values = set([force_text(v) for v in value])
307 305 for i, (option_value, option_label) in enumerate(chain(self.choices, choices)):
308 306 # If an ID attribute was given, add a numeric index as a suffix,
309 307 # so that the checkboxes don't all have the same ID attribute.
310 308 if has_id:
311 309 final_attrs = dict(final_attrs, id='%s_%s' % (attrs['id'], i))
312 310 label_for = u' for="%s"' % final_attrs['id']
313 311 else:
314 312 label_for = ''
315 313
316 314 cb = forms.CheckboxInput(final_attrs, check_test=lambda value: value in str_values)
317 315 option_value = force_text(option_value)
318 316 rendered_cb = cb.render(name, option_value)
319 317 option_label = conditional_escape(force_text(option_label))
320 318 output.append(u'<span><label%s>%s %s</label></span>' % (label_for, rendered_cb, option_label))
321 319 output.append(u'</div><br>')
322 320 return mark_safe(u'\n'.join(output))
1 NO CONTENT: modified file
General Comments 0
You need to be logged in to leave comments. Login now