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