##// END OF EJS Templates
Aplicacion de controlador de radar revisada. Un bug remanente en mix de experimentos pendiente.
gonzalesluisfrancisco -
r343:eea526c788c8
parent child
Show More
@@ -1,219 +1,232
1 1
2 2 :root{
3 3 --primary: #0200AE;
4 4 --dark-primary: #000080;
5 5 --light-primary: rgb(0, 0, 179, .7);
6 6 --secondary: #6F6F6F;
7 7 --tertiary: #0099FF;
8 8 --color-txt: #333;
9 9 --bg-main: rgba(80, 80, 80, .8);
10 10 --bg-invert: rgba(0, 0, 0, .2);
11 11 --bg-sections: #f9f9f9;
12 12 --bd-sections: 1px solid #D9D9D9;
13 13 --fs-nav: .875em;
14 14 --fs-trail: .87rem;
15 15 --hover-nav: rgba(0, 0, 0, 0.3);
16 16 --fg-nav: #2068A0;
17 17 --bs-nav: rgba(43, 43, 43, .4);
18 18 --bs-input: rgba(0, 113, 184, 0.5);
19 19 --bd-input: rgba(56, 181, 230, 0.75);
20 20 --bd-item: 1px solid #C9C9C9;
21 21 --bx-shadow: 0 2px 5px 0 var(--bs-nav);
22 22 }
23 23
24 label {
25 display: inline-block;
26 max-width: 100%;
27 margin-bottom: 5px;
28 font-weight: bold;
29 }
30
31 .form-check-input {
32 position: relative;
33 margin-top: .3rem;
34 margin-left: .3rem;
35 }
36
24 37 body {
25 38 color: #444;
26 39 font-family: "Helvetica Neue",Helvetica,Arial,sans-serif;
27 40 font-size: 14px;
28 41 }
29 42
30 43 main {
31 44 min-width: 100%;
32 45 min-height: 400px;
33 46 }
34 47
35 48 a:link { -webkit-tap-highlight-color: var(--tertiary); }
36 49
37 50 .titulo {
38 51 color: #898989;
39 52 font-size: 2rem;
40 53 font-family: 'Dosis', Arial, Verdana, serif;
41 54 }
42 55
43 56 .titulo:after {
44 57 display: flex;
45 58 width: 60px;
46 59 border-bottom: 3px solid #48C7EC;
47 60 content: '';
48 61 padding-top: .5rem;
49 62 margin: 0;
50 63 }
51 64
52 65 #sidebar a {
53 66 color: gray;
54 67 padding: 0.1rem;
55 68 }
56 69
57 70 #sidebar h5 {
58 71 color:#333;
59 72 }
60 73
61 74 .text-blue {
62 75 color: #003A8E;
63 76 }
64 77
65 78 .text-skyblue {
66 79 color: #00addc;
67 80 }
68 81
69 82 .nopadding {
70 83 padding: 0px !important;
71 84 }
72 85
73 86 .nomargin {
74 87 margin: 0px !important;
75 88 }
76 89
77 90 .legend {
78 91 list-style: none;
79 92 padding-left: 1rem;
80 93 padding-top: 1rem;
81 94 }
82 95
83 96 .legend span {
84 97 padding-left: 1em;
85 98 }
86 99
87 100 #loader {
88 101 margin-top: 40px;
89 102 color: var(--tertiary);
90 103 }
91 104
92 105 #plot {
93 106 margin-top: 2em;
94 107 margin-bottom: 2em;
95 108 }
96 109
97 110 /* Change Buttons Bootstrap */
98 111 .btn-primary {
99 112 color: #fff;
100 113 background-color: #00addc !important;
101 114 border-color: #00addc !important;
102 115 }
103 116
104 117 .btn-primary:hover {
105 118 color: #fff;
106 119 background-color: #23527c !important;
107 120 border-color: #23527c !important;
108 121 }
109 122
110 123 .card-text {
111 124 font-size: 0.8rem;
112 125 }
113 126
114 127 .tools-date {
115 128 font-size: 0.8rem;
116 129 }
117 130
118 131 /*------------------------------------------------*/
119 132
120 133 .panel {
121 134 margin-bottom: 20px;
122 135 background-color: #fafafa;
123 136 border: 1px solid transparent;
124 137 border-radius: 4px;
125 138 -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, .05);
126 139 box-shadow: 0 1px 1px rgba(0, 0, 0, .05);
127 140 }
128 141 .panel-body {
129 142 padding: 15px;
130 143 }
131 144 .panel-heading {
132 145 padding: 10px 15px;
133 146 border-bottom: 1px solid transparent;
134 147 border-top-left-radius: 3px;
135 148 border-top-right-radius: 3px;
136 149 }
137 150
138 151 .panel-title {
139 152 margin-top: 0;
140 153 margin-bottom: 0;
141 154
142 155
143 156 }
144 157
145 158 .panel-footer {
146 159 padding: 10px 15px;
147 160 background-color: #fafafa;
148 161 border-top: 1px solid #fafafa;
149 162 border-bottom-right-radius: 3px;
150 163 border-bottom-left-radius: 3px;
151 164 }
152 165
153 166 .panel-group {
154 167 margin-bottom: 20px;
155 168 }
156 169 .panel-group .panel {
157 170 margin-bottom: 0;
158 171 border-radius: 4px;
159 172 }
160 173 .panel-group .panel + .panel {
161 174 margin-top: 5px;
162 175 }
163 176 .panel-group .panel-heading {
164 177 border-bottom: 0;
165 178 }
166 179 .panel-group .panel-heading + .panel-collapse > .panel-body,
167 180
168 181 .panel-group .panel-footer {
169 182 border-top: 0;
170 183 }
171 184 .panel-group .panel-footer + .panel-collapse .panel-body {
172 185 border-bottom: 1px solid #fafafa;
173 186 }
174 187 .panel-default {
175 188 border-color: #fafafa;
176 189 }
177 190 .panel-default > .panel-heading {
178 191
179 192 background-color: #fafafa;
180 193 border-color: #fafafa;
181 194 }
182 195 .panel-default > .panel-heading + .panel-collapse > .panel-body {
183 196 border-top-color: #fafafa;
184 197 }
185 198 .panel-default > .panel-heading .badge {
186 199 color: #fafafa;
187 200 background-color: #fafafa;
188 201 }
189 202 .panel-default > .panel-footer + .panel-collapse > .panel-body {
190 203 border-bottom-color: #fafafa;
191 204 }
192 205
193 206
194 207 /* cards */
195 208
196 209 @media (min-width: 480px) {
197 210 .card-columns {
198 211 column-count: 2;
199 212 }
200 213 }
201 214
202 215 @media (min-width: 768px) {
203 216 .card-columns {
204 217 column-count: 3;
205 218 }
206 219 }
207 220
208 221 @media (min-width: 1180px) {
209 222 .card-columns {
210 223 column-count: 4;
211 224 }
212 225 }
213 226
214 227 @media (min-width: 1380px) {
215 228 .card-columns {
216 229 column-count: 5;
217 230 }
218 231 }
219 232
@@ -1,1930 +1,1932
1 1 import ast
2 2 import json
3 3 import hashlib
4 4 from datetime import datetime, timedelta
5 5
6 6 from django.shortcuts import render, redirect, get_object_or_404, HttpResponse
7 7 from django.utils.safestring import mark_safe
8 8 from django.http import HttpResponseRedirect
9 9 from django.urls import reverse
10 10 from django.db.models import Q
11 11 from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
12 12 from django.contrib import messages
13 13 from django.http.request import QueryDict
14 14 from django.contrib.auth.decorators import login_required, user_passes_test
15 15
16 16 try:
17 17 from urllib.parse import urlencode
18 18 except ImportError:
19 19 from urllib import urlencode
20 20
21 21 from .forms import CampaignForm, ExperimentForm, DeviceForm, ConfigurationForm, LocationForm, UploadFileForm, DownloadFileForm, OperationForm, NewForm
22 22 from .forms import OperationSearchForm, FilterForm, ChangeIpForm
23 23
24 24 from .tasks import task_start
25 25
26 26 from apps.rc.forms import RCConfigurationForm, RCLineCode, RCMixConfigurationForm
27 27 from apps.dds.forms import DDSConfigurationForm
28 28 from apps.jars.forms import JARSConfigurationForm
29 29 from apps.cgs.forms import CGSConfigurationForm
30 30 from apps.abs.forms import ABSConfigurationForm
31 31 from apps.usrp.forms import USRPConfigurationForm
32 32 from apps.dds_rest.forms import DDSRestConfigurationForm
33 33 from .utils import Params
34 34
35 35 from .models import Campaign, Experiment, Device, Configuration, Location, RunningExperiment, DEV_STATES
36 36 from apps.cgs.models import CGSConfiguration
37 37 from apps.jars.models import JARSConfiguration, EXPERIMENT_TYPE
38 38 from apps.usrp.models import USRPConfiguration
39 39 from apps.abs.models import ABSConfiguration
40 40 from apps.rc.models import RCConfiguration, RCLine, RCLineType, RCClock
41 41 from apps.dds.models import DDSConfiguration
42 42 from apps.dds_rest.models import DDSRestConfiguration
43 43
44 44 from radarsys.celery import app
45 45
46 46
47 47 CONF_FORMS = {
48 48 'rc': RCConfigurationForm,
49 49 'dds': DDSConfigurationForm,
50 50 'dds_rest': DDSRestConfigurationForm,
51 51 'jars': JARSConfigurationForm,
52 52 'cgs': CGSConfigurationForm,
53 53 'abs': ABSConfigurationForm,
54 54 'usrp': USRPConfigurationForm,
55 55 }
56 56
57 57 CONF_MODELS = {
58 58 'rc': RCConfiguration,
59 59 'dds': DDSConfiguration,
60 60 'dds_rest': DDSRestConfiguration,
61 61 'jars': JARSConfiguration,
62 62 'cgs': CGSConfiguration,
63 63 'abs': ABSConfiguration,
64 64 'usrp': USRPConfiguration,
65 65 }
66 66
67 67 MIX_MODES = {
68 68 '0': 'P',
69 69 '1': 'S',
70 70 }
71 71
72 72 MIX_OPERATIONS = {
73 73 '0': 'OR',
74 74 '1': 'XOR',
75 75 '2': 'AND',
76 76 '3': 'NAND',
77 77 }
78 78
79 79
80 80 def is_developer(user):
81 81
82 82 groups = [str(g.name) for g in user.groups.all()]
83 83 return 'Developer' in groups or user.is_staff
84 84
85 85
86 86 def is_operator(user):
87 87
88 88 groups = [str(g.name) for g in user.groups.all()]
89 89 return 'Operator' in groups or user.is_staff
90 90
91 91
92 92 def has_been_modified(model):
93 93
94 94 prev_hash = model.hash
95 95 new_hash = hashlib.sha256(str(model.parms_to_dict).encode()).hexdigest()
96 96 if prev_hash != new_hash:
97 97 model.hash = new_hash
98 98 model.save()
99 99 return True
100 100 return False
101 101
102 102
103 103 def index(request):
104 104 kwargs = {'no_sidebar': True}
105 105
106 106 return render(request, 'index.html', kwargs)
107 107
108 108
109 109 def locations(request):
110 110
111 111 page = request.GET.get('page')
112 112 order = ('name',)
113 113
114 114 kwargs = get_paginator(Location, page, order)
115 115
116 116 kwargs['keys'] = ['name', 'description']
117 117 kwargs['title'] = 'Radar System'
118 118 kwargs['suptitle'] = 'List'
119 119 kwargs['no_sidebar'] = True
120 120
121 121 return render(request, 'base_list.html', kwargs)
122 122
123 123
124 124 def location(request, id_loc):
125 125
126 126 location = get_object_or_404(Location, pk=id_loc)
127 127
128 128 kwargs = {}
129 129 kwargs['location'] = location
130 130 kwargs['location_keys'] = ['name', 'description']
131 131
132 132 kwargs['title'] = 'Location'
133 133 kwargs['suptitle'] = 'Details'
134 134
135 135 return render(request, 'location.html', kwargs)
136 136
137 137
138 138 @login_required
139 139 def location_new(request):
140 140
141 141 if request.method == 'GET':
142 142 form = LocationForm()
143 143
144 144 if request.method == 'POST':
145 145 form = LocationForm(request.POST)
146 146
147 147 if form.is_valid():
148 148 form.save()
149 149 return redirect('url_locations')
150 150
151 151 kwargs = {}
152 152 kwargs['form'] = form
153 153 kwargs['title'] = 'Radar System'
154 154 kwargs['suptitle'] = 'New'
155 155 kwargs['button'] = 'Create'
156 156
157 157 return render(request, 'base_edit.html', kwargs)
158 158
159 159
160 160 @login_required
161 161 def location_edit(request, id_loc):
162 162
163 163 location = get_object_or_404(Location, pk=id_loc)
164 164
165 165 if request.method == 'GET':
166 166 form = LocationForm(instance=location)
167 167
168 168 if request.method == 'POST':
169 169 form = LocationForm(request.POST, instance=location)
170 170
171 171 if form.is_valid():
172 172 form.save()
173 173 return redirect('url_locations')
174 174
175 175 kwargs = {}
176 176 kwargs['form'] = form
177 177 kwargs['title'] = 'Location'
178 178 kwargs['suptitle'] = 'Edit'
179 179 kwargs['button'] = 'Update'
180 180
181 181 return render(request, 'base_edit.html', kwargs)
182 182
183 183
184 184 @login_required
185 185 def location_delete(request, id_loc):
186 186
187 187 location = get_object_or_404(Location, pk=id_loc)
188 188
189 189 if request.method == 'POST':
190 190
191 191 if is_developer(request.user):
192 192 location.delete()
193 193 return redirect('url_locations')
194 194
195 195 messages.error(request, 'Not enough permission to delete this object')
196 196 return redirect(location.get_absolute_url())
197 197
198 198 kwargs = {
199 199 'title': 'Delete',
200 200 'suptitle': 'Location',
201 201 'object': location,
202 202 'delete': True
203 203 }
204 204
205 205 return render(request, 'confirm.html', kwargs)
206 206
207 207
208 208 def devices(request):
209 209
210 210 page = request.GET.get('page')
211 211 order = ('location', 'device_type')
212 212
213 213 filters = request.GET.copy()
214 214 kwargs = get_paginator(Device, page, order, filters)
215 215 form = FilterForm(initial=request.GET, extra_fields=['tags'])
216 216
217 217 kwargs['keys'] = ['device_type', 'location',
218 218 'ip_address', 'port_address', 'actions']
219 219 kwargs['title'] = 'Device'
220 220 kwargs['suptitle'] = 'List'
221 221 kwargs['no_sidebar'] = True
222 222 kwargs['form'] = form
223 223 kwargs['add_url'] = reverse('url_add_device')
224 224 filters.pop('page', None)
225 225 kwargs['q'] = urlencode(filters)
226 226 kwargs['menu_devices'] = 'active'
227 227 return render(request, 'base_list.html', kwargs)
228 228
229 229
230 230 def device(request, id_dev):
231 231
232 232 device = get_object_or_404(Device, pk=id_dev)
233 233
234 234 kwargs = {}
235 235 kwargs['device'] = device
236 236 kwargs['device_keys'] = ['device_type',
237 237 'ip_address', 'port_address', 'description']
238 238
239 239 kwargs['title'] = 'Device'
240 240 kwargs['suptitle'] = 'Details'
241 241 kwargs['menu_devices'] = 'active'
242 242
243 243 return render(request, 'device.html', kwargs)
244 244
245 245
246 246 @login_required
247 247 def device_new(request):
248 248
249 249 if request.method == 'GET':
250 250 form = DeviceForm()
251 251
252 252 if request.method == 'POST':
253 253 form = DeviceForm(request.POST)
254 254
255 255 if form.is_valid():
256 256 form.save()
257 257 return redirect('url_devices')
258 258
259 259 kwargs = {}
260 260 kwargs['form'] = form
261 261 kwargs['title'] = 'Device'
262 262 kwargs['suptitle'] = 'New_2'
263 263 kwargs['button'] = 'Create'
264 264 kwargs['menu_devices'] = 'active'
265 265
266 266 return render(request, 'base_edit.html', kwargs)
267 267
268 268
269 269 @login_required
270 270 def device_edit(request, id_dev):
271 271
272 272 device = get_object_or_404(Device, pk=id_dev)
273 273
274 274 if request.method == 'GET':
275 275 form = DeviceForm(instance=device)
276 276
277 277 if request.method == 'POST':
278 278 form = DeviceForm(request.POST, instance=device)
279 279
280 280 if form.is_valid():
281 281 form.save()
282 282 return redirect(device.get_absolute_url())
283 283
284 284 kwargs = {}
285 285 kwargs['form'] = form
286 286 kwargs['title'] = 'Device'
287 287 kwargs['suptitle'] = 'Edit'
288 288 kwargs['button'] = 'Update'
289 289 kwargs['menu_devices'] = 'active'
290 290
291 291 return render(request, 'base_edit.html', kwargs)
292 292
293 293
294 294 @login_required
295 295 def device_delete(request, id_dev):
296 296
297 297 device = get_object_or_404(Device, pk=id_dev)
298 298
299 299 if request.method == 'POST':
300 300
301 301 if is_developer(request.user):
302 302 device.delete()
303 303 return redirect('url_devices')
304 304
305 305 messages.error(request, 'Not enough permission to delete this object')
306 306 return redirect(device.get_absolute_url())
307 307
308 308 kwargs = {
309 309 'title': 'Delete',
310 310 'suptitle': 'Device',
311 311 'object': device,
312 312 'delete': True
313 313 }
314 314 kwargs['menu_devices'] = 'active'
315 315
316 316 return render(request, 'confirm.html', kwargs)
317 317
318 318
319 319 @login_required
320 320 def device_change_ip(request, id_dev):
321 321
322 322 device = get_object_or_404(Device, pk=id_dev)
323 323
324 324 if request.method == 'POST':
325 325
326 326 if is_developer(request.user):
327 327 device.change_ip(**request.POST.dict())
328 328 level, message = device.message.split('|')
329 329 messages.add_message(request, level, message)
330 330 else:
331 331 messages.error(
332 332 request, 'Not enough permission to delete this object')
333 333 return redirect(device.get_absolute_url())
334 334
335 335 kwargs = {
336 336 'title': 'Device',
337 337 'suptitle': 'Change IP',
338 338 'object': device,
339 339 'previous': device.get_absolute_url(),
340 340 'form': ChangeIpForm(initial={'ip_address': device.ip_address}),
341 341 'message': ' ',
342 342 }
343 343 kwargs['menu_devices'] = 'active'
344 344
345 345 return render(request, 'confirm.html', kwargs)
346 346
347 347
348 348 def campaigns(request):
349 349
350 350 page = request.GET.get('page')
351 351 order = ('-start_date',)
352 352 filters = request.GET.copy()
353 353
354 354 kwargs = get_paginator(Campaign, page, order, filters)
355 355
356 356 form = FilterForm(initial=request.GET, extra_fields=[
357 357 'range_date', 'tags', 'template'])
358 358 kwargs['keys'] = ['name', 'start_date', 'end_date', 'actions']
359 359 kwargs['title'] = 'Campaign'
360 360 kwargs['suptitle'] = 'List'
361 361 kwargs['no_sidebar'] = True
362 362 kwargs['form'] = form
363 363 kwargs['add_url'] = reverse('url_add_campaign')
364 364 filters.pop('page', None)
365 365 kwargs['q'] = urlencode(filters)
366 366 kwargs['menu_campaigns'] = 'active'
367 367
368 368 return render(request, 'base_list.html', kwargs)
369 369
370 370
371 371 def campaign(request, id_camp):
372 372
373 373 campaign = get_object_or_404(Campaign, pk=id_camp)
374 374 experiments = Experiment.objects.filter(campaign=campaign)
375 375
376 376 form = CampaignForm(instance=campaign)
377 377
378 378 kwargs = {}
379 379 kwargs['campaign'] = campaign
380 380 kwargs['campaign_keys'] = ['template', 'name',
381 381 'start_date', 'end_date', 'tags', 'description']
382 382
383 383 kwargs['experiments'] = experiments
384 384 kwargs['experiment_keys'] = [
385 385 'name', 'radar_system', 'start_time', 'end_time']
386 386
387 387 kwargs['title'] = 'Campaign'
388 388 kwargs['suptitle'] = 'Details'
389 389
390 390 kwargs['form'] = form
391 391 kwargs['button'] = 'Add Experiment'
392 392 kwargs['menu_campaigns'] = 'active'
393 393
394 394 return render(request, 'campaign.html', kwargs)
395 395
396 396
397 397 @login_required
398 398 def campaign_new(request):
399 399
400 400 kwargs = {}
401 401
402 402 if request.method == 'GET':
403 403
404 404 if 'template' in request.GET:
405 405 if request.GET['template'] == '0':
406 406 form = NewForm(initial={'create_from': 2},
407 407 template_choices=Campaign.objects.filter(template=True).values_list('id', 'name'))
408 408 else:
409 409 kwargs['button'] = 'Create'
410 410 kwargs['experiments'] = Configuration.objects.filter(
411 411 experiment=request.GET['template'])
412 412 kwargs['experiment_keys'] = ['name', 'start_time', 'end_time']
413 413 camp = Campaign.objects.get(pk=request.GET['template'])
414 414 form = CampaignForm(instance=camp,
415 415 initial={'name': '{}_{:%Y%m%d}'.format(camp.name, datetime.now()),
416 416 'template': False})
417 417 elif 'blank' in request.GET:
418 418 kwargs['button'] = 'Create'
419 419 form = CampaignForm()
420 420 else:
421 421 form = NewForm()
422 422
423 423 if request.method == 'POST':
424 424 kwargs['button'] = 'Create'
425 425 post = request.POST.copy()
426 426 experiments = []
427 427
428 428 for id_exp in post.getlist('experiments'):
429 429 exp = Experiment.objects.get(pk=id_exp)
430 430 new_exp = exp.clone(template=False)
431 431 experiments.append(new_exp)
432 432
433 433 post.setlist('experiments', [])
434 434
435 435 form = CampaignForm(post)
436 436
437 437 if form.is_valid():
438 438 campaign = form.save(commit=False)
439 439 campaign.author = request.user
440 440 for exp in experiments:
441 441 campaign.experiments.add(exp)
442 442 campaign.save()
443 443 return redirect('url_campaign', id_camp=campaign.id)
444 444
445 445 kwargs['form'] = form
446 446 kwargs['title'] = 'Campaign'
447 447 kwargs['suptitle'] = 'New'
448 448 kwargs['menu_campaigns'] = 'active'
449 449
450 450 return render(request, 'campaign_edit.html', kwargs)
451 451
452 452
453 453 @login_required
454 454 def campaign_edit(request, id_camp):
455 455
456 456 campaign = get_object_or_404(Campaign, pk=id_camp)
457 457
458 458 if request.method == 'GET':
459 459 form = CampaignForm(instance=campaign)
460 460
461 461 if request.method == 'POST':
462 462 exps = campaign.experiments.all().values_list('pk', flat=True)
463 463 post = request.POST.copy()
464 464 new_exps = post.getlist('experiments')
465 465 post.setlist('experiments', [])
466 466 form = CampaignForm(post, instance=campaign)
467 467
468 468 if form.is_valid():
469 469 camp = form.save()
470 470 for id_exp in new_exps:
471 471 if int(id_exp) in exps:
472 472 exps.pop(id_exp)
473 473 else:
474 474 exp = Experiment.objects.get(pk=id_exp)
475 475 if exp.template:
476 476 camp.experiments.add(exp.clone(template=False))
477 477 else:
478 478 camp.experiments.add(exp)
479 479
480 480 for id_exp in exps:
481 481 camp.experiments.remove(Experiment.objects.get(pk=id_exp))
482 482
483 483 return redirect('url_campaign', id_camp=id_camp)
484 484
485 485 kwargs = {}
486 486 kwargs['form'] = form
487 487 kwargs['title'] = 'Campaign'
488 488 kwargs['suptitle'] = 'Edit'
489 489 kwargs['button'] = 'Update'
490 490 kwargs['menu_campaigns'] = 'active'
491 491
492 492 return render(request, 'campaign_edit.html', kwargs)
493 493
494 494
495 495 @login_required
496 496 def campaign_delete(request, id_camp):
497 497
498 498 campaign = get_object_or_404(Campaign, pk=id_camp)
499 499
500 500 if request.method == 'POST':
501 501 if is_developer(request.user):
502 502
503 503 for exp in campaign.experiments.all():
504 504 for conf in Configuration.objects.filter(experiment=exp):
505 505 conf.delete()
506 506 exp.delete()
507 507 campaign.delete()
508 508
509 509 return redirect('url_campaigns')
510 510
511 511 messages.error(request, 'Not enough permission to delete this object')
512 512 return redirect(campaign.get_absolute_url())
513 513
514 514 kwargs = {
515 515 'title': 'Delete',
516 516 'suptitle': 'Campaign',
517 517 'object': campaign,
518 518 'delete': True
519 519 }
520 520 kwargs['menu_campaigns'] = 'active'
521 521
522 522 return render(request, 'confirm.html', kwargs)
523 523
524 524
525 525 @login_required
526 526 def campaign_export(request, id_camp):
527 527
528 528 campaign = get_object_or_404(Campaign, pk=id_camp)
529 529 content = campaign.parms_to_dict()
530 530 content_type = 'application/json'
531 531 filename = '%s_%s.json' % (campaign.name, campaign.id)
532 532
533 533 response = HttpResponse(content_type=content_type)
534 534 response['Content-Disposition'] = 'attachment; filename="%s"' % filename
535 535 response.write(json.dumps(content, indent=2))
536 536
537 537 return response
538 538
539 539
540 540 @login_required
541 541 def campaign_import(request, id_camp):
542 542
543 543 campaign = get_object_or_404(Campaign, pk=id_camp)
544 544
545 545 if request.method == 'GET':
546 546 file_form = UploadFileForm()
547 547
548 548 if request.method == 'POST':
549 549 file_form = UploadFileForm(request.POST, request.FILES)
550 550
551 551 if file_form.is_valid():
552 552 new_camp = campaign.dict_to_parms(
553 553 json.load(request.FILES['file']), CONF_MODELS)
554 554 messages.success(
555 555 request, "Parameters imported from: '%s'." % request.FILES['file'].name)
556 556 return redirect(new_camp.get_absolute_url_edit())
557 557
558 558 messages.error(request, "Could not import parameters from file")
559 559
560 560 kwargs = {}
561 561 kwargs['title'] = 'Campaign'
562 562 kwargs['form'] = file_form
563 563 kwargs['suptitle'] = 'Importing file'
564 564 kwargs['button'] = 'Import'
565 565 kwargs['menu_campaigns'] = 'active'
566 566
567 567 return render(request, 'campaign_import.html', kwargs)
568 568
569 569
570 570 def experiments(request):
571 571
572 572 page = request.GET.get('page')
573 573 order = ('location',)
574 574 filters = request.GET.copy()
575 575
576 576 if 'my experiments' in filters:
577 577 filters.pop('my experiments', None)
578 578 filters['mine'] = request.user.id
579 579
580 580 kwargs = get_paginator(Experiment, page, order, filters)
581 581
582 582 fields = ['tags', 'template']
583 583 if request.user.is_authenticated:
584 584 fields.append('my experiments')
585 585
586 586 form = FilterForm(initial=request.GET, extra_fields=fields)
587 587
588 588 kwargs['keys'] = ['name', 'radar_system',
589 589 'start_time', 'end_time', 'actions']
590 590 kwargs['title'] = 'Experiment'
591 591 kwargs['suptitle'] = 'List'
592 592 kwargs['no_sidebar'] = True
593 593 kwargs['form'] = form
594 594 kwargs['add_url'] = reverse('url_add_experiment')
595 595 filters = request.GET.copy()
596 596 filters.pop('page', None)
597 597 kwargs['q'] = urlencode(filters)
598 598 kwargs['menu_experiments'] = 'active'
599 599
600 600 return render(request, 'base_list.html', kwargs)
601 601
602 602
603 603 def experiment(request, id_exp):
604 604
605 605 experiment = get_object_or_404(Experiment, pk=id_exp)
606 606
607 607 configurations = Configuration.objects.filter(
608 608 experiment=experiment, type=0)
609 609
610 610 kwargs = {}
611 611
612 612 kwargs['experiment_keys'] = ['template', 'radar_system',
613 613 'name', 'freq', 'start_time', 'end_time']
614 614 kwargs['experiment'] = experiment
615 615 kwargs['configuration_keys'] = ['name', 'device__ip_address',
616 616 'device__port_address', 'device__status']
617 617 kwargs['configurations'] = configurations
618 618 kwargs['title'] = 'Experiment'
619 619 kwargs['suptitle'] = 'Details'
620 620 kwargs['button'] = 'Add Configuration'
621 621 kwargs['menu_experiments'] = 'active'
622 622
623 623 ###### SIDEBAR ######
624 624 kwargs.update(sidebar(experiment=experiment))
625 625
626 626 return render(request, 'experiment.html', kwargs)
627 627
628 628
629 629 @login_required
630 630 def experiment_new(request, id_camp=None):
631 631
632 632 if not is_developer(request.user):
633 633 messages.error(
634 634 request, 'Developer required, to create new Experiments')
635 635 return redirect('index')
636 636 kwargs = {}
637 637
638 638 if request.method == 'GET':
639 639 if 'template' in request.GET:
640 640 if request.GET['template'] == '0':
641 641 form = NewForm(initial={'create_from': 2},
642 642 template_choices=Experiment.objects.filter(template=True).values_list('id', 'name'))
643 643 else:
644 644 kwargs['button'] = 'Create'
645 645 kwargs['configurations'] = Configuration.objects.filter(
646 646 experiment=request.GET['template'])
647 647 kwargs['configuration_keys'] = ['name', 'device__name',
648 648 'device__ip_address', 'device__port_address']
649 649 exp = Experiment.objects.get(pk=request.GET['template'])
650 650 form = ExperimentForm(instance=exp,
651 651 initial={'name': '{}_{:%y%m%d}'.format(exp.name, datetime.now()),
652 652 'template': False})
653 653 elif 'blank' in request.GET:
654 654 kwargs['button'] = 'Create'
655 655 form = ExperimentForm()
656 656 else:
657 657 form = NewForm()
658 658
659 659 if request.method == 'POST':
660 660 form = ExperimentForm(request.POST)
661 661 if form.is_valid():
662 662 experiment = form.save(commit=False)
663 663 experiment.author = request.user
664 664 experiment.save()
665 665
666 666 if 'template' in request.GET:
667 667 configurations = Configuration.objects.filter(
668 668 experiment=request.GET['template'], type=0)
669 669 for conf in configurations:
670 670 conf.clone(experiment=experiment, template=False)
671 671
672 672 return redirect('url_experiment', id_exp=experiment.id)
673 673
674 674 kwargs['form'] = form
675 675 kwargs['title'] = 'Experiment'
676 676 kwargs['suptitle'] = 'New'
677 677 kwargs['menu_experiments'] = 'active'
678 678
679 679 return render(request, 'experiment_edit.html', kwargs)
680 680
681 681
682 682 @login_required
683 683 def experiment_edit(request, id_exp):
684 684
685 685 experiment = get_object_or_404(Experiment, pk=id_exp)
686 686
687 687 if request.method == 'GET':
688 688 form = ExperimentForm(instance=experiment)
689 689
690 690 if request.method == 'POST':
691 691 form = ExperimentForm(request.POST, instance=experiment)
692 692
693 693 if form.is_valid():
694 694 experiment = form.save()
695 695 return redirect('url_experiment', id_exp=experiment.id)
696 696
697 697 kwargs = {}
698 698 kwargs['form'] = form
699 699 kwargs['title'] = 'Experiment'
700 700 kwargs['suptitle'] = 'Edit'
701 701 kwargs['button'] = 'Update'
702 702 kwargs['menu_experiments'] = 'active'
703 703
704 704 return render(request, 'experiment_edit.html', kwargs)
705 705
706 706
707 707 @login_required
708 708 def experiment_delete(request, id_exp):
709 709
710 710 experiment = get_object_or_404(Experiment, pk=id_exp)
711 711
712 712 if request.method == 'POST':
713 713 if is_developer(request.user):
714 714 for conf in Configuration.objects.filter(experiment=experiment):
715 715 conf.delete()
716 716 experiment.delete()
717 717 return redirect('url_experiments')
718 718
719 719 messages.error(request, 'Not enough permission to delete this object')
720 720 return redirect(experiment.get_absolute_url())
721 721
722 722 kwargs = {
723 723 'title': 'Delete',
724 724 'suptitle': 'Experiment',
725 725 'object': experiment,
726 726 'delete': True
727 727 }
728 728
729 729 return render(request, 'confirm.html', kwargs)
730 730
731 731
732 732 @login_required
733 733 def experiment_export(request, id_exp):
734 734
735 735 experiment = get_object_or_404(Experiment, pk=id_exp)
736 736 content = experiment.parms_to_dict()
737 737 content_type = 'application/json'
738 738 filename = '%s_%s.json' % (experiment.name, experiment.id)
739 739
740 740 response = HttpResponse(content_type=content_type)
741 741 response['Content-Disposition'] = 'attachment; filename="%s"' % filename
742 742 response.write(json.dumps(content, indent=2))
743 743
744 744 return response
745 745
746 746
747 747 @login_required
748 748 def experiment_import(request, id_exp):
749 749
750 750 experiment = get_object_or_404(Experiment, pk=id_exp)
751 751 configurations = Configuration.objects.filter(experiment=experiment)
752 752
753 753 if request.method == 'GET':
754 754 file_form = UploadFileForm()
755 755
756 756 if request.method == 'POST':
757 757 file_form = UploadFileForm(request.POST, request.FILES)
758 758
759 759 if file_form.is_valid():
760 760 new_exp = experiment.dict_to_parms(
761 761 json.load(request.FILES['file']), CONF_MODELS)
762 762 messages.success(
763 763 request, "Parameters imported from: '%s'." % request.FILES['file'].name)
764 764 return redirect(new_exp.get_absolute_url_edit())
765 765
766 766 messages.error(request, "Could not import parameters from file")
767 767
768 768 kwargs = {}
769 769 kwargs['title'] = 'Experiment'
770 770 kwargs['form'] = file_form
771 771 kwargs['suptitle'] = 'Importing file'
772 772 kwargs['button'] = 'Import'
773 773 kwargs['menu_experiments'] = 'active'
774 774
775 775 kwargs.update(sidebar(experiment=experiment))
776 776
777 777 return render(request, 'experiment_import.html', kwargs)
778 778
779 779
780 780 @login_required
781 781 def experiment_start(request, id_exp):
782 782
783 783 exp = get_object_or_404(Experiment, pk=id_exp)
784 784
785 785 if exp.status == 2:
786 786 messages.warning(request, 'Experiment {} already runnnig'.format(exp))
787 787 else:
788 788 exp.status = exp.start()
789 789 if exp.status == 0:
790 790 messages.error(request, 'Experiment {} not start'.format(exp))
791 791 if exp.status == 2:
792 792 messages.success(request, 'Experiment {} started'.format(exp))
793 793
794 794 exp.save()
795 795
796 796 return redirect(exp.get_absolute_url())
797 797
798 798
799 799 @login_required
800 800 def experiment_stop(request, id_exp):
801 801
802 802 exp = get_object_or_404(Experiment, pk=id_exp)
803 803
804 804 if exp.status == 2:
805 805 exp.status = exp.stop()
806 806 exp.save()
807 807 messages.success(request, 'Experiment {} stopped'.format(exp))
808 808 else:
809 809 messages.error(request, 'Experiment {} not running'.format(exp))
810 810
811 811 return redirect(exp.get_absolute_url())
812 812
813 813
814 814 def experiment_status(request, id_exp):
815 815
816 816 exp = get_object_or_404(Experiment, pk=id_exp)
817 817
818 818 exp.get_status()
819 819
820 820 return redirect(exp.get_absolute_url())
821 821
822 822
823 823 @login_required
824 824 def experiment_mix(request, id_exp):
825 825
826 826 experiment = get_object_or_404(Experiment, pk=id_exp)
827 827 rc_confs = [conf for conf in RCConfiguration.objects.filter(
828 828 experiment=id_exp,
829 829 type=0,
830 830 mix=False)]
831 831
832 832 if len(rc_confs) < 2:
833 833 messages.warning(
834 834 request, 'You need at least two RC Configurations to make a mix')
835 835 return redirect(experiment.get_absolute_url())
836 836
837 837 mix_confs = RCConfiguration.objects.filter(experiment=id_exp, mix=True, type=0)
838 838
839 839 if mix_confs:
840 840 mix = mix_confs[0]
841 841 else:
842 842 mix = RCConfiguration(experiment=experiment,
843 843 device=rc_confs[0].device,
844 844 ipp=rc_confs[0].ipp,
845 845 clock_in=rc_confs[0].clock_in,
846 846 clock_divider=rc_confs[0].clock_divider,
847 847 mix=True,
848 848 parameters='')
849 849 mix.save()
850 850
851 851 line_type = RCLineType.objects.get(name='mix')
852 print("VIew obteniendo len getlines")
853 print(len(rc_confs[0].get_lines()))
852 854 for i in range(len(rc_confs[0].get_lines())):
853 855 line = RCLine(rc_configuration=mix, line_type=line_type, channel=i)
854 856 line.save()
855 857
856 858 initial = {'name': mix.name,
857 859 'result': parse_mix_result(mix.parameters),
858 860 'delay': 0,
859 861 'mask': [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
860 862 }
861 863
862 864 if request.method == 'GET':
863 865 form = RCMixConfigurationForm(confs=rc_confs, initial=initial)
864 866
865 867 if request.method == 'POST':
866 868 result = mix.parameters
867 869
868 870 if '{}|'.format(request.POST['experiment']) in result:
869 871 messages.error(request, 'Configuration already added')
870 872 else:
871 873 if 'operation' in request.POST:
872 874 operation = MIX_OPERATIONS[request.POST['operation']]
873 875 else:
874 876 operation = ' '
875 877
876 878 mode = MIX_MODES[request.POST['mode']]
877 879
878 880 if result:
879 881 result = '{}-{}|{}|{}|{}|{}'.format(mix.parameters,
880 882 request.POST['experiment'],
881 883 mode,
882 884 operation,
883 885 float(
884 886 request.POST['delay']),
885 887 parse_mask(
886 888 request.POST.getlist('mask'))
887 889 )
888 890 else:
889 891 result = '{}|{}|{}|{}|{}'.format(request.POST['experiment'],
890 892 mode,
891 893 operation,
892 894 float(request.POST['delay']),
893 895 parse_mask(
894 896 request.POST.getlist('mask'))
895 897 )
896 898
897 899 mix.parameters = result
898 900 mix.save()
899 901 mix.update_pulses()
900 902
901 903 initial['result'] = parse_mix_result(result)
902 904 initial['name'] = mix.name
903 905
904 906 form = RCMixConfigurationForm(initial=initial, confs=rc_confs)
905 907
906 908 kwargs = {
907 909 'title': 'Experiment',
908 910 'suptitle': 'Mix Configurations',
909 911 'form': form,
910 912 'extra_button': 'Delete',
911 913 'button': 'Add',
912 914 'cancel': 'Back',
913 915 'previous': experiment.get_absolute_url(),
914 916 'id_exp': id_exp,
915 917
916 918 }
917 919 kwargs['menu_experiments'] = 'active'
918 920
919 921 return render(request, 'experiment_mix.html', kwargs)
920 922
921 923
922 924 @login_required
923 925 def experiment_mix_delete(request, id_exp):
924 926
925 927 conf = RCConfiguration.objects.get(experiment=id_exp, mix=True, type=0)
926 928 values = conf.parameters.split('-')
927 929 conf.parameters = '-'.join(values[:-1])
928 930 conf.save()
929 931
930 932 return redirect('url_mix_experiment', id_exp=id_exp)
931 933
932 934
933 935 def experiment_summary(request, id_exp):
934 936
935 937 experiment = get_object_or_404(Experiment, pk=id_exp)
936 938 configurations = Configuration.objects.filter(
937 939 experiment=experiment, type=0)
938 940
939 941 kwargs = {}
940 942 kwargs['experiment_keys'] = ['radar_system',
941 943 'name', 'freq', 'start_time', 'end_time']
942 944 kwargs['experiment'] = experiment
943 945 kwargs['configurations'] = []
944 946 kwargs['title'] = 'Experiment Summary'
945 947 kwargs['suptitle'] = 'Details'
946 948 kwargs['button'] = 'Verify Parameters'
947 949
948 950 c_vel = 3.0*(10**8) # m/s
949 951 ope_freq = experiment.freq*(10**6) # 1/s
950 952 radar_lambda = c_vel/ope_freq # m
951 953 kwargs['radar_lambda'] = radar_lambda
952 954
953 955 ipp = None
954 956 nsa = 1
955 957 code_id = 0
956 958 tx_line = {}
957 959
958 960 for configuration in configurations.filter(device__device_type__name = 'rc'):
959 961
960 962 if configuration.mix:
961 963 continue
962 964 conf = {'conf': configuration}
963 965 conf['keys'] = []
964 966 conf['NTxs'] = configuration.ntx
965 967 conf['keys'].append('NTxs')
966 968 ipp = configuration.ipp
967 969 conf['IPP'] = ipp
968 970 conf['keys'].append('IPP')
969 971 lines = configuration.get_lines(line_type__name='tx')
970 972
971 973 for tx_line in lines:
972 974 tx_params = json.loads(tx_line.params)
973 975 conf[tx_line.get_name()] = '{} Km'.format(tx_params['pulse_width'])
974 976 conf['keys'].append(tx_line.get_name())
975 977 delays = tx_params['delays']
976 978 if delays not in ('', '0'):
977 979 n = len(delays.split(','))
978 980 taus = '{} Taus: {}'.format(n, delays)
979 981 else:
980 982 taus = '-'
981 983 conf['Taus ({})'.format(tx_line.get_name())] = taus
982 984 conf['keys'].append('Taus ({})'.format(tx_line.get_name()))
983 985 for code_line in configuration.get_lines(line_type__name='codes'):
984 986 code_params = json.loads(code_line.params)
985 987 code_id = code_params['code']
986 988 if tx_line.pk == int(code_params['TX_ref']):
987 989 conf['Code ({})'.format(tx_line.get_name())] = '{}:{}'.format(RCLineCode.objects.get(pk=code_params['code']),
988 990 '-'.join(code_params['codes']))
989 991 conf['keys'].append('Code ({})'.format(tx_line.get_name()))
990 992
991 993 for windows_line in configuration.get_lines(line_type__name='windows'):
992 994 win_params = json.loads(windows_line.params)
993 995 if tx_line.pk == int(win_params['TX_ref']):
994 996 windows = ''
995 997 nsa = win_params['params'][0]['number_of_samples']
996 998 for i, params in enumerate(win_params['params']):
997 999 windows += 'W{}: Ho={first_height} km DH={resolution} km NSA={number_of_samples}<br>'.format(
998 1000 i, **params)
999 1001 conf['Window'] = mark_safe(windows)
1000 1002 conf['keys'].append('Window')
1001 1003
1002 1004 kwargs['configurations'].append(conf)
1003 1005
1004 1006 for configuration in configurations.filter(device__device_type__name = 'jars'):
1005 1007
1006 1008 conf = {'conf': configuration}
1007 1009 conf['keys'] = []
1008 1010 conf['Type of Data'] = EXPERIMENT_TYPE[configuration.exp_type][1]
1009 1011 conf['keys'].append('Type of Data')
1010 1012 channels_number = configuration.channels_number
1011 1013 exp_type = configuration.exp_type
1012 1014 fftpoints = configuration.fftpoints
1013 1015 filter_parms = json.loads(configuration.filter_parms)
1014 1016 spectral_number = configuration.spectral_number
1015 1017 acq_profiles = configuration.acq_profiles
1016 1018 cohe_integr = configuration.cohe_integr
1017 1019 profiles_block = configuration.profiles_block
1018 1020
1019 1021 conf['Num of Profiles'] = acq_profiles
1020 1022 conf['keys'].append('Num of Profiles')
1021 1023
1022 1024 conf['Prof per Block'] = profiles_block
1023 1025 conf['keys'].append('Prof per Block')
1024 1026
1025 1027 conf['Blocks per File'] = configuration.raw_data_blocks
1026 1028 conf['keys'].append('Blocks per File')
1027 1029
1028 1030 if exp_type == 0: # Short
1029 1031 bytes_ = 2
1030 1032 b = nsa*2*bytes_*channels_number
1031 1033 else: # Float
1032 1034 bytes_ = 4
1033 1035 channels = channels_number + spectral_number
1034 1036 b = nsa*2*bytes_*fftpoints*channels
1035 1037
1036 1038 codes_num = 7
1037 1039 if code_id == 2:
1038 1040 codes_num = 7
1039 1041 elif code_id == 12:
1040 1042 codes_num = 15
1041 1043
1042 1044 #Jars filter values:
1043 1045
1044 1046 clock = float(filter_parms['clock'])
1045 1047 filter_2 = int(filter_parms['cic_2'])
1046 1048 filter_5 = int(filter_parms['cic_5'])
1047 1049 filter_fir = int(filter_parms['fir'])
1048 1050 Fs_MHz = clock/(filter_2*filter_5*filter_fir)
1049 1051
1050 1052 #Jars values:
1051 1053 if ipp is not None:
1052 1054 IPP_units = ipp/0.15*Fs_MHz
1053 1055 IPP_us = IPP_units / Fs_MHz
1054 1056 IPP_s = IPP_units / (Fs_MHz * (10**6))
1055 1057 Ts = 1/(Fs_MHz*(10**6))
1056 1058
1057 1059 Va = radar_lambda/(4*Ts*cohe_integr)
1058 1060 rate_bh = ((nsa-codes_num)*channels_number*2 *
1059 1061 bytes_/IPP_us)*(36*(10**8)/cohe_integr)
1060 1062 rate_gh = rate_bh/(1024*1024*1024)
1061 1063
1062 1064 conf['Time per Block'] = IPP_s * profiles_block * cohe_integr
1063 1065 conf['keys'].append('Time per Block')
1064 1066 conf['Acq time'] = IPP_s * acq_profiles
1065 1067 conf['keys'].append('Acq time')
1066 1068 conf['Data rate'] = str(rate_gh)+" (GB/h)"
1067 1069 conf['keys'].append('Data rate')
1068 1070 conf['Va (m/s)'] = Va
1069 1071 conf['keys'].append('Va (m/s)')
1070 1072 conf['Vrange (m/s)'] = 3/(2*IPP_s*cohe_integr)
1071 1073 conf['keys'].append('Vrange (m/s)')
1072 1074
1073 1075 kwargs['configurations'].append(conf)
1074 1076 kwargs['menu_experiments'] = 'active'
1075 1077
1076 1078 ###### SIDEBAR ######
1077 1079 kwargs.update(sidebar(experiment=experiment))
1078 1080
1079 1081 return render(request, 'experiment_summary.html', kwargs)
1080 1082
1081 1083
1082 1084 @login_required
1083 1085 def experiment_verify(request, id_exp):
1084 1086
1085 1087 experiment = get_object_or_404(Experiment, pk=id_exp)
1086 1088 experiment_data = experiment.parms_to_dict()
1087 1089 configurations = Configuration.objects.filter(
1088 1090 experiment=experiment, type=0)
1089 1091
1090 1092 kwargs = {}
1091 1093
1092 1094 kwargs['experiment_keys'] = ['template',
1093 1095 'radar_system', 'name', 'start_time', 'end_time']
1094 1096 kwargs['experiment'] = experiment
1095 1097
1096 1098 kwargs['configuration_keys'] = ['name', 'device__ip_address',
1097 1099 'device__port_address', 'device__status']
1098 1100 kwargs['configurations'] = configurations
1099 1101 kwargs['experiment_data'] = experiment_data
1100 1102
1101 1103 kwargs['title'] = 'Verify Experiment'
1102 1104 kwargs['suptitle'] = 'Parameters'
1103 1105
1104 1106 kwargs['button'] = 'Update'
1105 1107
1106 1108 jars_conf = False
1107 1109 rc_conf = False
1108 1110 dds_conf = False
1109 1111
1110 1112 for configuration in configurations:
1111 1113 #-------------------- JARS -----------------------:
1112 1114 if configuration.device.device_type.name == 'jars':
1113 1115 jars_conf = True
1114 1116 jars = configuration
1115 1117 kwargs['jars_conf'] = jars_conf
1116 1118 filter_parms = json.loads(jars.filter_parms)
1117 1119 kwargs['filter_parms'] = filter_parms
1118 1120 #--Sampling Frequency
1119 1121 clock = filter_parms['clock']
1120 1122 filter_2 = filter_parms['cic_2']
1121 1123 filter_5 = filter_parms['cic_5']
1122 1124 filter_fir = filter_parms['fir']
1123 1125 samp_freq_jars = clock/filter_2/filter_5/filter_fir
1124 1126
1125 1127 kwargs['samp_freq_jars'] = samp_freq_jars
1126 1128 kwargs['jars'] = configuration
1127 1129
1128 1130 #--------------------- RC ----------------------:
1129 1131 if configuration.device.device_type.name == 'rc' and not configuration.mix:
1130 1132 rc_conf = True
1131 1133 rc = configuration
1132 1134
1133 1135 rc_parms = configuration.parms_to_dict()
1134 1136
1135 1137 win_lines = rc.get_lines(line_type__name='windows')
1136 1138 if win_lines:
1137 1139 dh = json.loads(win_lines[0].params)['params'][0]['resolution']
1138 1140 #--Sampling Frequency
1139 1141 samp_freq_rc = 0.15/dh
1140 1142 kwargs['samp_freq_rc'] = samp_freq_rc
1141 1143
1142 1144 kwargs['rc_conf'] = rc_conf
1143 1145 kwargs['rc'] = configuration
1144 1146
1145 1147 #-------------------- DDS ----------------------:
1146 1148 if configuration.device.device_type.name == 'dds':
1147 1149 dds_conf = True
1148 1150 dds = configuration
1149 1151 dds_parms = configuration.parms_to_dict()
1150 1152
1151 1153 kwargs['dds_conf'] = dds_conf
1152 1154 kwargs['dds'] = configuration
1153 1155
1154 1156 #------------Validation------------:
1155 1157 #Clock
1156 1158 if dds_conf and rc_conf and jars_conf:
1157 1159 if float(filter_parms['clock']) != float(rc_parms['configurations']['byId'][str(rc.pk)]['clock_in']) and float(rc_parms['configurations']['byId'][str(rc.pk)]['clock_in']) != float(dds_parms['configurations']['byId'][str(dds.pk)]['clock']):
1158 1160 messages.warning(request, "Devices don't have the same clock.")
1159 1161 elif rc_conf and jars_conf:
1160 1162 if float(filter_parms['clock']) != float(rc_parms['configurations']['byId'][str(rc.pk)]['clock_in']):
1161 1163 messages.warning(request, "Devices don't have the same clock.")
1162 1164 elif rc_conf and dds_conf:
1163 1165 if float(rc_parms['configurations']['byId'][str(rc.pk)]['clock_in']) != float(dds_parms['configurations']['byId'][str(dds.pk)]['clock']):
1164 1166 messages.warning(request, "Devices don't have the same clock.")
1165 1167 if float(samp_freq_rc) != float(dds_parms['configurations']['byId'][str(dds.pk)]['frequencyA']):
1166 1168 messages.warning(
1167 1169 request, "Devices don't have the same Frequency A.")
1168 1170
1169 1171 #------------POST METHOD------------:
1170 1172 if request.method == 'POST':
1171 1173 if request.POST['suggest_clock']:
1172 1174 try:
1173 1175 suggest_clock = float(request.POST['suggest_clock'])
1174 1176 except:
1175 1177 messages.warning(request, "Invalid value in CLOCK IN.")
1176 1178 return redirect('url_verify_experiment', id_exp=experiment.id)
1177 1179 else:
1178 1180 suggest_clock = ""
1179 1181 if suggest_clock:
1180 1182 if rc_conf:
1181 1183 rc.clock_in = suggest_clock
1182 1184 rc.save()
1183 1185 if jars_conf:
1184 1186 filter_parms = jars.filter_parms
1185 1187 filter_parms = ast.literal_eval(filter_parms)
1186 1188 filter_parms['clock'] = suggest_clock
1187 1189 jars.filter_parms = json.dumps(filter_parms)
1188 1190 jars.save()
1189 1191 kwargs['filter_parms'] = filter_parms
1190 1192 if dds_conf:
1191 1193 dds.clock = suggest_clock
1192 1194 dds.save()
1193 1195
1194 1196 if request.POST['suggest_frequencyA']:
1195 1197 try:
1196 1198 suggest_frequencyA = float(request.POST['suggest_frequencyA'])
1197 1199 except:
1198 1200 messages.warning(request, "Invalid value in FREQUENCY A.")
1199 1201 return redirect('url_verify_experiment', id_exp=experiment.id)
1200 1202 else:
1201 1203 suggest_frequencyA = ""
1202 1204 if suggest_frequencyA:
1203 1205 if jars_conf:
1204 1206 filter_parms = jars.filter_parms
1205 1207 filter_parms = ast.literal_eval(filter_parms)
1206 1208 filter_parms['fch'] = suggest_frequencyA
1207 1209 jars.filter_parms = json.dumps(filter_parms)
1208 1210 jars.save()
1209 1211 kwargs['filter_parms'] = filter_parms
1210 1212 if dds_conf:
1211 1213 dds.frequencyA_Mhz = request.POST['suggest_frequencyA']
1212 1214 dds.save()
1213 1215
1214 1216 kwargs['menu_experiments'] = 'active'
1215 1217 kwargs.update(sidebar(experiment=experiment))
1216 1218 return render(request, 'experiment_verify.html', kwargs)
1217 1219
1218 1220
1219 1221 def parse_mix_result(s):
1220 1222
1221 1223 values = s.split('-')
1222 1224 html = 'EXP MOD OPE DELAY MASK\r\n'
1223 1225
1224 1226 if not values or values[0] in ('', ' '):
1225 1227 return mark_safe(html)
1226 1228
1227 1229 for i, value in enumerate(values):
1228 1230 if not value:
1229 1231 continue
1230 1232 pk, mode, operation, delay, mask = value.split('|')
1231 1233 conf = RCConfiguration.objects.get(pk=pk)
1232 1234 if i == 0:
1233 1235 html += '{:20.18}{:3}{:4}{:9}km{:>6}\r\n'.format(
1234 1236 conf.name,
1235 1237 mode,
1236 1238 ' ',
1237 1239 delay,
1238 1240 mask)
1239 1241 else:
1240 1242 html += '{:20.18}{:3}{:4}{:9}km{:>6}\r\n'.format(
1241 1243 conf.name,
1242 1244 mode,
1243 1245 operation,
1244 1246 delay,
1245 1247 mask)
1246 1248
1247 1249 return mark_safe(html)
1248 1250
1249 1251
1250 1252 def parse_mask(l):
1251 1253
1252 1254 values = []
1253 1255
1254 1256 for x in range(16):
1255 1257 if '{}'.format(x) in l:
1256 1258 values.append(1)
1257 1259 else:
1258 1260 values.append(0)
1259 1261
1260 1262 values.reverse()
1261 1263
1262 1264 return int(''.join([str(x) for x in values]), 2)
1263 1265
1264 1266
1265 1267 def dev_confs(request):
1266 1268
1267 1269 page = request.GET.get('page')
1268 1270 order = ('-programmed_date', )
1269 1271 filters = request.GET.copy()
1270 1272 if 'my configurations' in filters:
1271 1273 filters.pop('my configurations', None)
1272 1274 filters['mine'] = request.user.id
1273 1275 kwargs = get_paginator(Configuration, page, order, filters)
1274 1276 fields = ['tags', 'template', 'historical']
1275 1277 if request.user.is_authenticated:
1276 1278 fields.append('my configurations')
1277 1279 form = FilterForm(initial=request.GET, extra_fields=fields)
1278 1280 kwargs['keys'] = ['name', 'experiment',
1279 1281 'type', 'programmed_date', 'actions']
1280 1282 kwargs['title'] = 'Configuration'
1281 1283 kwargs['suptitle'] = 'List'
1282 1284 kwargs['no_sidebar'] = True
1283 1285 kwargs['form'] = form
1284 1286 kwargs['add_url'] = reverse('url_add_dev_conf', args=[0])
1285 1287 filters = request.GET.copy()
1286 1288 filters.pop('page', None)
1287 1289 kwargs['q'] = urlencode(filters)
1288 1290 kwargs['menu_configurations'] = 'active'
1289 1291
1290 1292 return render(request, 'base_list.html', kwargs)
1291 1293
1292 1294
1293 1295 def dev_conf(request, id_conf):
1294 1296
1295 1297 conf = get_object_or_404(Configuration, pk=id_conf)
1296 1298
1297 1299 return redirect(conf.get_absolute_url())
1298 1300
1299 1301
1300 1302 @login_required
1301 1303 def dev_conf_new(request, id_exp=0, id_dev=0):
1302 1304
1303 1305 if not is_developer(request.user):
1304 1306 messages.error(
1305 1307 request, 'Developer required, to create new configurations')
1306 1308 return redirect('index')
1307 1309
1308 1310 initial = {}
1309 1311 kwargs = {}
1310 1312
1311 1313 if id_exp != 0:
1312 1314 initial['experiment'] = id_exp
1313 1315
1314 1316 if id_dev != 0:
1315 1317 initial['device'] = id_dev
1316 1318
1317 1319 if request.method == 'GET':
1318 1320
1319 1321 if id_dev:
1320 1322 kwargs['button'] = 'Create'
1321 1323 device = Device.objects.get(pk=id_dev)
1322 1324 DevConfForm = CONF_FORMS[device.device_type.name]
1323 1325 initial['name'] = request.GET['name']
1324 1326 form = DevConfForm(initial=initial)
1325 1327 else:
1326 1328 if 'template' in request.GET:
1327 1329 if request.GET['template'] == '0':
1328 1330 choices = [(conf.pk, '{}'.format(conf))
1329 1331 for conf in Configuration.objects.filter(template=True)]
1330 1332 form = NewForm(initial={'create_from': 2},
1331 1333 template_choices=choices)
1332 1334 else:
1333 1335 kwargs['button'] = 'Create'
1334 1336 conf = Configuration.objects.get(
1335 1337 pk=request.GET['template'])
1336 1338 id_dev = conf.device.pk
1337 1339 DevConfForm = CONF_FORMS[conf.device.device_type.name]
1338 1340 form = DevConfForm(instance=conf,
1339 1341 initial={'name': '{}_{:%y%m%d}'.format(conf.name, datetime.now()),
1340 1342 'template': False,
1341 1343 'experiment': id_exp})
1342 1344 elif 'blank' in request.GET:
1343 1345 kwargs['button'] = 'Create'
1344 1346 form = ConfigurationForm(initial=initial)
1345 1347 else:
1346 1348 form = NewForm()
1347 1349
1348 1350 if request.method == 'POST':
1349 1351
1350 1352 device = Device.objects.get(pk=request.POST['device'])
1351 1353 DevConfForm = CONF_FORMS[device.device_type.name]
1352 1354
1353 1355 form = DevConfForm(request.POST)
1354 1356 kwargs['button'] = 'Create'
1355 1357 if form.is_valid():
1356 1358 conf = form.save(commit=False)
1357 1359 conf.author = request.user
1358 1360 conf.save()
1359 1361
1360 1362 if 'template' in request.GET and conf.device.device_type.name == 'rc':
1361 1363 lines = RCLine.objects.filter(
1362 1364 rc_configuration=request.GET['template'])
1363 1365 for line in lines:
1364 1366 line.clone(rc_configuration=conf)
1365 1367
1366 1368 new_lines = conf.get_lines()
1367 1369 for line in new_lines:
1368 1370 line_params = json.loads(line.params)
1369 1371 if 'TX_ref' in line_params:
1370 1372 ref_line = RCLine.objects.get(pk=line_params['TX_ref'])
1371 1373 line_params['TX_ref'] = ['{}'.format(
1372 1374 l.pk) for l in new_lines if l.get_name() == ref_line.get_name()][0]
1373 1375 line.params = json.dumps(line_params)
1374 1376 line.save()
1375 1377 elif conf.device.device_type.name == 'rc':
1376 1378 clk = RCClock(rc_configuration=conf)
1377 1379 clk.save()
1378 1380
1379 1381 return redirect('url_dev_conf', id_conf=conf.pk)
1380 1382
1381 1383 kwargs['id_exp'] = id_exp
1382 1384 kwargs['form'] = form
1383 1385 kwargs['title'] = 'Configuration'
1384 1386 kwargs['suptitle'] = 'New'
1385 1387 kwargs['menu_configurations'] = 'active'
1386 1388
1387 1389 if id_dev != 0:
1388 1390 device = Device.objects.get(pk=id_dev)
1389 1391 kwargs['device'] = device.device_type.name
1390 1392 print(id_exp)
1391 1393 return render(request, 'dev_conf_edit.html', kwargs)
1392 1394
1393 1395
1394 1396 @login_required
1395 1397 def dev_conf_edit(request, id_conf):
1396 1398
1397 1399 conf = get_object_or_404(Configuration, pk=id_conf)
1398 1400
1399 1401 DevConfForm = CONF_FORMS[conf.device.device_type.name]
1400 1402
1401 1403 if request.method == 'GET':
1402 1404 form = DevConfForm(instance=conf)
1403 1405
1404 1406 if request.method == 'POST':
1405 1407 form = DevConfForm(request.POST, instance=conf)
1406 1408
1407 1409 if form.is_valid():
1408 1410 form.save()
1409 1411 return redirect('url_dev_conf', id_conf=id_conf)
1410 1412
1411 1413 kwargs = {}
1412 1414 kwargs['form'] = form
1413 1415 kwargs['title'] = 'Device Configuration'
1414 1416 kwargs['suptitle'] = 'Edit'
1415 1417 kwargs['button'] = 'Update'
1416 1418 kwargs['menu_configurations'] = 'active'
1417 1419
1418 1420 ###### SIDEBAR ######
1419 1421 kwargs.update(sidebar(conf=conf))
1420 1422
1421 1423 return render(request, '%s_conf_edit.html' % conf.device.device_type.name, kwargs)
1422 1424
1423 1425
1424 1426 @login_required
1425 1427 def dev_conf_start(request, id_conf):
1426 1428
1427 1429 conf = get_object_or_404(Configuration, pk=id_conf)
1428 1430
1429 1431 if conf.start_device():
1430 1432 messages.success(request, conf.message)
1431 1433 else:
1432 1434 messages.error(request, conf.message)
1433 1435
1434 1436 #conf.status_device()
1435 1437
1436 1438 return redirect(conf.get_absolute_url())
1437 1439
1438 1440
1439 1441 @login_required
1440 1442 def dev_conf_stop(request, id_conf):
1441 1443
1442 1444 conf = get_object_or_404(Configuration, pk=id_conf)
1443 1445
1444 1446 if conf.stop_device():
1445 1447 messages.success(request, conf.message)
1446 1448 else:
1447 1449 messages.error(request, conf.message)
1448 1450
1449 1451 #conf.status_device()
1450 1452
1451 1453 return redirect(conf.get_absolute_url())
1452 1454
1453 1455
1454 1456 @login_required
1455 1457 def dev_conf_status(request, id_conf):
1456 1458
1457 1459 conf = get_object_or_404(Configuration, pk=id_conf)
1458 1460
1459 1461 conf_active = Configuration.objects.filter(pk=conf.device.conf_active).first()
1460 1462 if conf_active!=conf:
1461 1463 url = '#' if conf_active is None else conf_active.get_absolute_url()
1462 1464 label = 'None' if conf_active is None else conf_active.label
1463 1465 messages.warning(
1464 1466 request,
1465 1467 mark_safe('The current configuration has not been written to device, the active configuration is <a href="{}">{}</a>'.format(
1466 1468 url,
1467 1469 label
1468 1470 ))
1469 1471 )
1470 1472
1471 1473 return redirect(conf.get_absolute_url())
1472 1474
1473 1475 if conf.status_device():
1474 1476 messages.success(request, conf.message)
1475 1477 else:
1476 1478 messages.error(request, conf.message)
1477 1479
1478 1480 return redirect(conf.get_absolute_url())
1479 1481
1480 1482
1481 1483 @login_required
1482 1484 def dev_conf_reset(request, id_conf):
1483 1485
1484 1486 conf = get_object_or_404(Configuration, pk=id_conf)
1485 1487
1486 1488 if conf.reset_device():
1487 1489 messages.success(request, conf.message)
1488 1490 else:
1489 1491 messages.error(request, conf.message)
1490 1492
1491 1493 return redirect(conf.get_absolute_url())
1492 1494
1493 1495
1494 1496 @login_required
1495 1497 def dev_conf_write(request, id_conf):
1496 1498
1497 1499 conf = get_object_or_404(Configuration, pk=id_conf)
1498 1500
1499 1501 if request.method == 'POST':
1500 1502 if conf.write_device():
1501 1503 conf.device.conf_active = conf.pk
1502 1504 conf.device.save()
1503 1505 messages.success(request, conf.message)
1504 1506 if has_been_modified(conf):
1505 1507 conf.clone(type=1, template=False)
1506 1508 else:
1507 1509 messages.error(request, conf.message)
1508 1510
1509 1511 return redirect(get_object_or_404(Configuration, pk=id_conf).get_absolute_url())
1510 1512
1511 1513 kwargs = {
1512 1514 'title': 'Write Configuration',
1513 1515 'suptitle': conf.label,
1514 1516 'message': 'Are you sure yo want to write this {} configuration?'.format(conf.device),
1515 1517 'delete': False
1516 1518 }
1517 1519 kwargs['menu_configurations'] = 'active'
1518 1520
1519 1521 return render(request, 'confirm.html', kwargs)
1520 1522
1521 1523
1522 1524 @login_required
1523 1525 def dev_conf_read(request, id_conf):
1524 1526
1525 1527 conf = get_object_or_404(Configuration, pk=id_conf)
1526 1528
1527 1529 DevConfForm = CONF_FORMS[conf.device.device_type.name]
1528 1530
1529 1531 if request.method == 'GET':
1530 1532
1531 1533 parms = conf.read_device()
1532 1534 #conf.status_device()
1533 1535
1534 1536 if not parms:
1535 1537 messages.error(request, conf.message)
1536 1538 return redirect(conf.get_absolute_url())
1537 1539
1538 1540 form = DevConfForm(initial=parms, instance=conf)
1539 1541
1540 1542 if request.method == 'POST':
1541 1543 form = DevConfForm(request.POST, instance=conf)
1542 1544
1543 1545 if form.is_valid():
1544 1546 form.save()
1545 1547 return redirect(conf.get_absolute_url())
1546 1548
1547 1549 messages.error(request, "Parameters could not be saved")
1548 1550
1549 1551 kwargs = {}
1550 1552 kwargs['id_dev'] = conf.id
1551 1553 kwargs['form'] = form
1552 1554 kwargs['title'] = 'Device Configuration'
1553 1555 kwargs['suptitle'] = 'Parameters read from device'
1554 1556 kwargs['button'] = 'Save'
1555 1557
1556 1558 ###### SIDEBAR ######
1557 1559 kwargs.update(sidebar(conf=conf))
1558 1560
1559 1561 return render(request, '%s_conf_edit.html' % conf.device.device_type.name, kwargs)
1560 1562
1561 1563
1562 1564 @login_required
1563 1565 def dev_conf_import(request, id_conf):
1564 1566
1565 1567 conf = get_object_or_404(Configuration, pk=id_conf)
1566 1568 DevConfForm = CONF_FORMS[conf.device.device_type.name]
1567 1569
1568 1570 if request.method == 'GET':
1569 1571 file_form = UploadFileForm()
1570 1572
1571 1573 if request.method == 'POST':
1572 1574 file_form = UploadFileForm(request.POST, request.FILES)
1573 1575
1574 1576 if file_form.is_valid():
1575 1577
1576 1578 data = conf.import_from_file(request.FILES['file'])
1577 1579 parms = Params(data=data).get_conf(
1578 1580 dtype=conf.device.device_type.name)
1579 1581
1580 1582 if parms:
1581 1583
1582 1584 form = DevConfForm(initial=parms, instance=conf)
1583 1585
1584 1586 kwargs = {}
1585 1587 kwargs['id_dev'] = conf.id
1586 1588 kwargs['form'] = form
1587 1589 kwargs['title'] = 'Device Configuration'
1588 1590 kwargs['suptitle'] = 'Parameters imported'
1589 1591 kwargs['button'] = 'Save'
1590 1592 kwargs['action'] = conf.get_absolute_url_edit()
1591 1593 kwargs['previous'] = conf.get_absolute_url()
1592 1594
1593 1595 ###### SIDEBAR ######
1594 1596 kwargs.update(sidebar(conf=conf))
1595 1597
1596 1598 messages.success(
1597 1599 request, "Parameters imported from: '%s'." % request.FILES['file'].name)
1598 1600
1599 1601 return render(request, '%s_conf_edit.html' % conf.device.device_type.name, kwargs)
1600 1602
1601 1603 messages.error(request, "Could not import parameters from file")
1602 1604
1603 1605 kwargs = {}
1604 1606 kwargs['id_dev'] = conf.id
1605 1607 kwargs['title'] = 'Device Configuration'
1606 1608 kwargs['form'] = file_form
1607 1609 kwargs['suptitle'] = 'Importing file'
1608 1610 kwargs['button'] = 'Import'
1609 1611 kwargs['menu_configurations'] = 'active'
1610 1612
1611 1613 kwargs.update(sidebar(conf=conf))
1612 1614
1613 1615 return render(request, 'dev_conf_import.html', kwargs)
1614 1616
1615 1617
1616 1618 @login_required
1617 1619 def dev_conf_export(request, id_conf):
1618 1620
1619 1621 conf = get_object_or_404(Configuration, pk=id_conf)
1620 1622
1621 1623 if request.method == 'GET':
1622 1624 file_form = DownloadFileForm(conf.device.device_type.name)
1623 1625
1624 1626 if request.method == 'POST':
1625 1627 file_form = DownloadFileForm(
1626 1628 conf.device.device_type.name, request.POST)
1627 1629
1628 1630 if file_form.is_valid():
1629 1631 fields = conf.export_to_file(
1630 1632 format=file_form.cleaned_data['format'])
1631 1633 if not fields['content']:
1632 1634 messages.error(request, conf.message)
1633 1635 return redirect(conf.get_absolute_url_export())
1634 1636 response = HttpResponse(content_type=fields['content_type'])
1635 1637 response['Content-Disposition'] = 'attachment; filename="%s"' % fields['filename']
1636 1638 response.write(fields['content'])
1637 1639
1638 1640 return response
1639 1641
1640 1642 messages.error(request, "Could not export parameters")
1641 1643
1642 1644 kwargs = {}
1643 1645 kwargs['id_dev'] = conf.id
1644 1646 kwargs['title'] = 'Device Configuration'
1645 1647 kwargs['form'] = file_form
1646 1648 kwargs['suptitle'] = 'Exporting file'
1647 1649 kwargs['button'] = 'Export'
1648 1650 kwargs['menu_configurations'] = 'active'
1649 1651
1650 1652 return render(request, 'dev_conf_export.html', kwargs)
1651 1653
1652 1654
1653 1655 @login_required
1654 1656 def dev_conf_delete(request, id_conf):
1655 1657
1656 1658 conf = get_object_or_404(Configuration, pk=id_conf)
1657 1659
1658 1660 if request.method == 'POST':
1659 1661 if is_developer(request.user):
1660 1662 conf.delete()
1661 1663 return redirect('url_dev_confs')
1662 1664
1663 1665 messages.error(request, 'Not enough permission to delete this object')
1664 1666 return redirect(conf.get_absolute_url())
1665 1667
1666 1668 kwargs = {
1667 1669 'title': 'Delete',
1668 1670 'suptitle': 'Configuration',
1669 1671 'object': conf,
1670 1672 'delete': True
1671 1673 }
1672 1674 kwargs['menu_configurations'] = 'active'
1673 1675
1674 1676 return render(request, 'confirm.html', kwargs)
1675 1677
1676 1678
1677 1679 def sidebar(**kwargs):
1678 1680
1679 1681 side_data = {}
1680 1682
1681 1683 conf = kwargs.get('conf', None)
1682 1684 experiment = kwargs.get('experiment', None)
1683 1685
1684 1686 if not experiment:
1685 1687 experiment = conf.experiment
1686 1688
1687 1689 if experiment:
1688 1690 side_data['experiment'] = experiment
1689 1691 campaign = experiment.campaign_set.all()
1690 1692 if campaign:
1691 1693 side_data['campaign'] = campaign[0]
1692 1694 experiments = campaign[0].experiments.all().order_by('name')
1693 1695 else:
1694 1696 experiments = [experiment]
1695 1697 configurations = experiment.configuration_set.filter(type=0)
1696 1698 side_data['side_experiments'] = experiments
1697 1699 side_data['side_configurations'] = configurations.order_by(
1698 1700 'device__device_type__name')
1699 1701
1700 1702 return side_data
1701 1703
1702 1704
1703 1705 def get_paginator(model, page, order, filters={}, n=8):
1704 1706
1705 1707 kwargs = {}
1706 1708 query = Q()
1707 1709 if isinstance(filters, QueryDict):
1708 1710 filters = filters.dict()
1709 1711 [filters.pop(key) for key in filters.keys() if filters[key] in ('', ' ')]
1710 1712 filters.pop('page', None)
1711 1713
1712 1714 fields = [f.name for f in model._meta.get_fields()]
1713 1715
1714 1716 if 'template' in filters:
1715 1717 filters['template'] = True
1716 1718 if 'historical' in filters:
1717 1719 filters.pop('historical')
1718 1720 filters['type'] = 1
1719 1721 elif 'type' in fields:
1720 1722 filters['type'] = 0
1721 1723 if 'start_date' in filters:
1722 1724 filters['start_date__gte'] = filters.pop('start_date')
1723 1725 if 'end_date' in filters:
1724 1726 filters['start_date__lte'] = filters.pop('end_date')
1725 1727 if 'tags' in filters:
1726 1728 tags = filters.pop('tags')
1727 1729 if 'tags' in fields:
1728 1730 query = query | Q(tags__icontains=tags)
1729 1731 if 'label' in fields:
1730 1732 query = query | Q(label__icontains=tags)
1731 1733 if 'location' in fields:
1732 1734 query = query | Q(location__name__icontains=tags)
1733 1735 if 'device' in fields:
1734 1736 query = query | Q(device__device_type__name__icontains=tags)
1735 1737 query = query | Q(device__location__name__icontains=tags)
1736 1738 if 'device_type' in fields:
1737 1739 query = query | Q(device_type__name__icontains=tags)
1738 1740
1739 1741 if 'mine' in filters:
1740 1742 filters['author_id'] = filters['mine']
1741 1743 filters.pop('mine')
1742 1744 object_list = model.objects.filter(query, **filters).order_by(*order)
1743 1745 paginator = Paginator(object_list, n)
1744 1746
1745 1747 try:
1746 1748 objects = paginator.page(page)
1747 1749 except PageNotAnInteger:
1748 1750 objects = paginator.page(1)
1749 1751 except EmptyPage:
1750 1752 objects = paginator.page(paginator.num_pages)
1751 1753
1752 1754 kwargs['objects'] = objects
1753 1755 kwargs['offset'] = (int(page)-1)*n if page else 0
1754 1756
1755 1757 return kwargs
1756 1758
1757 1759
1758 1760 def operation(request, id_camp=None):
1759 1761
1760 1762 kwargs = {}
1761 1763 kwargs['title'] = 'Radars Operation'
1762 1764 kwargs['no_sidebar'] = True
1763 1765 kwargs['menu_operation'] = 'active'
1764 1766 campaigns = Campaign.objects.filter(start_date__lte=datetime.now(),
1765 1767 end_date__gte=datetime.now()).order_by('-start_date')
1766 1768
1767 1769 if id_camp:
1768 1770 campaign = get_object_or_404(Campaign, pk=id_camp)
1769 1771 form = OperationForm(
1770 1772 initial={'campaign': campaign.id}, campaigns=campaigns)
1771 1773 kwargs['campaign'] = campaign
1772 1774 else:
1773 1775 # form = OperationForm(campaigns=campaigns)
1774 1776 kwargs['campaigns'] = campaigns
1775 1777 return render(request, 'operation.html', kwargs)
1776 1778
1777 1779 #---Experiment
1778 1780 keys = ['id', 'name', 'start_time', 'end_time', 'status']
1779 1781 kwargs['experiment_keys'] = keys[1:]
1780 1782 kwargs['experiments'] = experiments
1781 1783 #---Radar
1782 1784 kwargs['locations'] = campaign.get_experiments_by_radar()
1783 1785 kwargs['form'] = form
1784 1786
1785 1787 return render(request, 'operation.html', kwargs)
1786 1788
1787 1789
1788 1790 @login_required
1789 1791 def radar_start(request, id_camp, id_radar):
1790 1792
1791 1793 campaign = get_object_or_404(Campaign, pk=id_camp)
1792 1794 experiments = campaign.get_experiments_by_radar(id_radar)[0]['experiments']
1793 1795 now = datetime.now()
1794 1796 for exp in experiments:
1795 1797 start = datetime.combine(datetime.now().date(), exp.start_time)
1796 1798 end = datetime.combine(datetime.now().date(), exp.end_time)
1797 1799 if end < start:
1798 1800 end += timedelta(1)
1799 1801
1800 1802 if exp.status == 2:
1801 1803 messages.warning(
1802 1804 request, 'Experiment {} already running'.format(exp))
1803 1805 continue
1804 1806
1805 1807 if exp.status == 3:
1806 1808 messages.warning(
1807 1809 request, 'Experiment {} already programmed'.format(exp))
1808 1810 continue
1809 1811
1810 1812 if start > campaign.end_date or start < campaign.start_date:
1811 1813 messages.warning(request, 'Experiment {} out of date'.format(exp))
1812 1814 continue
1813 1815
1814 1816 app.control.revoke(exp.task)
1815 1817
1816 1818 if now > start and now <= end:
1817 1819 task = task_start.delay(exp.id)
1818 1820 exp.status = task.wait()
1819 1821 if exp.status == 0:
1820 1822 messages.error(request, 'Experiment {} not start'.format(exp))
1821 1823 if exp.status == 2:
1822 1824 messages.success(request, 'Experiment {} started'.format(exp))
1823 1825 else:
1824 1826 task = task_start.apply_async(
1825 1827 (exp.pk, ), eta=start+timedelta(hours=5))
1826 1828 exp.task = task.id
1827 1829 exp.status = 3
1828 1830 messages.success(
1829 1831 request, 'Experiment {} programmed to start at {}'.format(exp, start))
1830 1832
1831 1833 exp.save()
1832 1834
1833 1835 return HttpResponseRedirect(reverse('url_operation', args=[id_camp]))
1834 1836
1835 1837
1836 1838 @login_required
1837 1839 def radar_stop(request, id_camp, id_radar):
1838 1840
1839 1841 campaign = get_object_or_404(Campaign, pk=id_camp)
1840 1842 experiments = campaign.get_experiments_by_radar(id_radar)[0]['experiments']
1841 1843
1842 1844 for exp in experiments:
1843 1845
1844 1846 if exp.task:
1845 1847 app.control.revoke(exp.task)
1846 1848 if exp.status == 2:
1847 1849 exp.stop()
1848 1850 messages.warning(request, 'Experiment {} stopped'.format(exp))
1849 1851 exp.status = 1
1850 1852 exp.save()
1851 1853
1852 1854 return HttpResponseRedirect(reverse('url_operation', args=[id_camp]))
1853 1855
1854 1856
1855 1857 @login_required
1856 1858 def radar_refresh(request, id_camp, id_radar):
1857 1859
1858 1860 campaign = get_object_or_404(Campaign, pk=id_camp)
1859 1861 experiments = campaign.get_experiments_by_radar(id_radar)[0]['experiments']
1860 1862
1861 1863 i = app.control.inspect()
1862 1864 scheduled = i.scheduled().values()[0]
1863 1865 revoked = i.revoked().values()[0]
1864 1866
1865 1867 for exp in experiments:
1866 1868 if exp.task in revoked:
1867 1869 exp.status = 1
1868 1870 elif exp.task in [t['request']['id'] for t in scheduled if 'task_stop' in t['request']['name']]:
1869 1871 exp.status = 2
1870 1872 elif exp.task in [t['request']['id'] for t in scheduled if 'task_start' in t['request']['name']]:
1871 1873 exp.status = 3
1872 1874 else:
1873 1875 exp.status = 4
1874 1876 exp.save()
1875 1877 return HttpResponseRedirect(reverse('url_operation', args=[id_camp]))
1876 1878
1877 1879 @login_required
1878 1880 def revoke_tasks(request, id_camp):
1879 1881
1880 1882 i = app.control.inspect()
1881 1883 scheduled = i.scheduled().values()[0]
1882 1884 revoked = i.revoked().values()[0]
1883 1885
1884 1886 for t in scheduled:
1885 1887 if t['request']['id'] in revoked:
1886 1888 continue
1887 1889 app.control.revoke(t['request']['id'])
1888 1890 exp = Experiment.objects.get(pk=eval(t['request']['args'])[0])
1889 1891 eta = t['eta']
1890 1892 task = t['request']['name'].split('.')[-1]
1891 1893 messages.warning(request, 'Scheduled {} at {} for experiment {} revoked'.format(task, eta, exp.name))
1892 1894
1893 1895 return HttpResponseRedirect(reverse('url_operation', args=[id_camp]))
1894 1896
1895 1897 @login_required
1896 1898 def show_tasks(request, id_camp):
1897 1899
1898 1900 i = app.control.inspect()
1899 1901 scheduled = i.scheduled().values()[0]
1900 1902 revoked = i.revoked().values()[0]
1901 1903
1902 1904 for t in scheduled:
1903 1905 if t['request']['id'] in revoked:
1904 1906 continue
1905 1907 exp = Experiment.objects.get(pk=eval(t['request']['args'])[0])
1906 1908 eta = t['eta']
1907 1909 task = t['request']['name'].split('.')[-1]
1908 1910 messages.success(request, 'Task {} scheduled at {} for experiment {}'.format(task, eta, exp.name))
1909 1911
1910 1912 return HttpResponseRedirect(reverse('url_operation', args=[id_camp]))
1911 1913
1912 1914 def real_time(request):
1913 1915
1914 1916 graphic_path = "/home/fiorella/Pictures/catwbeanie.jpg"
1915 1917
1916 1918 kwargs = {}
1917 1919 kwargs['title'] = 'CLAIRE'
1918 1920 kwargs['suptitle'] = 'Real Time'
1919 1921 kwargs['no_sidebar'] = True
1920 1922 kwargs['graphic_path'] = graphic_path
1921 1923 kwargs['graphic1_path'] = 'http://www.bluemaize.net/im/girls-accessories/shark-beanie-11.jpg'
1922 1924
1923 1925 return render(request, 'real_time.html', kwargs)
1924 1926
1925 1927 def theme(request, theme):
1926 1928
1927 1929 user = request.user
1928 1930 user.profile.theme = theme
1929 1931 user.save()
1930 1932 return redirect('index')
@@ -1,1032 +1,1041
1 1
2 2
3 3 import ast
4 4 import json
5 5 import requests
6 6 import numpy as np
7 7 from base64 import b64encode
8 8 from struct import pack
9 9
10 10 from django.db import models
11 11 from django.urls import reverse
12 12 from django.core.validators import MinValueValidator, MaxValueValidator
13 13
14 14 from apps.main.models import Configuration
15 15 from apps.main.utils import Params
16 16 from devices.rc import api
17 17 from apps.rc.utils import RCFile
18 18
19 19
20 20 LINE_TYPES = (
21 21 ('none', 'Not used'),
22 22 ('tr', 'Transmission/reception selector signal'),
23 23 ('tx', 'A modulating signal (Transmission pulse)'),
24 24 ('codes', 'BPSK modulating signal'),
25 25 ('windows', 'Sample window signal'),
26 26 ('sync', 'Synchronizing signal'),
27 27 ('flip', 'IPP related periodic signal'),
28 28 ('prog_pulses', 'Programmable pulse'),
29 29 ('mix', 'Mixed line'),
30 30 )
31 31
32 32
33 33 SAMPLING_REFS = (
34 34 ('none', 'No Reference'),
35 35 ('begin_baud', 'Begin of the first baud'),
36 36 ('first_baud', 'Middle of the first baud'),
37 37 ('sub_baud', 'Middle of the sub-baud')
38 38 )
39 39
40 40 DAT_CMDS = {
41 41 # Pulse Design commands
42 42 'DISABLE' : 0, # Disables pulse generation
43 43 'ENABLE' : 24, # Enables pulse generation
44 44 'DELAY_START' : 40, # Write delay status to memory
45 45 'FLIP_START' : 48, # Write flip status to memory
46 46 'SAMPLING_PERIOD' : 64, # Establish Sampling Period
47 47 'TX_ONE' : 72, # Output '0' in line TX
48 48 'TX_ZERO' : 88, # Output '0' in line TX
49 49 'SW_ONE' : 104, # Output '0' in line SW
50 50 'SW_ZERO' : 112, # Output '1' in line SW
51 51 'RESTART': 120, # Restarts CR8 Firmware
52 52 'CONTINUE' : 253, # Function Unknown
53 53 # Commands available to new controllers
54 54 # In Pulse Design Executable, the clock divisor code is written as 12 at the start, but it should be written as code 22(below) just before the final enable.
55 55 'CLOCK_DIVISOR_INIT' : 12, # Specifies Clock Divisor. Legacy command, ignored in the actual .dat conversion
56 56 'CLOCK_DIVISOR_LAST' : 22, # Specifies Clock Divisor (default 60 if not included) syntax: 255,22 254,N-1.
57 57 'CLOCK_DIVIDER' : 8,
58 58 }
59 59
60 60 MAX_BITS = 8
61 61
62 62 # Rotate left: 0b1001 --> 0b0011
63 63 rol = lambda val, r_bits: \
64 64 (val << r_bits%MAX_BITS) & (2**MAX_BITS-1) | \
65 65 ((val & (2**MAX_BITS-1)) >> (MAX_BITS-(r_bits%MAX_BITS)))
66 66
67 67 # Rotate right: 0b1001 --> 0b1100
68 68 ror = lambda val, r_bits: \
69 69 ((val & (2**MAX_BITS-1)) >> r_bits%MAX_BITS) | \
70 70 (val << (MAX_BITS-(r_bits%MAX_BITS)) & (2**MAX_BITS-1))
71 71
72 72
73 73 class RCConfiguration(Configuration):
74 74
75 75 ipp = models.FloatField(verbose_name='IPP [Km]', validators=[MinValueValidator(1)], default=300)
76 76 ntx = models.PositiveIntegerField(verbose_name='Number of TX', validators=[MinValueValidator(1)], default=1)
77 77 clock_in = models.FloatField(verbose_name='Clock in [MHz]', validators=[MinValueValidator(1), MaxValueValidator(80)], default=1)
78 78 clock_divider = models.PositiveIntegerField(verbose_name='Clock divider', validators=[MinValueValidator(1), MaxValueValidator(256)], default=1)
79 79 clock = models.FloatField(verbose_name='Clock Master [MHz]', blank=True, default=1)
80 80 time_before = models.PositiveIntegerField(verbose_name='Time before [&mu;S]', default=12)
81 81 time_after = models.PositiveIntegerField(verbose_name='Time after [&mu;S]', default=1)
82 82 sync = models.PositiveIntegerField(verbose_name='Synchro delay', default=0)
83 83 sampling_reference = models.CharField(verbose_name='Sampling Reference', choices=SAMPLING_REFS, default='none', max_length=40)
84 84 control_tx = models.BooleanField(verbose_name='Control Switch TX', default=False)
85 85 control_sw = models.BooleanField(verbose_name='Control Switch SW', default=False)
86 86 total_units = models.PositiveIntegerField(default=0)
87 87 mix = models.BooleanField(default=False)
88 88
89 89 class Meta:
90 90 db_table = 'rc_configurations'
91 91
92 92 def get_absolute_url_plot(self):
93 93 return reverse('url_plot_rc_pulses', args=[str(self.id)])
94 94
95 95 @property
96 96 def ipp_unit(self):
97 97
98 98 return '{} ({})'.format(self.ipp, int(self.ipp*self.km2unit))
99 99
100 100 @property
101 101 def us2unit(self):
102 102
103 103 return self.clock_in/self.clock_divider
104 104
105 105 @property
106 106 def km2unit(self):
107 107
108 108 return 20./3*(self.clock_in/self.clock_divider)
109 109
110 110 def clone(self, **kwargs):
111 111
112 112 lines = self.get_lines()
113 113 self.pk = None
114 114 self.id = None
115 115 for attr, value in kwargs.items():
116 116 setattr(self, attr, value)
117 117 self.save()
118 118
119 119 for line in lines:
120 120 line.clone(rc_configuration=self)
121 121
122 122 new_lines = self.get_lines()
123 123 for line in new_lines:
124 124 line_params = json.loads(line.params)
125 125 if 'TX_ref' in line_params and (line_params['TX_ref'] != '0'):
126 126 ref_line = RCLine.objects.get(pk=line_params['TX_ref'])
127 127 line_params['TX_ref'] = ['{}'.format(l.pk) for l in new_lines if l.get_name()==ref_line.get_name()][0]
128 128 line.params = json.dumps(line_params)
129 129 line.save()
130 130
131 131 return self
132 132
133 133 def get_lines(self, **kwargs):
134 134 '''
135 135 Retrieve configuration lines
136 136 '''
137 137
138 138 return RCLine.objects.filter(rc_configuration=self.pk, **kwargs)
139 139
140 140
141 141 def clean_lines(self):
142 142 '''
143 143 '''
144 144
145 145 empty_line = RCLineType.objects.get(name='none')
146 146
147 147 for line in self.get_lines():
148 148 line.line_type = empty_line
149 149 line.params = '{}'
150 150 line.save()
151 151
152 152 def dict_to_parms(self, params, id=None):
153 153 '''
154 154 '''
155 155
156 156 if id:
157 157 data = Params(params).get_conf(id_conf=id)
158 158 else:
159 159 data = Params(params).get_conf(dtype='rc')
160 160
161 161 #print(data)
162 162 # self.name = data['name']
163 163 self.ipp = data['ipp']
164 164 self.ntx = data['ntx']
165 165 self.clock_in = data['clock_in']
166 166 self.clock_divider = data['clock_divider']
167 167 self.clock = data['clock']
168 168 self.time_before = data['time_before']
169 169 self.time_after = data['time_after']
170 170 self.sync = data['sync']
171 171 self.sampling_reference = data['sampling_reference']
172 172 self.total_units = self.ipp*self.ntx*self.km2unit
173 173 self.save()
174 174 self.clean_lines()
175 175
176 176 #print(params)
177 177
178 178 positions = {'tx':0, 'tr':0}
179 179 for i, id in enumerate(data['lines']):
180 180 line_data = params['lines']['byId'][id]
181 181 line_type = RCLineType.objects.get(name=line_data['line_type'])
182 182 if line_type.name == 'codes':
183 183 code = RCLineCode.objects.get(name=line_data['params']['code'])
184 184 line_data['params']['code'] = code.pk
185 185 if line_type.name == 'tx':
186 186 position = positions['tx']
187 187 positions['tx'] += 1
188 188 elif line_type.name == 'tr':
189 189 position = positions['tr']
190 190 positions['tr'] += 1
191 191 else:
192 192 position = 0
193 193 line, dum = RCLine.objects.update_or_create(
194 194 rc_configuration=self,
195 195 channel=i,
196 196 position=position,
197 197 defaults={
198 198 'line_type': line_type,
199 199 'params': json.dumps(line_data['params'])
200 200 }
201 201 )
202 202
203 203 for i, line in enumerate(self.get_lines()):
204 204 line_params = json.loads(line.params)
205 205 if 'TX_ref' in line_params:
206 206 if line_params['TX_ref'] in (0, '0'):
207 207 line_params['TX_ref'] = '0'
208 208 else:
209 209 ref_id = '{}'.format(line_params['TX_ref'])
210 210 ref_line = params['lines']['byId'][ref_id]
211 211 line_params['TX_ref'] = RCLine.objects.get(
212 212 rc_configuration=self,
213 213 params=json.dumps(ref_line['params'])
214 214 ).pk
215 215 line.params = json.dumps(line_params)
216 216 print(line.params)
217 217 line.save()
218 218 print("Fin de dict to param")
219 219
220 220 def get_delays(self):
221 221
222 222 pulses = [line.pulses_as_points() for line in self.get_lines()]
223 223 points = [tup for tups in pulses for tup in tups]
224 224 points = set([x for tup in points for x in tup])
225 225 points = list(points)
226 226 points.sort()
227 227
228 228 if points[0]!=0:
229 229 points.insert(0, 0)
230 230
231 231 return [points[i+1]-points[i] for i in range(len(points)-1)]
232 232
233 233
234 234 def get_pulses(self, binary=True):
235 235
236 236 pulses = [line.pulses_as_points() for line in self.get_lines()]
237 237 tuples = [tup for tups in pulses for tup in tups]
238 238 points = set([x for tup in tuples for x in tup])
239 239 points = list(points)
240 240 points.sort()
241 241 states = []
242 242 last = [0 for x in pulses]
243 243
244 244 for x in points:
245 245 dum = []
246 246 for i, tups in enumerate(pulses):
247 247 ups = [tup[0] for tup in tups if tup!=(0,0)]
248 248 dws = [tup[1] for tup in tups if tup!=(0,0)]
249 249 if x in ups:
250 250 dum.append(1)
251 251 elif x in dws:
252 252 dum.append(0)
253 253 else:
254 254 dum.append(last[i])
255 255 states.append(dum)
256 256 last = dum
257 257
258 258 if binary:
259 259 ret = []
260 260 for flips in states:
261 261 flips.reverse()
262 262 ret.append(int(''.join([str(x) for x in flips]), 2))
263 263 states = ret
264 264
265 265 return states[:-1]
266 266
267 267 def add_cmd(self, cmd):
268 268
269 269 if cmd in DAT_CMDS:
270 270 return (255, DAT_CMDS[cmd])
271 271
272 272 def add_data(self, value):
273 273
274 274 return (254, value-1)
275 275
276 276 def parms_to_binary(self, dat=True):
277 277 '''
278 278 Create "dat" stream to be send to CR
279 279 '''
280 280
281 281 data = bytearray()
282 282 # create header
283 283 data.extend(self.add_cmd('DISABLE'))
284 284 data.extend(self.add_cmd('CONTINUE'))
285 285 data.extend(self.add_cmd('RESTART'))
286 286
287 287 if self.control_sw:
288 288 data.extend(self.add_cmd('SW_ONE'))
289 289 else:
290 290 data.extend(self.add_cmd('SW_ZERO'))
291 291
292 292 if self.control_tx:
293 293 data.extend(self.add_cmd('TX_ONE'))
294 294 else:
295 295 data.extend(self.add_cmd('TX_ZERO'))
296 296
297 297 # write divider
298 298 data.extend(self.add_cmd('CLOCK_DIVIDER'))
299 299 data.extend(self.add_data(self.clock_divider))
300 300
301 301 # write delays
302 302 data.extend(self.add_cmd('DELAY_START'))
303 303 # first delay is always zero
304 304 data.extend(self.add_data(1))
305 305
306 306 delays = self.get_delays()
307 307
308 308 for delay in delays:
309 309 while delay>252:
310 310 data.extend(self.add_data(253))
311 311 delay -= 253
312 312 data.extend(self.add_data(int(delay)))
313 313
314 314 # write flips
315 315 data.extend(self.add_cmd('FLIP_START'))
316 316
317 317 states = self.get_pulses(binary=True)
318 318
319 319
320 320 last = 0
321 321 for flip, delay in zip(states, delays):
322 322 data.extend(self.add_data((flip^last)+1))
323 323 last = flip
324 324 while delay>252:
325 325 data.extend(self.add_data(1))
326 326 delay -= 253
327 327
328 328 # write sampling period
329 329 data.extend(self.add_cmd('SAMPLING_PERIOD'))
330 330 wins = self.get_lines(line_type__name='windows')
331 331 if wins:
332 332 win_params = json.loads(wins[0].params)['params']
333 333 if win_params:
334 334 dh = int(win_params[0]['resolution']*self.km2unit)
335 335 else:
336 336 dh = 1
337 337 else:
338 338 dh = 1
339 339 data.extend(self.add_data(dh))
340 340
341 341 # write enable
342 342 data.extend(self.add_cmd('ENABLE'))
343 343
344 344 if not dat:
345 345 return data
346 346
347 347 return '\n'.join(['{}'.format(x) for x in data])
348 348
349 349 def update_pulses(self):
350
350 contador = 0
351 351 for line in self.get_lines():
352 contador=contador+1
353 print(contador)
352 354 line.update_pulses()
353 355
354 356 def plot_pulses2(self, km=False):
355 357
356 358 import matplotlib
357 359 matplotlib.use('Agg')
358 360 import matplotlib.pyplot as plt
359 361 from bokeh.resources import CDN
360 362 from bokeh.embed import components
361 363 from bokeh.mpl import to_bokeh
362 364 from bokeh.models.tools import WheelZoomTool, ResetTool, PanTool, HoverTool, SaveTool
363 365
364 366 lines = self.get_lines()
365 367
366 368 N = len(lines)
367 369 npoints = self.total_units/self.km2unit if km else self.total_units
368 370 fig = plt.figure(figsize=(12, 2+N*0.5))
369 371 ax = fig.add_subplot(111)
370 372 labels = ['IPP']
371 373
372 374 for i, line in enumerate(lines):
373 375 labels.append(line.get_name(channel=True))
374 376 l = ax.plot((0, npoints),(N-i-1, N-i-1))
375 377 points = [(tup[0], tup[1]-tup[0]) for tup in line.pulses_as_points(km=km) if tup!=(0,0)]
376 378 ax.broken_barh(points, (N-i-1, 0.5),
377 379 edgecolor=l[0].get_color(), facecolor='none')
378 380
379 381 n = 0
380 382 f = ((self.ntx+50)/100)*5 if ((self.ntx+50)/100)*10>0 else 2
381 383 for x in np.arange(0, npoints, self.ipp if km else self.ipp*self.km2unit):
382 384 if n%f==0:
383 385 ax.text(x, N, '%s' % n, size=10)
384 386 n += 1
385 387
386 388 labels.reverse()
387 389 ax.set_yticks(range(len(labels)))
388 390 ax.set_yticklabels(labels)
389 391 ax.set_xlabel = 'Units'
390 392 plot = to_bokeh(fig, use_pandas=False)
391 393 plot.tools = [PanTool(dimensions="width"), WheelZoomTool(dimensions="width"), ResetTool(), SaveTool()]
392 394 plot.toolbar_location="above"
393 395
394 396 return components(plot, CDN)
395 397
396 398 def plot_pulses(self, km=False):
397 399
398 400 from bokeh.plotting import figure
399 401 from bokeh.resources import CDN
400 402 from bokeh.embed import components
401 403 from bokeh.models import FixedTicker, PrintfTickFormatter
402 404 from bokeh.models.tools import WheelZoomTool, ResetTool, PanTool, HoverTool, SaveTool
403 405 from bokeh.models.sources import ColumnDataSource
404 406
405 407 lines = self.get_lines().reverse()
406 408
407 409 N = len(lines)
408 410 npoints = self.total_units/self.km2unit if km else self.total_units
409 411 ipp = self.ipp if km else self.ipp*self.km2unit
410 412
411 413 hover = HoverTool(tooltips=[("Line", "@name"),
412 414 ("IPP", "@ipp"),
413 415 ("X", "@left")])
414 416
415 417 tools = [PanTool(dimensions="width"),
416 418 WheelZoomTool(dimensions="width"),
417 419 hover, SaveTool()]
418 420
419 421 plot = figure(width=1000,
420 422 height=40+N*50,
421 423 y_range = (0, N),
422 424 tools=tools,
423 425 toolbar_location='above',
424 426 toolbar_sticky=False,)
425 427
426 428 plot.xaxis.axis_label = 'Km' if km else 'Units'
427 429 plot.xaxis[0].formatter = PrintfTickFormatter(format='%d')
428 430 plot.yaxis.axis_label = 'Pulses'
429 431 plot.yaxis[0].ticker=FixedTicker(ticks=list(range(N)))
430 432 plot.yaxis[0].formatter = PrintfTickFormatter(format='Line %d')
431 433
432 434 for i, line in enumerate(lines):
433 435
434 436 points = [tup for tup in line.pulses_as_points(km=km) if tup!=(0,0)]
435 437
436 438 source = ColumnDataSource(data = dict(
437 439 bottom = [i for tup in points],
438 440 top = [i+0.5 for tup in points],
439 441 left = [tup[0] for tup in points],
440 442 right = [tup[1] for tup in points],
441 443 ipp = [int(tup[0]/ipp) for tup in points],
442 444 name = [line.get_name() for tup in points]
443 445 ))
444 446
445 447 plot.quad(
446 448 bottom = 'bottom',
447 449 top = 'top',
448 450 left = 'left',
449 451 right = 'right',
450 452 source = source,
451 453 fill_alpha = 0,
452 454 #line_color = 'blue',
453 455 )
454 456
455 457 plot.line([0, npoints], [i, i])#, color='blue')
456 458
457 459 return components(plot, CDN)
458 460
459 461 def request(self, cmd, method='get', **kwargs):
460 462
461 463 req = getattr(requests, method)(self.device.url(cmd), **kwargs)
462 464 payload = req.json()
463 465
464 466 return payload
465 467
466 468 def status_device(self):
467 469
468 470 try:
469 471 self.device.status = 0
470 472 payload = self.request('status')
471 473 if payload['status']=='enable':
472 474 self.device.status = 3
473 475 elif payload['status']=='disable':
474 476 self.device.status = 2
475 477 else:
476 478 self.device.status = 1
477 479 self.device.save()
478 480 self.message = 'RC status: {}'.format(payload['status'])
479 481 return False
480 482 except Exception as e:
481 483 if 'No route to host' not in str(e):
482 484 self.device.status = 4
483 485 self.device.save()
484 486 self.message = 'RC status: {}'.format(str(e))
485 487 return False
486 488
487 489 self.device.save()
488 490 return True
489 491
490 492 def reset_device(self):
491 493
492 494 try:
493 495 payload = self.request('reset', 'post')
494 496 if payload['reset']=='ok':
495 497 self.message = 'RC restarted OK'
496 498 self.device.status = 2
497 499 self.device.save()
498 500 else:
499 501 self.message = 'RC restart fail'
500 502 self.device.status = 4
501 503 self.device.save()
502 504 except Exception as e:
503 505 self.message = 'RC reset: {}'.format(str(e))
504 506 return False
505 507
506 508 return True
507 509
508 510 def stop_device(self):
509 511
510 512 try:
511 513 payload = self.request('stop', 'post')
512 514 self.message = 'RC stop: {}'.format(payload['stop'])
513 515 if payload['stop']=='ok':
514 516 self.device.status = 2
515 517 self.device.save()
516 518 else:
517 519 self.device.status = 4
518 520 self.device.save()
519 521 return False
520 522 except Exception as e:
521 523 if 'No route to host' not in str(e):
522 524 self.device.status = 4
523 525 else:
524 526 self.device.status = 0
525 527 self.message = 'RC stop: {}'.format(str(e))
526 528 self.device.save()
527 529 return False
528 530
529 531 return True
530 532
531 533 def start_device(self):
532 534
533 535 try:
534 536 payload = self.request('start', 'post')
535 537 self.message = 'RC start: {}'.format(payload['start'])
536 538 if payload['start']=='ok':
537 539 self.device.status = 3
538 540 self.device.save()
539 541 else:
540 542 return False
541 543 except Exception as e:
542 544 if 'No route to host' not in str(e):
543 545 self.device.status = 4
544 546 else:
545 547 self.device.status = 0
546 548 self.message = 'RC start: {}'.format(str(e))
547 549 self.device.save()
548 550 return False
549 551
550 552 return True
551 553
552 554 def write_device(self, raw=False):
553 555
554 556 if not raw:
555 557 clock = RCClock.objects.get(rc_configuration=self)
556 558 if clock.mode:
557 559 data = {'default': clock.frequency}
558 560 else:
559 561 data = {'manual': [clock.multiplier, clock.divisor, clock.reference]}
560 562 payload = self.request('setfreq', 'post', data=json.dumps(data))
561 563 if payload['command'] != 'ok':
562 564 self.message = 'RC write: {}'.format(payload['command'])
563 565 else:
564 566 self.message = payload['programming']
565 567 if payload['programming'] == 'fail':
566 568 self.message = 'RC write: error programming CGS chip'
567 569
568 570 values = []
569 571 for pulse, delay in zip(self.get_pulses(), self.get_delays()):
570 572 while delay>65536:
571 573 values.append((pulse, 65535))
572 574 delay -= 65536
573 575 values.append((pulse, delay-1))
574 576 data = bytearray()
575 577 #reset
576 578 data.extend((128, 0))
577 579 #disable
578 580 data.extend((129, 0))
579 581 #SW switch
580 582 if self.control_sw:
581 583 data.extend((130, 2))
582 584 else:
583 585 data.extend((130, 0))
584 586 #divider
585 587 data.extend((131, self.clock_divider-1))
586 588 #enable writing
587 589 data.extend((139, 62))
588 590
589 591 last = 0
590 592 for tup in values:
591 593 vals = pack('<HH', last^tup[0], tup[1])
592 594 last = tup[0]
593 595 data.extend((133, vals[1], 132, vals[0], 133, vals[3], 132, vals[2]))
594 596
595 597 #enable
596 598 data.extend((129, 1))
597 599
598 600 if raw:
599 601 return b64encode(data)
600 602
601 603 try:
602 604 payload = self.request('stop', 'post')
603 605 payload = self.request('reset', 'post')
604 606 #payload = self.request('divider', 'post', data={'divider': self.clock_divider-1})
605 607 #payload = self.request('write', 'post', data=b64encode(bytearray((139, 62))), timeout=20)
606 608 n = len(data)
607 609 x = 0
608 610 #while x < n:
609 611 payload = self.request('write', 'post', data=b64encode(data))
610 612 # x += 1024
611 613
612 614 if payload['write']=='ok':
613 615 self.device.status = 3
614 616 self.device.save()
615 617 self.message = 'RC configured and started'
616 618 else:
617 619 self.device.status = 1
618 620 self.device.save()
619 621 self.message = 'RC write: {}'.format(payload['write'])
620 622 return False
621 623
622 624 #payload = self.request('start', 'post')
623 625
624 626 except Exception as e:
625 627 if 'No route to host' not in str(e):
626 628 self.device.status = 4
627 629 else:
628 630 self.device.status = 0
629 631 self.message = 'RC write: {}'.format(str(e))
630 632 self.device.save()
631 633 return False
632 634
633 635 return True
634 636
635 637
636 638 def get_absolute_url_import(self):
637 639 return reverse('url_import_rc_conf', args=[str(self.id)])
638 640
639 641
640 642 class RCLineCode(models.Model):
641 643
642 644 name = models.CharField(max_length=40)
643 645 bits_per_code = models.PositiveIntegerField(default=0)
644 646 number_of_codes = models.PositiveIntegerField(default=0)
645 647 codes = models.TextField(blank=True, null=True)
646 648
647 649 class Meta:
648 650 db_table = 'rc_line_codes'
649 651 ordering = ('name',)
650 652
651 653 def __str__(self):
652 654 return u'%s' % self.name
653 655
654 656
655 657 class RCLineType(models.Model):
656 658
657 659 name = models.CharField(choices=LINE_TYPES, max_length=40)
658 660 description = models.TextField(blank=True, null=True)
659 661 params = models.TextField(default='[]')
660 662
661 663 class Meta:
662 664 db_table = 'rc_line_types'
663 665
664 666 def __str__(self):
665 667 return u'%s - %s' % (self.name.upper(), self.get_name_display())
666 668
667 669
668 670 class RCLine(models.Model):
669 671
670 672 rc_configuration = models.ForeignKey('RCConfiguration', on_delete=models.CASCADE)
671 673 line_type = models.ForeignKey('RCLineType',on_delete=models.CASCADE)
672 674 channel = models.PositiveIntegerField(default=0)
673 675 position = models.PositiveIntegerField(default=0)
674 676 params = models.TextField(default='{}')
675 677 pulses = models.TextField(default='')
676 678
677 679 class Meta:
678 680 db_table = 'rc_lines'
679 681 ordering = ['channel']
680 682
681 683 def __str__(self):
682 684 if self.rc_configuration:
683 685 return u'{}|{} - {}'.format(self.pk, self.get_name(), self.rc_configuration.name)
684 686
685 687 def jsonify(self):
686 688
687 689 data = {}
688 690 data['params'] = json.loads(self.params)
689 691 data['id'] = '{}'.format(self.pk)
690 692 data['line_type'] = self.line_type.name
691 693 data['name'] = self.get_name()
692 694 if data['line_type']=='codes':
693 695 data['params']['code'] = RCLineCode.objects.get(pk=data['params']['code']).name
694 696
695 697 return data
696 698
697 699
698 700 def clone(self, **kwargs):
699 701
700 702 self.pk = None
701 703 self.id = None
702 704
703 705 for attr, value in kwargs.items():
704 706 setattr(self, attr, value)
705 707
706 708 self.save()
707 709
708 710 return self
709 711
710 712 def get_name(self, channel=False):
711 713
712 714 chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
713 715 s = ''
714 716
715 717 if self.line_type.name in ('tx',):
716 718 s = chars[self.position]
717 719 elif self.line_type.name in ('codes', 'windows', 'tr'):
718 720 if 'TX_ref' in json.loads(self.params):
719 721 pk = json.loads(self.params)['TX_ref']
720 722 if pk in (0, '0'):
721 723 s = ','.join(chars[l.position] for l in self.rc_configuration.get_lines(line_type__name='tx'))
722 724 else:
723 725 ref = RCLine.objects.get(pk=pk)
724 726 s = chars[ref.position]
725 727 s = '({})'.format(s)
726 728
727 729 s = '{}{}'.format(self.line_type.name.upper(), s)
728 730
729 731 if channel:
730 732 return '{} {}'.format(s, self.channel)
731 733 else:
732 734 return s
733 735
734 736 def get_lines(self, **kwargs):
735 737
736 738 return RCLine.objects.filter(rc_configuration=self.rc_configuration, **kwargs)
737 739
738 740 def pulses_as_array(self):
739 741
740 742 y = np.zeros(self.rc_configuration.total_units)
741 743
742 744 for tup in ast.literal_eval(self.pulses):
743 745 y[tup[0]:tup[1]] = 1
744 746
745 747 return y.astype(np.int8)
746 748
747 749 def pulses_as_points(self, km=False):
748 750
749 751 if km:
750 752 unit2km = 1/self.rc_configuration.km2unit
751 753 return [(tup[0]*unit2km, tup[1]*unit2km) for tup in ast.literal_eval(self.pulses)]
752 754 else:
753 755 return ast.literal_eval(self.pulses)
754 756
755 757 def get_win_ref(self, params, tx_id, km2unit):
756 758
757 759 ref = self.rc_configuration.sampling_reference
758 760 codes = [line for line in self.get_lines(line_type__name='codes') if int(json.loads(line.params)['TX_ref'])==int(tx_id)]
759 761
760 762 if codes:
761 763 tx_width = float(json.loads(RCLine.objects.get(pk=tx_id).params)['pulse_width'])*km2unit/len(json.loads(codes[0].params)['codes'][0])
762 764 else:
763 765 tx_width = float(json.loads(RCLine.objects.get(pk=tx_id).params)['pulse_width'])*km2unit
764 766
765 767 if ref=='first_baud':
766 768 return int(1 + round((tx_width + 1)/2 + params['first_height']*km2unit - params['resolution']*km2unit))
767 769 elif ref=='sub_baud':
768 770 return np.ceil(1 + params['first_height']*km2unit - params['resolution']*km2unit/2)
769 771 else:
770 772 return 0
771 773
772 774 def update_pulses(self):
773 775 '''
774 776 Update pulses field
775 777 '''
776 778
777 779 km2unit = self.rc_configuration.km2unit
778 780 us2unit = self.rc_configuration.us2unit
779 781 ipp = self.rc_configuration.ipp
780 782 ntx = int(self.rc_configuration.ntx)
781 783 ipp_u = int(ipp*km2unit)
782 784 total = ipp_u*ntx if self.rc_configuration.total_units==0 else self.rc_configuration.total_units
783 785 y = []
784 786
785 787 if self.line_type.name=='tr':
786 788 tr_params = json.loads(self.params)
787 789 #print(tr_params)
788 790 #print(tr_params['TX_ref'])
789 791 if tr_params['TX_ref'] in ('0', 0):
790 792 txs = self.get_lines(line_type__name='tx')
791 793 else:
792 794 txs = RCLine.objects.filter(pk=tr_params['TX_ref'])
793 795
794 796 for tx in txs:
795 797 params = json.loads(tx.params)
796 798
797 799 if float(params['pulse_width'])==0:
798 800 continue
799 801 delays = [float(d)*km2unit for d in params['delays'].split(',') if d]
800 802 width = float(params['pulse_width'])*km2unit+int(self.rc_configuration.time_before*us2unit)
801 803 before = 0
802 804 after = int(self.rc_configuration.time_after*us2unit)
803 805
804 806 y_tx = self.points(ntx, ipp_u, width,
805 807 delay=delays,
806 808 before=before,
807 809 after=after,
808 810 sync=self.rc_configuration.sync)
809 811
810 812 ranges = params['range'].split(',')
811 813
812 814 if len(ranges)>0 and ranges[0]!='0':
813 815 y_tx = self.mask_ranges(y_tx, ranges)
814 816
815 817 tr_ranges = tr_params['range'].split(',')
816 818
817 819 if len(tr_ranges)>0 and tr_ranges[0]!='0':
818 820 y_tx = self.mask_ranges(y_tx, tr_ranges)
819 821
820 822 y.extend(y_tx)
821 823
822 824 self.pulses = str(y)
823 825 y = self.array_to_points(self.pulses_as_array())
824 826
825 827 elif self.line_type.name=='tx':
826 828 params = json.loads(self.params)
827 829 delays = [float(d)*km2unit for d in params['delays'].split(',') if d]
828 830 width = float(params['pulse_width'])*km2unit
829 831
830 832 if width>0:
831 833 before = int(self.rc_configuration.time_before*us2unit)
832 834 after = 0
833 835
834 836 y = self.points(ntx, ipp_u, width,
835 837 delay=delays,
836 838 before=before,
837 839 after=after,
838 840 sync=self.rc_configuration.sync)
839 841
840 842 ranges = params['range'].split(',')
841 843
842 844 if len(ranges)>0 and ranges[0]!='0':
843 845 y = self.mask_ranges(y, ranges)
844 846
845 847 elif self.line_type.name=='flip':
846 848 n = float(json.loads(self.params)['number_of_flips'])
847 849 width = n*ipp*km2unit
848 850 y = self.points(int((ntx+1)/(2*n)), ipp_u*n*2, width)
849 851
850 852 elif self.line_type.name=='codes':
851 853 params = json.loads(self.params)
852 854 tx = RCLine.objects.get(pk=params['TX_ref'])
853 855 tx_params = json.loads(tx.params)
854 856 delays = [float(d)*km2unit for d in tx_params['delays'].split(',') if d]
855 857 f = int(float(tx_params['pulse_width'])*km2unit/len(params['codes'][0]))
856 858 codes = [(np.fromstring(''.join([s*f for s in code]), dtype=np.uint8)-48).astype(np.int8) for code in params['codes']]
857 859 codes = [self.array_to_points(code) for code in codes]
858 860 n = len(codes)
859 861
860 862 ranges = tx_params['range'].split(',')
861 863 if len(ranges)>0 and ranges[0]!='0':
862 864 dum = self.mask_ranges(tx.pulses_as_points(), ranges)
863 865 else:
864 866 dum = tx.pulses_as_points()
865 867
866 868 for i, tup in enumerate(dum):
867 869 if tup==(0,0): continue
868 870 code = codes[i%n]
869 871 y.extend([(c[0]+tup[0], c[1]+tup[0]) for c in code])
870 872
871 873 elif self.line_type.name=='sync':
872 874 params = json.loads(self.params)
873 875 n = ipp_u*ntx
874 876 if params['invert'] in ('1', 1):
875 877 y = [(n-1, n)]
876 878 else:
877 879 y = [(0, 1)]
878 880
879 881 elif self.line_type.name=='prog_pulses':
880 882 params = json.loads(self.params)
881 883 if int(params['periodic'])==0:
882 884 nntx = 1
883 885 nipp = ipp_u*ntx
884 886 else:
885 887 nntx = ntx
886 888 nipp = ipp_u
887 889
888 890 if 'params' in params and len(params['params'])>0:
889 891 for p in params['params']:
890 892 y_pp = self.points(nntx, nipp,
891 893 p['end']-p['begin'],
892 894 before=p['begin'])
893 895
894 896 y.extend(y_pp)
895 897
896 898 elif self.line_type.name=='windows':
897 899 params = json.loads(self.params)
898 900 if 'params' in params and len(params['params'])>0:
899 901 tx = RCLine.objects.get(pk=params['TX_ref'])
900 902 tx_params = json.loads(tx.params)
901 903 ranges = tx_params['range'].split(',')
902 904 for p in params['params']:
903 905 y_win = self.points(ntx, ipp_u,
904 906 p['resolution']*p['number_of_samples']*km2unit,
905 907 before=int(self.rc_configuration.time_before*us2unit)+p['first_height']*km2unit,
906 908 sync=self.rc_configuration.sync+self.get_win_ref(p, params['TX_ref'], km2unit))
907 909
908 910
909 911 if len(ranges)>0 and ranges[0]!='0':
910 912 y_win = self.mask_ranges(y_win, ranges)
911 913
912 914 y.extend(y_win)
913 915
914 916 elif self.line_type.name=='mix':
915 917 values = self.rc_configuration.parameters.split('-')
916 918 confs = [RCConfiguration.objects.get(pk=value.split('|')[0]) for value in values]
917 919 modes = [value.split('|')[1] for value in values]
918 920 ops = [value.split('|')[2] for value in values]
919 921 delays = [value.split('|')[3] for value in values]
920 922 masks = [value.split('|')[4] for value in values]
923 print("masks")
924 print(masks)
925 print('{:8b}'.format(int(masks[0])))
921 926 mask = list('{:8b}'.format(int(masks[0])))
927 print("mask")
928 print(mask)
922 929 mask.reverse()
930 print("mask reverse")
931 print(mask)
923 932 if mask[self.channel] in ('0', '', ' '):
924 933 y = np.zeros(confs[0].total_units, dtype=np.int8)
925 934 else:
926 935 y = confs[0].get_lines(channel=self.channel)[0].pulses_as_array()
927 936
928 937 for i in range(1, len(values)):
929 938 mask = list('{:8b}'.format(int(masks[i])))
930 939 mask.reverse()
931 940
932 941 if mask[self.channel] in ('0', '', ' '):
933 942 continue
934 943 Y = confs[i].get_lines(channel=self.channel)[0].pulses_as_array()
935 944 delay = float(delays[i])*km2unit
936 945
937 946 if modes[i]=='P':
938 947 if delay>0:
939 948 if delay<self.rc_configuration.ipp*km2unit and len(Y)==len(y):
940 949 y_temp = np.empty_like(Y)
941 950 y_temp[:delay] = 0
942 951 y_temp[delay:] = Y[:-delay]
943 952 elif delay+len(Y)>len(y):
944 953 y_new = np.zeros(delay+len(Y), dtype=np.int8)
945 954 y_new[:len(y)] = y
946 955 y = y_new
947 956 y_temp = np.zeros(delay+len(Y), dtype=np.int8)
948 957 y_temp[-len(Y):] = Y
949 958 elif delay+len(Y)==len(y):
950 959 y_temp = np.zeros(delay+len(Y))
951 960 y_temp[-len(Y):] = Y
952 961 elif delay+len(Y)<len(y):
953 962 y_temp = np.zeros(len(y), dtype=np.int8)
954 963 y_temp[delay:delay+len(Y)] = Y
955 964 else:
956 965 y_temp = Y.copy()
957 966
958 967 if ops[i]=='OR':
959 968 y = y | y_temp
960 969 elif ops[i]=='XOR':
961 970 y = y ^ y_temp
962 971 elif ops[i]=='AND':
963 972 y = y & y_temp
964 973 elif ops[i]=='NAND':
965 974 y = y & ~y_temp
966 975 else:
967 976 y = np.concatenate([y, Y])
968 977
969 978 total = len(y)
970 979 y = self.array_to_points(y)
971 980
972 981 else:
973 982 y = []
974 983
975 984 if self.rc_configuration.total_units != total:
976 985 self.rc_configuration.total_units = total
977 986 self.rc_configuration.save()
978 987
979 988 self.pulses = str(y)
980 989 self.save()
981 990
982 991 @staticmethod
983 992 def array_to_points(X):
984 993
985 994 if X.size==0:
986 995 return []
987 996
988 997 d = X[1:]-X[:-1]
989 998
990 999 up = np.where(d==1)[0]
991 1000 if X[0]==1:
992 1001 up = np.concatenate((np.array([-1]), up))
993 1002 up += 1
994 1003
995 1004 dw = np.where(d==-1)[0]
996 1005 if X[-1]==1:
997 1006 dw = np.concatenate((dw, np.array([len(X)-1])))
998 1007 dw += 1
999 1008
1000 1009 return [(tup[0], tup[1]) for tup in zip(up, dw)]
1001 1010
1002 1011 @staticmethod
1003 1012 def mask_ranges(Y, ranges):
1004 1013
1005 1014 y = [(0, 0) for __ in Y]
1006 1015
1007 1016 for index in ranges:
1008 1017 if '-' in index:
1009 1018 args = [int(a) for a in index.split('-')]
1010 1019 y[args[0]-1:args[1]] = Y[args[0]-1:args[1]]
1011 1020 else:
1012 1021 y[int(index)-1] = Y[int(index)-1]
1013 1022
1014 1023 return y
1015 1024
1016 1025 @staticmethod
1017 1026 def points(ntx, ipp, width, delay=[0], before=0, after=0, sync=0):
1018 1027
1019 1028 delays = len(delay)
1020 1029
1021 1030 Y = [(int(ipp*x+before+delay[x%delays]+sync), int(ipp*x+width+before+delay[x%delays]+after+sync)) for x in range(ntx)]
1022 1031
1023 1032 return Y
1024 1033
1025 1034 class RCClock(models.Model):
1026 1035
1027 1036 rc_configuration = models.ForeignKey('RCConfiguration', on_delete=models.CASCADE)
1028 1037 mode = models.BooleanField(default=True, choices=((True, 'Auto'), (False, 'Manual')))
1029 1038 multiplier = models.PositiveIntegerField(default=60)
1030 1039 divisor = models.PositiveIntegerField(default=10)
1031 1040 reference = models.PositiveSmallIntegerField(default=1, choices=((0, 'Internal (25MHz)'), (1, 'External (10MHz)')))
1032 1041 frequency = models.FloatField(default=60.0) No newline at end of file
@@ -1,322 +1,322
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 261
262 262
263 263 return mark_safe(html)
264 264
265 265
266 266 class HiddenWidget(forms.widgets.HiddenInput):
267 267
268 268 def render(self, name, value, attrs=None,renderer=None):
269 269 label = name
270 270 disabled = 'disabled' if attrs.get('disabled', False) else ''
271 271 name = self.attrs.get('name', label)
272 272
273 273 html = '<input {0} type="hidden" class="form-control" id="id_{1}" name="{2}" value="{3}">'.format(disabled, label, name, value)
274 274
275 275 return mark_safe(html)
276 276
277 277
278 278 class CodesWidget(forms.widgets.Textarea):
279 279
280 280 def render(self, name, value, attrs=None,renderer=None):
281 281 label = name
282 282 disabled = 'disabled' if attrs.get('disabled', False) else ''
283 283 name = attrs.get('name', label)
284 284
285 285 if '[' in value:
286 286 value = ast.literal_eval(value)
287 287
288 288 if isinstance(value, list):
289 289 codes = '\r\n'.join(value)
290 290 else:
291 291 codes = value
292 292
293 293 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 294
295 295 return mark_safe(html)
296 296
297 297 class HCheckboxSelectMultiple(forms.CheckboxSelectMultiple):
298 298
299 299 def render(self, name, value, attrs=None, choices=(),renderer=None):
300 300
301 301 if value is None: value = []
302 302 has_id = attrs and 'id' in attrs
303 final_attrs = self.build_attrs(attrs, name=name)
303 final_attrs = self.build_attrs(attrs, {'name': name})
304 304 output = [u'<br><ul>']
305 305 # Normalize to strings
306 306 str_values = set([force_text(v) for v in value])
307 307 for i, (option_value, option_label) in enumerate(chain(self.choices, choices)):
308 308 # If an ID attribute was given, add a numeric index as a suffix,
309 309 # so that the checkboxes don't all have the same ID attribute.
310 310 if has_id:
311 311 final_attrs = dict(final_attrs, id='%s_%s' % (attrs['id'], i))
312 312 label_for = u' for="%s"' % final_attrs['id']
313 313 else:
314 314 label_for = ''
315 315
316 316 cb = forms.CheckboxInput(final_attrs, check_test=lambda value: value in str_values)
317 317 option_value = force_text(option_value)
318 318 rendered_cb = cb.render(name, option_value)
319 319 option_label = conditional_escape(force_text(option_label))
320 320 output.append(u'<span><label%s>%s %s</label></span>' % (label_for, rendered_cb, option_label))
321 321 output.append(u'</div><br>')
322 322 return mark_safe(u'\n'.join(output))
@@ -1,219 +1,232
1 1
2 2 :root{
3 3 --primary: #0200AE;
4 4 --dark-primary: #000080;
5 5 --light-primary: rgb(0, 0, 179, .7);
6 6 --secondary: #6F6F6F;
7 7 --tertiary: #0099FF;
8 8 --color-txt: #333;
9 9 --bg-main: rgba(80, 80, 80, .8);
10 10 --bg-invert: rgba(0, 0, 0, .2);
11 11 --bg-sections: #f9f9f9;
12 12 --bd-sections: 1px solid #D9D9D9;
13 13 --fs-nav: .875em;
14 14 --fs-trail: .87rem;
15 15 --hover-nav: rgba(0, 0, 0, 0.3);
16 16 --fg-nav: #2068A0;
17 17 --bs-nav: rgba(43, 43, 43, .4);
18 18 --bs-input: rgba(0, 113, 184, 0.5);
19 19 --bd-input: rgba(56, 181, 230, 0.75);
20 20 --bd-item: 1px solid #C9C9C9;
21 21 --bx-shadow: 0 2px 5px 0 var(--bs-nav);
22 22 }
23 23
24 label {
25 display: inline-block;
26 max-width: 100%;
27 margin-bottom: 5px;
28 font-weight: bold;
29 }
30
31 .form-check-input {
32 position: relative;
33 margin-top: .3rem;
34 margin-left: .3rem;
35 }
36
24 37 body {
25 38 color: #444;
26 39 font-family: "Helvetica Neue",Helvetica,Arial,sans-serif;
27 40 font-size: 14px;
28 41 }
29 42
30 43 main {
31 44 min-width: 100%;
32 45 min-height: 400px;
33 46 }
34 47
35 48 a:link { -webkit-tap-highlight-color: var(--tertiary); }
36 49
37 50 .titulo {
38 51 color: #898989;
39 52 font-size: 2rem;
40 53 font-family: 'Dosis', Arial, Verdana, serif;
41 54 }
42 55
43 56 .titulo:after {
44 57 display: flex;
45 58 width: 60px;
46 59 border-bottom: 3px solid #48C7EC;
47 60 content: '';
48 61 padding-top: .5rem;
49 62 margin: 0;
50 63 }
51 64
52 65 #sidebar a {
53 66 color: gray;
54 67 padding: 0.1rem;
55 68 }
56 69
57 70 #sidebar h5 {
58 71 color:#333;
59 72 }
60 73
61 74 .text-blue {
62 75 color: #003A8E;
63 76 }
64 77
65 78 .text-skyblue {
66 79 color: #00addc;
67 80 }
68 81
69 82 .nopadding {
70 83 padding: 0px !important;
71 84 }
72 85
73 86 .nomargin {
74 87 margin: 0px !important;
75 88 }
76 89
77 90 .legend {
78 91 list-style: none;
79 92 padding-left: 1rem;
80 93 padding-top: 1rem;
81 94 }
82 95
83 96 .legend span {
84 97 padding-left: 1em;
85 98 }
86 99
87 100 #loader {
88 101 margin-top: 40px;
89 102 color: var(--tertiary);
90 103 }
91 104
92 105 #plot {
93 106 margin-top: 2em;
94 107 margin-bottom: 2em;
95 108 }
96 109
97 110 /* Change Buttons Bootstrap */
98 111 .btn-primary {
99 112 color: #fff;
100 113 background-color: #00addc !important;
101 114 border-color: #00addc !important;
102 115 }
103 116
104 117 .btn-primary:hover {
105 118 color: #fff;
106 119 background-color: #23527c !important;
107 120 border-color: #23527c !important;
108 121 }
109 122
110 123 .card-text {
111 124 font-size: 0.8rem;
112 125 }
113 126
114 127 .tools-date {
115 128 font-size: 0.8rem;
116 129 }
117 130
118 131 /*------------------------------------------------*/
119 132
120 133 .panel {
121 134 margin-bottom: 20px;
122 135 background-color: #fafafa;
123 136 border: 1px solid transparent;
124 137 border-radius: 4px;
125 138 -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, .05);
126 139 box-shadow: 0 1px 1px rgba(0, 0, 0, .05);
127 140 }
128 141 .panel-body {
129 142 padding: 15px;
130 143 }
131 144 .panel-heading {
132 145 padding: 10px 15px;
133 146 border-bottom: 1px solid transparent;
134 147 border-top-left-radius: 3px;
135 148 border-top-right-radius: 3px;
136 149 }
137 150
138 151 .panel-title {
139 152 margin-top: 0;
140 153 margin-bottom: 0;
141 154
142 155
143 156 }
144 157
145 158 .panel-footer {
146 159 padding: 10px 15px;
147 160 background-color: #fafafa;
148 161 border-top: 1px solid #fafafa;
149 162 border-bottom-right-radius: 3px;
150 163 border-bottom-left-radius: 3px;
151 164 }
152 165
153 166 .panel-group {
154 167 margin-bottom: 20px;
155 168 }
156 169 .panel-group .panel {
157 170 margin-bottom: 0;
158 171 border-radius: 4px;
159 172 }
160 173 .panel-group .panel + .panel {
161 174 margin-top: 5px;
162 175 }
163 176 .panel-group .panel-heading {
164 177 border-bottom: 0;
165 178 }
166 179 .panel-group .panel-heading + .panel-collapse > .panel-body,
167 180
168 181 .panel-group .panel-footer {
169 182 border-top: 0;
170 183 }
171 184 .panel-group .panel-footer + .panel-collapse .panel-body {
172 185 border-bottom: 1px solid #fafafa;
173 186 }
174 187 .panel-default {
175 188 border-color: #fafafa;
176 189 }
177 190 .panel-default > .panel-heading {
178 191
179 192 background-color: #fafafa;
180 193 border-color: #fafafa;
181 194 }
182 195 .panel-default > .panel-heading + .panel-collapse > .panel-body {
183 196 border-top-color: #fafafa;
184 197 }
185 198 .panel-default > .panel-heading .badge {
186 199 color: #fafafa;
187 200 background-color: #fafafa;
188 201 }
189 202 .panel-default > .panel-footer + .panel-collapse > .panel-body {
190 203 border-bottom-color: #fafafa;
191 204 }
192 205
193 206
194 207 /* cards */
195 208
196 209 @media (min-width: 480px) {
197 210 .card-columns {
198 211 column-count: 2;
199 212 }
200 213 }
201 214
202 215 @media (min-width: 768px) {
203 216 .card-columns {
204 217 column-count: 3;
205 218 }
206 219 }
207 220
208 221 @media (min-width: 1180px) {
209 222 .card-columns {
210 223 column-count: 4;
211 224 }
212 225 }
213 226
214 227 @media (min-width: 1380px) {
215 228 .card-columns {
216 229 column-count: 5;
217 230 }
218 231 }
219 232
General Comments 0
You need to be logged in to leave comments. Login now