##// END OF EJS Templates
Add users and groups
eynilupu -
r445:046e9870ce02
parent child
Show More
@@ -0,0 +1,71
1 from django.core.management import BaseCommand
2 from django.contrib.auth.models import User, Group , Permission
3 import logging
4
5 GROUPS = {
6 "Developer": {
7 #General permissions
8 #"log entry" : ["add","delete","change","view"],
9 #"group" : ["add","delete","change","view"],
10 #"permission" : ["add","delete","change","view"],
11 #"user" : ["add","delete","change","view"],
12 #"content type" : ["add","delete","change","view"],
13 #"session" : ["add","delete","change","view"],
14
15 #Specific permissions
16 "profile" : ["add","delete","change","view"],
17 "experiment" : ["add","delete","change","view"],
18 "configuration" : ["add","delete","change","view"],
19 "device" : ["add","delete","change","view"],
20 "device type" : ["add","delete","change","view"],
21 "generator configuration" : ["add","delete","change","view"],
22 "pedestal configuration" : ["add","delete","change","view"],
23 "usrprx configuration" : ["add","delete","change","view"],
24 "tx code" : ["add","delete","change","view"],
25 "usrptx configuration" : ["add","delete","change","view"],
26 },
27
28 "Operator": {
29 #Specific permissions
30 "profile" : ["view"],
31 "experiment" : ["view"],
32 "configuration" : ["view"],
33 "device" : ["view"],
34 "device type" : ["view"],
35 "generator configuration" : ["view"],
36 "pedestal configuration" : ["view"],
37 "usrprx configuration" : ["view"],
38 "tx code" : ["view"],
39 "usrptx configuration" : ["view"],
40 },
41 }
42
43 class Command(BaseCommand):
44
45 help = "Creates read only default permission groups for users"
46
47 def handle(self, *args, **options):
48 for group_name in GROUPS:
49 try:
50 Group.objects.get(name=group_name)
51 self.stdout.write(f'Local group "{group_name}" currently exists')
52 continue
53 except:
54 new_group = Group.objects.create(name=group_name)
55 # Loop models in group
56 for app_model in GROUPS[group_name]:
57
58 # Loop permissions in group/model
59 for permission_name in GROUPS[group_name][app_model]:
60
61 # Generate permission name as Django would generate it
62 name = "Can {} {}".format(permission_name, app_model)
63 self.stdout.write(f'Creating "{name}"')
64
65 try:
66 model_add_perm = Permission.objects.get(name=name)
67 except Permission.DoesNotExist:
68 logging.warning("Permission not found with name '{}'.".format(name))
69 continue
70
71 new_group.permissions.add(model_add_perm) No newline at end of file
@@ -0,0 +1,60
1 import os
2 from django.core.management.base import BaseCommand
3 from django.contrib.auth.models import User, Group
4
5 class Command(BaseCommand):
6 """
7 Create a superuser and user if none exist
8 Example:
9 manage.py create_users
10 """
11
12 help = "Create a superuser and user if none exist"
13
14 def handle(self, *args, **options):
15
16 users = {
17 'Superuser': {
18 'username': os.environ.get('SIRM_SUPER_USER', 'superuser'),
19 'password': os.environ.get('SIRM_SUPER_PASSWORD', 'SuperuseROJ'),
20 'email' : os.environ.get('SIRM_SUPER_EMAIL', 'superuser@igp.gob.pe')},
21 'Developer': {
22 'username': os.environ.get('SIRM_DEV_USER', 'developer'),
23 'password': os.environ.get('SIRM_DEV_PASSWORD', 'DevelopeROJ'),
24 'email' : os.environ.get('SIRM_DEV_EMAIL', 'developer@igp.gob.pe')},
25 'Operator': {
26 'username': os.environ.get('SIRM_USER', 'operator'),
27 'password': os.environ.get('SIRM_PASSWORD', 'OperatoROJ'),
28 'email' : os.environ.get('SIRM_EMAIL', 'operator@igp.gob.pe')}
29 }
30
31 for key, value in users.items():
32 if key == 'Superuser':
33 if User.objects.filter(is_superuser=True):
34 self.stdout.write(f'Local {key} currently exists')
35 else:
36 user, created = User.objects.get_or_create(username=value["username"], first_name=value["username"], email=value["email"], is_superuser = True, is_staff = True)
37 if created:
38 user.set_password(value["password"])
39 user.save()
40 self.stdout.write(f'Local {key} "{value["username"]}" was created')
41 else:
42 self.stdout.write(f'Unable to create this local superuser: "superuser already exists"')
43 else:
44 if User.objects.filter(groups__name=key):
45 if User.objects.filter(groups__name=key, is_superuser=True):
46 self.stdout.write(f"{key} group must not have a superuser, remove superusers and create a new user")
47 else:
48 self.stdout.write(f"Local {key} currently exists")
49 else:
50 user, created = User.objects.get_or_create(username=value["username"], first_name=value["username"], email=value["email"])
51 if created:
52 user.set_password(value["password"])
53 user.save()
54 self.stdout.write(f'Local {key} "{value["username"]}" was created')
55
56 group = Group.objects.get(name=key)
57 group.user_set.add(user)
58 self.stdout.write(f'Local {key} "{value["username"]}" was added to {key} group')
59 else:
60 self.stdout.write(f'Unable to create and join to {key} group this local user: "user already exists"') No newline at end of file
@@ -1,39 +1,49
1 1 #General settings
2 2 TZ=America/Lima
3 3 LC_ALL=C.UTF-8
4 4 SIRM_SITE=<SIRM SITE>
5 5 PROC_SITE=<PROC SITE>
6 6 CAM_SITE=<CAM SITE>
7 7 SCHAIN_SITE=<SCHAIN SITE>
8 8 GENERAL_PORT=<GENERAL PORT>
9 9 BROKER_URL=<BROKER SITE>
10 10 SOPHY_TOPIC=<SOPHY TOPIC>
11 11 TXA_SITE=<IP TXA>
12 12 TXB_SITE=<IP TXB>
13 13 SIRM_MAX_UPLOAD_SIZE_MB=<SIZE MB>
14 14
15 15 #Pedestal - az offset
16 16 AZ_OFFSET=<AZ OFFSET>
17 17
18 18 #Postgres settings
19 19 POSTGRES_PORT_5432_TCP_ADDR=sirm-postgres
20 20 POSTGRES_PORT_5432_TCP_PORT=5432
21 21 DB_NAME=radarsys
22 22 DB_USER=docker
23 23 DB_PASSWORD=docker
24 24 PGDATA=/var/lib/postgresql/data
25 25
26 26 #Volumes - path
27 27 EXPOSE_SIRM=./volumes/sirm
28 28 EXPOSE_PROC=./volumes/proc
29 29 EXPOSE_CAM=/path/to/cam
30 30 EXPOSE_SCHAIN=./volumes/schain
31 31 EXPOSE_NAS=/path/to/nas_data
32 32 EXPOSE_PGDATA=/path/to/pg_data
33 33 EXPOSE_CERTS=/path/to/certs
34 34 EXPOSE_DHPARAM=/path/to/dhparam
35 35
36 36 #Superuser settings
37 SIRM_SUPER_USER=*****
38 SIRM_SUPER_PASSWORD=*******
39 SIRM_SUPER_EMAIL=*****@igp.gob.pe
40
41 #Developer user settings
42 SIRM_DEV_USER=*****
43 SIRM_DEV_PASSWORD=*******
44 SIRM_DEV_EMAIL=*****@igp.gob.pe
45
46 #Operator user settings
37 47 SIRM_USER=*****
38 48 SIRM_PASSWORD=*******
39 49 SIRM_EMAIL=*****@igp.gob.pe No newline at end of file
@@ -1,272 +1,278
1 1 # docker-compose up -d --build
2 2 version: '3'
3 3
4 4 volumes:
5 5 sirm_web:
6 6 name: sirm_web
7 7 driver: local
8 8 driver_opts:
9 9 type: "none"
10 10 o: "bind"
11 11 device: "${EXPOSE_SIRM}"
12 12 sirm_pgdata:
13 13 name: sirm_pgdata
14 14 driver: local
15 15 driver_opts:
16 16 type: "none"
17 17 o: "bind"
18 18 device: "${EXPOSE_PGDATA}"
19 19 sirm_certs:
20 20 name: sirm_certs
21 21 driver: local
22 22 driver_opts:
23 23 type: "none"
24 24 o: "bind"
25 25 device: "${EXPOSE_CERTS}"
26 26 sirm_dhparam:
27 27 name: sirm_dhparam
28 28 driver: local
29 29 driver_opts:
30 30 type: "none"
31 31 o: "bind"
32 32 device: "${EXPOSE_DHPARAM}"
33 33 sirm_proc:
34 34 name: sirm_proc
35 35 driver: local
36 36 driver_opts:
37 37 type: "none"
38 38 o: "bind"
39 39 device: "${EXPOSE_PROC}"
40 40 sirm_nas:
41 41 name: sirm_nas
42 42 driver: local
43 43 driver_opts:
44 44 type: "none"
45 45 o: "bind"
46 46 device: "${EXPOSE_NAS}"
47 47 sirm_cam:
48 48 name: sirm_cam
49 49 driver: local
50 50 driver_opts:
51 51 type: "none"
52 52 o: "bind"
53 53 device: "${EXPOSE_CAM}"
54 54 sirm_schain:
55 55 name: sirm_schain
56 56 driver: local
57 57 driver_opts:
58 58 type: "none"
59 59 o: "bind"
60 60 device: "${EXPOSE_SCHAIN}"
61 61
62 62 services:
63 63 sirm-nginx-proxy:
64 64 container_name: sirm-nginx-proxy
65 65 restart: always
66 66 build:
67 67 context: ./images/
68 68 dockerfile: nginx-proxy/Dockerfile
69 69 args:
70 70 - SIRM_MAX_UPLOAD_SIZE_MB=${SIRM_MAX_UPLOAD_SIZE_MB}
71 71 depends_on:
72 72 - sirm-web
73 73 networks:
74 74 - frontend_sirm
75 75 - backend_sirm
76 76 ports:
77 77 - 0.0.0.0:${GENERAL_PORT}:80
78 78 volumes:
79 79 - /var/run/docker.sock:/tmp/docker.sock:ro
80 80 - sirm_certs:/etc/nginx/certs:ro
81 81 - sirm_dhparam:/etc/nginx/dhparam
82 82 logging:
83 83 driver: "json-file"
84 84 options:
85 85 max-size: "12m"
86 86
87 87 sirm-web:
88 88 container_name: 'sirm-web'
89 89 restart: always
90 90 build:
91 91 context: .
92 92 environment:
93 93 - LC_ALL=${LC_ALL}
94 94 - DB_USER=${DB_USER}
95 95 - DB_NAME=${DB_NAME}
96 96 - DB_PASSWORD=${DB_PASSWORD}
97 97 - POSTGRES_PORT_5432_TCP_ADDR=${POSTGRES_PORT_5432_TCP_ADDR}
98 98 - POSTGRES_PORT_5432_TCP_PORT=${POSTGRES_PORT_5432_TCP_PORT}
99 99 - EXPOSE_NAS=${EXPOSE_NAS}
100 100 - PROC_SITE=${PROC_SITE}
101 101 - SCHAIN_SITE=${SCHAIN_SITE}
102 - SIRM_SUPER_USER=${SIRM_SUPER_USER}
103 - SIRM_SUPER_PASSWORD=${SIRM_SUPER_PASSWORD}
104 - SIRM_SUPER_EMAIL=${SIRM_SUPER_EMAIL}
105 - SIRM_DEV_USER=${SIRM_DEV_USER}
106 - SIRM_DEV_PASSWORD=${SIRM_DEV_PASSWORD}
107 - SIRM_DEV_EMAIL=${SIRM_DEV_EMAIL}
102 108 - SIRM_USER=${SIRM_USER}
103 109 - SIRM_PASSWORD=${SIRM_PASSWORD}
104 110 - SIRM_EMAIL=${SIRM_EMAIL}
105 111 - AZ_OFFSET=${AZ_OFFSET}
106 112 - VIRTUAL_HOST=${SIRM_SITE}
107 113 volumes:
108 114 - 'sirm_web:/workspace/sirm'
109 115 - 'sirm_nas:/data'
110 116 depends_on:
111 117 - sirm-postgres
112 118 networks:
113 119 - frontend_sirm
114 120 - backend_sirm
115 121 labels:
116 122 ofelia.enabled: "true"
117 123 ofelia.job-exec.restart-reception.schedule: "0 1/5 * * * *"
118 124 ofelia.job-exec.restart-reception.command: "python manage.py restart_reception"
119 125 ofelia.job-exec.restart-pedestal.schedule: "0 2/10 * * * *"
120 126 ofelia.job-exec.restart-pedestal.command: "python manage.py restart_pedestal"
121 127 ofelia.job-exec.restart-experiment.schedule: "0 0 5 * * *"
122 128 ofelia.job-exec.restart-experiment.command: "python manage.py restart_experiment"
123 129 logging:
124 130 driver: "json-file"
125 131 options:
126 132 max-size: "12m"
127 133
128 134 sirm-job:
129 135 container_name: 'sirm-job'
130 image: mcuadros/ofelia:latest
136 image: mcuadros/ofelia:v0.3.6
131 137 depends_on:
132 138 - sirm-web
133 139 networks:
134 - frontend_sirm
140 #- frontend_sirm
135 141 - backend_sirm
136 142 command: daemon --docker
137 143 volumes:
138 144 - /var/run/docker.sock:/var/run/docker.sock:ro
139 145 logging:
140 146 driver: "json-file"
141 147 options:
142 148 max-size: "12m"
143 149
144 150 sirm-postgres:
145 151 container_name: 'sirm-postgres'
146 152 restart: always
147 153 build:
148 154 context: ./images/
149 155 dockerfile: postgres/Dockerfile
150 156 args:
151 157 - PGDATA=${PGDATA}
152 158 environment:
153 159 - LC_ALL=${LC_ALL}
154 160 - DB_USER=${DB_USER}
155 161 - DB_NAME=${DB_NAME}
156 162 - DB_PASSWORD=${DB_PASSWORD}
157 163 - POSTGRES_PORT_5432_TCP_ADDR=${POSTGRES_PORT_5432_TCP_ADDR}
158 164 - POSTGRES_PORT_5432_TCP_PORT=${POSTGRES_PORT_5432_TCP_PORT}
159 165 volumes:
160 166 - sirm_pgdata:/var/lib/postgresql/data
161 167 networks:
162 168 - backend_sirm
163 169 logging:
164 170 driver: "json-file"
165 171 options:
166 172 max-size: "12m"
167 173
168 174 sirm-proc:
169 175 container_name: 'sirm-proc'
170 176 restart: always
171 177 build:
172 178 context: ./volumes/proc/
173 179 environment:
174 180 - BROKER_URL=${BROKER_URL}
175 181 - SOPHY_TOPIC=${SOPHY_TOPIC}
176 182 - TXA_SITE=${TXA_SITE}
177 183 - TXB_SITE=${TXB_SITE}
178 184 - SCHAIN_SITE=${SCHAIN_SITE}
179 185 - VIRTUAL_HOST=${PROC_SITE}
180 186 volumes:
181 187 - 'sirm_proc:/app'
182 188 - 'sirm_nas:/data'
183 189 networks:
184 190 - frontend_sirm
185 191 logging:
186 192 driver: "json-file"
187 193 options:
188 194 max-size: "12m"
189 195
190 196 sirm-monitor:
191 197 container_name: 'sirm-monitor'
192 198 restart: always
193 199 image: 'sirm_sirm-proc'
194 200 command: ["python", "monitor.py"]
195 201 environment:
196 202 - BROKER_URL=${BROKER_URL}
197 203 - TXA_SITE=${TXA_SITE}
198 204 - TXB_SITE=${TXB_SITE}
199 205 volumes:
200 206 - 'sirm_proc:/app'
201 207 - 'sirm_nas:/data'
202 208 networks:
203 209 - frontend_sirm
204 210 depends_on:
205 211 - sirm-proc
206 212 logging:
207 213 driver: "json-file"
208 214 options:
209 215 max-size: "12m"
210 216
211 217 sirm-acq:
212 218 container_name: 'sirm-acq'
213 219 restart: always
214 220 image: 'sirm_sirm-proc'
215 221 command: ["python", "acq.py"]
216 222 environment:
217 223 - BROKER_URL=${BROKER_URL}
218 224 - TXA_SITE=${TXA_SITE}
219 225 - TXB_SITE=${TXB_SITE}
220 226 - PROC_SITE=${PROC_SITE}
221 227 volumes:
222 228 - 'sirm_proc:/app'
223 229 - 'sirm_nas:/data'
224 230 networks:
225 231 - frontend_sirm
226 232 depends_on:
227 233 - sirm-proc
228 234 logging:
229 235 driver: "json-file"
230 236 options:
231 237 max-size: "12m"
232 238
233 239 sirm-cam:
234 240 container_name: 'sirm-cam'
235 241 image: bkjaya1952/ivms4200-v2.8.2.2_ml-linux
236 242 restart: always
237 243 environment:
238 244 - VIRTUAL_HOST=${CAM_SITE}
239 245 volumes:
240 246 - 'sirm_cam:/root/.wine/drive_c/iVMS-4200'
241 247 networks:
242 248 - frontend_sirm
243 249 logging:
244 250 driver: "json-file"
245 251 options:
246 252 max-size: "12m"
247 253
248 254 sirm-schain:
249 255 container_name: 'sirm-schain'
250 256 restart: always
251 257 build:
252 258 context: ./volumes/schain/
253 259 environment:
254 260 - BROKER_URL=${BROKER_URL}
255 261 - BACKEND=Agg
256 262 - TZ=${TZ}
257 263 - VIRTUAL_HOST=${SCHAIN_SITE}
258 264 volumes:
259 265 - 'sirm_nas:/data'
260 266 - 'sirm_schain:/app'
261 267 networks:
262 268 - frontend_sirm
263 269 logging:
264 270 driver: "json-file"
265 271 options:
266 272 max-size: "12m"
267 273
268 274 networks:
269 275 frontend_sirm:
270 276 name: frontend_sirm
271 277 backend_sirm:
272 278 name: backend_sirm No newline at end of file
@@ -1,32 +1,35
1 1 #!/bin/bash
2 2
3 3 python ../setup/prerun.py || { echo '[DJANGO prerun] FAILED. Exiting...' ; exit 1; }
4 4
5 5 if [ -f .gitkeep ];
6 6 then
7 7 echo "The commands 'makemigrations', 'migrate' and '.gitkeep' were not exectued"
8 8 else
9 9 # Apply database makemigrations
10 10 echo "Apply makemigrations"
11 11 python manage.py makemigrations
12 12
13 13 # Apply database migrations
14 14 echo "Apply database migrations"
15 15 python manage.py migrate
16 16 python manage.py loaddata main
17 17 python manage.py loaddata tx
18 18
19 19 # Collect static files
20 20 #echo "Collect static files"
21 21 #python manage.py collectstatic --noinput
22 22
23 23 # Create ".gitkeep" file in "setup" folder
24 24 echo "Create .gitkeep"
25 25 touch .gitkeep
26 26 fi
27 27
28 echo "Create Superuser"
29 python manage.py createsuperuser_if_none_exists
28 echo "Create Groups"
29 python manage.py create_groups
30
31 echo "Create User"
32 python manage.py create_users
30 33
31 34 echo "Run server"
32 35 python manage.py runserver 0.0.0.0:8080 No newline at end of file
@@ -1,101 +1,116
1 1
2 2 import json
3 3
4 4 from django.contrib import messages
5 5 from django.utils.safestring import mark_safe
6 6 from django.shortcuts import render, redirect, get_object_or_404, HttpResponse
7 7 from django.contrib.auth.decorators import login_required
8 8
9 9 from apps.main.models import Experiment, Device
10 10 from apps.main.views import sidebar
11 11
12 12 from .models import GeneratorConfiguration
13 13 from .forms import GeneratorConfigurationForm, GeneratorImportForm
14 14
15 def is_developer(user):
16 groups = [str(g.name) for g in user.groups.all()]
17 #return 'Developer' in groups or user.is_staff
18 return 'Developer' in groups or user.is_superuser
19
20
21 def is_operator(user):
22 groups = [str(g.name) for g in user.groups.all()]
23 #return 'Operator' in groups or user.is_staff
24 return 'Operator' in groups or user.is_superuser
25
15 26
16 27 def conf(request, conf_id):
17 28
18 29 conf = get_object_or_404(GeneratorConfiguration, pk=conf_id)
19 30
20 31 kwargs = {}
21 32 kwargs['dev_conf'] = conf
22 33
23 34 if conf.enable_2:
24 35 kwargs['dev_conf_keys'] = ['delay', 'periode_1', 'width_1', 'ntx_1', 'periode_2', 'width_2', 'ntx_2', 'selector']
25 36 else:
26 37 kwargs['dev_conf_keys'] = ['delay', 'periode_1', 'width_1', 'ntx_1', 'selector']
27 38
28 39 kwargs['title'] = 'Configuration'
29 40 kwargs['suptitle'] = 'Detail'
30 41
31 42 kwargs['button'] = 'Edit Configuration'
32 43
33 44 conf.status_device()
34 45
35 46 ###### SIDEBAR ######
36 47 kwargs.update(sidebar(conf=conf))
37 48
38 49 return render(request, 'generator_conf.html', kwargs)
39 50
40 51 @login_required
41 52 def conf_edit(request, conf_id):
42 53
43 54 conf = get_object_or_404(GeneratorConfiguration, pk=conf_id)
44 55
56 if not is_developer(request.user):
57 messages.error(request, 'You must be an developer to edit this configuration')
58 return redirect(conf.get_absolute_url())
59
45 60 if request.method=='GET':
46 61
47 62 form = GeneratorConfigurationForm(instance=conf)
48 63
49 64 elif request.method=='POST':
50 65
51 66 form = GeneratorConfigurationForm(request.POST, instance=conf)
52 67
53 68 if form.is_valid():
54 69 form.save()
55 70
56 71 messages.success(request, 'Generator configuration successfully updated')
57 72
58 73 return redirect(conf.get_absolute_url())
59 74
60 75 kwargs = {}
61 76 kwargs['dev_conf'] = conf
62 77 kwargs['form'] = form
63 78 kwargs['edit'] = True
64 79
65 80 kwargs['title'] = 'Generator Configuration'
66 81 kwargs['suptitle'] = 'Edit'
67 82 kwargs['button'] = 'Update'
68 83
69 84 return render(request, 'generator_conf_edit.html', kwargs)
70 85
71 86 def import_file(request, conf_id):
72 87
73 88 conf = get_object_or_404(GeneratorConfiguration, pk=conf_id)
74 89 if request.method=='POST':
75 90 form = GeneratorImportForm(request.POST, request.FILES)
76 91 if form.is_valid():
77 92 try:
78 93 data = conf.import_from_file(request.FILES['file_name'])
79 94 conf.dict_to_parms(data)
80 95 messages.success(request, 'Configuration "%s" loaded succesfully' % request.FILES['file_name'])
81 96 return redirect(conf.get_absolute_url_edit())
82 97
83 98 except Exception as e:
84 99 messages.error(request, 'Error parsing file: "%s" - %s' % (request.FILES['file_name'], repr(e)))
85 100 else:
86 101 messages.warning(request, 'Your current configuration will be replaced')
87 102 form = GeneratorImportForm()
88 103
89 104 kwargs = {}
90 105 kwargs['form'] = form
91 106 kwargs['title'] = 'Generator Configuration'
92 107 kwargs['suptitle'] = 'Import file'
93 108 kwargs['button'] = 'Upload'
94 109 kwargs['previous'] = conf.get_absolute_url()
95 110
96 111 return render(request, 'generator_import.html', kwargs)
97 112
98 113 def conf_raw(request, conf_id):
99 114 conf = get_object_or_404(GeneratorConfiguration, pk=conf_id)
100 115 raw = conf.write_device(raw=True)
101 116 return HttpResponse(raw, content_type='application/json') No newline at end of file
@@ -1,655 +1,655
1 1 import os
2 2 import json
3 3 import requests
4 4 import time
5 5 from datetime import datetime
6 6 import base64
7 7
8 8 try:
9 9 from polymorphic.models import PolymorphicModel
10 10 except:
11 11 from polymorphic import PolymorphicModel
12 12
13 13 from django.template.base import kwarg_re
14 14 from django.db import models
15 15 from django.urls import reverse
16 16 from django.core.validators import MinValueValidator, MaxValueValidator
17 17 from django.shortcuts import get_object_or_404
18 18 from django.contrib.auth.models import User
19 19 from django.db.models.signals import post_save
20 20 from django.dispatch import receiver
21 21
22 22 from apps.main.utils import Params
23 23
24 24 DEV_PORTS = {
25 25 'pedestal' : 80,
26 26 'pedestal_dev' : 80,
27 27 'generator' : 80,
28 28 'usrp_rx' : 2000,
29 29 'usrp_tx' : 2000,
30 30 }
31 31
32 32 RADAR_STATES = (
33 33 (0, 'No connected'),
34 34 (1, 'Connected'),
35 35 (2, 'Configured'),
36 36 (3, 'Running'),
37 37 (4, 'Scheduled'),
38 38 )
39 39
40 40 EXPERIMENT_TYPE = (
41 41 (0, 'RAW_DATA'),
42 42 (1, 'PDATA'),
43 43 )
44 44
45 45 DECODE_TYPE = (
46 46 (0, 'None'),
47 47 (1, 'TimeDomain'),
48 48 (2, 'FreqDomain'),
49 49 (3, 'InvFreqDomain'),
50 50 )
51 51
52 52 DEV_STATES = (
53 53 (0, 'Unknown'),
54 54 (1, 'Connected'),
55 55 (2, 'Configured'),
56 56 (3, 'Running'),
57 57 (4, 'Offline'),
58 58 )
59 59
60 60 DEV_TYPES = (
61 61 ('', 'Select a device type'),
62 62 ('pedestal', 'Pedestal Controller'),
63 63 ('pedestal_dev', 'Pedestal Controller Dev Mode'),
64 64 ('generator', 'Pulse Generator'),
65 65 ('usrp_rx', 'Universal Software Radio Peripheral Rx'),
66 66 ('usrp_tx', 'Universal Software Radio Peripheral Tx'),
67 67 )
68 68
69 69 EXP_STATES = (
70 70 (0,'Error'), #RED
71 71 (1,'Cancelled'), #YELLOW
72 72 (2,'Running'), #GREEN
73 73 (3,'Scheduled'), #BLUE
74 74 (4,'Unknown'), #WHITE
75 75 (5,'Other'), #ORANGE
76 76 )
77 77
78 78 CONF_TYPES = (
79 79 (0, 'Active'),
80 80 (1, 'Historical'),
81 81 )
82 82
83 83 class Profile(models.Model):
84 84 user = models.OneToOneField(User, on_delete=models.CASCADE)
85 85 theme = models.CharField(max_length=30, default='spacelab')
86 86
87 87
88 88 @receiver(post_save, sender=User)
89 89 def create_user_profile(sender, instance, created, **kwargs):
90 90 if created:
91 91 Profile.objects.create(user=instance)
92 92
93 93 @receiver(post_save, sender=User)
94 94 def save_user_profile(sender, instance, **kwargs):
95 95 instance.profile.save()
96 96
97 97
98 98 class DeviceType(models.Model):
99 99
100 100 name = models.CharField(max_length = 15, choices = DEV_TYPES, default = 'pedestal')
101 101 sequence = models.PositiveSmallIntegerField(default=55)
102 102 description = models.TextField(blank=True, null=True)
103 103
104 104 class Meta:
105 105 db_table = 'db_device_types'
106 106
107 107 def __str__(self):
108 108 return u'%s' % self.name.title()
109 109
110 110 class Device(models.Model):
111 111
112 112 device_type = models.ForeignKey('DeviceType', on_delete=models.CASCADE)
113 113 ip_address = models.GenericIPAddressField(verbose_name = 'IP address', protocol='IPv4', default='0.0.0.0')
114 114 port_address = models.PositiveSmallIntegerField(default=2000)
115 115 description = models.TextField(blank=True, null=True)
116 116 status = models.PositiveSmallIntegerField(default=4, choices=DEV_STATES)
117 117 conf_active = models.PositiveIntegerField(default=0, verbose_name='Current configuration')
118 118
119 119 class Meta:
120 120 db_table = 'db_devices'
121 121
122 122 def __str__(self):
123 123 ret = self.device_type
124 124 return str(ret)
125 125
126 126 @property
127 127 def name(self):
128 128 return str(self)
129 129
130 130 def get_status(self):
131 131 return self.status
132 132
133 133 @property
134 134 def status_color(self):
135 135 color = 'muted'
136 136 if self.status == 0:
137 137 color = "danger"
138 138 elif self.status == 1:
139 139 color = "primary"
140 140 elif self.status == 2:
141 141 color = "info"
142 142 elif self.status == 3:
143 143 color = "success"
144 144
145 145 return color
146 146
147 147 def url(self, path=None):
148 148
149 149 if path:
150 150 return 'http://{}:{}/{}/'.format(self.ip_address, self.port_address, path)
151 151 else:
152 152 return 'http://{}:{}/'.format(self.ip_address, self.port_address)
153 153
154 154 def get_absolute_url(self):
155 155 return reverse('url_device', args=[str(self.id)])
156 156
157 157 def get_absolute_url_edit(self):
158 158 return reverse('url_edit_device', args=[str(self.id)])
159 159
160 160 def get_absolute_url_delete(self):
161 161 return reverse('url_delete_device', args=[str(self.id)])
162 162
163 163 def change_ip(self, ip_address, mask, gateway, dns, **kwargs):
164 164
165 165 if self.device_type.name=='pedestal':
166 166 headers = {'content-type': "application/json",
167 167 'cache-control': "no-cache"}
168 168
169 169 ip = [int(x) for x in ip_address.split('.')]
170 170 dns = [int(x) for x in dns.split('.')]
171 171 gateway = [int(x) for x in gateway.split('.')]
172 172 subnet = [int(x) for x in mask.split('.')]
173 173
174 174 payload = {
175 175 "ip": ip,
176 176 "dns": dns,
177 177 "gateway": gateway,
178 178 "subnet": subnet
179 179 }
180 180
181 181 req = requests.post(self.url('changeip'), data=json.dumps(payload), headers=headers)
182 182 try:
183 183 answer = req.json()
184 184 if answer['changeip']=='ok':
185 185 self.message = '25|IP succesfully changed'
186 186 self.ip_address = ip_address
187 187 self.save()
188 188 else:
189 189 self.message = '30|An error ocuur when changing IP'
190 190 except Exception as e:
191 191 self.message = '40|{}'.format(str(e))
192 192 else:
193 193 self.message = 'Not implemented'
194 194 return False
195 195
196 196 return True
197 197
198 198
199 199 class Experiment(PolymorphicModel):
200 200
201 201 name = models.CharField(max_length=40, default='', unique=True)
202 202 pedestal = models.ForeignKey('pedestal.PedestalConfiguration', null=False, blank=False, on_delete=models.PROTECT, default=None, limit_choices_to={'type': 0}, related_name = "pedestal_conf")
203 203 generator = models.ForeignKey('Device', null=False, blank=False, on_delete=models.PROTECT, default=2, editable=False, limit_choices_to={'device_type__name': 'generator'}, related_name = "generator_conf")
204 204 reception_rx = models.ForeignKey('usrp_rx.USRPRXConfiguration', null=False, blank=False, on_delete=models.PROTECT, default=None, limit_choices_to={'type': 0}, related_name = "usrp_rx_CONF")
205 205 transmission_tx = models.ForeignKey('usrp_tx.USRPTXConfiguration', null=False, blank=False, on_delete=models.PROTECT, default=None, limit_choices_to={'type': 0}, related_name = "usrp_tx")
206 206 task = models.CharField(max_length=36, default='', blank=True, null=True)
207 207 status = models.PositiveSmallIntegerField(default=4, choices=EXP_STATES)
208 208 author = models.ForeignKey(User, null=True, blank=True, on_delete=models.CASCADE)
209 209 hash = models.CharField(default='', max_length=64, null=True, blank=True)
210 210 latitude = models.FloatField(null=False, blank=False, default=0, editable=False)
211 211 longitude = models.FloatField(null=False, blank=False, default=0, editable=False)
212 212 altitude = models.FloatField(null=False, blank=False, default=0, editable=False)
213 213 heading = models.FloatField(null=True, blank=True)
214 214 mode_stop = models.CharField(max_length=3, null=False, blank=False, default='web', editable=False)
215 215
216 216 class Meta:
217 217 db_table = 'db_experiments'
218 218 ordering = ('name',)
219 219
220 220 def __str__(self):
221 221 return u'%s' % (self.name)
222 222
223 223 def jsonify(self):
224 224
225 225 data = {}
226 226
227 227 ignored = []
228 228
229 229 for field in self._meta.fields:
230 230 if field.name in ignored:
231 231 continue
232 232 data[field.name] = field.value_from_object(self)
233 233
234 234 data['configurations'] = ['{}'.format(conf.pk) for
235 235 conf in Configuration.objects.filter(experiment=self, type=0)]
236 236
237 237 return data
238 238
239 239 def clone(self, **kwargs):
240 240
241 241 confs = Configuration.objects.filter(experiment=self, type=0)
242 242 self.pk = None
243 243 self.name = '{}_{:%y%m%d}'.format(self.name, datetime.now())
244 244 for attr, value in kwargs.items():
245 245 setattr(self, attr, value)
246 246
247 247 self.save()
248 248
249 249 for conf in confs:
250 250 conf.clone(experiment=self)
251 251
252 252 return self
253 253
254 254
255 255 def generator_start(self):
256 256 try:
257 257 experiment = get_object_or_404(Experiment, pk=self.id)
258 258 generator_url = experiment.generator.url()
259 259
260 260 period = self.transmission_tx.ipp*2/0.3
261 261 if self.transmission_tx.enable_2:
262 262 payload = {"Delay": 1 + self.transmission_tx.delay, "periode1": period, "width1": self.transmission_tx.pulse_1 + 6, "repeatability1": self.transmission_tx.repetitions_1, "periode2": period, "width2": self.transmission_tx.pulse_2 + 6, "repeatability2": self.transmission_tx.repetitions_2, "enable": 1}
263 263 else:
264 264 payload = {"Delay": 1 + self.transmission_tx.delay, "periode1": period, "width1": self.transmission_tx.pulse_1 + 6, "repeatability1": 1, "periode2": period, "width2": self.transmission_tx.pulse_1 + 6, "repeatability2": 1, "enable": 1}
265 265
266 266 json_trmode = json.dumps(payload)
267 267
268 268 base64_trmode = base64.standard_b64encode(json_trmode.encode('ascii'))
269 269
270 270 trmode_url = generator_url + "trmode?params="
271 271 complete_url_trmode = trmode_url + base64_trmode.decode('ascii')
272 272
273 273 requests.get(complete_url_trmode)
274 274 except:
275 275 return False
276 276 return True
277 277
278 278 def generator_stop(self):
279 279 try:
280 280 experiment = get_object_or_404(Experiment, pk=self.id)
281 281 generator_url = experiment.generator.url()
282 282
283 283 payload = {"enable": 0}
284 284
285 285 json_trmode_selector = json.dumps(payload)
286 286 base64_trmode_selector = base64.standard_b64encode(json_trmode_selector.encode('ascii'))
287 287
288 288 trmode_url = generator_url + "trmode?params="
289 289 url_trmode_selector = trmode_url + base64_trmode_selector.decode('ascii')
290 290 requests.get(url_trmode_selector)
291 291 except:
292 292 return False
293 293 return True
294 294
295 295 def start(self):
296 296 '''
297 297 Configure and start experiments's devices
298 298 '''
299 299 all_status = Experiment.objects.filter(status=2)
300 300
301 301 if self.status != 2:
302 302 if len(all_status) == 0:
303 303 data = {
304 304 'name': '{}@{}'.format(self.name, datetime.now().strftime('%Y-%m-%dT%H-%M-%S')),
305 305 'latitude': self.latitude,
306 306 'longitude': self.longitude,
307 307 'altitude': self.altitude,
308 308 'heading': self.heading
309 309 }
310 310
311 311 try:
312 312 data['pedestal'] = self.pedestal.start_device(name_experiment=data['name'])
313 313 time.sleep(1.0)
314 314 self.generator_start()
315 315 time.sleep(1.0)
316 316 data['usrp_tx'] = self.transmission_tx.start_device(name_experiment=data['name'])
317 317 time.sleep(1.0)
318 318 data['usrp_rx'] = self.reception_rx.start_device(name_experiment=data['name'])
319 319 time.sleep(0.1)
320 320 proc_url = 'http://'+os.environ['PROC_SITE']+'/start'
321 321 requests.post(proc_url, json=data)
322 322
323 323 except:
324 324 return 0
325 325 return 2
326 326 else:
327 327 return 5
328 328 else:
329 329 return 2
330 330
331 331
332 332 def stop(self):
333 333 '''
334 334 Stop experiments's devices
335 335 PEDESTAL, GENERATOR & USRP's
336 336 '''
337 337
338 338 try:
339 339 self.transmission_tx.stop_device()
340 340 time.sleep(1.0)
341 341 self.generator_stop()
342 342 time.sleep(0.1)
343 343 self.reception_rx.stop_device()
344 344 time.sleep(0.1)
345 345 self.pedestal.reset_device()
346 time.sleep(14)
346 time.sleep(0.1)
347 347 self.pedestal.stop_device()
348 348 time.sleep(0.1)
349 349 proc_url = 'http://'+os.environ['PROC_SITE']+'/stop'
350 350 requests.get(proc_url)
351 351 except:
352 352 return 0
353 353 return 4
354 354
355 355 def get_status(self):
356 356
357 357 if self.status == 3:
358 358 return
359 359
360 360 confs = Configuration.objects.filter(experiment=self, type=0)
361 361
362 362 for conf in confs:
363 363 conf.status_device()
364 364
365 365 total = confs.aggregate(models.Sum('device__status'))['device__status__sum']
366 366
367 367 if total==2*confs.count():
368 368 status = 1
369 369 elif total == 3*confs.count():
370 370 status = 2
371 371 else:
372 372 status = 0
373 373
374 374 self.status = status
375 375 self.save()
376 376
377 377 def status_color(self):
378 378 color = 'muted'
379 379 if self.status == 0:
380 380 color = "danger"
381 381 elif self.status == 1:
382 382 color = "warning"
383 383 elif self.status == 2:
384 384 color = "success"
385 385 elif self.status == 3:
386 386 color = "info"
387 387
388 388 return color
389 389
390 390 def parms_to_dict(self):
391 391
392 392 params = Params({})
393 393 params.add(self.jsonify(), 'experiments')
394 394
395 395 configurations = Configuration.objects.filter(experiment=self, type=0)
396 396
397 397 for conf in configurations:
398 398 params.add(conf.jsonify(), 'configurations')
399 399
400 400 return params.data
401 401
402 402 def dict_to_parms(self, parms, CONF_MODELS, id_exp=None):
403 403
404 404 configurations = Configuration.objects.filter(experiment=self)
405 405
406 406 if id_exp is not None:
407 407 exp_parms = parms['experiments']['byId'][id_exp]
408 408 else:
409 409 exp_parms = parms['experiments']['byId'][parms['experiments']['allIds'][0]]
410 410
411 411 if configurations:
412 412 for configuration in configurations:
413 413 configuration.delete()
414 414
415 415 for id_conf in exp_parms['configurations']:
416 416 conf_parms = parms['configurations']['byId'][id_conf]
417 417 device = Device.objects.filter(device_type__name=conf_parms['device_type'])[0]
418 418 model = CONF_MODELS[conf_parms['device_type']]
419 419 conf = model(
420 420 experiment = self,
421 421 device = device,
422 422 )
423 423 conf.dict_to_parms(parms, id=id_conf)
424 424
425 425
426 426 self.name = '{}-{}'.format(exp_parms['name'], datetime.now().strftime('%y%m%d'))
427 427 self.save()
428 428
429 429 return self
430 430
431 431 def get_absolute_url(self):
432 432 return reverse('url_experiment', args=[str(self.id)])
433 433
434 434 def get_absolute_url_edit(self):
435 435 return reverse('url_edit_experiment', args=[str(self.id)])
436 436
437 437 def get_absolute_url_delete(self):
438 438 return reverse('url_delete_experiment', args=[str(self.id)])
439 439
440 440 def get_absolute_url_import(self):
441 441 return reverse('url_import_experiment', args=[str(self.id)])
442 442
443 443 def get_absolute_url_export(self):
444 444 return reverse('url_export_experiment', args=[str(self.id)])
445 445
446 446 def get_absolute_url_start(self):
447 447 return reverse('url_start_experiment', args=[str(self.id)])
448 448
449 449 def get_absolute_url_stop(self):
450 450 return reverse('url_stop_experiment', args=[str(self.id)])
451 451
452 452
453 453 class Configuration(PolymorphicModel):
454 454
455 455 id = models.AutoField(primary_key=True)
456 456 experiment = models.CharField(default='empty', editable=False, max_length=64, null=True, blank=True)
457 457 experiment_date = models.DateTimeField(default=datetime.now, editable=False)
458 458 device = models.ForeignKey('Device', verbose_name='Device', null=True, on_delete=models.CASCADE)
459 459 type = models.PositiveSmallIntegerField(default=0, choices=CONF_TYPES)
460 460 created_date = models.DateTimeField(auto_now_add=True)
461 461 programmed_date = models.DateTimeField(auto_now=True)
462 462 parameters = models.TextField(default='{}')
463 463 author = models.ForeignKey(User, null=True, blank=True,on_delete=models.CASCADE)
464 464 hash = models.CharField(default='', max_length=64, null=True, blank=True)
465 465 message = ""
466 466
467 467 class Meta:
468 468 db_table = 'db_configurations'
469 469 ordering = ('device__device_type__name',)
470 470
471 471 def __str__(self):
472 472
473 473 ret = u'{} '.format(self.device.device_type.name.upper())
474 474
475 475 if 'mix' in [f.name for f in self._meta.get_fields()]:
476 476 if self.mix:
477 477 ret = '{} MIX '.format(self.device.device_type.name.upper())
478 478
479 479 if 'label' in [f.name for f in self._meta.get_fields()]:
480 480 ret += '{}'.format(self.label)
481 481
482 482 return ret
483 483
484 484 @property
485 485 def name(self):
486 486
487 487 return str(self)
488 488
489 489 @property
490 490 def label(self):
491 491
492 492 return str(self)
493 493
494 494 def jsonify(self):
495 495
496 496 data = {}
497 497
498 498 ignored = ('type', 'polymorphic_ctype', 'configuration_ptr',
499 499 'created_date', 'programmed_date', 'device',
500 500 'experiment', 'author')
501 501
502 502 for field in self._meta.fields:
503 503 if field.name in ignored:
504 504 continue
505 505 data[field.name] = field.value_from_object(self)
506 506
507 507 data['device_type'] = self.device.device_type.name
508 508 return data
509 509
510 510 def clone(self, **kwargs):
511 511 before_id = self.id
512 512
513 513 self.pk = None
514 514 self.id = None
515 515 for attr, value in kwargs.items():
516 516 setattr(self, attr, value)
517 517 self.save()
518 518
519 519 self.id = before_id
520 520 return self
521 521
522 522 def parms_to_dict(self):
523 523
524 524 params = Params({})
525 525 params.add(self.jsonify(), 'configurations')
526 526 return params.data
527 527
528 528 def parms_to_text(self):
529 529
530 530 raise NotImplementedError("This method should be implemented in %s Configuration model" %str(self.device.device_type.name).upper())
531 531
532 532
533 533 def parms_to_binary(self):
534 534
535 535 raise NotImplementedError("This method should be implemented in %s Configuration model" %str(self.device.device_type.name).upper())
536 536
537 537
538 538 def dict_to_parms(self, parameters, id=None):
539 539
540 540 params = Params(parameters)
541 541
542 542 if id:
543 543 data = params.get_conf(id_conf=id)
544 544 else:
545 545 data = params.get_conf(dtype=self.device.device_type.name)
546 546
547 547 for key, value in data.items():
548 548 if key not in ('id', 'device_type'):
549 549 setattr(self, key, value)
550 550
551 551 self.save()
552 552
553 553
554 554 def export_to_file(self, format="json"):
555 555
556 556 content_type = ''
557 557
558 558 if format == 'racp':
559 559 content_type = 'text/plain'
560 560 filename = '%s_%s.%s' %(self.device.device_type.name, self.name, 'racp')
561 561 content = self.parms_to_text(file_format = 'racp')
562 562
563 563 if format == 'text':
564 564 content_type = 'text/plain'
565 565 filename = '%s_%s.%s' %(self.device.device_type.name, self.name, self.device.device_type.name)
566 566 content = self.parms_to_text()
567 567
568 568 if format == 'binary':
569 569 content_type = 'application/octet-stream'
570 570 filename = '%s_%s.bin' %(self.device.device_type.name, self.name)
571 571 content = self.parms_to_binary()
572 572
573 573 if not content_type:
574 574 content_type = 'application/json'
575 575 filename = '%s_%s.json' %(self.device.device_type.name, self.name)
576 576 content = json.dumps(self.parms_to_dict(), indent=2)
577 577
578 578
579 579 fields = {'content_type':content_type,
580 580 'filename':filename,
581 581 'content':content
582 582 }
583 583
584 584 return fields
585 585
586 586 def import_from_file(self, fp):
587 587
588 588 parms = {}
589 589
590 590 path, ext = os.path.splitext(fp.name)
591 591
592 592 if ext == '.json':
593 593 parms = json.load(fp)
594 594
595 595 return parms
596 596
597 597 def status_device(self):
598 598
599 599 self.message = 'Function not supported'
600 600 return False
601 601
602 602
603 603 def stop_device(self):
604 604
605 605 self.message = 'Function not supported'
606 606 return False
607 607
608 608
609 609 def start_device(self):
610 610
611 611 self.message = 'Function not supported'
612 612 return False
613 613
614 614
615 615 def write_device(self):
616 616
617 617 self.message = 'Function not supported'
618 618 return False
619 619
620 620
621 621 def read_device(self):
622 622
623 623 self.message = 'Function not supported'
624 624 return False
625 625
626 626
627 627 def get_absolute_url(self):
628 628 return reverse('url_%s_conf' % self.device.device_type.name, args=[str(self.id)])
629 629
630 630 def get_absolute_url_edit(self):
631 631 return reverse('url_edit_%s_conf' % self.device.device_type.name, args=[str(self.id)])
632 632
633 633 def get_absolute_url_delete(self):
634 634 return reverse('url_delete_dev_conf', args=[str(self.id)])
635 635
636 636 def get_absolute_url_import(self):
637 637 return reverse('url_import_dev_conf', args=[str(self.id)])
638 638
639 639 def get_absolute_url_export(self):
640 640 return reverse('url_export_dev_conf', args=[str(self.id)])
641 641
642 642 def get_absolute_url_write(self):
643 643 return reverse('url_write_dev_conf', args=[str(self.id)])
644 644
645 645 def get_absolute_url_read(self):
646 646 return reverse('url_read_dev_conf', args=[str(self.id)])
647 647
648 648 def get_absolute_url_start(self):
649 649 return reverse('url_start_dev_conf', args=[str(self.id)])
650 650
651 651 def get_absolute_url_stop(self):
652 652 return reverse('url_stop_dev_conf', args=[str(self.id)])
653 653
654 654 def get_absolute_url_status(self):
655 655 return reverse('url_status_dev_conf', args=[str(self.id)])
@@ -1,1316 +1,1344
1 1 import ast
2 2 import json
3 3 import hashlib
4 4 from datetime import datetime, timedelta
5 5
6 6 from django.shortcuts import render, redirect, get_object_or_404, HttpResponse
7 7 from django.utils.safestring import mark_safe
8 8 from django.http import HttpResponseRedirect
9 9 from django.urls import reverse
10 10 from django.db.models import Q
11 11 from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
12 12 from django.contrib import messages
13 13 from django.http.request import QueryDict
14 14 from django.contrib.auth.decorators import login_required, user_passes_test
15 15
16 16 from django.utils.timezone import is_aware
17 17
18 18 try:
19 19 from urllib.parse import urlencode
20 20 except ImportError:
21 21 from urllib import urlencode
22 22
23 23 from .forms import ExperimentForm, ExperimentEditionForm, DeviceForm, ConfigurationForm, UploadFileForm, DownloadFileForm, NewForm
24 24 from .forms import FilterForm, ChangeIpForm
25 25
26 26 from apps.pedestal.forms import PedestalConfigurationForm, PedestalEditionForm
27 27 from apps.generator.forms import GeneratorConfigurationForm
28 28 from apps.usrp_rx.forms import USRPRXConfigurationForm, USRPRXEditionForm
29 29 from apps.usrp_tx.forms import USRPTXConfigurationForm, USRPTXEditionForm
30 30 from .utils import Params
31 31
32 32 from .models import Experiment, Device, Configuration, DEV_STATES
33 33 from apps.pedestal.models import PedestalConfiguration
34 34 from apps.generator.models import GeneratorConfiguration
35 35 from apps.usrp_rx.models import USRPRXConfiguration
36 36 from apps.usrp_tx.models import USRPTXConfiguration
37 37 from apps.usrp_tx.validations import validation_usrp_tx_code
38 38 from .gps import gps_response
39 39
40 40
41 41 #comentario test
42 42 CONF_FORMS = {
43 43 'pedestal': PedestalConfigurationForm,
44 44 'generator': GeneratorConfigurationForm,
45 45 'usrp_rx': USRPRXConfigurationForm,
46 46 'usrp_tx': USRPTXConfigurationForm,
47 47 }
48 48
49 49 CONF_MODELS = {
50 50 'pedestal': PedestalConfiguration,
51 51 'generator': GeneratorConfiguration,
52 52 'usrp_rx': USRPRXConfiguration,
53 53 'usrp_tx': USRPTXConfiguration,
54 54 }
55 55
56 56 MIX_MODES = {
57 57 '0': 'P',
58 58 '1': 'S',
59 59 }
60 60
61 61 MIX_OPERATIONS = {
62 62 '0': 'OR',
63 63 '1': 'XOR',
64 64 '2': 'AND',
65 65 '3': 'NAND',
66 66 }
67 67
68 68
69 69 def is_developer(user):
70
71 70 groups = [str(g.name) for g in user.groups.all()]
72 return 'Developer' in groups or user.is_staff
71 #return 'Developer' in groups or user.is_staff
72 return 'Developer' in groups or user.is_superuser
73 73
74 74
75 75 def is_operator(user):
76
77 76 groups = [str(g.name) for g in user.groups.all()]
78 return 'Operator' in groups or user.is_staff
77 #return 'Operator' in groups or user.is_staff
78 return 'Operator' in groups or user.is_superuser
79 79
80 80
81 81 def has_been_modified(model):
82 82
83 83 prev_hash = model.hash
84 84 new_hash = hashlib.sha256(str(model.parms_to_dict).encode()).hexdigest()
85 85 if prev_hash != new_hash:
86 86 model.hash = new_hash
87 87 model.save()
88 88 return True
89 89 return False
90 90
91 91
92 92 def index(request):
93 93 kwargs = {'no_sidebar': True}
94 94
95 95 return render(request, 'index.html', kwargs)
96 96
97 97
98 98 def devices(request):
99 99
100 100 page = request.GET.get('page')
101 101 order = ('device_type',)
102 102
103 103 filters = request.GET.copy()
104 104 kwargs = get_paginator(Device, page, order, filters)
105 105 form = FilterForm(initial=request.GET, extra_fields=['tags'])
106 106
107 107 kwargs['keys'] = ['device_type',
108 108 'ip_address', 'port_address', 'actions']
109 109 kwargs['title'] = 'Device'
110 110 kwargs['suptitle'] = 'List'
111 111 kwargs['no_sidebar'] = True
112 112 kwargs['form'] = form
113 113 kwargs['add_url'] = reverse('url_add_device')
114 114 filters.pop('page', None)
115 115 kwargs['q'] = urlencode(filters)
116 116 kwargs['menu_devices'] = 'active'
117 117 return render(request, 'base_list.html', kwargs)
118 118
119 119
120 120 def device(request, id_dev):
121 121
122 122 device = get_object_or_404(Device, pk=id_dev)
123 123
124 124 kwargs = {}
125 125 kwargs['device'] = device
126 126 kwargs['device_keys'] = ['device_type',
127 127 'ip_address', 'port_address', 'description']
128 128
129 129 kwargs['title'] = 'Device'
130 130 kwargs['suptitle'] = 'Details'
131 131 kwargs['menu_devices'] = 'active'
132 132
133 133 return render(request, 'device.html', kwargs)
134 134
135 135
136 136 @login_required
137 137 def device_new(request):
138
139 if not is_developer(request.user):
140 messages.error(request, 'You must be an developer to create a new experiment')
141 return redirect('url_devices')
138 142
139 143 if request.method == 'GET':
140 144 form = DeviceForm()
141 145
142 146 if request.method == 'POST':
143 147 form = DeviceForm(request.POST)
144 148
145 149 if form.is_valid():
146 150 form.save()
147 151 return redirect('url_devices')
148 152
149 153 kwargs = {}
150 154 kwargs['form'] = form
151 155 kwargs['title'] = 'Device'
152 156 kwargs['suptitle'] = 'New'
153 157 kwargs['button'] = 'Create'
154 158 kwargs['menu_devices'] = 'active'
155 159
156 160 return render(request, 'base_edit.html', kwargs)
157 161
158 162
159 163 @login_required
160 164 def device_edit(request, id_dev):
161 165
162 166 device = get_object_or_404(Device, pk=id_dev)
167
168 if not is_developer(request.user):
169 messages.error(request, 'You must be an developer to edit this object')
170 return redirect(device.get_absolute_url())
163 171
164 172 if request.method == 'GET':
165 173 form = DeviceForm(instance=device)
166 174
167 175 if request.method == 'POST':
168 176 form = DeviceForm(request.POST, instance=device)
169 177
170 178 if form.is_valid():
171 179 form.save()
172 180 return redirect(device.get_absolute_url())
173 181
174 182 kwargs = {}
175 183 kwargs['form'] = form
176 184 kwargs['title'] = 'Device'
177 185 kwargs['suptitle'] = 'Edit'
178 186 kwargs['button'] = 'Update'
179 187 kwargs['menu_devices'] = 'active'
180 188
181 189 return render(request, 'base_edit.html', kwargs)
182 190
183 191
184 192 @login_required
185 193 def device_delete(request, id_dev):
186 194
187 195 device = get_object_or_404(Device, pk=id_dev)
188 196
189 197 if request.method == 'POST':
190 198
191 199 if is_developer(request.user):
192 200 device.delete()
193 201 return redirect('url_devices')
194 202
195 203 messages.error(request, 'Not enough permission to delete this object')
196 204 return redirect(device.get_absolute_url())
197 205
198 206 kwargs = {
199 207 'title': 'Delete',
200 208 'suptitle': 'Device',
201 209 'object': device,
202 210 'delete': True
203 211 }
204 212 kwargs['menu_devices'] = 'active'
205 213
206 214 return render(request, 'confirm.html', kwargs)
207 215
208 216
209 217 @login_required
210 218 def device_change_ip(request, id_dev):
211 219
212 220 device = get_object_or_404(Device, pk=id_dev)
213 221
214 222 if request.method == 'POST':
215 223
216 224 if is_developer(request.user):
217 225 device.change_ip(**request.POST.dict())
218 226 level, message = device.message.split('|')
219 227 messages.add_message(request, level, message)
220 228 else:
221 229 messages.error(
222 230 request, 'Not enough permission to delete this object')
223 231 return redirect(device.get_absolute_url())
224 232
225 233 kwargs = {
226 234 'title': 'Device',
227 235 'suptitle': 'Change IP',
228 236 'object': device,
229 237 'previous': device.get_absolute_url(),
230 238 'form': ChangeIpForm(initial={'ip_address': device.ip_address}),
231 239 'message': ' ',
232 240 }
233 241 kwargs['menu_devices'] = 'active'
234 242
235 243 return render(request, 'confirm.html', kwargs)
236 244
237 245
238 246 def experiments(request):
239 247
240 248 page = request.GET.get('page')
241 249 order = ('id',)
242 250 filters = request.GET.copy()
243 251
244 252 if 'my experiments' in filters:
245 253 filters.pop('my experiments', None)
246 254 filters['mine'] = request.user.id
247 255
248 256 kwargs = get_paginator(Experiment, page, order, filters)
249 257
250 258 fields = ['tags']
251 259 if request.user.is_authenticated:
252 260 fields.append('my experiments')
253 261
254 262 form = FilterForm(initial=request.GET, extra_fields=fields)
255 263
256 264 kwargs['keys'] = ['name', 'pedestal', 'reception_rx', 'transmission_tx', 'actions']
257 265 kwargs['title'] = 'Experiment'
258 266 kwargs['suptitle'] = 'List'
259 267 kwargs['no_sidebar'] = True
260 268 kwargs['form'] = form
261 269 kwargs['add_url'] = reverse('url_add_experiment')
262 270 filters = request.GET.copy()
263 271 filters.pop('page', None)
264 272 kwargs['q'] = urlencode(filters)
265 273 kwargs['menu_experiments'] = 'active'
266 274
267 275 return render(request, 'base_list.html', kwargs)
268 276
269 277
270 278 def experiment(request, id_exp):
271 279
272 280 experiment = get_object_or_404(Experiment, pk=id_exp)
273 281 id_p = experiment.pedestal_id
274 282 id_rx = experiment.reception_rx_id
275 283 id_tx = experiment.transmission_tx_id
276 284 conf_pedestal = PedestalConfiguration.objects.get(id = id_p)
277 285 conf_rx = USRPRXConfiguration.objects.get(id = id_rx)
278 286 conf_tx = USRPTXConfiguration.objects.get(id = id_tx)
279 287
280 288 gps_data = gps_response(experiment.generator.ip_address)
281 289 experiment.latitude = gps_data["statusRpt"]["lat"]
282 290 experiment.longitude = gps_data["statusRpt"]["lng"]
283 291 experiment.altitude = gps_data["statusRpt"]["alt"]
284 292 experiment.save()
285 293
286 294 kwargs = {}
287 295 kwargs['experiment_keys'] = ['name', 'latitude', 'longitude', 'altitude', 'heading']
288 296 kwargs['experiment'] = experiment
289 297
290 298 if conf_pedestal.mode == 'position':
291 299 kwargs['experiment_pedestal_keys'] = ['mode', 'axis', 'angle']
292 300 elif conf_pedestal.mode == 'speed':
293 301 kwargs['experiment_pedestal_keys'] = ['mode', 'axis', 'speed']
294 302 else:
295 303 kwargs['experiment_pedestal_keys'] = ['mode', 'axis', 'speed', 'angle', 'min_value', 'max_value']
296 304 kwargs['experiment_pedestal'] = conf_pedestal
297 305
298 306 kwargs['experiment_rx_keys'] = ['ip_address_rx', 'daughterboard_rx', 'antenna_rx', 'samplerate_rx', 'frequency_rx', 'datadir', 'clocksource', 'timesource', 'clockrate']
299 307 kwargs['experiment_rx'] = conf_rx
300 308
301 309 if not conf_tx.enable_2:
302 310 kwargs['experiment_tx_keys'] = ['ip_address', 'daughterboard', 'antenna', 'frequency', 'samplerate', 'ipp', 'delay', 'pulse_1', 'code_type_1', 'code_1', 'repetitions_1']
303 311 else:
304 312 kwargs['experiment_tx_keys'] = ['ip_address', 'daughterboard', 'antenna', 'frequency', 'samplerate', 'ipp', 'delay', 'pulse_1', 'code_type_1', 'code_1', 'repetitions_1',
305 313 'pulse_2', 'code_type_2', 'code_2', 'repetitions_2']
306 314 kwargs['experiment_tx'] = conf_tx
307 315
308 316 kwargs['title'] = 'Experiment'
309 317 kwargs['suptitle'] = 'Details'
310 318 kwargs['button'] = 'Add Configuration'
311 319 kwargs['menu_experiments'] = 'active'
312 320
313 321 ###### SIDEBAR ######
314 322 kwargs.update(sidebar(confs=[conf_pedestal, conf_rx, conf_tx]))
315 323
316 324 return render(request, 'experiment.html', kwargs)
317 325
318 326
319 327 @login_required
320 328 def experiment_new(request, id_camp=None):
321 329
322 330 if not is_developer(request.user):
323 messages.error(
324 request, 'Developer required, to create new Experiments')
325 return redirect('index')
331 messages.error(request, 'You must be an developer to create a new experiment')
332 return redirect('url_experiments')
333
326 334 kwargs = {}
327 335
328 336 if request.method == 'GET':
329 337 kwargs['button'] = 'Create'
330 338 form = ExperimentForm()
331 339
332 340 if request.method == 'POST':
333 341 form = ExperimentForm(request.POST)
334 342 if form.is_valid():
335 343 experiment = form.save(commit=False)
336 344 experiment.author = request.user
337 345 experiment.save()
338 346 messages.success(request, 'Experiment configuration successfully created')
339 347 return redirect('url_experiment', id_exp=experiment.id)
340 348
341 349 kwargs['form'] = form
342 350 kwargs['title'] = 'Experiment'
343 351 kwargs['suptitle'] = 'New'
344 352 kwargs['menu_experiments'] = 'active'
345 353
346 354 return render(request, 'experiment_edit.html', kwargs)
347 355
348 356
349 357 @login_required
350 358 def experiment_edit(request, id_exp):
351
352 359 experiment = get_object_or_404(Experiment, pk=id_exp)
360
361 if not is_developer(request.user):
362 messages.error(request, 'You must be an developer to edit this experiment')
363 return redirect(experiment.get_absolute_url())
364
353 365 id_p = experiment.pedestal_id
354 366 id_rx = experiment.reception_rx_id
355 367 id_tx = experiment.transmission_tx_id
356 368 conf_pedestal = PedestalConfiguration.objects.get(id = id_p)
357 369 conf_rx = USRPRXConfiguration.objects.get(id = id_rx)
358 370 conf_tx = USRPTXConfiguration.objects.get(id = id_tx)
359 371
360 372 if request.method == 'GET':
361 373 form = ExperimentEditionForm(instance=experiment)
362 374 form_pedestal = PedestalEditionForm(instance=conf_pedestal)
363 375 form_rx = USRPRXEditionForm(instance=conf_rx)
364 376 form_tx = USRPTXEditionForm(instance=conf_tx)
365 377
366 378 if request.method == 'POST':
367 379 form = ExperimentEditionForm(request.POST, instance=experiment)
368 380 form_pedestal = PedestalEditionForm(request.POST, instance=conf_pedestal)
369 381 form_rx = USRPRXEditionForm(request.POST, instance=conf_rx)
370 382 form_tx = USRPTXEditionForm(request.POST, instance=conf_tx)
371 383
372 384 if form.is_valid() and form_pedestal.is_valid() and form_rx.is_valid() and form_tx.is_valid():
373 385 experiment = form.save(commit=False)
374 386 pedestal = form_pedestal.save(commit=False)
375 387 rx = form_rx.save(commit=False)
376 388 tx = form_tx.save(commit=False)
377 389
378 390 pedestal.save()
379 391 rx.save()
380 392 validation_usrp_tx_code(request, tx)
381 393 tx.save()
382 394 messages.success(request, 'Experiment configuration successfully updated')
383 395 return redirect('url_experiment', id_exp=experiment.id)
384 396
385 397 kwargs = {}
386 398 kwargs['form'] = form
387 399 kwargs['form_pedestal'] = form_pedestal
388 400 kwargs['form_rx'] = form_rx
389 401 kwargs['form_tx'] = form_tx
390 402 kwargs['title'] = 'Experiment'
391 403 kwargs['suptitle'] = 'Edit'
392 404 kwargs['button'] = 'Update'
393 405 kwargs['menu_experiments'] = 'active'
394 406
395 407 return render(request, 'experiment_edit.html', kwargs)
396 408
397 409
398 410 @login_required
399 411 def experiment_delete(request, id_exp):
400 412
401 413 experiment = get_object_or_404(Experiment, pk=id_exp)
402 414
403 415 if request.method == 'POST':
404 416 if is_developer(request.user):
405 417 #for conf in Configuration.objects.filter(experiment=experiment):
406 418 #conf.delete()
407 419 experiment.delete()
408 420 return redirect('url_experiments')
409 421
410 messages.error(request, 'Not enough permission to delete this object')
422 messages.error(request, 'Not enough permission to delete this experiment')
411 423 return redirect(experiment.get_absolute_url())
412 424
413 425 kwargs = {
414 426 'title': 'Delete',
415 427 'suptitle': 'Experiment',
416 428 'object': experiment,
417 429 'delete': True
418 430 }
419 431
420 432 return render(request, 'confirm.html', kwargs)
421 433
422 434
423 435 @login_required
424 436 def experiment_export(request, id_exp):
425 437
426 438 experiment = get_object_or_404(Experiment, pk=id_exp)
427 439 content = experiment.parms_to_dict()
428 440 content_type = 'application/json'
429 441 filename = '%s_%s.json' % (experiment.name, experiment.id)
430 442
431 443 response = HttpResponse(content_type=content_type)
432 444 response['Content-Disposition'] = 'attachment; filename="%s"' % filename
433 445 response.write(json.dumps(content, indent=2))
434 446
435 447 return response
436 448
437 449
438 450 @login_required
439 451 def experiment_import(request, id_exp):
440 452
441 453 experiment = get_object_or_404(Experiment, pk=id_exp)
442 454 configurations = Configuration.objects.filter(experiment=experiment)
443 455
444 456 if request.method == 'GET':
445 457 file_form = UploadFileForm()
446 458
447 459 if request.method == 'POST':
448 460 file_form = UploadFileForm(request.POST, request.FILES)
449 461
450 462 if file_form.is_valid():
451 463 new_exp = experiment.dict_to_parms(
452 464 json.load(request.FILES['file']), CONF_MODELS)
453 465 messages.success(
454 466 request, "Parameters imported from: '%s'." % request.FILES['file'].name)
455 467 return redirect(new_exp.get_absolute_url_edit())
456 468
457 469 messages.error(request, "Could not import parameters from file")
458 470
459 471 kwargs = {}
460 472 kwargs['title'] = 'Experiment'
461 473 kwargs['form'] = file_form
462 474 kwargs['suptitle'] = 'Importing file'
463 475 kwargs['button'] = 'Import'
464 476 kwargs['menu_experiments'] = 'active'
465 477
466 478 kwargs.update(sidebar(experiment=experiment))
467 479
468 480 return render(request, 'experiment_import.html', kwargs)
469 481
470 482
471 483 @login_required
472 484 def experiment_start(request, id_exp):
473 485 exp = get_object_or_404(Experiment, pk=id_exp)
474 486
487 if not is_developer(request.user) and not is_operator(request.user):
488 messages.error(request, 'You must be an developer or operator to start this experiment')
489 return redirect(exp.get_absolute_url())
490
475 491 if exp.status == 2:
476 492 messages.warning(request, 'Experiment {} already runnnig'.format(exp.name))
477 493 else:
478 494 exp.status = exp.start()
479 495 if exp.status == 5:
480 496 messages.warning(request, 'Experiment {} already runnnig'.format(Experiment.objects.filter(status=2)[0]))
481 497 if exp.status == 0:
482 498 messages.error(request, 'Experiment {} not start'.format(exp))
483 499 if exp.status == 2:
484 500 messages.success(request, 'Experiment {} started'.format(exp))
485 501
486 502 exp.save()
487 503
488 504 return redirect(exp.get_absolute_url())
489 505
490 506
491 507 @login_required
492 508 def experiment_stop(request, id_exp):
493 509 all_status = Experiment.objects.filter(status=2)
494 510 exp = get_object_or_404(Experiment, pk=id_exp)
495
511
512 if not is_developer(request.user) and not is_operator(request.user):
513 messages.error(request, 'You must be an developer or operator to stop this experiment')
514 return redirect(exp.get_absolute_url())
515
496 516 if exp.status == 2 or exp.status == 4 or exp.status == 5:
497 517 for one_exp in all_status:
498 518 if one_exp != exp:
499 519 one_exp.status = 4
500 520 one_exp.mode_stop = 'web'
501 521 one_exp.save()
502 522
503 523 exp.status = exp.stop()
504 524 exp.mode_stop = 'web'
505 525 exp.save()
506 526 messages.success(request, 'Experiment {} stopped'.format(exp))
507 527 else:
508 528 messages.error(request, 'Experiment {} not running'.format(exp))
509 529
510 530 return redirect(exp.get_absolute_url())
511 531
512 532
513 533 def experiment_status(request, id_exp):
514 534
515 535 exp = get_object_or_404(Experiment, pk=id_exp)
516 536
517 537 exp.get_status()
518 538
519 539 return redirect(exp.get_absolute_url())
520 540
521 541
522 542 def experiment_summary(request, id_exp):
523 543
524 544 experiment = get_object_or_404(Experiment, pk=id_exp)
525 545 configurations = Configuration.objects.filter(
526 546 experiment=experiment, type=0)
527 547
528 548 kwargs = {}
529 549 kwargs['experiment_keys'] = ['radar_system',
530 550 'name', 'freq', 'start_time', 'end_time']
531 551 kwargs['experiment'] = experiment
532 552 kwargs['configurations'] = []
533 553 kwargs['title'] = 'Experiment Summary'
534 554 kwargs['suptitle'] = 'Details'
535 555 kwargs['button'] = 'Verify Parameters'
536 556
537 557 c_vel = 3.0*(10**8) # m/s
538 558 ope_freq = experiment.freq*(10**6) # 1/s
539 559 radar_lambda = c_vel/ope_freq # m
540 560 kwargs['radar_lambda'] = radar_lambda
541 561
542 562 ipp = None
543 563 nsa = 1
544 564 code_id = 0
545 565 tx_line = {}
546 566
547 567 for configuration in configurations.filter(device__device_type__name = 'pedestal'):
548 568
549 569 if configuration.mix:
550 570 continue
551 571 conf = {'conf': configuration}
552 572 conf['keys'] = []
553 573 conf['NTxs'] = configuration.ntx
554 574 conf['keys'].append('NTxs')
555 575 ipp = configuration.ipp
556 576 conf['IPP'] = ipp
557 577 conf['keys'].append('IPP')
558 578 lines = configuration.get_lines(line_type__name='tx')
559 579
560 580 for tx_line in lines:
561 581 tx_params = json.loads(tx_line.params)
562 582 conf[tx_line.get_name()] = '{} Km'.format(tx_params['pulse_width'])
563 583 conf['keys'].append(tx_line.get_name())
564 584 delays = tx_params['delays']
565 585 if delays not in ('', '0'):
566 586 n = len(delays.split(','))
567 587 taus = '{} Taus: {}'.format(n, delays)
568 588 else:
569 589 taus = '-'
570 590 conf['Taus ({})'.format(tx_line.get_name())] = taus
571 591 conf['keys'].append('Taus ({})'.format(tx_line.get_name()))
572 592 for code_line in configuration.get_lines(line_type__name='codes'):
573 593 code_params = json.loads(code_line.params)
574 594 code_id = code_params['code']
575 595 if tx_line.pk == int(code_params['TX_ref']):
576 596 conf['Code ({})'.format(tx_line.get_name())] = '{}:{}'.format(RCLineCode.objects.get(pk=code_params['code']),
577 597 '-'.join(code_params['codes']))
578 598 conf['keys'].append('Code ({})'.format(tx_line.get_name()))
579 599
580 600 for windows_line in configuration.get_lines(line_type__name='windows'):
581 601 win_params = json.loads(windows_line.params)
582 602 if tx_line.pk == int(win_params['TX_ref']):
583 603 windows = ''
584 604 nsa = win_params['params'][0]['number_of_samples']
585 605 for i, params in enumerate(win_params['params']):
586 606 windows += 'W{}: Ho={first_height} km DH={resolution} km NSA={number_of_samples}<br>'.format(
587 607 i, **params)
588 608 conf['Window'] = mark_safe(windows)
589 609 conf['keys'].append('Window')
590 610
591 611 kwargs['configurations'].append(conf)
592 612
593 613 for configuration in configurations.filter(device__device_type__name = 'jars'):
594 614
595 615 conf = {'conf': configuration}
596 616 conf['keys'] = []
597 617 conf['Type of Data'] = EXPERIMENT_TYPE[configuration.exp_type][1]
598 618 conf['keys'].append('Type of Data')
599 619 channels_number = configuration.channels_number
600 620 exp_type = configuration.exp_type
601 621 fftpoints = configuration.fftpoints
602 622 filter_parms = json.loads(configuration.filter_parms)
603 623 spectral_number = configuration.spectral_number
604 624 acq_profiles = configuration.acq_profiles
605 625 cohe_integr = configuration.cohe_integr
606 626 profiles_block = configuration.profiles_block
607 627
608 628 conf['Num of Profiles'] = acq_profiles
609 629 conf['keys'].append('Num of Profiles')
610 630
611 631 conf['Prof per Block'] = profiles_block
612 632 conf['keys'].append('Prof per Block')
613 633
614 634 conf['Blocks per File'] = configuration.raw_data_blocks
615 635 conf['keys'].append('Blocks per File')
616 636
617 637 if exp_type == 0: # Short
618 638 bytes_ = 2
619 639 b = nsa*2*bytes_*channels_number
620 640 else: # Float
621 641 bytes_ = 4
622 642 channels = channels_number + spectral_number
623 643 b = nsa*2*bytes_*fftpoints*channels
624 644
625 645 codes_num = 7
626 646 if code_id == 2:
627 647 codes_num = 7
628 648 elif code_id == 12:
629 649 codes_num = 15
630 650
631 651 #Jars filter values:
632 652
633 653 clock = float(filter_parms['clock'])
634 654 filter_2 = int(filter_parms['cic_2'])
635 655 filter_5 = int(filter_parms['cic_5'])
636 656 filter_fir = int(filter_parms['fir'])
637 657 Fs_MHz = clock/(filter_2*filter_5*filter_fir)
638 658
639 659 #Jars values:
640 660 if ipp is not None:
641 661 IPP_units = ipp/0.15*Fs_MHz
642 662 IPP_us = IPP_units / Fs_MHz
643 663 IPP_s = IPP_units / (Fs_MHz * (10**6))
644 664 Ts = 1/(Fs_MHz*(10**6))
645 665
646 666 Va = radar_lambda/(4*Ts*cohe_integr)
647 667 rate_bh = ((nsa-codes_num)*channels_number*2 *
648 668 bytes_/IPP_us)*(36*(10**8)/cohe_integr)
649 669 rate_gh = rate_bh/(1024*1024*1024)
650 670
651 671 conf['Time per Block'] = IPP_s * profiles_block * cohe_integr
652 672 conf['keys'].append('Time per Block')
653 673 conf['Acq time'] = IPP_s * acq_profiles
654 674 conf['keys'].append('Acq time')
655 675 conf['Data rate'] = str(rate_gh)+" (GB/h)"
656 676 conf['keys'].append('Data rate')
657 677 conf['Va (m/s)'] = Va
658 678 conf['keys'].append('Va (m/s)')
659 679 conf['Vrange (m/s)'] = 3/(2*IPP_s*cohe_integr)
660 680 conf['keys'].append('Vrange (m/s)')
661 681
662 682 kwargs['configurations'].append(conf)
663 683 kwargs['menu_experiments'] = 'active'
664 684
665 685 ###### SIDEBAR ######
666 686 kwargs.update(sidebar(experiment=experiment))
667 687
668 688 return render(request, 'experiment_summary.html', kwargs)
669 689
670 690
671 691 @login_required
672 692 def experiment_verify(request, id_exp):
673 693
674 694 experiment = get_object_or_404(Experiment, pk=id_exp)
675 695 experiment_data = experiment.parms_to_dict()
676 696 configurations = Configuration.objects.filter(
677 697 experiment=experiment, type=0)
678 698
679 699 kwargs = {}
680 700
681 701 kwargs['experiment_keys'] = ['name', 'start_time', 'end_time']
682 702 kwargs['experiment'] = experiment
683 703
684 704 kwargs['configuration_keys'] = ['name', 'device__ip_address',
685 705 'device__port_address', 'device__status']
686 706 kwargs['configurations'] = configurations
687 707 kwargs['experiment_data'] = experiment_data
688 708
689 709 kwargs['title'] = 'Verify Experiment'
690 710 kwargs['suptitle'] = 'Parameters'
691 711
692 712 kwargs['button'] = 'Update'
693 713
694 714 jars_conf = False
695 715 rc_conf = False
696 716 dds_conf = False
697 717
698 718 for configuration in configurations:
699 719 #-------------------- JARS -----------------------:
700 720 if configuration.device.device_type.name == 'jars':
701 721 jars_conf = True
702 722 jars = configuration
703 723 kwargs['jars_conf'] = jars_conf
704 724 filter_parms = json.loads(jars.filter_parms)
705 725 kwargs['filter_parms'] = filter_parms
706 726 #--Sampling Frequency
707 727 clock = filter_parms['clock']
708 728 filter_2 = filter_parms['cic_2']
709 729 filter_5 = filter_parms['cic_5']
710 730 filter_fir = filter_parms['fir']
711 731 samp_freq_jars = clock/filter_2/filter_5/filter_fir
712 732
713 733 kwargs['samp_freq_jars'] = samp_freq_jars
714 734 kwargs['jars'] = configuration
715 735
716 736 #--------------------- RC ----------------------:
717 737 if configuration.device.device_type.name == 'pedestal' and not configuration.mix:
718 738 rc_conf = True
719 739 rc = configuration
720 740
721 741 rc_parms = configuration.parms_to_dict()
722 742
723 743 win_lines = rc.get_lines(line_type__name='windows')
724 744 if win_lines:
725 745 dh = json.loads(win_lines[0].params)['params'][0]['resolution']
726 746 #--Sampling Frequency
727 747 samp_freq_rc = 0.15/dh
728 748 kwargs['samp_freq_rc'] = samp_freq_rc
729 749
730 750 kwargs['rc_conf'] = rc_conf
731 751 kwargs['rc'] = configuration
732 752
733 753 #-------------------- DDS ----------------------:
734 754 if configuration.device.device_type.name == 'dds':
735 755 dds_conf = True
736 756 dds = configuration
737 757 dds_parms = configuration.parms_to_dict()
738 758
739 759 kwargs['dds_conf'] = dds_conf
740 760 kwargs['dds'] = configuration
741 761
742 762 #------------Validation------------:
743 763 #Clock
744 764 if dds_conf and rc_conf and jars_conf:
745 765 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']):
746 766 messages.warning(request, "Devices don't have the same clock.")
747 767 elif rc_conf and jars_conf:
748 768 if float(filter_parms['clock']) != float(rc_parms['configurations']['byId'][str(rc.pk)]['clock_in']):
749 769 messages.warning(request, "Devices don't have the same clock.")
750 770 elif rc_conf and dds_conf:
751 771 if float(rc_parms['configurations']['byId'][str(rc.pk)]['clock_in']) != float(dds_parms['configurations']['byId'][str(dds.pk)]['clock']):
752 772 messages.warning(request, "Devices don't have the same clock.")
753 773 if float(samp_freq_rc) != float(dds_parms['configurations']['byId'][str(dds.pk)]['frequencyA']):
754 774 messages.warning(
755 775 request, "Devices don't have the same Frequency A.")
756 776
757 777 #------------POST METHOD------------:
758 778 if request.method == 'POST':
759 779 if request.POST['suggest_clock']:
760 780 try:
761 781 suggest_clock = float(request.POST['suggest_clock'])
762 782 except:
763 783 messages.warning(request, "Invalid value in CLOCK IN.")
764 784 return redirect('url_verify_experiment', id_exp=experiment.id)
765 785 else:
766 786 suggest_clock = ""
767 787 if suggest_clock:
768 788 if rc_conf:
769 789 rc.clock_in = suggest_clock
770 790 rc.save()
771 791 if jars_conf:
772 792 filter_parms = jars.filter_parms
773 793 filter_parms = ast.literal_eval(filter_parms)
774 794 filter_parms['clock'] = suggest_clock
775 795 jars.filter_parms = json.dumps(filter_parms)
776 796 jars.save()
777 797 kwargs['filter_parms'] = filter_parms
778 798 if dds_conf:
779 799 dds.clock = suggest_clock
780 800 dds.save()
781 801
782 802 if request.POST['suggest_frequencyA']:
783 803 try:
784 804 suggest_frequencyA = float(request.POST['suggest_frequencyA'])
785 805 except:
786 806 messages.warning(request, "Invalid value in FREQUENCY A.")
787 807 return redirect('url_verify_experiment', id_exp=experiment.id)
788 808 else:
789 809 suggest_frequencyA = ""
790 810 if suggest_frequencyA:
791 811 if jars_conf:
792 812 filter_parms = jars.filter_parms
793 813 filter_parms = ast.literal_eval(filter_parms)
794 814 filter_parms['fch'] = suggest_frequencyA
795 815 jars.filter_parms = json.dumps(filter_parms)
796 816 jars.save()
797 817 kwargs['filter_parms'] = filter_parms
798 818 if dds_conf:
799 819 dds.frequencyA_Mhz = request.POST['suggest_frequencyA']
800 820 dds.save()
801 821
802 822 kwargs['menu_experiments'] = 'active'
803 823 kwargs.update(sidebar(experiment=experiment))
804 824 return render(request, 'experiment_verify.html', kwargs)
805 825
806 826
807 827 def dev_confs(request):
808 828
809 829 page = request.GET.get('page')
810 830 order = ('-programmed_date', )
811 831 filters = request.GET.copy()
812 832 if 'my configurations' in filters:
813 833 filters.pop('my configurations', None)
814 834 filters['mine'] = request.user.id
815 835 kwargs = get_paginator(Configuration, page, order, filters)
816 836 fields = ['tags', 'historical']
817 837 if request.user.is_authenticated:
818 838 fields.append('my configurations')
819 839 form = FilterForm(initial=request.GET, extra_fields=fields)
820 840 kwargs['keys'] = ['name', 'device', 'type', 'actions']
821 841 if request.GET.get('historical') == 'on':
822 842 kwargs['keys'].insert(3, 'experiment')
823 843 kwargs['keys'].insert(4, 'experiment_date')
824 844 else:
825 845 kwargs['keys'].insert(3, 'programmed_date')
826 846
827 847 kwargs['title'] = 'Configuration'
828 848 kwargs['suptitle'] = 'List'
829 849 kwargs['no_sidebar'] = True
830 850 kwargs['form'] = form
831 851 kwargs['add_url'] = reverse('url_add_dev_conf', args=[0])
832 852 filters = request.GET.copy()
833 853 filters.pop('page', None)
834 854 kwargs['q'] = urlencode(filters)
835 855 kwargs['menu_configurations'] = 'active'
836 856
837 857 return render(request, 'base_list.html', kwargs)
838 858
839 859
840 860 def dev_conf(request, id_conf):
841 861
842 862 conf = get_object_or_404(Configuration, pk=id_conf)
843 863
844 864 return redirect(conf.get_absolute_url())
845 865
846 866
847 867 @login_required
848 868 def dev_conf_new(request, id_exp=0, id_dev=0):
849 869
850 870 if not is_developer(request.user):
851 871 messages.error(
852 872 request, 'Developer required, to create new configurations')
853 return redirect('index')
873 return redirect('url_dev_confs')
854 874
855 875 initial = {}
856 876 kwargs = {}
857 877
858 878 if id_exp != 0:
859 879 initial['experiment'] = id_exp
860 880
861 881 if id_dev != 0:
862 882 initial['device'] = id_dev
863 883
864 884 if request.method == 'GET':
865 885
866 886 if id_dev:
867 887 kwargs['button'] = 'Create'
868 888 device = Device.objects.get(pk=id_dev)
869 889 DevConfForm = CONF_FORMS[device.device_type.name]
870 890 initial['name'] = request.GET['name']
871 891 form = DevConfForm(initial=initial)
872 892 else:
873 893 kwargs['button'] = 'Create'
874 894 form = ConfigurationForm(initial=initial)
875 895
876 896 if request.method == 'POST':
877 897
878 898 device = Device.objects.get(pk=request.POST['device'])
879 899 DevConfForm = CONF_FORMS[device.device_type.name]
880 900
881 901 form = DevConfForm(request.POST)
882 902 kwargs['button'] = 'Create'
883 903 if form.is_valid():
884 904 conf = form.save(commit=False)
885 905
886 906 if device.device_type.name == 'usrp_tx':
887 907 validation_usrp_tx_code(request, conf)
888 908
889 909 conf.save()
890 910 conf.author = request.user
891 911
892 912 messages.success(request, device.device_type.name + ' configuration successfully created')
893 913 return redirect('url_dev_conf', id_conf=conf.pk)
894 914
895 915 kwargs['id_exp'] = id_exp
896 916 kwargs['form'] = form
897 917 kwargs['title'] = 'Configuration'
898 918 kwargs['suptitle'] = 'New'
899 919 kwargs['menu_configurations'] = 'active'
900 920
901 921 if id_dev != 0:
902 922 device = Device.objects.get(pk=id_dev)
903 923 kwargs['device'] = device.device_type.name
904 924 return render(request, 'dev_conf_edit.html', kwargs)
905 925
906 926
907 927 @login_required
908 928 def dev_conf_edit(request, id_conf):
909 929
910 930 conf = get_object_or_404(Configuration, pk=id_conf)
911 931
912 932 DevConfForm = CONF_FORMS[conf.device.device_type.name]
913 933
914 934 if request.method == 'GET':
915 935 form = DevConfForm(instance=conf)
916 936
917 937 if request.method == 'POST':
918 938 form = DevConfForm(request.POST, instance=conf)
919 939
920 940 if form.is_valid():
921 941 form.save()
922 942 return redirect('url_dev_conf', id_conf=id_conf)
923 943
924 944 kwargs = {}
925 945 kwargs['form'] = form
926 946 kwargs['title'] = 'Device Configuration'
927 947 kwargs['suptitle'] = 'Edit'
928 948 kwargs['button'] = 'Update'
929 949 kwargs['menu_configurations'] = 'active'
930 950
931 951 ###### SIDEBAR ######
932 952 kwargs.update(sidebar(conf=conf))
933 953
934 954 return render(request, '%s_conf_edit.html' % conf.device.device_type.name, kwargs)
935 955
936 956
937 957 @login_required
938 958 def dev_conf_start(request, id_conf):
939 959
940 960 conf = get_object_or_404(Configuration, pk=id_conf)
941 961
962 if not is_developer(request.user) and not is_operator(request.user):
963 messages.error(request, 'You must be an developer or operator to start this configuration')
964 return redirect(conf.get_absolute_url())
965
942 966 if conf.start_device():
943 967 messages.success(request, conf.message)
944 968 else:
945 969 messages.error(request, conf.message)
946 970
947 971 #conf.status_device()
948 972
949 973 return redirect(conf.get_absolute_url())
950 974
951 975
952 976 @login_required
953 977 def dev_conf_stop(request, id_conf):
954 978
955 979 conf = get_object_or_404(Configuration, pk=id_conf)
956 980
981 if not is_developer(request.user) and not is_operator(request.user):
982 messages.error(request, 'You must be an developer or operator to stop this configuration')
983 return redirect(conf.get_absolute_url())
984
957 985 if conf.stop_device():
958 986 messages.success(request, conf.message)
959 987 else:
960 988 messages.error(request, conf.message)
961 989
962 990 #conf.status_device()
963 991
964 992 return redirect(conf.get_absolute_url())
965 993
966 994
967 995 @login_required
968 996 def dev_conf_status(request, id_conf):
969 997
970 998 conf = get_object_or_404(Configuration, pk=id_conf)
971 999
972 1000 conf_active = Configuration.objects.filter(pk=conf.device.conf_active).first()
973 1001 if conf_active!=conf:
974 1002 url = '#' if conf_active is None else conf_active.get_absolute_url()
975 1003 label = 'None' if conf_active is None else conf_active.label
976 1004 messages.warning(
977 1005 request,
978 1006 mark_safe('The current configuration has not been written to device, the active configuration is <a href="{}">{}</a>'.format(
979 1007 url,
980 1008 label
981 1009 ))
982 1010 )
983 1011
984 1012 return redirect(conf.get_absolute_url())
985 1013
986 1014 if conf.status_device():
987 1015 messages.success(request, conf.message)
988 1016 else:
989 1017 messages.error(request, conf.message)
990 1018
991 1019 return redirect(conf.get_absolute_url())
992 1020
993 1021
994 1022 @login_required
995 1023 def dev_conf_reset(request, id_conf):
996 1024
997 1025 conf = get_object_or_404(Configuration, pk=id_conf)
998 1026
999 1027 if conf.reset_device():
1000 1028 messages.success(request, conf.message)
1001 1029 else:
1002 1030 messages.error(request, conf.message)
1003 1031
1004 1032 return redirect(conf.get_absolute_url())
1005 1033
1006 1034
1007 1035 @login_required
1008 1036 def dev_conf_write(request, id_conf):
1009 1037
1010 1038 conf = get_object_or_404(Configuration, pk=id_conf)
1011 1039
1012 1040 if request.method == 'POST':
1013 1041 if conf.write_device():
1014 1042 conf.device.conf_active = conf.pk
1015 1043 conf.device.save()
1016 1044 messages.success(request, conf.message)
1017 1045 if has_been_modified(conf):
1018 1046 conf.clone(type=1)
1019 1047 else:
1020 1048 messages.error(request, conf.message)
1021 1049
1022 1050 return redirect(get_object_or_404(Configuration, pk=id_conf).get_absolute_url())
1023 1051
1024 1052 kwargs = {
1025 1053 'title': 'Write Configuration',
1026 1054 'suptitle': conf.label,
1027 1055 'message': 'Are you sure yo want to write this {} configuration?'.format(conf.device),
1028 1056 'delete': False
1029 1057 }
1030 1058 kwargs['menu_configurations'] = 'active'
1031 1059
1032 1060 return render(request, 'confirm.html', kwargs)
1033 1061
1034 1062
1035 1063 @login_required
1036 1064 def dev_conf_read(request, id_conf):
1037 1065
1038 1066 conf = get_object_or_404(Configuration, pk=id_conf)
1039 1067
1040 1068 DevConfForm = CONF_FORMS[conf.device.device_type.name]
1041 1069
1042 1070 if request.method == 'GET':
1043 1071 parms = conf.read_device()
1044 1072 #conf.status_device()
1045 1073
1046 1074 if not parms:
1047 1075 messages.error(request, conf.message)
1048 1076 return redirect(conf.get_absolute_url())
1049 1077
1050 1078 form = DevConfForm(initial=parms, instance=conf)
1051 1079
1052 1080 if request.method == 'POST':
1053 1081 form = DevConfForm(request.POST, instance=conf)
1054 1082
1055 1083 if form.is_valid():
1056 1084 form.save()
1057 1085 return redirect(conf.get_absolute_url())
1058 1086
1059 1087 messages.error(request, "Parameters could not be saved")
1060 1088
1061 1089 kwargs = {}
1062 1090 kwargs['id_dev'] = conf.id
1063 1091 kwargs['form'] = form
1064 1092 kwargs['title'] = 'Device Configuration'
1065 1093 kwargs['suptitle'] = 'Parameters read from device'
1066 1094 kwargs['button'] = 'Save'
1067 1095
1068 1096 ###### SIDEBAR ######
1069 1097 kwargs.update(sidebar(conf=conf))
1070 1098
1071 1099 return render(request, '%s_conf_edit.html' % conf.device.device_type.name, kwargs)
1072 1100
1073 1101
1074 1102 @login_required
1075 1103 def dev_conf_import(request, id_conf):
1076 1104
1077 1105 conf = get_object_or_404(Configuration, pk=id_conf)
1078 1106 DevConfForm = CONF_FORMS[conf.device.device_type.name]
1079 1107
1080 1108 if request.method == 'GET':
1081 1109 file_form = UploadFileForm()
1082 1110
1083 1111 if request.method == 'POST':
1084 1112 file_form = UploadFileForm(request.POST, request.FILES)
1085 1113
1086 1114 if file_form.is_valid():
1087 1115
1088 1116 data = conf.import_from_file(request.FILES['file'])
1089 1117 parms = Params(data=data).get_conf(
1090 1118 dtype=conf.device.device_type.name)
1091 1119
1092 1120 if parms:
1093 1121
1094 1122 form = DevConfForm(initial=parms, instance=conf)
1095 1123
1096 1124 kwargs = {}
1097 1125 kwargs['id_dev'] = conf.id
1098 1126 kwargs['form'] = form
1099 1127 kwargs['title'] = 'Device Configuration'
1100 1128 kwargs['suptitle'] = 'Parameters imported'
1101 1129 kwargs['button'] = 'Save'
1102 1130 kwargs['action'] = conf.get_absolute_url_edit()
1103 1131 kwargs['previous'] = conf.get_absolute_url()
1104 1132
1105 1133 ###### SIDEBAR ######
1106 1134 kwargs.update(sidebar(conf=conf))
1107 1135
1108 1136 messages.success(
1109 1137 request, "Parameters imported from: '%s'." % request.FILES['file'].name)
1110 1138
1111 1139 return render(request, '%s_conf_edit.html' % conf.device.device_type.name, kwargs)
1112 1140
1113 1141 messages.error(request, "Could not import parameters from file")
1114 1142
1115 1143 kwargs = {}
1116 1144 kwargs['id_dev'] = conf.id
1117 1145 kwargs['title'] = 'Device Configuration'
1118 1146 kwargs['form'] = file_form
1119 1147 kwargs['suptitle'] = 'Importing file'
1120 1148 kwargs['button'] = 'Import'
1121 1149 kwargs['menu_configurations'] = 'active'
1122 1150
1123 1151 kwargs.update(sidebar(conf=conf))
1124 1152
1125 1153 return render(request, 'dev_conf_import.html', kwargs)
1126 1154
1127 1155
1128 1156 @login_required
1129 1157 def dev_conf_export(request, id_conf):
1130 1158
1131 1159 conf = get_object_or_404(Configuration, pk=id_conf)
1132 1160
1133 1161 if request.method == 'GET':
1134 1162 file_form = DownloadFileForm(conf.device.device_type.name)
1135 1163
1136 1164 if request.method == 'POST':
1137 1165 file_form = DownloadFileForm(
1138 1166 conf.device.device_type.name, request.POST)
1139 1167
1140 1168 if file_form.is_valid():
1141 1169 fields = conf.export_to_file(
1142 1170 format=file_form.cleaned_data['format'])
1143 1171
1144 1172 if not fields['content']:
1145 1173 messages.error(request, conf.message)
1146 1174 return redirect(conf.get_absolute_url_export())
1147 1175 response = HttpResponse(content_type=fields['content_type'])
1148 1176 response['Content-Disposition'] = 'attachment; filename="%s"' % fields['filename']
1149 1177 response.write(fields['content'])
1150 1178
1151 1179 return response
1152 1180
1153 1181 messages.error(request, "Could not export parameters")
1154 1182
1155 1183 kwargs = {}
1156 1184 kwargs['id_dev'] = conf.id
1157 1185 kwargs['title'] = 'Device Configuration'
1158 1186 kwargs['form'] = file_form
1159 1187 kwargs['suptitle'] = 'Exporting file'
1160 1188 kwargs['button'] = 'Export'
1161 1189 kwargs['menu_configurations'] = 'active'
1162 1190
1163 1191 return render(request, 'dev_conf_export.html', kwargs)
1164 1192
1165 1193
1166 1194 @login_required
1167 1195 def dev_conf_delete(request, id_conf):
1168 1196
1169 1197 conf = get_object_or_404(Configuration, pk=id_conf)
1170 1198
1171 1199 if request.method == 'POST':
1172 1200 if is_developer(request.user):
1173 1201 try:
1174 1202 conf.delete()
1175 1203 except Exception as e:
1176 1204 messages.error(request, "The device configuration is protected")
1177 1205 return redirect('url_dev_confs')
1178 1206
1179 1207 messages.error(request, 'Not enough permission to delete this object')
1180 1208 return redirect(conf.get_absolute_url())
1181 1209
1182 1210 kwargs = {
1183 1211 'title': 'Delete',
1184 1212 'suptitle': 'Configuration',
1185 1213 'object': conf,
1186 1214 'delete': True
1187 1215 }
1188 1216 kwargs['menu_configurations'] = 'active'
1189 1217
1190 1218 return render(request, 'confirm.html', kwargs)
1191 1219
1192 1220
1193 1221 def sidebar(**kwargs):
1194 1222
1195 1223 side_data = {}
1196 1224
1197 1225 conf = kwargs.get('conf', None)
1198 1226 confs = kwargs.get('confs', None)
1199 1227 experiment = kwargs.get('experiment', None)
1200 1228
1201 1229 if confs:
1202 1230 side_data['side_configurations'] = confs
1203 1231
1204 1232 if experiment:
1205 1233 side_data['experiment'] = experiment
1206 1234 experiments = [experiment]
1207 1235 #configurations = experiment.configuration_set.filter(type=0)
1208 1236 side_data['side_experiments'] = experiments
1209 1237 #side_data['side_configurations'] = configurations.order_by('device__device_type__name')
1210 1238
1211 1239 return side_data
1212 1240
1213 1241
1214 1242 def get_paginator(model, page, order, filters={}, n=8):
1215 1243
1216 1244 kwargs = {}
1217 1245 query = Q()
1218 1246 if isinstance(filters, QueryDict):
1219 1247 filters = filters.dict()
1220 1248 [filters.pop(key) for key in list(filters) if filters[key] in ('', ' ')]
1221 1249 filters.pop('page', None)
1222 1250
1223 1251 fields = [f.name for f in model._meta.get_fields()]
1224 1252
1225 1253 if 'historical' in filters:
1226 1254 filters.pop('historical')
1227 1255 filters['type'] = 1
1228 1256 elif 'type' in fields:
1229 1257 filters['type'] = 0
1230 1258 if 'start_date' in filters:
1231 1259 filters['start_date__gte'] = filters.pop('start_date')
1232 1260 if 'end_date' in filters:
1233 1261 filters['start_date__lte'] = filters.pop('end_date')
1234 1262 if 'tags' in filters:
1235 1263 tags = filters.pop('tags')
1236 1264 if 'tags' in fields:
1237 1265 query = query | Q(tags__icontains=tags)
1238 1266 if 'label' in fields:
1239 1267 query = query | Q(label__icontains=tags)
1240 1268 if 'device' in fields:
1241 1269 query = query | Q(device__device_type__name__icontains=tags)
1242 1270 if 'device_type' in fields:
1243 1271 query = query | Q(device_type__name__icontains=tags)
1244 1272
1245 1273 if 'mine' in filters:
1246 1274 filters['author_id'] = filters['mine']
1247 1275 filters.pop('mine')
1248 1276 object_list = model.objects.filter(query, **filters).order_by(*order)
1249 1277 paginator = Paginator(object_list, n)
1250 1278
1251 1279 try:
1252 1280 objects = paginator.page(page)
1253 1281 except PageNotAnInteger:
1254 1282 objects = paginator.page(1)
1255 1283 except EmptyPage:
1256 1284 objects = paginator.page(paginator.num_pages)
1257 1285
1258 1286 kwargs['objects'] = objects
1259 1287 kwargs['offset'] = (int(page)-1)*n if page else 0
1260 1288
1261 1289 return kwargs
1262 1290
1263 1291 @login_required
1264 1292 def revoke_tasks(request, id_camp):
1265 1293
1266 1294 i = app.control.inspect()
1267 1295 scheduled = list(i.scheduled().values())[0]
1268 1296 revoked = list(i.revoked().values())[0]
1269 1297
1270 1298 for t in scheduled:
1271 1299 if t['request']['id'] in revoked:
1272 1300 continue
1273 1301 app.control.revoke(t['request']['id'])
1274 1302 exp = Experiment.objects.get(pk=eval(str(t['request']['args']))[0])
1275 1303 eta = t['eta']
1276 1304 task = t['request']['name'].split('.')[-1]
1277 1305 messages.warning(request, 'Scheduled {} at {} for experiment {} revoked'.format(task, eta, exp.name))
1278 1306
1279 1307 return HttpResponseRedirect(reverse('url_operation', args=[id_camp]))
1280 1308
1281 1309 @login_required
1282 1310 def show_tasks(request, id_camp):
1283 1311
1284 1312 i = app.control.inspect()
1285 1313 scheduled = list(i.scheduled().values())[0]
1286 1314 revoked = list(i.revoked().values())[0]
1287 1315
1288 1316 for t in scheduled:
1289 1317 if t['request']['id'] in revoked:
1290 1318 continue
1291 1319 exp = Experiment.objects.get(pk=eval(str(t['request']['args']))[0])
1292 1320 eta = t['eta']
1293 1321 task = t['request']['name'].split('.')[-1]
1294 1322 messages.success(request, 'Task {} scheduled at {} for experiment {}'.format(task, eta, exp.name))
1295 1323
1296 1324 return HttpResponseRedirect(reverse('url_operation', args=[id_camp]))
1297 1325
1298 1326 def real_time(request):
1299 1327
1300 1328 graphic_path = "/home/fiorella/Pictures/catwbeanie.jpg"
1301 1329
1302 1330 kwargs = {}
1303 1331 kwargs['title'] = 'CLAIRE'
1304 1332 kwargs['suptitle'] = 'Real Time'
1305 1333 kwargs['no_sidebar'] = True
1306 1334 kwargs['graphic_path'] = graphic_path
1307 1335 kwargs['graphic1_path'] = 'http://www.bluemaize.net/im/girls-accessories/shark-beanie-11.jpg'
1308 1336
1309 1337 return render(request, 'real_time.html', kwargs)
1310 1338
1311 1339 def theme(request, theme):
1312 1340
1313 1341 user = request.user
1314 1342 user.profile.theme = theme
1315 1343 user.save()
1316 1344 return redirect('index')
@@ -1,132 +1,150
1 1
2 2 import json
3 3
4 4 from django.contrib import messages
5 5 from django.utils.safestring import mark_safe
6 6 from django.shortcuts import render, redirect, get_object_or_404, HttpResponse
7 7 from django.contrib.auth.decorators import login_required
8 8
9 9 from apps.main.models import Experiment, Device
10 10 from apps.main.views import sidebar
11 11
12 12 from .models import PedestalConfiguration
13 13 from .forms import PedestalConfigurationForm, PedestalImportForm
14 14
15 def is_developer(user):
16 groups = [str(g.name) for g in user.groups.all()]
17 #return 'Developer' in groups or user.is_staff
18 return 'Developer' in groups or user.is_superuser
19
20
21 def is_operator(user):
22 groups = [str(g.name) for g in user.groups.all()]
23 #return 'Operator' in groups or user.is_staff
24 return 'Operator' in groups or user.is_superuser
25
15 26
16 27 def conf(request, conf_id):
17 28
18 29 conf = get_object_or_404(PedestalConfiguration, pk=conf_id)
19 30
20 31 kwargs = {}
21 32 kwargs['dev_conf'] = conf
22 33
23 34 if conf.mode == 'position':
24 35 kwargs['dev_conf_keys'] = ['mode', 'axis', 'angle']
25 36 elif conf.mode == 'speed':
26 37 kwargs['dev_conf_keys'] = ['mode', 'axis', 'speed']
27 38 else:
28 39 kwargs['dev_conf_keys'] = ['mode', 'axis', 'speed', 'angle', 'min_value', 'max_value']
29 40
30 41
31 42 kwargs['title'] = 'Configuration'
32 43 kwargs['suptitle'] = 'Detail'
33 44
34 45 kwargs['button'] = 'Edit Configuration'
35 46
36 47 conf.status_device()
37 48
38 49 ###### SIDEBAR ######
39 50 kwargs.update(sidebar(conf=conf))
40 51
41 52 return render(request, 'pedestal_conf.html', kwargs)
42 53
43 54 @login_required
44 55 def conf_edit(request, conf_id):
45 56
46 57 conf = get_object_or_404(PedestalConfiguration, pk=conf_id)
47 58
59 if not is_developer(request.user):
60 messages.error(request, 'You must be an developer to edit this configuration')
61 return redirect(conf.get_absolute_url())
48 62
49 63 if request.method=='GET':
50 64
51 65 form = PedestalConfigurationForm(instance=conf)
52 66 if conf.mode == 'position':
53 67 form.fields['speed'].disabled = True
54 68 form.fields['max_value'].disabled = True
55 69 form.fields['min_value'].disabled = True
56 70 elif conf.mode == 'speed':
57 71 form.fields['angle'].disabled = True
58 72 form.fields['max_value'].disabled = True
59 73 form.fields['min_value'].disabled = True
60 74
61 75 elif request.method=='POST':
62 76
63 77 line_data = {}
64 78 conf_data = {}
65 79 clock_data = {}
66 80 extras = []
67 81
68 82 #classified post fields
69 83
70 84 form = PedestalConfigurationForm(request.POST, instance=conf)
71 85
72 86 if form.is_valid():
73 87 form.save()
74 88
75 89 messages.success(request, 'Pedestal configuration successfully updated')
76 90
77 91 return redirect(conf.get_absolute_url())
78 92
79 93 kwargs = {}
80 94 kwargs['dev_conf'] = conf
81 95 kwargs['form'] = form
82 96 kwargs['edit'] = True
83 97
84 98 kwargs['title'] = 'Pedestal Configuration'
85 99 kwargs['suptitle'] = 'Edit'
86 100 kwargs['button'] = 'Update'
87 101
88 102 return render(request, 'pedestal_conf_edit.html', kwargs)
89 103
90 104 def import_file(request, conf_id):
91 105
92 106 conf = get_object_or_404(PedestalConfiguration, pk=conf_id)
93 107 if request.method=='POST':
94 108 form = PedestalImportForm(request.POST, request.FILES)
95 109 if form.is_valid():
96 110 try:
97 111 data = conf.import_from_file(request.FILES['file_name'])
98 112 conf.dict_to_parms(data)
99 113 messages.success(request, 'Configuration "%s" loaded succesfully' % request.FILES['file_name'])
100 114 return redirect(conf.get_absolute_url_edit())
101 115
102 116 except Exception as e:
103 117 messages.error(request, 'Error parsing file: "%s" - %s' % (request.FILES['file_name'], repr(e)))
104 118 else:
105 119 messages.warning(request, 'Your current configuration will be replaced')
106 120 form = PedestalImportForm()
107 121
108 122 kwargs = {}
109 123 kwargs['form'] = form
110 124 kwargs['title'] = 'Pedestal Configuration'
111 125 kwargs['suptitle'] = 'Import file'
112 126 kwargs['button'] = 'Upload'
113 127 kwargs['previous'] = conf.get_absolute_url()
114 128
115 129 return render(request, 'pedestal_import.html', kwargs)
116 130
117 131 @login_required
118 132 def conf_reset(request, conf_id):
119 133
120 134 conf = get_object_or_404(PedestalConfiguration, pk=conf_id)
121 135
136 if not is_developer(request.user) and not is_operator(request.user):
137 messages.error(request, 'You must be an developer or operator to reset this pedestal')
138 return redirect(conf.get_absolute_url())
139
122 140 if conf.reset_device():
123 141 messages.success(request, conf.message)
124 142 else:
125 143 messages.error(request, conf.message)
126 144
127 145 return redirect(conf.get_absolute_url())
128 146
129 147 def conf_raw(request, conf_id):
130 148 conf = get_object_or_404(PedestalConfiguration, pk=conf_id)
131 149 raw = conf.write_device(raw=True)
132 150 return HttpResponse(raw, content_type='application/json') No newline at end of file
@@ -1,129 +1,141
1 1
2 2 import json
3 3
4 4 from django.contrib import messages
5 5 from django.utils.safestring import mark_safe
6 6 from django.shortcuts import render, redirect, get_object_or_404, HttpResponse
7 7 from django.contrib.auth.decorators import login_required
8 8
9 9 from apps.main.models import Experiment, Device
10 10 from apps.main.views import sidebar
11 11
12 12 from .models import USRPRXConfiguration
13 13 from .forms import USRPRXConfigurationForm, USRPRXImportForm
14 14
15 def is_developer(user):
16 groups = [str(g.name) for g in user.groups.all()]
17 #return 'Developer' in groups or user.is_staff
18 return 'Developer' in groups or user.is_superuser
19
20
21 def is_operator(user):
22 groups = [str(g.name) for g in user.groups.all()]
23 #return 'Operator' in groups or user.is_staff
24 return 'Operator' in groups or user.is_superuser
15 25
16 26 def conf(request, conf_id):
17 27
18 28 conf = get_object_or_404(USRPRXConfiguration, pk=conf_id)
19 29
20 30 kwargs = {}
21 31 kwargs['dev_conf'] = conf
22 32 kwargs['dev_conf_keys'] = ['ip_address_rx', 'daughterboard_rx', 'antenna_rx', 'samplerate_rx', 'frequency_rx', 'datadir', 'clocksource', 'timesource', 'clockrate']
23 33
24 34 kwargs['title'] = 'Configuration'
25 35 kwargs['suptitle'] = 'Detail'
26 36
27 37 kwargs['button'] = 'Edit Configuration'
28 38
29 39 conf.status_device()
30 40
31 41 ###### SIDEBAR ######
32 42 kwargs.update(sidebar(conf=conf))
33 43
34 44 return render(request, 'usrp_rx_conf.html', kwargs)
35 45
36 46 @login_required
37 47 def conf_edit(request, conf_id):
38 48
39 49 conf = get_object_or_404(USRPRXConfiguration, pk=conf_id)
40 50
51 if not is_developer(request.user):
52 messages.error(request, 'You must be an developer to edit this configuration')
53 return redirect(conf.get_absolute_url())
54
41 55 if request.method=='GET':
42
43 56 form = USRPRXConfigurationForm(instance=conf)
44 57
45 58 elif request.method=='POST':
46
47 59 line_data = {}
48 60 conf_data = {}
49 61 clock_data = {}
50 62 extras = []
51 63
52 64 #classified post fields
53 65 for label,value in request.POST.items():
54 66 if label=='csrfmiddlewaretoken':
55 67 continue
56 68
57 69 if label.count('|')==0:
58 70 if label in ('mode', 'multiplier', 'divisor', 'reference'):
59 71 clock_data[label] = value
60 72 else:
61 73 conf_data[label] = value
62 74 continue
63 75
64 76 elif label.split('|')[0]!='-1':
65 77 extras.append(label)
66 78 continue
67 79
68 80 x, pk, name = label.split('|')
69 81
70 82 if name=='codes':
71 83 value = [s for s in value.split('\r\n') if s]
72 84
73 85 if pk in line_data:
74 86 line_data[pk][name] = value
75 87 else:
76 88 line_data[pk] = {name:value}
77 89
78 90 form = USRPRXConfigurationForm(conf_data, instance=conf)
79 91
80 92 if form.is_valid():
81 93 form.save()
82 94
83 95 messages.success(request, 'USRP Rx configuration successfully updated')
84 96
85 97 return redirect(conf.get_absolute_url())
86 98
87 99 kwargs = {}
88 100 kwargs['dev_conf'] = conf
89 101 kwargs['form'] = form
90 102 kwargs['edit'] = True
91 103
92 104 kwargs['title'] = 'USRP Rx Configuration'
93 105 kwargs['suptitle'] = 'Edit'
94 106 kwargs['button'] = 'Update'
95 107
96 108 return render(request, 'usrp_rx_conf_edit.html', kwargs)
97 109
98 110 def import_file(request, conf_id):
99 111
100 112 conf = get_object_or_404(USRPRXConfiguration, pk=conf_id)
101 113 if request.method=='POST':
102 114 form = USRPRXImportForm(request.POST, request.FILES)
103 115 if form.is_valid():
104 116 try:
105 117 data = conf.import_from_file(request.FILES['file_name'])
106 118 conf.dict_to_parms(data)
107 119 conf.update_pulses()
108 120 messages.success(request, 'Configuration "%s" loaded succesfully' % request.FILES['file_name'])
109 121 return redirect(conf.get_absolute_url_edit())
110 122
111 123 except Exception as e:
112 124 messages.error(request, 'Error parsing file: "%s" - %s' % (request.FILES['file_name'], repr(e)))
113 125 else:
114 126 messages.warning(request, 'Your current configuration will be replaced')
115 127 form = USRPRXImportForm()
116 128
117 129 kwargs = {}
118 130 kwargs['form'] = form
119 131 kwargs['title'] = 'USRP Rx Configuration'
120 132 kwargs['suptitle'] = 'Import file'
121 133 kwargs['button'] = 'Upload'
122 134 kwargs['previous'] = conf.get_absolute_url()
123 135
124 136 return render(request, 'usrp_rx_import.html', kwargs)
125 137
126 138 def conf_raw(request, conf_id):
127 139 conf = get_object_or_404(USRPRXConfiguration, pk=conf_id)
128 140 raw = conf.write_device(raw=True)
129 141 return HttpResponse(raw, content_type='application/json') No newline at end of file
@@ -1,106 +1,121
1 1
2 2 import json
3 3
4 4 from django.contrib import messages
5 5 from django.utils.safestring import mark_safe
6 6 from django.shortcuts import render, redirect, get_object_or_404, HttpResponse
7 7 from django.contrib.auth.decorators import login_required
8 8
9 9 from apps.main.models import Experiment, Device
10 10 from apps.main.views import sidebar
11 11
12 12 from .models import USRPTXConfiguration, TXCode
13 13 from .forms import USRPTXConfigurationForm, USRPTXImportForm
14 14 from .validations import validation_usrp_tx_code
15 15
16 def is_developer(user):
17 groups = [str(g.name) for g in user.groups.all()]
18 #return 'Developer' in groups or user.is_staff
19 return 'Developer' in groups or user.is_superuser
20
21
22 def is_operator(user):
23 groups = [str(g.name) for g in user.groups.all()]
24 #return 'Operator' in groups or user.is_staff
25 return 'Operator' in groups or user.is_superuser
26
16 27
17 28 def conf(request, conf_id):
18 29
19 30 conf = get_object_or_404(USRPTXConfiguration, pk=conf_id)
20 31
21 32 kwargs = {}
22 33 kwargs['dev_conf'] = conf
23 34 if not conf.enable_2:
24 35 kwargs['dev_conf_keys'] = ['ip_address', 'daughterboard', 'antenna', 'frequency', 'samplerate', 'ipp', 'delay', 'pulse_1',
25 36 'code_type_1', 'code_1', 'repetitions_1']
26 37 else:
27 38 kwargs['dev_conf_keys'] = ['ip_address', 'daughterboard', 'antenna', 'frequency', 'samplerate', 'ipp', 'delay', 'pulse_1',
28 39 'code_type_1', 'code_1', 'repetitions_1', 'pulse_2', 'code_type_2', 'code_2', 'repetitions_2']
29 40
30 41 kwargs['title'] = 'Configuration'
31 42 kwargs['suptitle'] = 'Detail'
32 43
33 44 kwargs['button'] = 'Edit Configuration'
34 45
35 46 conf.status_device()
36 47
37 48 ###### SIDEBAR ######
38 49 kwargs.update(sidebar(conf=conf))
39 50
40 51 return render(request, 'usrp_tx_conf.html', kwargs)
41 52
42 53 @login_required
43 54 def conf_edit(request, conf_id):
44 55
45 56 conf = get_object_or_404(USRPTXConfiguration, pk=conf_id)
46 57
58 if not is_developer(request.user):
59 messages.error(request, 'You must be an developer to edit this configuration')
60 return redirect(conf.get_absolute_url())
61
47 62 if request.method=='GET':
48 63
49 64 form = USRPTXConfigurationForm(instance=conf)
50 65
51 66
52 67 elif request.method=='POST':
53 68
54 69 form = USRPTXConfigurationForm(request.POST, instance=conf)
55 70
56 71 if form.is_valid():
57 72
58 73 tx = form.save(commit=False)
59 74 validation_usrp_tx_code(request, tx)
60 75 tx.save()
61 76 messages.success(request, 'USRP Tx configuration successfully updated')
62 77 return redirect(conf.get_absolute_url())
63 78
64 79 kwargs = {}
65 80 kwargs['dev_conf'] = conf
66 81 kwargs['form'] = form
67 82 kwargs['edit'] = True
68 83
69 84 kwargs['title'] = 'USRP Tx Configuration'
70 85 kwargs['suptitle'] = 'Edit'
71 86 kwargs['button'] = 'Update'
72 87
73 88 return render(request, 'usrp_tx_conf_edit.html', kwargs)
74 89
75 90 def import_file(request, conf_id):
76 91
77 92 conf = get_object_or_404(USRPTXConfiguration, pk=conf_id)
78 93 if request.method=='POST':
79 94 form = USRPTXImportForm(request.POST, request.FILES)
80 95 if form.is_valid():
81 96 try:
82 97 data = conf.import_from_file(request.FILES['file_name'])
83 98 conf.dict_to_parms(data)
84 99 #conf.update_pulses()
85 100 messages.success(request, 'Configuration "%s" loaded succesfully' % request.FILES['file_name'])
86 101 return redirect(conf.get_absolute_url_edit())
87 102
88 103 except Exception as e:
89 104 messages.error(request, 'Error parsing file: "%s" - %s' % (request.FILES['file_name'], repr(e)))
90 105 else:
91 106 messages.warning(request, 'Your current configuration will be replaced')
92 107 form = USRPTXImportForm()
93 108
94 109 kwargs = {}
95 110 kwargs['form'] = form
96 111 kwargs['title'] = 'USRP Tx Configuration'
97 112 kwargs['suptitle'] = 'Import file'
98 113 kwargs['button'] = 'Upload'
99 114 kwargs['previous'] = conf.get_absolute_url()
100 115
101 116 return render(request, 'usrp_tx_import.html', kwargs)
102 117
103 118 def conf_raw(request, conf_id):
104 119 conf = get_object_or_404(USRPTXConfiguration, pk=conf_id)
105 120 raw = conf.write_device(raw=True)
106 121 return HttpResponse(raw, content_type='application/json') No newline at end of file
1 NO CONTENT: file was removed
General Comments 0
You need to be logged in to leave comments. Login now