##// END OF EJS Templates
Add 'reset pedestal' option
eynilupu -
r444:d8e453ba0459
parent child
Show More
@@ -1,200 +1,210
1 1 from django.core.management.base import BaseCommand
2 2 from apps.main.models import Experiment
3 3 from django.shortcuts import get_object_or_404
4 4 import os, fnmatch
5 5 import time
6 6 from datetime import datetime
7 7 import h5py
8 8 import numpy as np
9 9
10 10 class Command(BaseCommand):
11 11 """
12 12 Check pedestal acquisition each 10 minutes.
13 13 Example:
14 14 manage.py restart_pedestal
15 15 """
16 16 def handle(self, *args, **options):
17 17 #start = time.time()
18 18 #time.sleep(1)
19 19 restart_pedestal(self)
20 20 #end = time.time()
21 21 #self.stdout.write(f'TIME: "{end - start}"')
22 22
23 23 def check_experiment():
24 24 if len(Experiment.objects.filter(status=2)) > 0:
25 25 return True
26 26 else:
27 27 return False
28 28
29 29 def pedestal_start(self, id_exp):
30 30 all_status = Experiment.objects.filter(status=2)
31 31 check_id = False
32 32
33 33 if len(all_status) > 0:
34 34 check_id = all_status[0].pk
35 35
36 36 if check_id and check_id == id_exp:
37 37 exp = get_object_or_404(Experiment, pk=id_exp)
38 38 name = '{}-R@{}'.format(exp.name, datetime.now().strftime('%Y-%m-%dT%H-%M-%S'))
39 39 exp.pedestal.start_device(name_experiment=name)
40 40 self.stdout.write(f'"{exp.name}" experiment: Pedestal acquisition was restarted')
41 41
42 def pedestal_reset(self, id_exp):
43 all_status = Experiment.objects.filter(status=2)
44 check_id = False
45
46 if len(all_status) > 0:
47 check_id = all_status[0].pk
48
49 if check_id and check_id == id_exp:
50 exp = get_object_or_404(Experiment, pk=id_exp)
51 exp.pedestal.reset_device()
52 self.stdout.write(f'"{exp.name}" experiment: Pedestal acquisition is resetting')
53
42 54 def pedestal_stop(self, id_exp):
43 55 all_status = Experiment.objects.filter(status=2)
44 56 check_id = False
45 57
46 58 if len(all_status) > 0:
47 59 check_id = all_status[0].pk
48 60
49 61 if check_id and check_id == id_exp:
50 62 exp = get_object_or_404(Experiment, pk=id_exp)
51 63 exp.pedestal.stop_device()
52 self.stdout.write(f'"{exp.name}" experiment: Pedestal acquisition "{exp.name}" was stopped')
64 self.stdout.write(f'"{exp.name}" experiment: Pedestal acquisition was stopped')
53 65
54 66 def hdf5_list_content(get_file):
55 67 table_records = np.array(get_file).tolist()
56 68 table_dim = get_file.ndim
57 69 table_rows = get_file.shape[0]
58 70
59 71 if table_dim == 1 and table_rows >= 1:
60 72 #type(table_records[0]) -> float
61 73 return table_records
62 74 else:
63 75 return False
64 76
65 77 def hdf5_read(file):
66 78 dataspeed = {"ele_speed": False, "azi_speed": False}
67 79
68 80 for key, value in dataspeed.items():
69 81 with h5py.File(file, 'r') as hdf:
70 82 get = hdf.get('Data'+'/'+key)
71 83 if get is not None:
72 84 # 10 values
73 85 dataspeed[key] = hdf5_list_content(get)[-10:]
74 86
75 87 return dataspeed
76 88
77 89 def count_data(last_position):
78 90 pattern = "pos@*.h5"
79 91 count = 0
80 92 list_data = []
81 93
82 94 list_position = os.listdir(last_position)
83 95
84 96 for entry in sorted(list_position):
85 97 if fnmatch.fnmatch(entry, pattern):
86 98 count = count + 1
87 99 list_data.append(os.path.join(last_position, entry))
88 100
89 101 if len(list_data) > 1:
90 102 list_data = list_data[-2]
91 103 else:
92 104 list_data = False
93 105
94 106 return count, list_data
95 107
96 108 def response_data(datadir, old_path_datetime, old_position, new_position):
97 109 path_position = True
98 110 path_datetime = False
99 111 read_files = False
100 112
101 113 rootdir = os.path.join(datadir, 'position')
102 114 if os.path.isdir(rootdir):
103 115 path_datetime = path_data(os.path.join(datadir, 'position'))
104 116
105 117 if path_datetime:
106 118 if not old_path_datetime or path_datetime != old_path_datetime:
107 119 old_position, read_files = count_data(path_datetime)
108 120 time.sleep(65)
109 121 new_position, read_files = count_data(path_datetime)
110 122 else:
111 123 time.sleep(65)
112 124 else:
113 125 path_position = False
114 126
115 127 return path_position, path_datetime, old_position, new_position, read_files
116 128
117 129 def path_data(rootdir):
118 130 list_=[]
119 131 for it in os.scandir(rootdir):
120 132 if it.is_dir():
121 133 try:
122 134 datetime.strptime(it.path.split("/")[-1], "%Y-%m-%dT%H-00-00")
123 135 list_.append(it.path)
124 136 except ValueError:
125 137 pass
126 138
127 139 list_ = sorted(list_, reverse=True)
128 140 try:
129 141 return list_[0]
130 142 except:
131 143 return False
132 144
133 145 def check_count(datadir):
134 146 old_numbers = 0
135 147 new_numbers = 0
136 148 validation = False
137 149 path_datetime = False
138 150 speed = {"ele_speed": False, "azi_speed": False}
139 151
140 152 path_position, path_datetime, old_numbers, new_numbers, read_files = response_data(datadir, path_datetime, old_numbers, new_numbers)
141 153
142 154 for u in range(2):
143 155 if new_numbers > old_numbers:
144 156 validation = True
145 157
146 158 data = hdf5_read(read_files)
147 159 for key, value in data.items():
148 160 try:
149 161 if not max(data[key]) <= 0.1:
150 162 speed[key] = True
151 163 except:
152 164 pass
153 165 break
154 166 else:
155 167 if u < 1:
156 168 path_position, path_datetime, old_numbers, new_numbers, read_files = response_data(datadir, path_datetime, old_numbers, new_numbers)
157 169
158 170 return path_position, path_datetime, validation, speed
159 171
160 172 def restart_pedestal(self):
161 173 if check_experiment():
162 174
163 175 all_status = Experiment.objects.filter(status=2)
164 176 id_exp = all_status[0].pk
165 177 datadir_exp = all_status[0].reception_rx.datadir
166 178 datadir_exp = datadir_exp.replace(os.environ.get('EXPOSE_NAS', '/DATA_RM/DATA'), '/data')
167 179 datadir_exp = datadir_exp.replace('/rawdata', '')
168 180
169 181 path_position, path_datetime, validation, speed = check_count(datadir_exp)
170 182 if path_position:
171 183 # Execute the process
172 184 if validation:
173 185 self.stdout.write(f'Acquisition pedestal is running')
174 186 if speed['ele_speed'] or speed['azi_speed']:
175 187 self.stdout.write(f'Pedestal speeds on Azimuth and Elevation are running')
176 188 else:
177 189 for key, value in speed.items():
178 190 if not value:
179 191 self.stdout.write(f'Speed on {key} is <= 0.1, retry')
180 192
181 193 pedestal_stop(self, id_exp)
182 194 time.sleep(14)
183 #pedestal_reset(self, id_exp)
184 #time.sleep(2)
185 195 pedestal_start(self, id_exp)
186 196
187 197 else:
188 198 if not path_datetime:
189 199 self.stdout.write(f'No such directory with datetime format "%Y-%m-%dT%H-00-00", retry!')
190 200 else:
191 201 self.stdout.write(f'No file increment, retry')
192 202
203 pedestal_reset(self, id_exp)
204 time.sleep(14)
193 205 pedestal_stop(self, id_exp)
194 206 time.sleep(14)
195 #pedestal_reset(self, id_exp)
196 #time.sleep(2)
197 207 pedestal_start(self, id_exp)
198 208
199 209 else:
200 210 self.stdout.write(f'No such directory: position, fail!') No newline at end of file
@@ -1,153 +1,157
1 1 from django.core.management.base import BaseCommand
2 2 from apps.main.models import Experiment
3 3 from django.shortcuts import get_object_or_404
4 4 import os, fnmatch
5 5 import time
6 6 from datetime import datetime
7 7 import requests
8 8
9 9 class Command(BaseCommand):
10 10 """
11 11 Check data acquisition each 05 minutes.
12 12 Example:
13 13 manage.py restart_reception
14 14 """
15 15 def handle(self, *args, **options):
16 16 #start = time.time()
17 17 time.sleep(15)
18 18 restart_acquisition(self)
19 19 #end = time.time()
20 20 #self.stdout.write(f'TIME: "{end - start}"')
21 21
22 22 def check_experiment():
23 23 if len(Experiment.objects.filter(status=2)) > 0:
24 24 return True
25 25 else:
26 26 return False
27 27
28 28 def acquisition_start(self, id_exp):
29 29 all_status = Experiment.objects.filter(status=2)
30 30 check_id = False
31 31
32 32 if len(all_status) > 0:
33 33 check_id = all_status[0].pk
34 34
35 35 if check_id and check_id == id_exp:
36 36 exp = get_object_or_404(Experiment, pk=id_exp)
37 37 name = '{}-R@{}'.format(exp.name, datetime.now().strftime('%Y-%m-%dT%H-%M-%S'))
38 38 exp.reception_rx.start_device(name_experiment = name, restart = True)
39 39 self.stdout.write(f'"{exp.name}" experiment: Data acquisition was restarted')
40
40 41 self.stdout.write(f'Restarting schain...')
42 datadir_exp = exp.reception_rx.datadir
43 datadir_exp = datadir_exp.replace(os.environ.get('EXPOSE_NAS', '/DATA_RM/DATA') + '/', '')
44 datadir_exp = datadir_exp.replace('/rawdata', '')
41 45
42 46 r = requests.get('http://'+os.environ.get('SCHAIN_SITE', 'sophy-schain')+'/stop')
43 47 time.sleep(1)
44 r = requests.post('http://'+os.environ.get('SCHAIN_SITE', 'sophy-schain')+'/start', json={'name': exp.name})
48 r = requests.post('http://'+os.environ.get('SCHAIN_SITE', 'sophy-schain')+'/start', json={'name': datadir_exp})
45 49
46 50 def acquisition_stop(self, id_exp):
47 51 all_status = Experiment.objects.filter(status=2)
48 52 check_id = False
49 53
50 54 if len(all_status) > 0:
51 55 check_id = all_status[0].pk
52 56
53 57 if check_id and check_id == id_exp:
54 58 exp = get_object_or_404(Experiment, pk=id_exp)
55 59 exp.reception_rx.stop_device()
56 60 self.stdout.write(f'"{exp.name}" experiment: Data acquisition "{exp.name}" was stopped')
57 61
58 62 def count_data(last_channel):
59 63 pattern = "rf@*.h5"
60 64 count = 0
61 65 list_channel = os.listdir(last_channel)
62 66
63 67 for entry in sorted(list_channel):
64 68 if fnmatch.fnmatch(entry, pattern):
65 69 count = count + 1
66 70 return count
67 71
68 72 def response_data(datadir, old_channel, old_rawdata, new_rawdata, search):
69 73 path_channels = {'ch0': True, 'ch1': True}
70 74 channel = {'ch0': False, 'ch1': False}
71 75
72 76 for key, value in path_channels.items():
73 77 rootdir = os.path.join(datadir, key)
74 78 if os.path.isdir(rootdir):
75 79 channel[key] = path_data(os.path.join(datadir, key))
76 80 if key in search:
77 81 if channel[key]:
78 82 if not old_channel[key] or channel[key] != old_channel[key]:
79 83 old_rawdata[key] = count_data(channel[key])
80 84 time.sleep(1)
81 85 new_rawdata[key] = count_data(channel[key])
82 86 else:
83 87 time.sleep(1)
84 88 else:
85 89 path_channels[key] = False
86 90
87 91 return path_channels, channel, old_rawdata, new_rawdata
88 92
89 93 def path_data(rootdir):
90 94 list_=[]
91 95 for it in os.scandir(rootdir):
92 96 if it.is_dir():
93 97 try:
94 98 datetime.strptime(it.path.split("/")[-1], "%Y-%m-%dT%H-00-00")
95 99 list_.append(it.path)
96 100 except ValueError:
97 101 pass
98 102
99 103 list_ = sorted(list_, reverse=True)
100 104 try:
101 105 return list_[0]
102 106 except:
103 107 return False
104 108
105 109 def check_count(datadir):
106 110 old_numbers = {'ch0': 0, 'ch1': 0}
107 111 new_numbers = {'ch0': 0, 'ch1': 0}
108 112 validation = {'ch0': False, 'ch1': False}
109 113 channel = {'ch0': False, 'ch1': False}
110 114
111 115 path_channels, channel, old_numbers, new_numbers = response_data(datadir, channel, old_numbers, new_numbers, ['ch0', 'ch1'])
112 116
113 117 for key, value in validation.items():
114 118 for _ in range(5):
115 119 if new_numbers[key] > old_numbers[key]:
116 120 validation[key] = True
117 121 break
118 122 else:
119 123 path_channels, channel, old_numbers, new_numbers = response_data(datadir, channel, old_numbers, new_numbers, [key])
120 124
121 125 return path_channels, channel, validation
122 126
123 127 def restart_acquisition(self):
124 128 if check_experiment():
125 129 all_status = Experiment.objects.filter(status=2)
126 130 id_exp = all_status[0].pk
127 131 datadir_exp = all_status[0].reception_rx.datadir
128 132 datadir_exp = datadir_exp.replace(os.environ.get('EXPOSE_NAS', '/DATA_RM/DATA'), '/data')
129 133
130 134 path_channels, channel, validation = check_count(datadir_exp)
131 135
132 136 if path_channels['ch0'] and path_channels['ch1']:
133 137 # Execute the process
134 138 if validation['ch0'] and validation['ch1']:
135 139 self.stdout.write(f'Data acquisition is running')
136 140 else:
137 141 if not channel['ch0'] or not channel['ch1']:
138 142 for key, value in channel.items():
139 143 if not value:
140 144 self.stdout.write(f'No such directory with datetime format "%Y-%m-%dT%H-00-00": channel["{key}"], retry!')
141 145 else:
142 146 for key, value in validation.items():
143 147 if not value:
144 148 self.stdout.write(f'No file increment: channel["{key}"]')
145 149
146 150 acquisition_stop(self, id_exp)
147 151 time.sleep(3)
148 152 acquisition_start(self, id_exp)
149 153
150 154 else:
151 155 for key, value in path_channels.items():
152 156 if not value:
153 157 self.stdout.write(f'No such directory: channel["{key}"], fail!') No newline at end of file
@@ -1,653 +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 self.pedestal.reset_device()
346 time.sleep(14)
345 347 self.pedestal.stop_device()
346 348 time.sleep(0.1)
347 349 proc_url = 'http://'+os.environ['PROC_SITE']+'/stop'
348 350 requests.get(proc_url)
349 351 except:
350 352 return 0
351 353 return 4
352 354
353 355 def get_status(self):
354 356
355 357 if self.status == 3:
356 358 return
357 359
358 360 confs = Configuration.objects.filter(experiment=self, type=0)
359 361
360 362 for conf in confs:
361 363 conf.status_device()
362 364
363 365 total = confs.aggregate(models.Sum('device__status'))['device__status__sum']
364 366
365 367 if total==2*confs.count():
366 368 status = 1
367 369 elif total == 3*confs.count():
368 370 status = 2
369 371 else:
370 372 status = 0
371 373
372 374 self.status = status
373 375 self.save()
374 376
375 377 def status_color(self):
376 378 color = 'muted'
377 379 if self.status == 0:
378 380 color = "danger"
379 381 elif self.status == 1:
380 382 color = "warning"
381 383 elif self.status == 2:
382 384 color = "success"
383 385 elif self.status == 3:
384 386 color = "info"
385 387
386 388 return color
387 389
388 390 def parms_to_dict(self):
389 391
390 392 params = Params({})
391 393 params.add(self.jsonify(), 'experiments')
392 394
393 395 configurations = Configuration.objects.filter(experiment=self, type=0)
394 396
395 397 for conf in configurations:
396 398 params.add(conf.jsonify(), 'configurations')
397 399
398 400 return params.data
399 401
400 402 def dict_to_parms(self, parms, CONF_MODELS, id_exp=None):
401 403
402 404 configurations = Configuration.objects.filter(experiment=self)
403 405
404 406 if id_exp is not None:
405 407 exp_parms = parms['experiments']['byId'][id_exp]
406 408 else:
407 409 exp_parms = parms['experiments']['byId'][parms['experiments']['allIds'][0]]
408 410
409 411 if configurations:
410 412 for configuration in configurations:
411 413 configuration.delete()
412 414
413 415 for id_conf in exp_parms['configurations']:
414 416 conf_parms = parms['configurations']['byId'][id_conf]
415 417 device = Device.objects.filter(device_type__name=conf_parms['device_type'])[0]
416 418 model = CONF_MODELS[conf_parms['device_type']]
417 419 conf = model(
418 420 experiment = self,
419 421 device = device,
420 422 )
421 423 conf.dict_to_parms(parms, id=id_conf)
422 424
423 425
424 426 self.name = '{}-{}'.format(exp_parms['name'], datetime.now().strftime('%y%m%d'))
425 427 self.save()
426 428
427 429 return self
428 430
429 431 def get_absolute_url(self):
430 432 return reverse('url_experiment', args=[str(self.id)])
431 433
432 434 def get_absolute_url_edit(self):
433 435 return reverse('url_edit_experiment', args=[str(self.id)])
434 436
435 437 def get_absolute_url_delete(self):
436 438 return reverse('url_delete_experiment', args=[str(self.id)])
437 439
438 440 def get_absolute_url_import(self):
439 441 return reverse('url_import_experiment', args=[str(self.id)])
440 442
441 443 def get_absolute_url_export(self):
442 444 return reverse('url_export_experiment', args=[str(self.id)])
443 445
444 446 def get_absolute_url_start(self):
445 447 return reverse('url_start_experiment', args=[str(self.id)])
446 448
447 449 def get_absolute_url_stop(self):
448 450 return reverse('url_stop_experiment', args=[str(self.id)])
449 451
450 452
451 453 class Configuration(PolymorphicModel):
452 454
453 455 id = models.AutoField(primary_key=True)
454 456 experiment = models.CharField(default='empty', editable=False, max_length=64, null=True, blank=True)
455 457 experiment_date = models.DateTimeField(default=datetime.now, editable=False)
456 458 device = models.ForeignKey('Device', verbose_name='Device', null=True, on_delete=models.CASCADE)
457 459 type = models.PositiveSmallIntegerField(default=0, choices=CONF_TYPES)
458 460 created_date = models.DateTimeField(auto_now_add=True)
459 461 programmed_date = models.DateTimeField(auto_now=True)
460 462 parameters = models.TextField(default='{}')
461 463 author = models.ForeignKey(User, null=True, blank=True,on_delete=models.CASCADE)
462 464 hash = models.CharField(default='', max_length=64, null=True, blank=True)
463 465 message = ""
464 466
465 467 class Meta:
466 468 db_table = 'db_configurations'
467 469 ordering = ('device__device_type__name',)
468 470
469 471 def __str__(self):
470 472
471 473 ret = u'{} '.format(self.device.device_type.name.upper())
472 474
473 475 if 'mix' in [f.name for f in self._meta.get_fields()]:
474 476 if self.mix:
475 477 ret = '{} MIX '.format(self.device.device_type.name.upper())
476 478
477 479 if 'label' in [f.name for f in self._meta.get_fields()]:
478 480 ret += '{}'.format(self.label)
479 481
480 482 return ret
481 483
482 484 @property
483 485 def name(self):
484 486
485 487 return str(self)
486 488
487 489 @property
488 490 def label(self):
489 491
490 492 return str(self)
491 493
492 494 def jsonify(self):
493 495
494 496 data = {}
495 497
496 498 ignored = ('type', 'polymorphic_ctype', 'configuration_ptr',
497 499 'created_date', 'programmed_date', 'device',
498 500 'experiment', 'author')
499 501
500 502 for field in self._meta.fields:
501 503 if field.name in ignored:
502 504 continue
503 505 data[field.name] = field.value_from_object(self)
504 506
505 507 data['device_type'] = self.device.device_type.name
506 508 return data
507 509
508 510 def clone(self, **kwargs):
509 511 before_id = self.id
510 512
511 513 self.pk = None
512 514 self.id = None
513 515 for attr, value in kwargs.items():
514 516 setattr(self, attr, value)
515 517 self.save()
516 518
517 519 self.id = before_id
518 520 return self
519 521
520 522 def parms_to_dict(self):
521 523
522 524 params = Params({})
523 525 params.add(self.jsonify(), 'configurations')
524 526 return params.data
525 527
526 528 def parms_to_text(self):
527 529
528 530 raise NotImplementedError("This method should be implemented in %s Configuration model" %str(self.device.device_type.name).upper())
529 531
530 532
531 533 def parms_to_binary(self):
532 534
533 535 raise NotImplementedError("This method should be implemented in %s Configuration model" %str(self.device.device_type.name).upper())
534 536
535 537
536 538 def dict_to_parms(self, parameters, id=None):
537 539
538 540 params = Params(parameters)
539 541
540 542 if id:
541 543 data = params.get_conf(id_conf=id)
542 544 else:
543 545 data = params.get_conf(dtype=self.device.device_type.name)
544 546
545 547 for key, value in data.items():
546 548 if key not in ('id', 'device_type'):
547 549 setattr(self, key, value)
548 550
549 551 self.save()
550 552
551 553
552 554 def export_to_file(self, format="json"):
553 555
554 556 content_type = ''
555 557
556 558 if format == 'racp':
557 559 content_type = 'text/plain'
558 560 filename = '%s_%s.%s' %(self.device.device_type.name, self.name, 'racp')
559 561 content = self.parms_to_text(file_format = 'racp')
560 562
561 563 if format == 'text':
562 564 content_type = 'text/plain'
563 565 filename = '%s_%s.%s' %(self.device.device_type.name, self.name, self.device.device_type.name)
564 566 content = self.parms_to_text()
565 567
566 568 if format == 'binary':
567 569 content_type = 'application/octet-stream'
568 570 filename = '%s_%s.bin' %(self.device.device_type.name, self.name)
569 571 content = self.parms_to_binary()
570 572
571 573 if not content_type:
572 574 content_type = 'application/json'
573 575 filename = '%s_%s.json' %(self.device.device_type.name, self.name)
574 576 content = json.dumps(self.parms_to_dict(), indent=2)
575 577
576 578
577 579 fields = {'content_type':content_type,
578 580 'filename':filename,
579 581 'content':content
580 582 }
581 583
582 584 return fields
583 585
584 586 def import_from_file(self, fp):
585 587
586 588 parms = {}
587 589
588 590 path, ext = os.path.splitext(fp.name)
589 591
590 592 if ext == '.json':
591 593 parms = json.load(fp)
592 594
593 595 return parms
594 596
595 597 def status_device(self):
596 598
597 599 self.message = 'Function not supported'
598 600 return False
599 601
600 602
601 603 def stop_device(self):
602 604
603 605 self.message = 'Function not supported'
604 606 return False
605 607
606 608
607 609 def start_device(self):
608 610
609 611 self.message = 'Function not supported'
610 612 return False
611 613
612 614
613 615 def write_device(self):
614 616
615 617 self.message = 'Function not supported'
616 618 return False
617 619
618 620
619 621 def read_device(self):
620 622
621 623 self.message = 'Function not supported'
622 624 return False
623 625
624 626
625 627 def get_absolute_url(self):
626 628 return reverse('url_%s_conf' % self.device.device_type.name, args=[str(self.id)])
627 629
628 630 def get_absolute_url_edit(self):
629 631 return reverse('url_edit_%s_conf' % self.device.device_type.name, args=[str(self.id)])
630 632
631 633 def get_absolute_url_delete(self):
632 634 return reverse('url_delete_dev_conf', args=[str(self.id)])
633 635
634 636 def get_absolute_url_import(self):
635 637 return reverse('url_import_dev_conf', args=[str(self.id)])
636 638
637 639 def get_absolute_url_export(self):
638 640 return reverse('url_export_dev_conf', args=[str(self.id)])
639 641
640 642 def get_absolute_url_write(self):
641 643 return reverse('url_write_dev_conf', args=[str(self.id)])
642 644
643 645 def get_absolute_url_read(self):
644 646 return reverse('url_read_dev_conf', args=[str(self.id)])
645 647
646 648 def get_absolute_url_start(self):
647 649 return reverse('url_start_dev_conf', args=[str(self.id)])
648 650
649 651 def get_absolute_url_stop(self):
650 652 return reverse('url_stop_dev_conf', args=[str(self.id)])
651 653
652 654 def get_absolute_url_status(self):
653 655 return reverse('url_status_dev_conf', args=[str(self.id)])
@@ -1,296 +1,317
1 1 import os
2 2 from datetime import datetime
3 3 import json
4 4 import requests
5 5 import base64
6 6 import struct
7 7 from struct import pack
8 8 import time
9 9 from django.contrib import messages
10 10 from django.db import models
11 11 from django.urls import reverse
12 12 from django.core.validators import MinValueValidator, MaxValueValidator
13 13
14 14 from apps.main.models import Configuration
15 15
16 16 MODE_VALUE = (
17 17 ('position', 'Position'),
18 18 ('speed', 'Speed'),
19 19 ('table', 'Table')
20 20 )
21 21
22 22 class PedestalConfiguration(Configuration):
23 23
24 24 mode = models.CharField(
25 25 verbose_name='Mode',
26 26 max_length=10,
27 27 choices=MODE_VALUE,
28 28 null=False,
29 29 blank=False
30 30 )
31 31
32 32 axis = models.CharField(
33 33 verbose_name="Axis",
34 34 max_length=1000,
35 35 blank=False,
36 36 null=False,
37 37 help_text="Please separate the values with commas when using table mode"
38 38 )
39 39
40 40 speed = models.CharField(
41 41 verbose_name='Speed [Β°/s]',
42 42 max_length=1000,
43 43 blank=True,
44 44 null=True
45 45 )
46 46
47 47 angle = models.CharField(
48 48 verbose_name="Angle(s) [Β°]",
49 49 max_length=1000,
50 50 blank=True,
51 51 null=True,
52 52 help_text="Please separate the values with commas when using table mode"
53 53 )
54 54
55 55 min_value = models.FloatField(
56 56 verbose_name='Min angle [Β°]',
57 57 validators=[MinValueValidator(-5), MaxValueValidator(185)],
58 58 blank=True,
59 59 null=True
60 60 )
61 61
62 62 max_value = models.FloatField(
63 63 verbose_name='Max angle [Β°]',
64 64 validators=[MinValueValidator(-5), MaxValueValidator(185)],
65 65 blank=True,
66 66 null=True
67 67 )
68 68
69 69 class Meta:
70 70 db_table = 'pedestal_configurations'
71 71
72 72 def __str__(self):
73 73 if self.mode=='position':
74 74 return u'Position: {}ΒΊ {}'.format(self.angle, self.axis.upper())
75 75 if self.mode=='speed':
76 76 return u'Speed: {}ΒΊ/s {}'.format(self.speed, self.axis.upper())
77 77 if self.mode=='table':
78 78 axis = [x.strip().upper() for x in self.axis.split(',')]
79 79 speeds = [float(x.strip()) for x in self.speed.split(',')]
80 80 table = [float(x.strip()) for x in self.angle.split(',')]
81 81 return u'Table: Axis {}, Speed {}ΒΊ/s, Steps {}'.format(axis, speeds, table)
82 82
83 83 @property
84 84 def label(self):
85 85 return str(self)
86 86
87 87 def get_absolute_url_plot(self):
88 88 return reverse('url_plot_pedestal_pulses', args=[str(self.id)])
89 89
90 90 def request(self, cmd, method='get', **kwargs):
91 91
92 92 req = getattr(requests, method)(self.device.url(cmd), **kwargs)
93 93 payload = req.json()
94 94
95 95 return payload
96 96
97 97 def status_device(self):
98 98
99 99 try:
100 100 payload = requests.get(self.device.url())
101 101
102 102 if payload:
103 103 self.device.status = 1
104 104 elif payload['status']=='disable':
105 105 self.device.status = 2
106 106 else:
107 107 self.device.status = 1
108 108 self.device.save()
109 109 self.message = 'Pedestal status: {}'.format(payload['status'])
110 110 return False
111 111 except Exception as e:
112 112 if 'No route to host' not in str(e):
113 113 self.device.status = 4
114 114 self.device.save()
115 115 self.message = 'Pedestal status: {}'.format(str(e))
116 116 return False
117 117
118 118 self.device.save()
119 119 return True
120 120
121 def reset_device(self, axi, angle):
121 def reset_device(self):
122
123 try:
124 r = requests.get(self.device.url() + 'reset')
125
126 if r:
127 #self.device.status = 3
128 #self.device.save()
129 self.message = 'Pedestal restarted'
130 else:
131 return False
132
133 except Exception as e:
134 self.message = "Pedestal can't restarted: {}".format(str(e))
135 return False
136
137 return True
138
139 def initial_device(self, axi, angle):
122 140
123 141 try:
124 142 url = self.device.url() + "position?params="
125 143
126 144 payload_el = {'axis': 'elevation'}
127 145 payload_az = {'axis': 'azimuth'}
128 146
129 147 if axi == 'elevation':
130 148 # CORRECT AZ OFFSET
131 149 azi = angle - float(os.environ.get('AZ_OFFSET', 26.27))
132 150 if azi<0: azi += 360
133 151 payload_az['position'] = round(azi, 2)
134 152 payload_el['position'] = 0
135 153 elif axi == 'azimuth':
136 154 payload_el['position'] = angle
137 155 payload_az['position'] = 0
138 156 else:
139 157 payload_el['position'] = 0
140 158 payload_az['position'] = 0
141 159
142 160 json_data_el = json.dumps(payload_el)
143 161 json_data_az = json.dumps(payload_az)
144 162
145 163 base64_table_el = base64.standard_b64encode(json_data_el.encode('ascii'))
146 164 base64_table_az = base64.standard_b64encode(json_data_az.encode('ascii'))
147 165
148 166 time.sleep(0.1)
149 167 r = requests.get(url + base64_table_el.decode('ascii'))
150 168 time.sleep(0.1)
151 169 r = requests.get(url + base64_table_az.decode('ascii'))
152 170
153 171 if r:
154 172 self.device.status = 3
155 173 self.device.save()
156 self.message = 'Pedestal reset'
174 self.message = 'Pedestal - initial position'
157 175 else:
158 176 return False
159 177
160 178 except Exception as e:
161 self.message = 'Pedestal reset: {}'.format(str(e))
179 self.message = 'Pedestal - initial position: {}'.format(str(e))
162 180 return False
163 181
164 182 return True
165 183
166 184 def stop_device(self):
167 185
168 186 try:
169 187 command = self.device.url() + "stop"
170 188 r = requests.get(command)
171 189
172 190 if self.mode == 'table':
173 191 AX = {'az':'azimuth', 'el':'elevation'}
174 192 axis = [AX[x.lower().strip()] for x in self.axis.split(',')]
175 193 list_of_floats = [float(x.strip()) for x in self.angle.split(",")]
176 self.reset_device(axis[0], list_of_floats[0])
194 self.initial_device(axis[0], list_of_floats[0])
177 195
178 196 if r:
179 197 self.device.status = 4
180 198 self.device.save()
181 199 self.message = 'Pedestal stopped'
182 200 else:
183 201 self.device.status = 4
184 202 self.device.save()
185 203 return False
186 204 except Exception as e:
187 205 if 'No route to host' not in str(e):
188 206 self.device.status = 4
189 207 else:
190 208 self.device.status = 0
191 209 #self.message = 'Pedestal stop: {}'.format(str(e))
192 210 self.message = "Pedestal can't start, please check network/device connection or IP address/port configuration"
193 211 self.device.save()
194 212 return False
195 213
196 214 return True
197 215
198 216 def start_device(self, name_experiment=False):
199 217
200 218 if self.mode == 'table':
201 219 if len(self.angle.split(',')) > 1:
202 220 list_speed = []
203 221 list_axis = []
204 222 for _ in range(len(self.angle.split(','))):
205 223 list_axis.append(self.axis)
206 224 list_speed.append(self.speed)
207 225
208 226 if len(self.axis.split(',')) == 1:
209 227 self.axis = ",".join(map(str, list_axis))
210 228 if len(self.speed.split(',')) == 1:
211 229 self.speed = ",".join(map(str, list_speed))
212 230
213 231 AX = {'az':'azimuth', 'el':'elevation'}
214 232 axis = [AX[x.lower().strip()] for x in self.axis.split(',')]
215 233 if len(axis)==1:
216 234 axis = axis[0]
217 235
218 236 try:
219 237 if self.mode == 'position':
220 238 url = self.device.url() + "position?params="
221 239 payload = {'axis': axis, 'position': float(self.angle)}
222 240 elif self.mode == 'speed':
223 241 url = self.device.url() + "speed?params="
224 242 payload = {'axis': axis, 'speed': float(self.speed)}
225 243 elif self.mode == 'table':
226 244 url = self.device.url() + "combinedtable?params="
227 245 list_of_floats = [float(x.strip()) for x in self.angle.split(",")]
228 246
229 247 # CORRECT AZ OFFSET
230 248 for i, ax in enumerate(axis):
231 249 if ax == 'elevation':
232 250 azi = list_of_floats[i] - float(os.environ.get('AZ_OFFSET', 26.27))
233 251 if azi<0: azi += 360
234 252 list_of_floats[i] = round(azi, 2)
235 253
236 254 byte_table = []
237 255 for x in list_of_floats:
238 256 temp = bytearray(struct.pack("f", x))
239 257 byte_table.append(temp[3])
240 258 byte_table.append(temp[2])
241 259 byte_table.append(temp[1])
242 260 byte_table.append(temp[0])
243 261
244 262 coded_table = base64.standard_b64encode(bytes(byte_table))
245 263 coded_table_ascii = coded_table.decode('ascii')
246 264 speed = [float(x.strip()) for x in self.speed.split(',')]
247 265
248 266 if isinstance(axis, str):
249 267 axis = [axis]
250 268
251 269 payload = {
252 270 'arraylength': len(speed),
253 271 'axis': axis,
254 272 'speed': speed,
255 273 'bottom': self.min_value,
256 274 'top': self.max_value,
257 275 'table': coded_table_ascii
258 276 }
259 277
260 278 json_data = json.dumps(payload)
261 279 print(json_data)
262 280 base64_table = base64.standard_b64encode(json_data.encode('ascii'))
263 281 url += base64_table.decode('ascii')
264 282 print(url)
265 283 r = requests.get(url)
266 284
267 285 if self.mode == 'table':
268 286 payload['table'] = list_of_floats
269 287
270 288 if name_experiment:
271 289 name_experiment = name_experiment.split("@")
272 290 dt = datetime.strptime(name_experiment[1], '%Y-%m-%dT%H-%M-%S')
273 291 self.clone(experiment=name_experiment[0], experiment_date=dt, type=1)
274 292 else:
275 293 self.clone(type=1, experiment = 'empty', experiment_date=datetime.now())
276 294
277 295 if r:
278 296 self.device.status = 3
279 297 self.device.save()
280 298 self.message = 'Pedestal configured and started'
281 299 else:
282 300 return False
283 301 except Exception as e:
284 302 if 'No route to host' not in str(e):
285 303 self.device.status = 4
286 304 else:
287 305 self.device.status = 0
288 306 #self.message = 'Pedestal start: {}'.format(str(e))
289 307 self.message = "Pedestal can't start, please check network/device connection or IP address/port configuration"
290 308 self.device.save()
291 309 return False
292 310
293 311 return payload
294 312
295 313 def get_absolute_url_import(self):
296 return reverse('url_import_pedestal_conf', args=[str(self.id)]) No newline at end of file
314 return reverse('url_import_pedestal_conf', args=[str(self.id)])
315
316 def get_absolute_url_reset(self):
317 return reverse('url_reset_pedestal_conf', args=[str(self.id)]) No newline at end of file
@@ -1,30 +1,34
1 1 {% extends "dev_conf.html" %}
2 2 {% load static %}
3 3 {% load bootstrap4 %}
4 4 {% load main_tags %}
5 5
6 {% block extra-menu-actions %}
7 <li><a href="{{ dev_conf.get_absolute_url_reset }}"><span class="fas fa-spinner" aria-hidden="true"></span> Reset </a></li>
8 {% endblock %}
9
6 10 {% block content-detail %}
7 11
8 12 <h2>Pedestal</h2>
9 13 <table class="table table-bordered">
10 14 <tr>
11 15 <th>Status</th>
12 16 <td class="text-{{dev_conf.device.status_color}}"><strong>{{dev_conf.device.get_status_display}}</strong></td>
13 17 </tr>
14 18
15 19 {% for key in dev_conf_keys %}
16 20 <tr>
17 21 <th>{% get_verbose_field_name dev_conf key %}</th>
18 22 <td>{{dev_conf|attr:key}}</td>
19 23 </tr>
20 24 {% endfor %}
21 25 </table>
22 26 {% endblock %}
23 27
24 28 {% block extra-js%}
25 29 <script type="text/javascript">
26 30 $("#bt_toggle").click(function() {
27 31 $(".panel-collapse").collapse('toggle')
28 32 });
29 33 </script>
30 34 {% endblock %} No newline at end of file
@@ -1,11 +1,12
1 1 from django.urls import path
2 2
3 3 from . import views
4 4
5 5 urlpatterns = (
6 6 path('<int:conf_id>/', views.conf, name='url_pedestal_conf'),
7 7 path('<int:conf_id>/import/', views.import_file, name='url_import_pedestal_conf'),
8 8 path('<int:conf_id>/edit/', views.conf_edit, name='url_edit_pedestal_conf'),
9 path('<int:conf_id>/reset/', views.conf_reset, name='url_reset_pedestal_conf'),
9 10 #url(r'^(?P<id_conf>-?\d+)/write/$', 'apps.main.views.dev_conf_write', name='url_write_pedestal_conf'),
10 11 #url(r'^(?P<id_conf>-?\d+)/read/$', 'apps.main.views.dev_conf_read', name='url_read_pedestal_conf'),
11 12 )
@@ -1,120 +1,132
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 15
16 16 def conf(request, conf_id):
17 17
18 18 conf = get_object_or_404(PedestalConfiguration, pk=conf_id)
19 19
20 20 kwargs = {}
21 21 kwargs['dev_conf'] = conf
22 22
23 23 if conf.mode == 'position':
24 24 kwargs['dev_conf_keys'] = ['mode', 'axis', 'angle']
25 25 elif conf.mode == 'speed':
26 26 kwargs['dev_conf_keys'] = ['mode', 'axis', 'speed']
27 27 else:
28 28 kwargs['dev_conf_keys'] = ['mode', 'axis', 'speed', 'angle', 'min_value', 'max_value']
29 29
30 30
31 31 kwargs['title'] = 'Configuration'
32 32 kwargs['suptitle'] = 'Detail'
33 33
34 34 kwargs['button'] = 'Edit Configuration'
35 35
36 36 conf.status_device()
37 37
38 38 ###### SIDEBAR ######
39 39 kwargs.update(sidebar(conf=conf))
40 40
41 41 return render(request, 'pedestal_conf.html', kwargs)
42 42
43 43 @login_required
44 44 def conf_edit(request, conf_id):
45 45
46 46 conf = get_object_or_404(PedestalConfiguration, pk=conf_id)
47 47
48 48
49 49 if request.method=='GET':
50 50
51 51 form = PedestalConfigurationForm(instance=conf)
52 52 if conf.mode == 'position':
53 53 form.fields['speed'].disabled = True
54 54 form.fields['max_value'].disabled = True
55 55 form.fields['min_value'].disabled = True
56 56 elif conf.mode == 'speed':
57 57 form.fields['angle'].disabled = True
58 58 form.fields['max_value'].disabled = True
59 59 form.fields['min_value'].disabled = True
60 60
61 61 elif request.method=='POST':
62 62
63 63 line_data = {}
64 64 conf_data = {}
65 65 clock_data = {}
66 66 extras = []
67 67
68 68 #classified post fields
69 69
70 70 form = PedestalConfigurationForm(request.POST, instance=conf)
71 71
72 72 if form.is_valid():
73 73 form.save()
74 74
75 75 messages.success(request, 'Pedestal configuration successfully updated')
76 76
77 77 return redirect(conf.get_absolute_url())
78 78
79 79 kwargs = {}
80 80 kwargs['dev_conf'] = conf
81 81 kwargs['form'] = form
82 82 kwargs['edit'] = True
83 83
84 84 kwargs['title'] = 'Pedestal Configuration'
85 85 kwargs['suptitle'] = 'Edit'
86 86 kwargs['button'] = 'Update'
87 87
88 88 return render(request, 'pedestal_conf_edit.html', kwargs)
89 89
90 90 def import_file(request, conf_id):
91 91
92 92 conf = get_object_or_404(PedestalConfiguration, pk=conf_id)
93 93 if request.method=='POST':
94 94 form = PedestalImportForm(request.POST, request.FILES)
95 95 if form.is_valid():
96 96 try:
97 97 data = conf.import_from_file(request.FILES['file_name'])
98 98 conf.dict_to_parms(data)
99 99 messages.success(request, 'Configuration "%s" loaded succesfully' % request.FILES['file_name'])
100 100 return redirect(conf.get_absolute_url_edit())
101 101
102 102 except Exception as e:
103 103 messages.error(request, 'Error parsing file: "%s" - %s' % (request.FILES['file_name'], repr(e)))
104 104 else:
105 105 messages.warning(request, 'Your current configuration will be replaced')
106 106 form = PedestalImportForm()
107 107
108 108 kwargs = {}
109 109 kwargs['form'] = form
110 110 kwargs['title'] = 'Pedestal Configuration'
111 111 kwargs['suptitle'] = 'Import file'
112 112 kwargs['button'] = 'Upload'
113 113 kwargs['previous'] = conf.get_absolute_url()
114 114
115 115 return render(request, 'pedestal_import.html', kwargs)
116 116
117 @login_required
118 def conf_reset(request, conf_id):
119
120 conf = get_object_or_404(PedestalConfiguration, pk=conf_id)
121
122 if conf.reset_device():
123 messages.success(request, conf.message)
124 else:
125 messages.error(request, conf.message)
126
127 return redirect(conf.get_absolute_url())
128
117 129 def conf_raw(request, conf_id):
118 130 conf = get_object_or_404(PedestalConfiguration, pk=conf_id)
119 131 raw = conf.write_device(raw=True)
120 132 return HttpResponse(raw, content_type='application/json') No newline at end of file
General Comments 0
You need to be logged in to leave comments. Login now