##// END OF EJS Templates
Scheduler funcional
Renato Huallpa -
r395:cfb0f9955b15
parent child
Show More
@@ -1,35 +1,35
1 1
2 2 REDIS_HOST=radarsys-redis
3 3 REDIS_PORT=6300
4 4 POSTGRES_PORT_5432_TCP_ADDR=radarsys-postgres
5 5 POSTGRES_PORT_5432_TCP_PORT=5432
6 6 #POSTGRES_HOST=postgres
7 7 POSTGRES_HOST=localhost
8 8 POSTGRES_USER=docker
9 9 POSTGRES_PASSWORD=docker
10 10 POSTGRES_DB=radarsys
11 11
12 12 # DB_NAME=radarsys
13 13 # DB_USER=docker
14 14 # DB_PASSWORD=docker
15 15 PGDATA=/var/lib/postgresql/data
16 16 LC_ALL=C.UTF-8
17 17 TZ=America/Lima
18 18 DOCKER_DATA=/data/dockers/radarsys/
19 19 LOCAL_IP=192.168.1.128
20 20
21 # MQTT_SERVER=10.10.10.200
22 MQTT_SERVER = 192.168.100.5
21 MQTT_SERVER=10.10.10.200
22 # MQTT_SERVER = 192.168.100.5
23 23 MQTT_PORT = 1883
24 24 MQTT_KEEPALIVE = 3660
25 25
26 26 MQTT_USER_ATRAD=''
27 27 MQTT_PASSWORD_ATRAD = ''
28 28 MQTT_TOPIC_ATRAD_RECIEVE = "atrad/test4"
29 29
30 30 MQTT_USER = abs
31 31 MQTT_PASSWORD = abs
32 32
33 33 TOPIC_ABS=abs/beams
34 34 TOPIC_ABS_ACK=abs/beams_ack
35 35 TOPIC_ABS_CHANGE=abs/change_beam
@@ -1,208 +1,213
1 1 from django.db import models
2 2 from apps.main.models import Configuration
3 3 from apps.main.utils import Params
4 4 from django.core.validators import MinValueValidator, MaxValueValidator
5 5
6 6 from .files import read_json_file
7 7 import requests
8 8
9 9 class ATRADData(models.Model):
10 10 datetime = models.DateTimeField()
11 11
12 12 nstx = models.SmallIntegerField()
13 13 status = models.SmallIntegerField()
14 14 temp_cll = models.SmallIntegerField()
15 15 nboards = models.SmallIntegerField()
16 16
17 17 tempdvr = models.SmallIntegerField()
18 18 potincdvr = models.SmallIntegerField()
19 19 potretdvr = models.SmallIntegerField()
20 20
21 21 temp1 = models.SmallIntegerField()
22 22 potinc1 = models.SmallIntegerField()
23 23 potret1 = models.SmallIntegerField()
24 24 temp2 = models.SmallIntegerField()
25 25 potinc2 = models.SmallIntegerField()
26 26 potret2 = models.SmallIntegerField()
27 27 temp3 = models.SmallIntegerField()
28 28 potinc3 = models.SmallIntegerField()
29 29 potret3 = models.SmallIntegerField()
30 30 temp4 = models.SmallIntegerField()
31 31 potinc4 = models.SmallIntegerField()
32 32 potret4 = models.SmallIntegerField()
33 33 temp5 = models.SmallIntegerField()
34 34 potinc5 = models.SmallIntegerField()
35 35 potret5 = models.SmallIntegerField()
36 36 temp6 = models.SmallIntegerField()
37 37 potinc6 = models.SmallIntegerField()
38 38 potret6 = models.SmallIntegerField()
39 39
40 40
41 41
42 42 class Meta:
43 43 db_table = 'atrad_datas'
44 44
45 45 def __unicode__(self):
46 46 return u'%s' % (self.name)
47 47
48 48 class ATRADConfiguration(Configuration):
49 49
50 50 topic = models.PositiveIntegerField(verbose_name='Topic',validators=[MaxValueValidator(10)], default = 0)
51 51
52 52 def status_device(self):
53 53
54 54 ip=self.device.ip_address
55 55 port=self.device.port_address
56 56
57 57 route = "http://" + str(ip) + ":" + str(port) + "/status/"
58 58 try:
59 59 r = requests.get(route, timeout=0.7)
60 60 except Exception as e:
61 61 self.device.status = 0
62 62 self.device.save()
63 63 self.message = 'Could not read TX status: ' + str(e)
64 64 return False
65 65
66 66 response = r.json()
67 67 self.device.status = response['status']
68 68 self.message = response['message']
69 69 self.device.save()
70 70
71 71 if response['components_status']==0:
72 72 return False
73 73
74 74 return True
75 75
76 76
77 77 def start_device(self):
78 78
79 79 ip=self.device.ip_address
80 80 port=self.device.port_address
81 81
82 82 #---Device must be configured
83 83 if not self.device.status == 2:
84 84 self.message = 'TX Device must be configured.'
85 85 return False
86 86 #---Frequencies from form
87 87 post_data = self.parms_to_dict()
88 88 route = "http://" + str(ip) + ":" + str(port) + "/write/"
89 89
90 90 try:
91 91 r = requests.post(route, post_data, timeout=0.7)
92 92 except Exception as e:
93 93 self.message = "Could not start TX device. "+str(e)
94 94 return False
95 95
96 96 response = r.json()
97 97 if response['status']==1:
98 98 self.device.status = 1
99 99 self.device.save()
100 100 self.message = response['message']
101 101 return False
102 102
103 103 self.device.status = response['status']
104 104 self.device.save()
105 105 self.message = response['message']
106 106
107 107 return True
108 108
109 109
110 110 def stop_device(self):
111 111
112 112 ip=self.device.ip_address
113 113 port=self.device.port_address
114 114
115 115 if self.device.status == 2: #Configured
116 116 self.message = 'TX device is already stopped.'
117 117 return False
118
119 # Se crea el modo ocupado para una vez inicia el STOP
120 self.device.status = 5
121 self.device.save()
122 # Por si se demora deteniendo, que su estado sea busy
118 123
119 124 post_data = {"topic":0}
120 125 route = "http://" + str(ip) + ":" + str(port) + "/write/"
121 126
122 127 try:
123 128 r = requests.post(route, post_data, timeout=0.7)
124 129 except Exception as e:
125 130 self.message = "Could not write TX parameters. "+str(e)
126 131 self.device.status = 0
127 132 self.device.save()
128 133 return False
129 134
130 135 response = r.json()
131 136 status = response['status']
132 137 if status == 1:
133 138 self.device.status = status
134 139 self.device.save()
135 140 self.message = 'Could not stop TX device.'
136 141 return False
137 142
138 143 self.message = 'TX device has been stopped successfully.'
139 144 self.device.status = 2
140 145 self.device.save()
141 146
142 147 return True
143 148
144 149
145 150 def read_device(self):
146 151
147 152 ip=self.device.ip_address
148 153 port=self.device.port_address
149 154
150 155 route = "http://" + str(ip) + ":" + str(port) + "/read/"
151 156 try:
152 157 frequencies = requests.get(route,timeout=0.7)
153 158 except:
154 159 self.message = "Could not read TX parameters from this device"
155 160 return None
156 161
157 162 frequencies = frequencies.json()
158 163 if frequencies:
159 164 frequencies = frequencies.get("Frequencies")
160 165 topic = frequencies.get("topic")
161 166
162 167 parms = {'topic': topic}
163 168
164 169 self.message = "TX parameters have been successfully read"
165 170 return parms
166 171 else:
167 172 self.message = "Error reading TX parameters"
168 173 return None
169 174
170 175
171 176 def write_device(self):
172 177
173 178 ip=self.device.ip_address
174 179 port=self.device.port_address
175 180
176 181 #---Frequencies from form
177 182 parms = self.parms_to_dict()['configurations']
178 183 for parm in parms['allIds']:
179 184 byid = parm
180 185 frequencies = parms['byId'][byid]
181 186 post_data = {}
182 187 for data in frequencies:
183 188 if data in ['topic']:
184 189 post_data[data] = frequencies[data]
185 190
186 191 route = "http://" + str(ip) + ":" + str(port) + "/write/"
187 192 print (post_data)
188 193 try:
189 194 r = requests.post(route, post_data, timeout=0.7)
190 195 except:
191 196 self.message = "Could not write TX parameters"
192 197 self.device.status = 0
193 198 self.device.save()
194 199 return False
195 200
196 201 response = r.json()
197 202 self.message = response['message']
198 203 self.device.status = response['status']
199 204 self.device.save()
200 205
201 206 if self.device.status==1:
202 207 return False
203 208
204 209 return True
205 210
206 211
207 212 class Meta:
208 213 db_table = 'atrad_configurations' No newline at end of file
@@ -1,184 +1,189
1 1 from django.db import models
2 2 from apps.main.models import Configuration
3 3 from apps.main.utils import Params
4 4 from django.core.validators import MinValueValidator, MaxValueValidator
5 5
6 6 from .files import read_json_file
7 7 import requests
8 8 # Create your models here. validators=[MinValueValidator(62.5e6), MaxValueValidator(450e6)]
9 9
10 10 class CGSConfiguration(Configuration):
11 11
12 12 freq0 = models.PositiveIntegerField(verbose_name='Frequency 0 (Hz)',validators=[MaxValueValidator(450e6)], default = 60)
13 13 freq1 = models.PositiveIntegerField(verbose_name='Frequency 1 (Hz)',validators=[MaxValueValidator(450e6)], default = 60)
14 14 freq2 = models.PositiveIntegerField(verbose_name='Frequency 2 (Hz)',validators=[MaxValueValidator(450e6)], default = 60)
15 15 freq3 = models.PositiveIntegerField(verbose_name='Frequency 3 (Hz)',validators=[MaxValueValidator(450e6)], default = 60)
16 16
17 17 def verify_frequencies(self):
18 18
19 19 return True
20 20
21 21
22 22 def status_device(self):
23 23
24 24 ip=self.device.ip_address
25 25 port=self.device.port_address
26 26
27 27 route = "http://" + str(ip) + ":" + str(port) + "/status/"
28 28 try:
29 29 r = requests.get(route, timeout=0.7)
30 30 except Exception as e:
31 31 self.device.status = 0
32 32 self.device.save()
33 33 self.message = 'Could not read CGS status: ' + str(e)
34 34 return False
35 35
36 36 response = r.json()
37 37 self.device.status = response['status']
38 38 self.message = response['message']
39 39 self.device.save()
40 40
41 41 if response['components_status']==0:
42 42 return False
43 43
44 44 return True
45 45
46 46
47 47 def start_device(self):
48 48
49 49 ip=self.device.ip_address
50 50 port=self.device.port_address
51 51
52 52 #---Device must be configured
53 53 if not self.device.status == 2:
54 54 self.message = 'CGS Device must be configured.'
55 55 return False
56 56 #---Frequencies from form
57 57 post_data = self.parms_to_dict()
58 58 route = "http://" + str(ip) + ":" + str(port) + "/write/"
59 59
60 60 try:
61 61 r = requests.post(route, post_data, timeout=0.7)
62 62 except Exception as e:
63 63 self.message = "Could not start CGS device. "+str(e)
64 64 return False
65 65
66 66 response = r.json()
67 67 if response['status']==1:
68 68 self.device.status = 1
69 69 self.device.save()
70 70 self.message = response['message']
71 71 return False
72 72
73 73 self.device.status = response['status']
74 74 self.device.save()
75 75 self.message = response['message']
76 76
77 77 return True
78 78
79 79
80 80 def stop_device(self):
81 81
82 82 ip=self.device.ip_address
83 83 port=self.device.port_address
84 84
85 85 if self.device.status == 2: #Configured
86 86 self.message = 'CGS device is already stopped.'
87 87 return False
88
89 # Se crea el modo ocupado para una vez inicia el STOP
90 self.device.status = 5
91 self.device.save()
92 # Por si se demora deteniendo, que su estado sea busy
88 93
89 94 post_data = {"freq0":0, "freq1":0, "freq2":0, "freq3":0}
90 95 route = "http://" + str(ip) + ":" + str(port) + "/write/"
91 96
92 97 try:
93 98 r = requests.post(route, post_data, timeout=0.7)
94 99 except Exception as e:
95 100 self.message = "Could not write CGS parameters. "+str(e)
96 101 self.device.status = 0
97 102 self.device.save()
98 103 return False
99 104
100 105 response = r.json()
101 106 status = response['status']
102 107 if status == 1:
103 108 self.device.status = status
104 109 self.device.save()
105 110 self.message = 'Could not stop CGS device.'
106 111 return False
107 112
108 113 self.message = 'CGS device has been stopped successfully.'
109 114 self.device.status = 2
110 115 self.device.save()
111 116
112 117 return True
113 118
114 119
115 120 def read_device(self):
116 121
117 122 ip=self.device.ip_address
118 123 port=self.device.port_address
119 124
120 125 route = "http://" + str(ip) + ":" + str(port) + "/read/"
121 126 try:
122 127 frequencies = requests.get(route,timeout=0.7)
123 128 except:
124 129 self.message = "Could not read CGS parameters from this device"
125 130 return None
126 131
127 132 frequencies = frequencies.json()
128 133 if frequencies:
129 134 frequencies = frequencies.get("Frequencies")
130 135 freq0 = frequencies.get("freq0")
131 136 freq1 = frequencies.get("freq1")
132 137 freq2 = frequencies.get("freq2")
133 138 freq3 = frequencies.get("freq3")
134 139
135 140 parms = {'freq0': freq0,
136 141 'freq1': freq1,
137 142 'freq2': freq2,
138 143 'freq3': freq3}
139 144
140 145 self.message = "CGS parameters have been successfully read"
141 146 return parms
142 147 else:
143 148 self.message = "Error reading CGS parameters"
144 149 return None
145 150
146 151
147 152 def write_device(self):
148 153
149 154 ip=self.device.ip_address
150 155 port=self.device.port_address
151 156
152 157 #---Frequencies from form
153 158 parms = self.parms_to_dict()['configurations']
154 159 for parm in parms['allIds']:
155 160 byid = parm
156 161 frequencies = parms['byId'][byid]
157 162 post_data = {}
158 163 for data in frequencies:
159 164 if data in ['freq0','freq1','freq2','freq3']:
160 165 post_data[data] = frequencies[data]
161 166
162 167 route = "http://" + str(ip) + ":" + str(port) + "/write/"
163 168 print (post_data)
164 169 try:
165 170 r = requests.post(route, post_data, timeout=0.7)
166 171 except:
167 172 self.message = "Could not write CGS parameters"
168 173 self.device.status = 0
169 174 self.device.save()
170 175 return False
171 176
172 177 response = r.json()
173 178 self.message = response['message']
174 179 self.device.status = response['status']
175 180 self.device.save()
176 181
177 182 if self.device.status==1:
178 183 return False
179 184
180 185 return True
181 186
182 187
183 188 class Meta:
184 189 db_table = 'cgs_configurations'
@@ -1,164 +1,169
1 1 from django.db import models
2 2 from apps.main.models import Configuration
3 3 from apps.main.utils import Params
4 4 # Create your models here.
5 5
6 6 from django.core.validators import MinValueValidator, MaxValueValidator
7 7 from django.core.exceptions import ValidationError
8 8
9 9 from devices.dds import api, data
10 10
11 11 ENABLE_TYPE = (
12 12 (False, 'Disabled'),
13 13 (True, 'Enabled'),
14 14 )
15 15 MOD_TYPES = (
16 16 (0, 'Single Tone'),
17 17 (1, 'FSK'),
18 18 (2, 'Ramped FSK'),
19 19 (3, 'Chirp'),
20 20 (4, 'BPSK'),
21 21 )
22 22
23 23 class DDSConfiguration(Configuration):
24 24
25 25 DDS_NBITS = 48
26 26
27 27 clock = models.FloatField(verbose_name='Clock In (MHz)',validators=[MinValueValidator(5), MaxValueValidator(75)], null=True, default=60)
28 28 multiplier = models.PositiveIntegerField(verbose_name='Multiplier',validators=[MinValueValidator(1), MaxValueValidator(20)], default=4)
29 29
30 30 frequencyA_Mhz = models.DecimalField(verbose_name='Frequency A (MHz)', validators=[MinValueValidator(0), MaxValueValidator(150)], max_digits=19, decimal_places=16, null=True, default=49.9200)
31 31 frequencyA = models.BigIntegerField(verbose_name='Frequency A (Decimal)',validators=[MinValueValidator(0), MaxValueValidator(2**DDS_NBITS-1)], blank=True, null=True)
32 32
33 33 frequencyB_Mhz = models.DecimalField(verbose_name='Frequency B (MHz)', validators=[MinValueValidator(0), MaxValueValidator(150)], max_digits=19, decimal_places=16, blank=True, null=True)
34 34 frequencyB = models.BigIntegerField(verbose_name='Frequency B (Decimal)',validators=[MinValueValidator(0), MaxValueValidator(2**DDS_NBITS-1)], blank=True, null=True)
35 35
36 36 phaseA_degrees = models.FloatField(verbose_name='Phase A (Degrees)', validators=[MinValueValidator(0), MaxValueValidator(360)], default=0)
37 37
38 38 phaseB_degrees = models.FloatField(verbose_name='Phase B (Degrees)', validators=[MinValueValidator(0), MaxValueValidator(360)], blank=True, null=True)
39 39
40 40 modulation = models.PositiveIntegerField(verbose_name='Modulation Type', choices = MOD_TYPES, default = 0)
41 41
42 42 amplitude_enabled = models.BooleanField(verbose_name='Amplitude Control', choices=ENABLE_TYPE, default=False)
43 43
44 44 amplitudeI = models.PositiveIntegerField(verbose_name='Amplitude CH1',validators=[MinValueValidator(0), MaxValueValidator(2**12-1)], blank=True, null=True)
45 45 amplitudeQ = models.PositiveIntegerField(verbose_name='Amplitude CH2',validators=[MinValueValidator(0), MaxValueValidator(2**12-1)], blank=True, null=True)
46 46
47 47
48 48 def get_nbits(self):
49 49
50 50 return self.DDS_NBITS
51 51
52 52 def clean(self):
53 53
54 54 if self.modulation in [1,2,3]:
55 55 if self.frequencyB is None or self.frequencyB_Mhz is None:
56 56 raise ValidationError({
57 57 'frequencyB': 'Frequency modulation has to be defined when FSK or Chirp modulation is selected'
58 58 })
59 59
60 60 if self.modulation in [4,]:
61 61 if self.phaseB_degrees is None:
62 62 raise ValidationError({
63 63 'phaseB': 'Phase modulation has to be defined when BPSK modulation is selected'
64 64 })
65 65
66 66 self.frequencyA_Mhz = data.binary_to_freq(self.frequencyA, self.clock*self.multiplier)
67 67 self.frequencyB_Mhz = data.binary_to_freq(self.frequencyB, self.clock*self.multiplier)
68 68
69 69 def verify_frequencies(self):
70 70
71 71 return True
72 72
73 73 def parms_to_text(self):
74 74
75 75 my_dict = self.parms_to_dict()['configurations']['byId'][str(self.id)]
76 76
77 77 text = data.dict_to_text(my_dict)
78 78
79 79 return text
80 80
81 81 def status_device(self):
82 82
83 83 try:
84 84 answer = api.status(ip = self.device.ip_address,
85 85 port = self.device.port_address)
86 86 if 'clock' in answer:
87 87 self.device.status = 1
88 88 else:
89 89 self.device.status = answer[0]
90 90 self.message = 'DDS - {}'.format(answer[2:])
91 91 except Exception as e:
92 92 self.message = str(e)
93 93 self.device.status = 0
94 94
95 95 self.device.save()
96 96
97 97 if self.device.status in (0, '0'):
98 98 return False
99 99 else:
100 100 return True
101 101
102 102 def reset_device(self):
103 103
104 104 answer = api.reset(ip = self.device.ip_address,
105 105 port = self.device.port_address)
106 106
107 107 if answer[0] != "1":
108 108 self.message = 'DDS - {}'.format(answer[2:])
109 109 return 0
110 110
111 111 self.message = 'DDS - {}'.format(answer[2:])
112 112 return 1
113 113
114 114 def stop_device(self):
115 115
116 # Se crea el modo ocupado para una vez inicia el STOP
117 self.device.status = 5
118 self.device.save()
119 # Por si se demora deteniendo, que su estado sea busy
120
116 121 try:
117 122 answer = api.disable_rf(ip = self.device.ip_address,
118 123 port = self.device.port_address)
119 124
120 125 return self.status_device()
121 126
122 127 except Exception as e:
123 128 self.message = str(e)
124 129 return False
125 130
126 131 def start_device(self):
127 132
128 133 try:
129 134 answer = api.enable_rf(ip = self.device.ip_address,
130 135 port = self.device.port_address)
131 136
132 137 return self.status_device()
133 138
134 139 except Exception as e:
135 140 self.message = str(e)
136 141 return False
137 142
138 143 def read_device(self):
139 144
140 145 parms = api.read_config(ip = self.device.ip_address,
141 146 port = self.device.port_address)
142 147 if not parms:
143 148 self.message = "Could not read DDS parameters from this device"
144 149 return parms
145 150
146 151 self.message = ""
147 152 return parms
148 153
149 154
150 155 def write_device(self):
151 156
152 157 try:
153 158 answer = api.write_config(ip = self.device.ip_address,
154 159 port = self.device.port_address,
155 160 parms = self.parms_to_dict()['configurations']['byId'][str(self.id)])
156 161
157 162 return self.status_device()
158 163
159 164 except Exception as e:
160 165 self.message = str(e)
161 166 return False
162 167
163 168 class Meta:
164 169 db_table = 'dds_configurations'
@@ -1,305 +1,310
1 1 import ast
2 2 import json
3 3 import requests
4 4 import numpy as np
5 5 from base64 import b64encode
6 6 from struct import pack
7 7
8 8 from django.urls import reverse
9 9 from django.db import models
10 10 from apps.main.models import Configuration
11 11 from apps.main.utils import Params
12 12 # Create your models here.
13 13
14 14 from django.core.validators import MinValueValidator, MaxValueValidator
15 15 from django.core.exceptions import ValidationError
16 16
17 17 from devices.dds_rest import api, data
18 18
19 19 ENABLE_TYPE = (
20 20 (False, 'Disabled'),
21 21 (True, 'Enabled'),
22 22 )
23 23 MOD_TYPES = (
24 24 (0, 'Single Tone'),
25 25 (1, 'FSK'),
26 26 (2, 'Ramped FSK'),
27 27 (3, 'Chirp'),
28 28 (4, 'BPSK'),
29 29 )
30 30
31 31 class DDSRestConfiguration(Configuration):
32 32
33 33 DDS_NBITS = 48
34 34
35 35 clock = models.FloatField(verbose_name='Clock In (MHz)',validators=[MinValueValidator(5), MaxValueValidator(75)], null=True, default=60)
36 36 multiplier = models.PositiveIntegerField(verbose_name='Multiplier',validators=[MinValueValidator(1), MaxValueValidator(20)], default=4)
37 37
38 38 frequencyA_Mhz = models.DecimalField(verbose_name='Frequency A (MHz)', validators=[MinValueValidator(0), MaxValueValidator(150)], max_digits=19, decimal_places=16, null=True, default=49.9200)
39 39 frequencyA = models.BigIntegerField(verbose_name='Frequency A (Decimal)',validators=[MinValueValidator(0), MaxValueValidator(2**DDS_NBITS-1)], blank=True, null=True)
40 40
41 41 frequencyB_Mhz = models.DecimalField(verbose_name='Frequency B (MHz)', validators=[MinValueValidator(0), MaxValueValidator(150)], max_digits=19, decimal_places=16, blank=True, null=True)
42 42 frequencyB = models.BigIntegerField(verbose_name='Frequency B (Decimal)',validators=[MinValueValidator(0), MaxValueValidator(2**DDS_NBITS-1)], blank=True, null=True)
43 43
44 44 delta_frequency_Mhz = models.DecimalField(verbose_name='Delta frequency (MHz)', validators=[MinValueValidator(0), MaxValueValidator(150)], max_digits=19, decimal_places=16, blank=True, null=True)
45 45 delta_frequency = models.BigIntegerField(verbose_name='Delta frequency (Decimal)',validators=[MinValueValidator(0), MaxValueValidator(2**DDS_NBITS-1)], blank=True, null=True)
46 46
47 47 update_clock_Mhz = models.DecimalField(verbose_name='Update clock (MHz)', validators=[MinValueValidator(0), MaxValueValidator(150)], max_digits=19, decimal_places=16, blank=True, null=True)
48 48 update_clock = models.BigIntegerField(verbose_name='Update clock (Decimal)',validators=[MinValueValidator(0), MaxValueValidator(2**32-1)], blank=True, null=True)
49 49
50 50 ramp_rate_clock_Mhz = models.DecimalField(verbose_name='Ramp rate clock (MHz)', validators=[MinValueValidator(0), MaxValueValidator(150)], max_digits=19, decimal_places=16, blank=True, null=True)
51 51 ramp_rate_clock = models.BigIntegerField(verbose_name='Ramp rate clock (Decimal)',validators=[MinValueValidator(0), MaxValueValidator(2**18-1)], blank=True, null=True)
52 52
53 53 phaseA_degrees = models.FloatField(verbose_name='Phase A (Degrees)', validators=[MinValueValidator(0), MaxValueValidator(360)], default=0)
54 54
55 55 phaseB_degrees = models.FloatField(verbose_name='Phase B (Degrees)', validators=[MinValueValidator(0), MaxValueValidator(360)], blank=True, null=True)
56 56
57 57 modulation = models.PositiveIntegerField(verbose_name='Modulation Type', choices = MOD_TYPES, default = 0)
58 58
59 59 amplitude_enabled = models.BooleanField(verbose_name='Amplitude Control', choices=ENABLE_TYPE, default=False)
60 60
61 61 amplitudeI = models.PositiveIntegerField(verbose_name='Amplitude CH1',validators=[MinValueValidator(0), MaxValueValidator(2**12-1)], blank=True, null=True)
62 62 amplitudeQ = models.PositiveIntegerField(verbose_name='Amplitude CH2',validators=[MinValueValidator(0), MaxValueValidator(2**12-1)], blank=True, null=True)
63 63
64 64
65 65 def get_nbits(self):
66 66
67 67 return self.DDS_NBITS
68 68
69 69 def clean(self):
70 70
71 71 if self.modulation in [1,2,3]:
72 72 if self.frequencyB is None or self.frequencyB_Mhz is None:
73 73 raise ValidationError({
74 74 'frequencyB': 'Frequency modulation has to be defined when FSK or Chirp modulation is selected'
75 75 })
76 76
77 77 if self.modulation in [4,]:
78 78 if self.phaseB_degrees is None:
79 79 raise ValidationError({
80 80 'phaseB': 'Phase modulation has to be defined when BPSK modulation is selected'
81 81 })
82 82
83 83 self.frequencyA_Mhz = data.binary_to_freq(self.frequencyA, self.clock*self.multiplier)
84 84 self.frequencyB_Mhz = data.binary_to_freq(self.frequencyB, self.clock*self.multiplier)
85 85
86 86 def verify_frequencies(self):
87 87
88 88 return True
89 89
90 90 def parms_to_text(self):
91 91
92 92 my_dict = self.parms_to_dict()['configurations']['byId'][str(self.id)]
93 93
94 94 text = data.dict_to_text(my_dict)
95 95
96 96 return text
97 97
98 98 def status_device(self):
99 99 print("Status ")
100 100 try:
101 101 self.device.status = 0
102 102 payload = self.request('status')
103 103 if payload['status']=='generating RF':
104 104 self.device.status = 3
105 105 elif payload['status']=='no generating RF':
106 106 self.device.status = 2
107 107 else:
108 108 self.device.status = 1
109 109 self.device.save()
110 110 self.message = 'DDS REST status: {}'.format(payload['status'])
111 111 return False
112 112 except Exception as e:
113 113 if 'No route to host' not in str(e):
114 114 self.device.status = 4
115 115 self.device.save()
116 116 self.message = 'DDS REST status: {}'.format(str(e))
117 117 return False
118 118
119 119 self.device.save()
120 120 return True
121 121
122 122 def reset_device(self):
123 123
124 124 try:
125 125 payload = self.request('reset', 'post')
126 126 if payload['reset']=='ok':
127 127 self.message = 'DDS REST restarted OK'
128 128 self.device.status = 2
129 129 self.device.save()
130 130 else:
131 131 self.message = 'DDS REST restart fail'
132 132 self.device.status = 4
133 133 self.device.save()
134 134 except Exception as e:
135 135 self.message = 'DDS REST reset: {}'.format(str(e))
136 136 return False
137 137
138 138 return True
139 139
140 140 def stop_device(self):
141 141
142 # Se crea el modo ocupado para una vez inicia el STOP
143 self.device.status = 5
144 self.device.save()
145 # Por si se demora deteniendo, que su estado sea busy
146
142 147 try:
143 148 payload = self.request('stop', 'post',data=json.dumps({'_rf_enable':0}))
144 149 self.message = 'DDS REST: {}'.format(payload['stop'])
145 150 if payload['stop']=='ok':
146 151 self.device.status = 2
147 152 self.device.save()
148 153 else:
149 154 self.device.status = 4
150 155 self.device.save()
151 156 return False
152 157 except Exception as e:
153 158 if 'No route to host' not in str(e):
154 159 self.device.status = 4
155 160 else:
156 161 self.device.status = 0
157 162 self.message = 'DDS REST stop: {}'.format(str(e))
158 163 self.device.save()
159 164 return False
160 165
161 166 return True
162 167
163 168 def start_device(self):
164 169
165 170 try:
166 171 payload = self.request('start', 'post',data=json.dumps({'_rf_enable':1}))
167 172 self.message = 'DDS REST start: {}'.format(payload['start'])
168 173 if payload['start']=='ok':
169 174 self.device.status = 3
170 175 self.device.save()
171 176 else:
172 177 self.device.status = 2
173 178 self.device.save()
174 179 return False
175 180 except Exception as e:
176 181 if 'No route to host' not in str(e):
177 182 self.device.status = 4
178 183 else:
179 184 self.device.status = 0
180 185 self.message = 'DDS REST start: {}'.format(str(e))
181 186 self.device.save()
182 187 return False
183 188
184 189 return True
185 190
186 191 def read_device(self):
187 192
188 193 parms = self.request('read')
189 194 print(parms)
190 195 if not parms:
191 196 self.message = "Could not read DDS REST parameters from this device"
192 197 return parms
193 198
194 199 self.message = ""
195 200 return parms
196 201
197 202 def arma_control(self,l_clock,l_multiplier,l_modulation):
198 203 sysclock = l_clock*l_multiplier
199 204 pll_range = 0
200 205 if(sysclock>=200):
201 206 pll_range = 1
202 207 l_control = ((l_modulation<<9)+(pll_range<<22)+(l_multiplier<<16)).to_bytes(4,'little')
203 208 return l_control
204 209
205 210 def conv_phase(self,l_phase):
206 211
207 212 l_phase_2B = int((l_phase*(2**14)/360)).to_bytes(2,'little')
208 213 return l_phase_2B
209 214
210 215 def arma_data_write(self):
211 216 #clock = RCClock.objects.get(rc_configuration=self)
212 217 clock = self.clock
213 218 print(clock)
214 219 multiplier = self.multiplier
215 220 print(multiplier)
216 221 frequencyA_Mhz = self.frequencyA_Mhz
217 222 print(frequencyA_Mhz)
218 223 frequencyA = self.frequencyA
219 224 print(frequencyA)
220 225 frequencyB_Mhz = self.frequencyB_Mhz
221 226 print(frequencyB_Mhz)
222 227 frequencyB = self.frequencyB
223 228 print(frequencyB)
224 229 phaseA_degrees = self.phaseA_degrees or 0
225 230 print(phaseA_degrees)
226 231 phaseB_degrees = self.phaseB_degrees or 0
227 232 print(phaseB_degrees)
228 233 modulation = self.modulation or 0
229 234 print(modulation)
230 235 amplitude_enabled = self.amplitude_enabled or 0
231 236 print(amplitude_enabled)
232 237 amplitudeI = self.amplitudeI or 0
233 238 print(amplitudeI)
234 239 amplitudeQ = self.amplitudeQ or 0
235 240 print(amplitudeQ)
236 241 delta_frequency = self.delta_frequency or 0
237 242 print(delta_frequency)
238 243 update_clock = self.update_clock or 0
239 244 print(update_clock)
240 245 ramp_rate_clock = self.ramp_rate_clock or 0
241 246 print(ramp_rate_clock)
242 247 osrr = 0
243 248 qdac = 0
244 249 control = self.arma_control(clock,multiplier,modulation)
245 250 phase1 = self.conv_phase(phaseA_degrees)
246 251 phase2 = self.conv_phase(phaseB_degrees)
247 252
248 253 cadena_json = {'clock': (b64encode(pack('<f',clock))).decode("UTF-8"),\
249 254 'multiplier': (b64encode(pack('<B',multiplier))).decode("UTF-8"),\
250 255 'frequencyA': (b64encode((frequencyA).to_bytes(6,'little'))).decode("UTF-8"),\
251 256 'frequencyB': (b64encode((frequencyB).to_bytes(6,'little'))).decode("UTF-8"),\
252 257 'delta_frequency': (b64encode((delta_frequency).to_bytes(6,'little'))).decode("UTF-8"),\
253 258 'update_clock': (b64encode((update_clock).to_bytes(4,'little'))).decode("UTF-8"),\
254 259 'ramp_rate_clock': (b64encode((ramp_rate_clock).to_bytes(3,'little'))).decode("UTF-8"),\
255 260 'control': (b64encode(control)).decode("UTF-8"),\
256 261 'amplitudeI': (b64encode((amplitudeI).to_bytes(2,'little'))).decode("UTF-8"),\
257 262 'amplitudeQ': (b64encode((amplitudeQ).to_bytes(2,'little'))).decode("UTF-8"),\
258 263 '_phase1': (b64encode((phase1))).decode("UTF-8"),\
259 264 '_phase2': (b64encode((phase2))).decode("UTF-8"),\
260 265 'osrr': (b64encode((osrr).to_bytes(1,'little'))).decode("UTF-8"),\
261 266 'qdac': (b64encode((qdac).to_bytes(2,'little'))).decode("UTF-8")
262 267 }
263 268 return cadena_json
264 269
265 270 def write_device(self, raw=False):
266 271 print("Ingreso a write")
267 272 try:
268 273
269 274 if not raw:
270 275 data = self.arma_data_write()
271 276 print(data)
272 277 payload = self.request('write', 'post', data=json.dumps(data))
273 278 print(payload)
274 279 if payload['write'] == 'ok':
275 280 self.device.status = 3
276 281 self.device.save()
277 282 self.message = 'DDS Rest write configured and started'
278 283 else:
279 284 self.message = payload['programming']
280 285 if payload['programming'] == 'fail':
281 286 self.message = 'DDS Rest write: error programming DDS chip'
282 287 if raw:
283 288 return b64encode(data)
284 289
285 290
286 291 except Exception as e:
287 292 if 'No route to host' not in str(e):
288 293 self.device.status = 4
289 294 else:
290 295 self.device.status = 0
291 296 self.message = 'DDS Rest write: {}'.format(str(e))
292 297 self.device.save()
293 298 return False
294 299
295 300 return True
296 301
297 302 def request(self, cmd, method='get', **kwargs):
298 303 print("Ingreso a request")
299 304 req = getattr(requests, method)(self.device.url(cmd), **kwargs)
300 305 payload = req.json()
301 306
302 307 return payload
303 308
304 309 class Meta:
305 310 db_table = 'ddsrest_configurations'
@@ -1,404 +1,409
1 1 import json
2 2 import requests
3 3
4 4 from django.db import models
5 5 from django.core.validators import MinValueValidator, MaxValueValidator
6 6 from django.urls import reverse
7 7
8 8 from apps.main.models import Configuration
9 9 from apps.main.utils import Params
10 10 from .utils import create_jarsfiles
11 11
12 12 # Create your models here.
13 13
14 14 EXPERIMENT_TYPE = (
15 15 (0, 'RAW_DATA'),
16 16 (1, 'PDATA'),
17 17 )
18 18
19 19 DATA_TYPE = (
20 20 (0, 'SHORT'),
21 21 (1, 'FLOAT'),
22 22 )
23 23
24 24 DECODE_TYPE = (
25 25 (0, 'None'),
26 26 (1, 'TimeDomain'),
27 27 (2, 'FreqDomain'),
28 28 (3, 'InvFreqDomain'),
29 29 )
30 30
31 31 FILTER = '{"id":1, "clock": 60, "multiplier": 5, "frequency": 49.92, "f_decimal": 721554506, "fir": 2, "cic_2": 12, "cic_5": 25}'
32 32
33 33 class JARSFilter(models.Model):
34 34
35 35 JARS_NBITS = 32
36 36
37 37 name = models.CharField(verbose_name='Name', max_length=60, unique=True, default='')
38 38 clock = models.FloatField(verbose_name='Clock In (MHz)', validators=[
39 39 MinValueValidator(5), MaxValueValidator(75)], null=True, default=60)
40 40 multiplier = models.PositiveIntegerField(verbose_name='Multiplier', validators=[
41 41 MinValueValidator(1), MaxValueValidator(20)], default=5)
42 42 frequency = models.FloatField(verbose_name='Frequency (MHz)', validators=[
43 43 MaxValueValidator(150)], null=True, default=49.9200)
44 44 f_decimal = models.BigIntegerField(verbose_name='Frequency (Decimal)', validators=[
45 45 MinValueValidator(-9223372036854775808), MaxValueValidator(2**JARS_NBITS-1)], null=True, default=721554505)
46 46 cic_2 = models.PositiveIntegerField(verbose_name='CIC2', validators=[
47 47 MinValueValidator(2), MaxValueValidator(100)], default=10)
48 48 scale_cic_2 = models.PositiveIntegerField(verbose_name='Scale CIC2', validators=[
49 49 MinValueValidator(0), MaxValueValidator(6)], default=1)
50 50 cic_5 = models.PositiveIntegerField(verbose_name='CIC5', validators=[
51 51 MinValueValidator(1), MaxValueValidator(100)], default=1)
52 52 scale_cic_5 = models.PositiveIntegerField(verbose_name='Scale CIC5', validators=[
53 53 MinValueValidator(0), MaxValueValidator(20)], default=5)
54 54 fir = models.PositiveIntegerField(verbose_name='FIR', validators=[
55 55 MinValueValidator(1), MaxValueValidator(100)], default=6)
56 56 scale_fir = models.PositiveIntegerField(verbose_name='Scale FIR', validators=[
57 57 MinValueValidator(0), MaxValueValidator(7)], default=3)
58 58 number_taps = models.PositiveIntegerField(verbose_name='Number of taps', validators=[
59 59 MinValueValidator(1), MaxValueValidator(256)], default=4)
60 60 taps = models.CharField(verbose_name='Taps', max_length=1600, default='0')
61 61
62 62 class Meta:
63 63 db_table = 'jars_filters'
64 64
65 65 def __unicode__(self):
66 66 return u'%s' % (self.name)
67 67
68 68 def jsonify(self):
69 69
70 70 data = {}
71 71 ignored = ()
72 72
73 73 for field in self._meta.fields:
74 74 if field.name in ignored:
75 75 continue
76 76 data[field.name] = field.value_from_object(self)
77 77
78 78 return data
79 79
80 80 def parms_to_dict(self):
81 81
82 82 parameters = {}
83 83
84 84 parameters['name'] = self.name
85 85 parameters['clock'] = float(self.clock)
86 86 parameters['multiplier'] = int(self.multiplier)
87 87 parameters['frequency'] = float(self.frequency)
88 88 parameters['f_decimal'] = int(self.frequency)
89 89 parameters['fir'] = int(self.fir)
90 90 parameters['cic_2'] = int(self.cic_2)
91 91 parameters['cic_5'] = int(self.cic_5)
92 92
93 93 return parameters
94 94
95 95 def dict_to_parms(self, parameters):
96 96
97 97 self.name = parameters['name']
98 98 self.clock = parameters['clock']
99 99 self.multiplier = parameters['multiplier']
100 100 self.frequency = parameters['frequency']
101 101 self.f_decimal = parameters['f_decimal']
102 102 self.fir = parameters['fir']
103 103 self.cic_2 = parameters['cic_2']
104 104 self.cic_5 = parameters['cic_5']
105 105
106 106 def dict_to_parms_new(self, parameters):
107 107
108 108 self.name = parameters['name']
109 109 self.clock = parameters['clock']
110 110 self.multiplier = parameters['multiplier']
111 111 self.frequency = parameters['frequency']
112 112 self.f_decimal = parameters['f_decimal']
113 113 self.fir = parameters['fir']
114 114 self.cic_2 = parameters['cic_2']
115 115 self.cic_5 = parameters['cic_5']
116 116 self.scale_fir = parameters['scale_fir']
117 117 self.scale_cic_2 = parameters['scale_cic_2']
118 118 self.scale_cic_5 = parameters['scale_cic_5']
119 119 self.number_taps = parameters['number_taps']
120 120 self.taps = parameters['taps']
121 121
122 122 class JARSConfiguration(Configuration):
123 123
124 124 ADC_RESOLUTION = 8
125 125 PCI_DIO_BUSWIDTH = 32
126 126 HEADER_VERSION = 1103
127 127 BEGIN_ON_START = True
128 128 REFRESH_RATE = 1
129 129
130 130 exp_type = models.PositiveIntegerField(
131 131 verbose_name='Experiment Type', choices=EXPERIMENT_TYPE, default=0)
132 132 cards_number = models.PositiveIntegerField(verbose_name='Number of Cards', validators=[
133 133 MinValueValidator(1), MaxValueValidator(4)], default=1)
134 134 channels_number = models.PositiveIntegerField(verbose_name='Number of Channels', validators=[
135 135 MinValueValidator(1), MaxValueValidator(8)], default=5)
136 136 channels = models.CharField(
137 137 verbose_name='Channels', max_length=15, default='1,2,3,4,5')
138 138 data_type = models.PositiveIntegerField(
139 139 verbose_name='Data Type', choices=DATA_TYPE, default=0)
140 140 raw_data_blocks = models.PositiveIntegerField(
141 141 verbose_name='Raw Data Blocks', validators=[MaxValueValidator(5000)], default=60)
142 142 profiles_block = models.PositiveIntegerField(
143 143 verbose_name='Profiles Per Block', default=400)
144 144 acq_profiles = models.PositiveIntegerField(
145 145 verbose_name='Acquired Profiles', default=400)
146 146 ftp_interval = models.PositiveIntegerField(
147 147 verbose_name='FTP Interval', default=60)
148 148 fftpoints = models.PositiveIntegerField(
149 149 verbose_name='FFT Points', default=16)
150 150 cohe_integr_str = models.PositiveIntegerField(
151 151 verbose_name='Coh. Int. Stride', validators=[MinValueValidator(1)], default=30)
152 152 cohe_integr = models.PositiveIntegerField(
153 153 verbose_name='Coherent Integrations', validators=[MinValueValidator(1)], default=30)
154 154 incohe_integr = models.PositiveIntegerField(
155 155 verbose_name='Incoherent Integrations', validators=[MinValueValidator(1)], default=30)
156 156 decode_data = models.PositiveIntegerField(
157 157 verbose_name='Decode Data', choices=DECODE_TYPE, default=0)
158 158 post_coh_int = models.BooleanField(
159 159 verbose_name='Post Coherent Integration', default=False)
160 160 spectral_number = models.PositiveIntegerField(
161 161 verbose_name='# Spectral Combinations', validators=[MinValueValidator(1)], default=1)
162 162 spectral = models.CharField(
163 163 verbose_name='Combinations', max_length=5000, default='[0, 0],')
164 164 create_directory = models.BooleanField(
165 165 verbose_name='Create Directory Per Day', default=True)
166 166 include_expname = models.BooleanField(
167 167 verbose_name='Experiment Name in Directory', default=False)
168 168 #view_raw_data = models.BooleanField(verbose_name='View Raw Data', default=True)
169 169 save_ch_dc = models.BooleanField(
170 170 verbose_name='Save Channels DC', default=True)
171 171 save_data = models.BooleanField(verbose_name='Save Data', default=True)
172 172 filter_parms = models.CharField(
173 173 max_length=10000, default=FILTER)
174 174 filter = models.ForeignKey(
175 175 'JARSFilter', verbose_name='Filter', null=True, blank=True, on_delete=models.CASCADE)
176 176
177 177 class Meta:
178 178 db_table = 'jars_configurations'
179 179
180 180 def filter_resolution(self):
181 181 filter_parms = json.loads(self.filter_parms)
182 182 clock = float(filter_parms['clock'])
183 183 cic_2 = filter_parms['cic_2']
184 184 cic_5 = filter_parms['cic_5']
185 185 fir = filter_parms['fir']
186 186 resolution = round((clock/(cic_2*cic_5*fir)), 2)
187 187 return resolution
188 188
189 189 def dict_to_parms(self, params, id=None):
190 190
191 191 if id is not None:
192 192 data = Params(params).get_conf(id_conf=id)
193 193 else:
194 194 data = Params(params).get_conf(dtype='jars')
195 195 data['filter_parms'] = params['filter_parms']
196 196
197 197 # self.name = data['name']
198 198 self.exp_type = data['exp_type']
199 199 #----PDATA----
200 200 if self.exp_type == 1:
201 201 self.incohe_integr = data['incohe_integr']
202 202 self.spectral_number = data['spectral_number']
203 203 self.spectral = data['spectral']
204 204 self.fftpoints = data['fftpoints']
205 205 self.save_ch_dc = data['save_ch_dc']
206 206 else:
207 207 self.raw_data_blocks = data['raw_data_blocks']
208 208 #----PDATA----
209 209 self.cards_number = data['cards_number']
210 210 self.channels_number = data['channels_number']
211 211 self.channels = data['channels']
212 212 self.data_type = data['data_type']
213 213 self.profiles_block = data['profiles_block']
214 214 self.acq_profiles = data['acq_profiles']
215 215 self.ftp_interval = data['ftp_interval']
216 216 self.cohe_integr_str = data['cohe_integr_str']
217 217 self.cohe_integr = data['cohe_integr']
218 218 #----DECODE----
219 219 self.decode_data = data['decode_data']
220 220 self.post_coh_int = data['post_coh_int']
221 221 #----DECODE----
222 222 self.create_directory = data['create_directory']
223 223 self.include_expname = data['include_expname']
224 224 self.save_data = data['save_data']
225 225 self.filter_parms = json.dumps(data['filter_parms'])
226 226
227 227 self.save()
228 228
229 229 def parms_to_text(self, file_format='jars'):
230 230
231 231 data = self.experiment.parms_to_dict()
232 232
233 233 for key in data['configurations']['allIds']:
234 234 if data['configurations']['byId'][key]['device_type'] in ('dds', 'cgs'):
235 235 data['configurations']['allIds'].remove(key)
236 236 data['configurations']['byId'].pop(key)
237 237 elif data['configurations']['byId'][key]['device_type'] == 'jars':
238 238 data['configurations']['byId'][key] = self.parms_to_dict(
239 239 )['configurations']['byId'][str(self.pk)]
240 240 elif data['configurations']['byId'][key]['device_type'] == 'rc':
241 241 data['configurations']['byId'][key]['pulses'] = ''
242 242 data['configurations']['byId'][key]['delays'] = ''
243 243 rc_ids = [pk for pk in data['configurations']['allIds']
244 244 if data['configurations']['byId'][pk]['device_type'] == 'rc']
245 245 mix_ids = [pk for pk in rc_ids if data['configurations']
246 246 ['byId'][pk]['mix']]
247 247
248 248 if mix_ids:
249 249 params = data['configurations']['byId'][mix_ids[0]]['parameters']
250 250 rc = data['configurations']['byId'][params.split(
251 251 '-')[0].split('|')[0]]
252 252 rc['mix'] = True
253 253 data['configurations']['byId'][rc['id']] = rc
254 254 elif len(rc_ids) == 0:
255 255 self.message = 'File needs RC configuration'
256 256 return ''
257 257
258 258 json_data = json.dumps(data)
259 259 racp_file, filter_file = create_jarsfiles(json_data)
260 260 if file_format == 'racp':
261 261 return racp_file
262 262
263 263 return filter_file
264 264
265 265 def request(self, cmd, method='get', **kwargs):
266 266
267 267 req = getattr(requests, method)(self.device.url(cmd), **kwargs)
268 268 payload = req.json()
269 269 return payload
270 270
271 271 def status_device(self):
272 272
273 273 try:
274 274 payload = self.request('status',
275 275 params={'name': self.experiment.name})
276 276 self.device.status = payload['status']
277 277 self.device.save()
278 278 self.message = payload['message']
279 279 except Exception as e:
280 280 self.device.status = 0
281 281 self.message = str(e)
282 282 self.device.save()
283 283 return False
284 284
285 285 return True
286 286
287 287 def stop_device(self):
288 288
289 # Se crea el modo ocupado para una vez inicia el STOP
290 self.device.status = 5
291 self.device.save()
292 # Por si se demora deteniendo, que su estado sea busy
293
289 294 try:
290 295 payload = self.request('stop', 'post')
291 296 self.device.status = payload['status']
292 297 self.device.save()
293 298 self.message = payload['message']
294 299 except Exception as e:
295 300 self.device.status = 0
296 301 self.message = str(e)
297 302 self.device.save()
298 303 return False
299 304
300 305 return True
301 306
302 307 def read_device(self):
303 308
304 309 try:
305 310 payload = self.request(
306 311 'read', params={'name': self.experiment.name})
307 312 self.message = 'Configuration loaded'
308 313 except:
309 314 self.device.status = 0
310 315 self.device.save()
311 316 self.message = 'Could not read JARS configuration.'
312 317 return False
313 318
314 319 return payload
315 320
316 321 def write_device(self):
317 322
318 323 if self.device.status == 3:
319 324 self.message = 'Could not configure device. Software Acquisition is running'
320 325 print('Could not configure device. Software Acquisition is running')
321 326 return False
322 327
323 328 data = self.experiment.parms_to_dict()
324 329 #print(data)
325 330 for key in data['configurations']['allIds']:
326 331 if data['configurations']['byId'][key]['device_type'] in ('dds', 'cgs'):
327 332 data['configurations']['allIds'].remove(key)
328 333 data['configurations']['byId'].pop(key)
329 334 elif data['configurations']['byId'][key]['device_type'] == 'rc':
330 335 data['configurations']['byId'][key]['pulses'] = ''
331 336 data['configurations']['byId'][key]['delays'] = ''
332 337 rc_ids = [pk for pk in data['configurations']['allIds']
333 338 if data['configurations']['byId'][pk]['device_type'] == 'rc']
334 339 if len(rc_ids) == 0:
335 340 self.message = 'Missing RC configuration'
336 341 return False
337 342
338 343 json_data = json.dumps(data)
339 344 print("STATUS:", self.device.status,flush=True)
340 345
341 346 try:
342 347 payload = self.request('write', 'post', json=json_data)
343 348 self.device.status = payload['status']
344 349 self.message = payload['message']
345 350 self.device.save()
346 351 if self.device.status == 1:
347 352 return False
348 353
349 354 except Exception as e:
350 355 self.device.status = 0
351 356 self.message = str(e)
352 357 self.device.save()
353 358 return False
354 359 return True
355 360
356 361 def start_device(self):
357 362
358 363 try:
359 364 payload = self.request('start', 'post',
360 365 json={'name': self.experiment.name})
361 366 self.device.status = payload['status']
362 367 self.message = payload['message']
363 368 self.device.save()
364 369 if self.device.status == 1:
365 370 return False
366 371
367 372 except Exception as e:
368 373 self.device.status = 0
369 374 self.message = str(e)
370 375 self.device.save()
371 376 return False
372 377 return True
373 378
374 379 def get_log(self):
375 380
376 381 payload = None
377 382
378 383 try:
379 384 payload = requests.get(self.device.url('get_log'), params={
380 385 'name': self.experiment.name})
381 386 except:
382 387 self.device.status = 0
383 388 self.device.save()
384 389 self.message = 'Jars API is not running.'
385 390 return False
386 391
387 392 self.message = 'Jars API is running'
388 393
389 394 return payload
390 395
391 396 def update_from_file(self, filename):
392 397
393 398 f = JARSFile(filename)
394 399 self.dict_to_parms(f.data)
395 400 self.save()
396 401
397 402 def get_absolute_url_import(self):
398 403 return reverse('url_import_jars_conf', args=[str(self.id)])
399 404
400 405 def get_absolute_url_read(self):
401 406 return reverse('url_read_jars_conf', args=[str(self.id)])
402 407
403 408 def get_absolute_url_log(self):
404 409 return reverse('url_get_jars_log', args=[str(self.id)])
@@ -1,856 +1,856
1 1
2 2 import os
3 3 import json
4 4 import requests
5 5 import time
6 6 from datetime import datetime
7 7
8 8 try:
9 9 from polymorphic.models import PolymorphicModel
10 10 except:
11 11 from polymorphic import PolymorphicModel
12 12
13 13 from django.template.base import kwarg_re
14 14 from django.db import models
15 15 from django.urls import reverse
16 16 from django.core.validators import MinValueValidator, MaxValueValidator
17 17 from django.shortcuts import get_object_or_404
18 18 from django.contrib.auth.models import User
19 19 from django.db.models.signals import post_save
20 20 from django.dispatch import receiver
21 21
22 22 from apps.main.utils import Params
23 23 from apps.rc.utils import RCFile
24 24 from apps.jars.utils import RacpFile
25 25 from devices.dds import api as dds_api
26 26 from devices.dds import data as dds_data
27 27
28 28
29 29 DEV_PORTS = {
30 30 'rc' : 2000,
31 31 'dds' : 2000,
32 32 'jars' : 2000,
33 33 'usrp' : 2000,
34 34 'cgs' : 8080,
35 35 'abs' : 8080,
36 36 'dds_rest': 80
37 37 }
38 38
39 39 RADAR_STATES = (
40 40 (0, 'No connected'),
41 41 (1, 'Connected'),
42 42 (2, 'Configured'),
43 43 (3, 'Running'),
44 44 (4, 'Scheduled'),
45 45 )
46 46
47 47 EXPERIMENT_TYPE = (
48 48 (0, 'RAW_DATA'),
49 49 (1, 'PDATA'),
50 50 )
51 51
52 52 DECODE_TYPE = (
53 53 (0, 'None'),
54 54 (1, 'TimeDomain'),
55 55 (2, 'FreqDomain'),
56 56 (3, 'InvFreqDomain'),
57 57 )
58 58
59 59 DEV_STATES = (
60 60 (0, 'No connected'),
61 61 (1, 'Connected'),
62 62 (2, 'Configured'),
63 63 (3, 'Running'),
64 64 (4, 'Unknown'),
65 65 (5, 'Busy')
66 66 )
67 67
68 68 DEV_TYPES = (
69 69 ('', 'Select a device type'),
70 70 ('rc', 'Radar Controller'),
71 71 ('dds', 'Direct Digital Synthesizer'),
72 72 ('jars', 'Jicamarca Radar Acquisition System'),
73 73 ('usrp', 'Universal Software Radio Peripheral'),
74 74 ('cgs', 'Clock Generator System'),
75 75 ('abs', 'Automatic Beam Switching'),
76 76 ('dds_rest', 'Direct Digital Synthesizer_REST'),
77 77 ('atrad', 'Transmitter ATRAD'),
78 78 )
79 79
80 80 EXP_STATES = (
81 81 (0,'Error'), #RED
82 82 (1,'Cancelled'), #YELLOW
83 83 (2,'Running'), #GREEN
84 84 (3,'Scheduled'), #BLUE
85 85 (4,'Unknown'), #WHITE
86 (5,'Busy'),
86 87 )
87 88
88 89 CONF_TYPES = (
89 90 (0, 'Active'),
90 91 (1, 'Historical'),
91 92 )
92 93
93 94 class Profile(models.Model):
94 95 user = models.OneToOneField(User, on_delete=models.CASCADE)
95 96 theme = models.CharField(max_length=30, default='spacelab')
96 97
97 98
98 99 @receiver(post_save, sender=User)
99 100 def create_user_profile(sender, instance, created, **kwargs):
100 101 if created:
101 102 Profile.objects.create(user=instance)
102 103
103 104 @receiver(post_save, sender=User)
104 105 def save_user_profile(sender, instance, **kwargs):
105 106 instance.profile.save()
106 107
107 108
108 109 class Location(models.Model):
109 110
110 111 name = models.CharField(max_length = 30)
111 112 description = models.TextField(blank=True, null=True)
112 113
113 114 class Meta:
114 115 db_table = 'db_location'
115 116
116 117 def __str__(self):
117 118 return u'%s' % self.name
118 119
119 120 def get_absolute_url(self):
120 121 return reverse('url_location', args=[str(self.id)])
121 122
122 123
123 124 class DeviceType(models.Model):
124 125
125 126 name = models.CharField(max_length = 10, choices = DEV_TYPES, default = 'dds_rest')
126 127 sequence = models.PositiveSmallIntegerField(default=55)
127 128 description = models.TextField(blank=True, null=True)
128 129
129 130 class Meta:
130 131 db_table = 'db_device_types'
131 132
132 133 def __str__(self):
133 134 return u'%s' % self.get_name_display()
134 135
135 136 class Device(models.Model):
136 137
137 138 device_type = models.ForeignKey('DeviceType', on_delete=models.CASCADE)
138 139 location = models.ForeignKey('Location', on_delete=models.CASCADE)
139 140 ip_address = models.GenericIPAddressField(protocol='IPv4', default='0.0.0.0')
140 141 port_address = models.PositiveSmallIntegerField(default=2000)
141 142 description = models.TextField(blank=True, null=True)
142 143 status = models.PositiveSmallIntegerField(default=4, choices=DEV_STATES)
143 144 conf_active = models.PositiveIntegerField(default=0, verbose_name='Current configuration')
144 145
145 146 class Meta:
146 147 db_table = 'db_devices'
147 148
148 149 def __str__(self):
149 150 ret = u'{} [{}]'.format(self.device_type.name.upper(), self.location.name)
150 151
151 152 return ret
152 153
153 154 @property
154 155 def name(self):
155 156 return str(self)
156 157
157 158 def get_status(self):
158 159 return self.status
159 160
160 161 @property
161 162 def status_color(self):
162 163 color = 'muted'
163 164 if self.status == 0:
164 165 color = "danger"
165 166 elif self.status == 1:
166 167 color = "warning"
167 168 elif self.status == 2:
168 169 color = "info"
169 170 elif self.status == 3:
170 171 color = "success"
171 172
172 173 return color
173 174
174 175 def url(self, path=None):
175 176
176 177 if path:
177 178 return 'http://{}:{}/{}/'.format(self.ip_address, self.port_address, path)
178 179 else:
179 180 return 'http://{}:{}/'.format(self.ip_address, self.port_address)
180 181
181 182 def get_absolute_url(self):
182 183 return reverse('url_device', args=[str(self.id)])
183 184
184 185 def get_absolute_url_edit(self):
185 186 return reverse('url_edit_device', args=[str(self.id)])
186 187
187 188 def get_absolute_url_delete(self):
188 189 return reverse('url_delete_device', args=[str(self.id)])
189 190
190 191 def change_ip(self, ip_address, mask, gateway, dns, **kwargs):
191 192
192 193 if self.device_type.name=='dds':
193 194 try:
194 195 answer = dds_api.change_ip(ip = self.ip_address,
195 196 port = self.port_address,
196 197 new_ip = ip_address,
197 198 mask = mask,
198 199 gateway = gateway)
199 200 if answer[0]=='1':
200 201 self.message = '25|DDS - {}'.format(answer)
201 202 self.ip_address = ip_address
202 203 self.save()
203 204 else:
204 205 self.message = '30|DDS - {}'.format(answer)
205 206 return False
206 207 except Exception as e:
207 208 self.message = '40|{}'.format(str(e))
208 209 return False
209 210
210 211 elif self.device_type.name=='rc':
211 212 headers = {'content-type': "application/json",
212 213 'cache-control': "no-cache"}
213 214
214 215 ip = [int(x) for x in ip_address.split('.')]
215 216 dns = [int(x) for x in dns.split('.')]
216 217 gateway = [int(x) for x in gateway.split('.')]
217 218 subnet = [int(x) for x in mask.split('.')]
218 219
219 220 payload = {
220 221 "ip": ip,
221 222 "dns": dns,
222 223 "gateway": gateway,
223 224 "subnet": subnet
224 225 }
225 226
226 227 req = requests.post(self.url('changeip'), data=json.dumps(payload), headers=headers)
227 228 try:
228 229 answer = req.json()
229 230 if answer['changeip']=='ok':
230 231 self.message = '25|IP succesfully changed'
231 232 self.ip_address = ip_address
232 233 self.save()
233 234 else:
234 235 self.message = '30|An error ocuur when changing IP'
235 236 except Exception as e:
236 237 self.message = '40|{}'.format(str(e))
237 238 else:
238 239 self.message = 'Not implemented'
239 240 return False
240 241
241 242 return True
242 243
243 244
244 245 class Campaign(models.Model):
245 246
246 247 template = models.BooleanField(default=False)
247 248 name = models.CharField(max_length=60, unique=True)
248 249 start_date = models.DateTimeField(blank=True, null=True)
249 250 end_date = models.DateTimeField(blank=True, null=True)
250 251 tags = models.CharField(max_length=40, blank=True, null=True)
251 252 description = models.TextField(blank=True, null=True)
252 253 experiments = models.ManyToManyField('Experiment', blank=True)
253 254 author = models.ForeignKey(User, null=True, blank=True,on_delete=models.CASCADE)
254 255
255 256 class Meta:
256 257 db_table = 'db_campaigns'
257 258 ordering = ('name',)
258 259
259 260 def __str__(self):
260 261 if self.template:
261 262 return u'{} (template)'.format(self.name)
262 263 else:
263 264 return u'{}'.format(self.name)
264 265
265 266 def jsonify(self):
266 267
267 268 data = {}
268 269
269 270 ignored = ('template')
270 271
271 272 for field in self._meta.fields:
272 273 if field.name in ignored:
273 274 continue
274 275 data[field.name] = field.value_from_object(self)
275 276
276 277 data['start_date'] = data['start_date'].strftime('%Y-%m-%d')
277 278 data['end_date'] = data['end_date'].strftime('%Y-%m-%d')
278 279
279 280 return data
280 281
281 282 def parms_to_dict(self):
282 283
283 284 params = Params({})
284 285 params.add(self.jsonify(), 'campaigns')
285 286
286 287 for exp in Experiment.objects.filter(campaign = self):
287 288 params.add(exp.jsonify(), 'experiments')
288 289 configurations = Configuration.objects.filter(experiment=exp, type=0)
289 290
290 291 for conf in configurations:
291 292 params.add(conf.jsonify(), 'configurations')
292 293 if conf.device.device_type.name=='rc':
293 294 for line in conf.get_lines():
294 295 params.add(line.jsonify(), 'lines')
295 296
296 297 return params.data
297 298
298 299 def dict_to_parms(self, parms, CONF_MODELS):
299 300
300 301 experiments = Experiment.objects.filter(campaign = self)
301 302
302 303 if experiments:
303 304 for experiment in experiments:
304 305 experiment.delete()
305 306
306 307 for id_exp in parms['experiments']['allIds']:
307 308 exp_parms = parms['experiments']['byId'][id_exp]
308 309 dum = (datetime.now() - datetime(1970, 1, 1)).total_seconds()
309 310 exp = Experiment(name='{}'.format(dum))
310 311 exp.save()
311 312 exp.dict_to_parms(parms, CONF_MODELS, id_exp=id_exp)
312 313 self.experiments.add(exp)
313 314
314 315 camp_parms = parms['campaigns']['byId'][parms['campaigns']['allIds'][0]]
315 316
316 317 self.name = '{}-{}'.format(camp_parms['name'], datetime.now().strftime('%y%m%d'))
317 318 self.start_date = camp_parms['start_date']
318 319 self.end_date = camp_parms['end_date']
319 320 self.tags = camp_parms['tags']
320 321 self.save()
321 322
322 323 return self
323 324
324 325 def get_experiments_by_radar(self, radar=None):
325 326
326 327 ret = []
327 328 if radar:
328 329 locations = Location.objects.filter(pk=radar)
329 330 else:
330 331 locations = set([e.location for e in self.experiments.all()])
331 332
332 333 for loc in locations:
333 334 dum = {}
334 335 dum['name'] = loc.name
335 336 dum['id'] = loc.pk
336 337 dum['experiments'] = [e for e in self.experiments.all() if e.location==loc]
337 338 ret.append(dum)
338 339 return ret
339 340
340 341 def get_absolute_url(self):
341 342 return reverse('url_campaign', args=[str(self.id)])
342 343
343 344 def get_absolute_url_edit(self):
344 345 return reverse('url_edit_campaign', args=[str(self.id)])
345 346
346 347 def get_absolute_url_delete(self):
347 348 return reverse('url_delete_campaign', args=[str(self.id)])
348 349
349 350 def get_absolute_url_export(self):
350 351 return reverse('url_export_campaign', args=[str(self.id)])
351 352
352 353 def get_absolute_url_import(self):
353 354 return reverse('url_import_campaign', args=[str(self.id)])
354 355
355 356
356 357 class RunningExperiment(models.Model):
357 358 radar = models.OneToOneField('Location', on_delete=models.CASCADE)
358 359 running_experiment = models.ManyToManyField('Experiment', blank = True)
359 360 status = models.PositiveSmallIntegerField(default=0, choices=RADAR_STATES)
360 361
361 362
362 363 class Experiment(models.Model):
363 364
364 365 template = models.BooleanField(default=False)
365 366 name = models.CharField(max_length=40, default='', unique=True)
366 367 location = models.ForeignKey('Location', null=True, blank=True, on_delete=models.CASCADE)
367 368 freq = models.FloatField(verbose_name='Operating Freq. (MHz)', validators=[MinValueValidator(1), MaxValueValidator(10000)], default=49.9200)
368 369 start_time = models.TimeField(default='00:00:00')
369 370 end_time = models.TimeField(default='23:59:59')
370 371 task = models.CharField(max_length=36, default='', blank=True, null=True)
371 372 status = models.PositiveSmallIntegerField(default=4, choices=EXP_STATES)
372 373 author = models.ForeignKey(User, null=True, blank=True,on_delete=models.CASCADE)
373 374 hash = models.CharField(default='', max_length=64, null=True, blank=True)
374 375
375 376 class Meta:
376 377 db_table = 'db_experiments'
377 378 ordering = ('template', 'name')
378 379
379 380 def __str__(self):
380 381 if self.template:
381 382 return u'%s (template)' % (self.name)
382 383 else:
383 384 return u'%s' % (self.name)
384 385
385 386 def jsonify(self):
386 387
387 388 data = {}
388 389
389 390 ignored = ('template')
390 391
391 392 for field in self._meta.fields:
392 393 if field.name in ignored:
393 394 continue
394 395 data[field.name] = field.value_from_object(self)
395 396
396 397 data['start_time'] = data['start_time'].strftime('%H:%M:%S')
397 398 data['end_time'] = data['end_time'].strftime('%H:%M:%S')
398 399 data['location'] = self.location.name
399 400 data['configurations'] = ['{}'.format(conf.pk) for
400 401 conf in Configuration.objects.filter(experiment=self, type=0)]
401 402
402 403 return data
403 404
404 405 @property
405 406 def radar_system(self):
406 407 return self.location
407 408
408 409 def clone(self, **kwargs):
409 410
410 411 confs = Configuration.objects.filter(experiment=self, type=0)
411 412 self.pk = None
412 413 self.name = '{}_{:%y%m%d%H%M%S}'.format(self.name, datetime.now())
413 414 for attr, value in kwargs.items():
414 415 setattr(self, attr, value)
415 416
416 417 self.save()
417 418
418 419 for conf in confs:
419 420 conf.clone(experiment=self, template=False)
420 421
421 422 return self
422 423
423 424 def start(self):
424 425 '''
425 426 Configure and start experiments's devices
426 427 ABS-CGS-DDS-RC-JARS
427 428 '''
428 429 self.status=5 #Busy
429 430 self.save()
430 # print("Guardando STATUS: {}".format(self.status))
431 print("Realizando operaciΓ³n. \nEXPERIMENT STATUS : {}".format(self.status))
431 432
432 433 confs = []
433 434 allconfs = Configuration.objects.filter(experiment=self, type = 0).order_by('-device__device_type__sequence')
434 435 rc_mix = [conf for conf in allconfs if conf.device.device_type.name=='rc' and conf.mix]
435 436 if rc_mix:
436 437 for conf in allconfs:
437 438 if conf.device.device_type.name == 'rc' and not conf.mix:
438 439 continue
439 440 confs.append(conf)
440 441 else:
441 442 confs = allconfs
442 443
443 444
444 445 for conf in confs:
445 print("conf->",conf)
446 print(conf.device)
447 print(conf.device.status)
448 446 print("--------------",flush=True)
447 print("STATUS: {}".format(conf.device.status))
449 448 print("Stop ",conf.name,flush=True)
450 449 if conf.stop_device() ==False:
451 450 print("FallΓ³ Stop ",conf.name)
452 451 print("Cancelando CampaΓ±a...",flush=True)
453 452 return 0
454 453 print("Write ",conf.name,flush=True)
455 454 if conf.write_device() ==False:
456 455 print("FallΓ³ Write ",conf.name)
457 456 print("Cancelando CampaΓ±a...",flush=True)
458 457 return 0
459 458 print("Save",conf.name,flush=True)
460 459 conf.device.conf_active = conf.pk
461 460 conf.device.save()
462 461 print("Start",conf.name,flush=True)
463 462 if conf.start_device()==False:
464 463 print("FallΓ³ Start ",conf.name)
465 464 print("Cancelando CampaΓ±a...",flush=True)
466 465 return 0
467 466 print("--- CONFIGURACIΓ“N EXITOSA ---",flush=True)
468 467 time.sleep(1)
469 468
470 469 return 2
471 470
472 471
473 472 def stop(self):
474 473 '''
475 474 Stop experiments's devices
476 475 DDS-JARS-RC-CGS-ABS
477 476 '''
478 477
479 478 confs = Configuration.objects.filter(experiment=self, type = 0).order_by('device__device_type__sequence')
480 479 confs = confs.exclude(device__device_type__name='cgs')
481 480 try:
482 481 for conf in confs:
483 482 conf.stop_device()
484 483 except:
485 484 return 0
486 485 return 1
487 486
488 487 def get_status(self):
489 488
490 489 if self.status == 3:
491 490 return
492 491
493 492 confs = Configuration.objects.filter(experiment=self, type=0)
494 493
495 494 for conf in confs:
496 495 conf.status_device()
497 496
498 497 total = confs.aggregate(models.Sum('device__status'))['device__status__sum']
499 498
500 499 if total==2*confs.count():
501 500 status = 1
502 501 elif total == 3*confs.count():
503 502 status = 2
504 503 else:
505 504 status = 0
506 505
507 506 self.status = status
508 507 self.save()
509 508
510 509 def status_color(self):
511 510 color = 'muted'
512 511 if self.status == 0:
513 512 color = "danger"
514 513 elif self.status == 1:
515 514 color = "warning"
516 515 elif self.status == 2:
517 516 color = "success"
518 517 elif self.status == 3:
519 518 color = "info"
520 519
521 520 return color
522 521
523 522 def parms_to_dict(self):
524 523
525 524 params = Params({})
526 525 params.add(self.jsonify(), 'experiments')
527 526
528 527 configurations = Configuration.objects.filter(experiment=self, type=0)
529 528
530 529 for conf in configurations:
531 530 params.add(conf.jsonify(), 'configurations')
532 531 if conf.device.device_type.name=='rc':
533 532 for line in conf.get_lines():
534 533 params.add(line.jsonify(), 'lines')
535 534
536 535 return params.data
537 536
538 537 def dict_to_parms(self, parms, CONF_MODELS, id_exp=None):
539 538
540 539 configurations = Configuration.objects.filter(experiment=self)
541 540
542 541 if id_exp is not None:
543 542 exp_parms = parms['experiments']['byId'][id_exp]
544 543 else:
545 544 exp_parms = parms['experiments']['byId'][parms['experiments']['allIds'][0]]
546 545
547 546 if configurations:
548 547 for configuration in configurations:
549 548 configuration.delete()
550 549
551 550 for id_conf in exp_parms['configurations']:
552 551 conf_parms = parms['configurations']['byId'][id_conf]
553 552 device = Device.objects.filter(device_type__name=conf_parms['device_type'])[0]
554 553 model = CONF_MODELS[conf_parms['device_type']]
555 554 conf = model(
556 555 experiment = self,
557 556 device = device,
558 557 )
559 558 conf.dict_to_parms(parms, id=id_conf)
560 559
561 560
562 561 location, created = Location.objects.get_or_create(name=exp_parms['location'])
563 562 self.name = '{}-{}'.format(exp_parms['name'], datetime.now().strftime('%y%m%d'))
564 563 self.location = location
565 564 self.start_time = exp_parms['start_time']
566 565 self.end_time = exp_parms['end_time']
567 566 self.save()
568 567
569 568 return self
570 569
571 570 def get_absolute_url(self):
572 571 return reverse('url_experiment', args=[str(self.id)])
573 572
574 573 def get_absolute_url_edit(self):
575 574 return reverse('url_edit_experiment', args=[str(self.id)])
576 575
577 576 def get_absolute_url_delete(self):
578 577 return reverse('url_delete_experiment', args=[str(self.id)])
579 578
580 579 def get_absolute_url_import(self):
581 580 return reverse('url_import_experiment', args=[str(self.id)])
582 581
583 582 def get_absolute_url_export(self):
584 583 return reverse('url_export_experiment', args=[str(self.id)])
585 584
586 585 def get_absolute_url_start(self):
587 586 return reverse('url_start_experiment', args=[str(self.id)])
588 587
589 588 def get_absolute_url_stop(self):
590 589 return reverse('url_stop_experiment', args=[str(self.id)])
591 590
592 591
593 592 class Configuration(PolymorphicModel):
594 593
595 594 template = models.BooleanField(default=False)
596 595 # name = models.CharField(verbose_name="Configuration Name", max_length=40, default='')
597 596 device = models.ForeignKey('Device', verbose_name='Device', null=True, on_delete=models.CASCADE)
598 597 label = models.CharField(verbose_name="Label", max_length=40, default='', blank=True, null=True)
599 598 experiment = models.ForeignKey('Experiment', verbose_name='Experiment', null=True, blank=True, on_delete=models.CASCADE)
600 599 type = models.PositiveSmallIntegerField(default=0, choices=CONF_TYPES)
601 600 created_date = models.DateTimeField(auto_now_add=True)
602 601 programmed_date = models.DateTimeField(auto_now=True)
603 602 parameters = models.TextField(default='{}')
604 603 author = models.ForeignKey(User, null=True, blank=True,on_delete=models.CASCADE)
605 604 hash = models.CharField(default='', max_length=64, null=True, blank=True)
606 605 message = ""
607 606
608 607 class Meta:
609 608 db_table = 'db_configurations'
610 609 ordering = ('device__device_type__name',)
611 610
612 611 def __str__(self):
613 612
614 613 ret = u'{} '.format(self.device.device_type.name.upper())
615 614
616 615 if 'mix' in [f.name for f in self._meta.get_fields()]:
617 616 if self.mix:
618 617 ret = '{} MIX '.format(self.device.device_type.name.upper())
619 618
620 619 if 'label' in [f.name for f in self._meta.get_fields()]:
621 620 ret += '{}'.format(self.label)
622 621
623 622 if self.template:
624 623 ret += ' (template)'
625 624
626 625 return ret
627 626
628 627 @property
629 628 def name(self):
630 629
631 630 return str(self)
632 631
633 632 def jsonify(self):
634 633
635 634 data = {}
636 635
637 636 ignored = ('type', 'polymorphic_ctype', 'configuration_ptr',
638 637 'created_date', 'programmed_date', 'template', 'device',
639 638 'experiment')
640 639
641 640 for field in self._meta.fields:
642 641 if field.name in ignored:
643 642 continue
644 643 data[field.name] = field.value_from_object(self)
645 644
646 645 data['device_type'] = self.device.device_type.name
647 646
648 647 if self.device.device_type.name == 'rc':
649 648 data['lines'] = ['{}'.format(line.pk) for line in self.get_lines()]
650 649 data['delays'] = self.get_delays()
651 650 data['pulses'] = self.get_pulses()
652 651
653 652 elif self.device.device_type.name == 'jars':
654 653 data['decode_type'] = DECODE_TYPE[self.decode_data][1]
655 654
656 655 elif self.device.device_type.name == 'dds':
657 656 data['frequencyA_Mhz'] = float(data['frequencyA_Mhz'])
658 657 data['frequencyB_Mhz'] = float(data['frequencyB_Mhz'])
659 658 data['phaseA'] = dds_data.phase_to_binary(data['phaseA_degrees'])
660 659 data['phaseB'] = dds_data.phase_to_binary(data['phaseB_degrees'])
661 660
662 661 elif self.device.device_type.name == 'dds_rest':
663 662 data['frequencyA_Mhz'] = float(data['frequencyA_Mhz'])
664 663 data['frequencyB_Mhz'] = float(data['frequencyB_Mhz'])
665 664 data['phaseA'] = dds_data.phase_to_binary(data['phaseA_degrees'])
666 665 data['phaseB'] = dds_data.phase_to_binary(data['phaseB_degrees'])
667 666 data['delta_frequency_Mhz'] = float(data['delta_frequency_Mhz'] or 0.00)
668 667 data['update_clock_Mhz'] = float(data['update_clock_Mhz'] or 0.00)
669 668 data['ramp_rate_clock_Mhz'] = float(data['ramp_rate_clock_Mhz'] or 0.0)
670 669 return data
671 670
672 671 def clone(self, **kwargs):
673 672
674 673 self.pk = None
675 674 self.id = None
676 675 for attr, value in kwargs.items():
677 676 setattr(self, attr, value)
678 677
679 678 self.save()
680 679
681 680 return self
682 681
683 682 def parms_to_dict(self):
684 683
685 684 params = Params({})
686 685 params.add(self.jsonify(), 'configurations')
687 686
688 687 if self.device.device_type.name=='rc':
689 688 for line in self.get_lines():
690 689 params.add(line.jsonify(), 'lines')
691 690
692 691 return params.data
693 692
694 693 def parms_to_text(self):
695 694
696 695 raise NotImplementedError("This method should be implemented in %s Configuration model" %str(self.device.device_type.name).upper())
697 696
698 697
699 698 def parms_to_binary(self):
700 699
701 700 raise NotImplementedError("This method should be implemented in %s Configuration model" %str(self.device.device_type.name).upper())
702 701
703 702
704 703 def dict_to_parms(self, parameters, id=None):
705 704
706 705 params = Params(parameters)
707 706
708 707 if id:
709 708 data = params.get_conf(id_conf=id)
710 709 else:
711 710 data = params.get_conf(dtype=self.device.device_type.name)
712 711
713 712 if data['device_type']=='rc':
714 713 self.clean_lines()
715 714 lines = data.pop('lines', None)
716 715 for line_id in lines:
717 716 pass
718 717
719 718 for key, value in data.items():
720 719 if key not in ('id', 'device_type'):
721 720 setattr(self, key, value)
722 721
723 722 self.save()
724 723
725 724
726 725 def export_to_file(self, format="json"):
727 726
728 727 content_type = ''
729 728
730 729 if format == 'racp':
731 730 content_type = 'text/plain'
732 731 filename = '%s_%s.%s' %(self.device.device_type.name, self.name, 'racp')
733 732 content = self.parms_to_text(file_format = 'racp')
734 733
735 734 if format == 'text':
736 735 content_type = 'text/plain'
737 736 filename = '%s_%s.%s' %(self.device.device_type.name, self.name, self.device.device_type.name)
738 737 content = self.parms_to_text()
739 738
740 739 if format == 'binary':
741 740 content_type = 'application/octet-stream'
742 741 filename = '%s_%s.bin' %(self.device.device_type.name, self.name)
743 742 content = self.parms_to_binary()
744 743
745 744 if not content_type:
746 745 content_type = 'application/json'
747 746 filename = '%s_%s.json' %(self.device.device_type.name, self.name)
748 747 content = json.dumps(self.parms_to_dict(), indent=2)
749 748
750 749 fields = {'content_type':content_type,
751 750 'filename':filename,
752 751 'content':content
753 752 }
754 753
755 754 return fields
756 755
757 756 def import_from_file(self, fp):
758 757
759 758 parms = {}
760 759
761 760 path, ext = os.path.splitext(fp.name)
762 761
763 762 if ext == '.json':
764 763 parms = json.load(fp)
765 764
766 765 if ext == '.dds':
767 766 lines = fp.readlines()
768 767 parms = dds_data.text_to_dict(lines)
769 768
770 769 if ext == '.racp':
771 770 if self.device.device_type.name == 'jars':
772 771 parms = RacpFile(fp).to_dict()
773 772 parms['filter_parms'] = json.loads(self.filter_parms)
774 773 return parms
775 774 parms = RCFile(fp).to_dict()
776 775
777 776 return parms
778 777
779 778 def status_device(self):
780 779
781 780 self.message = 'Function not implemented'
782 781 return False
783 782
784 783
785 784 def stop_device(self):
786 785
787 786 self.message = 'Function not implemented'
788 787 print("BUENAS SEΓ‘ALES??? NO LO CREO2",flush=True)
789 788 return False
790 789
791 790
792 791 def start_device(self):
793 792
794 793 self.message = 'Function not implemented'
795 794 print("BUENAS SEΓ‘ALES??? NO LO CREO",flush=True)
796 795 return False
797 796
798 797
799 798 def write_device(self, parms):
800 799
801 800 self.message = 'Function not implemented'
802 801 print("BUENAS SEΓ‘ALES??? NO LO CREO3",flush=True)
803 802 return False
804 803
805 804 def write_device_mqtt(self, parms):
806 805
807 806 self.message = 'Function not implemented'
808 807 return False
809 808
810 809 def read_device(self):
811 810
812 811 self.message = 'Function not implemented'
813 812 return False
814 813
815 814
816 815 def get_absolute_url(self):
817 816 return reverse('url_%s_conf' % self.device.device_type.name, args=[str(self.id)])
818 817
819 818 def get_absolute_mqtt_url(self):
819 print("----------------- {} ----------------------".format(self.device.device_type.name),flush=True)
820 820 if self.device.device_type.name=='abs':
821 821 return reverse('url_%s_conf_mqtt' % self.device.device_type.name, args=[str(self.id)])
822 822 else:
823 823 return reverse('url_%s_conf' % self.device.device_type.name, args=[str(self.id)])
824 824
825 825 def get_absolute_url_edit(self):
826 826 return reverse('url_edit_%s_conf' % self.device.device_type.name, args=[str(self.id)])
827 827
828 828 def get_absolute_url_delete(self):
829 829 return reverse('url_delete_dev_conf', args=[str(self.id)])
830 830
831 831 def get_absolute_url_import(self):
832 832 return reverse('url_import_dev_conf', args=[str(self.id)])
833 833
834 834 def get_absolute_url_export(self):
835 835 return reverse('url_export_dev_conf', args=[str(self.id)])
836 836
837 837 def get_absolute_url_write(self):
838 838 return reverse('url_write_dev_conf', args=[str(self.id)])
839 839
840 840 def get_absolute_url_write_mqtt(self):
841 841 return reverse('url_write_mqtt_dev_conf', args=[str(self.id)])
842 842
843 843 def get_absolute_url_read(self):
844 844 return reverse('url_read_dev_conf', args=[str(self.id)])
845 845
846 846 def get_absolute_url_start(self):
847 847 return reverse('url_start_dev_conf', args=[str(self.id)])
848 848
849 849 def get_absolute_url_stop(self):
850 850 return reverse('url_stop_dev_conf', args=[str(self.id)])
851 851
852 852 def get_absolute_url_stop_mqtt(self):
853 853 return reverse('url_stop_mqtt_dev_conf', args=[str(self.id)])
854 854
855 855 def get_absolute_url_status(self):
856 856 return reverse('url_status_dev_conf', args=[str(self.id)])
@@ -1,99 +1,99
1 1 {% extends "base.html" %}
2 2 {% load django_bootstrap5 %}
3 3 {% load static %}
4 4 {% load main_tags %}
5 5
6 6 {% block extra-head %}
7 7 <link href="{% static 'css/bootstrap-datetimepicker.min.css' %}" media="screen" rel="stylesheet">
8 8 {% endblock %}
9 9 {% block content-title %}{{title}}{% endblock %}
10 10 {% block content-suptitle %}{{suptitle}}{% endblock %}
11 11
12 12 {% block content %}
13 13
14 14 {% block content-filter %}
15 15 {% if form %}
16 16 <form class="form" method="get">
17 17 {% bootstrap_form form layout='horizontal' size='md' %}
18 18 <div class="pull-right">
19 19 <br>
20 20 <button type="button" class="btn btn-primary btn-sm" onclick="window.location.replace('?');"><span class="fas fa-sync-alt" aria-hidden="true"></span></button>
21 21 <button type="submit" class="btn btn-primary btn-sm"><span class="fas fa-search" aria-hidden="true"></span></button>
22 22 {% if add_url %}
23 23 <a class="btn btn-sm btn-info" href="{{add_url}}"><span class="fas fa-plus" aria-hidden="true"></span></a>
24 24 {% endif %}
25 25 </div>
26 26 </form>
27 27 {% endif %}
28 28 {% endblock %}
29 29 <div style="clear: both;"></div>
30 30 <br>
31 31 <table class="table table-hover">
32 32 <tr>
33 33 <th>#</th>
34 34 {% for key in keys %}
35 35 {% if key == 'location'%}
36 36 <th>System</th>
37 37 {% else %}
38 38 <th>{{ key|title }}</th>
39 39 {% endif %}
40 40 {% endfor%}
41 41 </tr>
42 42 {% for object in objects %}
43 <tr class="clickable-row" data-href="{{object.get_absolute_mqtt_url}}">
43 <tr class="clickable-row" data-href="{{object.get_absolute_url}}">
44 44 <td>{{ forloop.counter|add:offset }}</td>
45 45 {% for key in keys %}
46 46 {% if key == 'actions' %}
47 47 <td>
48 48 <a class="btn btn-sm btn-danger" href="{{object.get_absolute_url_delete}}"><span class="fas fa-times" aria-hidden="true"></span></a>
49 49 <a class="btn btn-sm btn-primary" href="{{object.get_absolute_url_edit}}"><span class="fa fa-pencil" aria-hidden="true"></span></a>
50 50 </td>
51 51 {% else %}
52 52 <td>{{ object|attr:key }}</td>
53 53 {% endif %}
54 54 {% endfor %}
55 55 </tr>
56 56 {% endfor %}
57 57 </table>
58 58
59 59 <div class="pagination">
60 60 <span class="step-links">
61 61 {% if objects.has_previous %}
62 62 <a href="?page={{ objects.previous_page_number }}&{{q}}"><span class="fas fa-chevron-left" aria-hidden="true"></span></a>
63 63 {% endif %}
64 64 <span class="current">
65 65 Page {{ objects.number }} of {{ objects.paginator.num_pages }}.
66 66 </span>
67 67 {% if objects.has_next %}
68 68 <a href="?page={{ objects.next_page_number }}&{{q}}"><span class="fas fa-chevron-right" aria-hidden="true"></span></a>
69 69 {% endif %}
70 70 </span>
71 71 </div>
72 72
73 73 {% endblock %}
74 74
75 75 {% block extra-js%}
76 76 <script src="{% static 'js/bootstrap-datetimepicker.min.js' %}"></script>
77 77 <script type="text/javascript">
78 78
79 79 $('.input-group.date').datetimepicker({
80 80 format: "YYYY-MM-DD",
81 81 icons: {
82 82 time: 'far fa-clock',
83 83 date: 'far fa-calendar-alt',
84 84 up: 'fas fa-arrow-up',
85 85 down: 'fas fa-arrow-down',
86 86 previous: 'fas fa-chevron-left',
87 87 next: 'fas fa-chevron-right',
88 88 today: 'far fa-calendar-check',
89 89 clear: 'far fa-trash-alt',
90 90 close: 'fas fa-times'
91 91 }
92 92 });
93 93
94 94 $(".clickable-row").click(function() {
95 95 document.location = $(this).data("href");
96 96 });
97 97
98 98 </script>
99 99 {% endblock %}
@@ -1,104 +1,104
1 1 {% extends "base.html" %}
2 2 {% load django_bootstrap5 %}
3 3 {% load static %}
4 4 {% load main_tags %}
5 5 {% block extra-head %}
6 6 <link href="{% static 'css/bootstrap-datetimepicker.min.css' %}" media="screen" rel="stylesheet">
7 7 {% endblock %}
8 8 {% block content-title %}{{title}}{% endblock %}
9 9 {% block content-suptitle %}{{suptitle}}{% endblock %}
10 10
11 11 {% block content %}
12 12
13 13 {% block menu-actions %}
14 14 <span class=" dropdown pull-right">
15 15 <a href="#" class="dropdown-toggle" data-toggle="dropdown"><span class="fas fa-bars" aria-hidden="true"></span></a>
16 16 <ul class="dropdown-menu" role="menu">
17 17 <li><a href="{% url 'url_edit_campaign' campaign.id %}"><span class="fa fa-pencil" aria-hidden="true"></span> Edit</a></li>
18 18 <li><a href="{% url 'url_delete_campaign' campaign.id %}"><span class="fa fa-times" aria-hidden="true"></span> Delete</a></li>
19 19 <li><a href="{{ campaign.get_absolute_url_import }}"><span class="fas fa-cloud-download-alt" aria-hidden="true"></span> Import </a></li>
20 20 <li><a href="{{ campaign.get_absolute_url_export }}"><span class="fas fa-cloud-upload-alt" aria-hidden="true"></span> Export </a></li>
21 21 {% block extra-menu-actions %}
22 22 {% endblock %}
23 23 <li><a>----------------</a></li>
24 24 <!--<li><a href="{{ dev_conf.get_absolute_url_status }}"><span class="glyphicon glyphicon-refresh" aria-hidden="true"></span> Status</a></li>
25 25 {% if not no_play %}
26 26 <li><a href="{{ dev_conf.get_absolute_url_start}}"><span class="glyphicon glyphicon-play" aria-hidden="true"></span> Start</a></li>
27 27 <li><a href="{{ dev_conf.get_absolute_url_stop }}"><span class="glyphicon glyphicon-stop" aria-hidden="true"></span> Stop</a></li>
28 28 {% endif %}
29 29 <li><a href="{{ dev_conf.get_absolute_url_write }}"><span class="glyphicon glyphicon-download" aria-hidden="true"></span> Write</a></li>
30 30 <li><a href="{{ dev_conf.get_absolute_url_read }}"><span class="glyphicon glyphicon-upload" aria-hidden="true"></span> Read</a></li>-->
31 31 </ul>
32 32 </span>
33 33 {% endblock %}
34 34
35 35 <table class="table table-bordered">
36 36 {% for key in campaign_keys %}
37 37 <tr><th>{{key|title}}</th><td>{{campaign|attr:key}}</td></tr>
38 38 {% endfor %}
39 39 </table>
40 40
41 41 <!--<button class="btn btn-primary pull-right" style="margin-left: 10px" id="bt_export">Export</button>-->
42 42 <!--<button class="btn btn-primary pull-right" style="margin-left: 10px" id="bt_edit">Edit</button>-->
43 43
44 44 <br></br>
45 45 <br></br>
46 46
47 47 <div class="panel-group" id="accordion" role="tablist" aria-multiselectable="true">
48 48
49 49 <div class="panel panel-default">
50 50 <div class="panel-heading" role="tab" id="headingTwo">
51 51 <h4 class="panel-title">
52 52 <a class="collapsed" role="button" data-toggle="collapse" data-parent="#accordion" href="#collapseTwo" aria-expanded="false" aria-controls="collapseTwo">
53 53 Experiment List
54 54 </a>
55 55 </h4>
56 56 </div>
57 57
58 58 <div id="collapseTwo" class="panel-collapse collapse in" role="tabpanel" aria-labelledby="headingTwo">
59 59 <div class="panel-body">
60 60 <table class="table table-hover">
61 61 <tr>
62 62 <th>#</th>
63 63 {% for header in experiment_keys %}
64 64 <th>{{ header|title }}</th>
65 65 {% endfor%}
66 66 </tr>
67 67 {% for item in experiments %}
68 <tr class="clickable-row" data-href="{% url 'url_experiment' item.id %}">
68 <tr class="clickable-row" s data-href="{% url 'url_experiment' item.id %}">
69 69 <td>{{ forloop.counter }}</td>
70 70 {% for key in experiment_keys %}
71 71 <td>{{ item|attr:key }}</td>
72 72 {% endfor %}
73 73 </tr>
74 74 {% endfor %}
75 75 </table>
76 76 </div>
77 77 </div>
78 78 </div>
79 79 </div>
80 80 <br>
81 81 <!--<button class="btn btn-primary pull-right" style="margin-left: 10px" id="bt_mix">Mix Experiments</button>-->
82 82 {% endblock %}
83 83
84 84 {% block sidebar%}
85 85 {% include "sidebar_devices.html" %}
86 86 {% endblock %}
87 87
88 88 {% block extra-js%}
89 89 <script type="text/javascript">
90 90
91 91 $(".clickable-row").click(function() {
92 92 document.location = $(this).data("href");
93 93 });
94 94
95 95 // $("#bt_edit").click(function() {
96 96 // document.location = "{% url 'url_edit_campaign' campaign.id %}";
97 97 // });
98 98
99 99 $("#bt_mix").click(function() {
100 100
101 101 });
102 102
103 103 </script>
104 104 {% endblock %}
@@ -1,1051 +1,1054
1 1
2 2
3 3 import ast
4 4 import json
5 5 import requests
6 6 import numpy as np
7 7 from base64 import b64encode
8 8 from struct import pack
9 9
10 10 from django.db import models
11 11 from django.urls import reverse
12 12 from django.core.validators import MinValueValidator, MaxValueValidator
13 13
14 14 from apps.main.models import Configuration
15 15 from apps.main.utils import Params
16 16 from devices.rc import api
17 17 from apps.rc.utils import RCFile
18 18
19 19
20 20 LINE_TYPES = (
21 21 ('none', 'Not used'),
22 22 ('tr', 'Transmission/reception selector signal'),
23 23 ('tx', 'A modulating signal (Transmission pulse)'),
24 24 ('codes', 'BPSK modulating signal'),
25 25 ('windows', 'Sample window signal'),
26 26 ('sync', 'Synchronizing signal'),
27 27 ('flip', 'IPP related periodic signal'),
28 28 ('prog_pulses', 'Programmable pulse'),
29 29 ('mix', 'Mixed line'),
30 30 )
31 31
32 32
33 33 SAMPLING_REFS = (
34 34 ('none', 'No Reference'),
35 35 ('begin_baud', 'Begin of the first baud'),
36 36 ('first_baud', 'Middle of the first baud'),
37 37 ('sub_baud', 'Middle of the sub-baud')
38 38 )
39 39
40 40 DAT_CMDS = {
41 41 # Pulse Design commands
42 42 'DISABLE' : 0, # Disables pulse generation
43 43 'ENABLE' : 24, # Enables pulse generation
44 44 'DELAY_START' : 40, # Write delay status to memory
45 45 'FLIP_START' : 48, # Write flip status to memory
46 46 'SAMPLING_PERIOD' : 64, # Establish Sampling Period
47 47 'TX_ONE' : 72, # Output '0' in line TX
48 48 'TX_ZERO' : 88, # Output '0' in line TX
49 49 'SW_ONE' : 104, # Output '0' in line SW
50 50 'SW_ZERO' : 112, # Output '1' in line SW
51 51 'RESTART': 120, # Restarts CR8 Firmware
52 52 'CONTINUE' : 253, # Function Unknown
53 53 # Commands available to new controllers
54 54 # In Pulse Design Executable, the clock divisor code is written as 12 at the start, but it should be written as code 22(below) just before the final enable.
55 55 'CLOCK_DIVISOR_INIT' : 12, # Specifies Clock Divisor. Legacy command, ignored in the actual .dat conversion
56 56 'CLOCK_DIVISOR_LAST' : 22, # Specifies Clock Divisor (default 60 if not included) syntax: 255,22 254,N-1.
57 57 'CLOCK_DIVIDER' : 8,
58 58 }
59 59
60 60 MAX_BITS = 8
61 61
62 62 # Rotate left: 0b1001 --> 0b0011
63 63 rol = lambda val, r_bits: \
64 64 (val << r_bits%MAX_BITS) & (2**MAX_BITS-1) | \
65 65 ((val & (2**MAX_BITS-1)) >> (MAX_BITS-(r_bits%MAX_BITS)))
66 66
67 67 # Rotate right: 0b1001 --> 0b1100
68 68 ror = lambda val, r_bits: \
69 69 ((val & (2**MAX_BITS-1)) >> r_bits%MAX_BITS) | \
70 70 (val << (MAX_BITS-(r_bits%MAX_BITS)) & (2**MAX_BITS-1))
71 71
72 72
73 73 class RCConfiguration(Configuration):
74 74
75 75 ipp = models.FloatField(verbose_name='IPP [Km]', validators=[MinValueValidator(1)], default=300)
76 76 ntx = models.PositiveIntegerField(verbose_name='Number of TX', validators=[MinValueValidator(1)], default=1)
77 77 clock_in = models.FloatField(verbose_name='Clock in [MHz]', validators=[MinValueValidator(1), MaxValueValidator(80)], default=1)
78 78 clock_divider = models.PositiveIntegerField(verbose_name='Clock divider', validators=[MinValueValidator(1), MaxValueValidator(256)], default=1)
79 79 clock = models.FloatField(verbose_name='Clock Master [MHz]', blank=True, default=1)
80 80 time_before = models.PositiveIntegerField(verbose_name='Time before [&mu;S]', default=12)
81 81 time_after = models.PositiveIntegerField(verbose_name='Time after [&mu;S]', default=1)
82 82 sync = models.PositiveIntegerField(verbose_name='Synchro delay', default=0)
83 83 sampling_reference = models.CharField(verbose_name='Sampling Reference', choices=SAMPLING_REFS, default='none', max_length=40)
84 84 control_tx = models.BooleanField(verbose_name='Control Switch TX', default=False)
85 85 control_sw = models.BooleanField(verbose_name='Control Switch SW', default=False)
86 86 total_units = models.PositiveIntegerField(default=0)
87 87 mix = models.BooleanField(default=False)
88 88
89 89 class Meta:
90 90 db_table = 'rc_configurations'
91 91
92 92 def get_absolute_url_plot(self):
93 93 return reverse('url_plot_rc_pulses', args=[str(self.id)])
94 94
95 95 @property
96 96 def ipp_unit(self):
97 97
98 98 return '{} ({})'.format(self.ipp, int(self.ipp*self.km2unit))
99 99
100 100 @property
101 101 def us2unit(self):
102 102
103 103 return self.clock_in/self.clock_divider
104 104
105 105 @property
106 106 def km2unit(self):
107 107
108 108 return 20./3*(self.clock_in/self.clock_divider)
109 109
110 110 def clone(self, **kwargs):
111 111
112 112 lines = self.get_lines()
113 113 self.pk = None
114 114 self.id = None
115 115 for attr, value in kwargs.items():
116 116 setattr(self, attr, value)
117 117 self.save()
118 118
119 119 for line in lines:
120 120 line.clone(rc_configuration=self)
121 121
122 122 new_lines = self.get_lines()
123 123 for line in new_lines:
124 124 line_params = json.loads(line.params)
125 125 if 'TX_ref' in line_params and (line_params['TX_ref'] != '0'):
126 126 ref_line = RCLine.objects.get(pk=line_params['TX_ref'])
127 127 line_params['TX_ref'] = ['{}'.format(l.pk) for l in new_lines if l.get_name()==ref_line.get_name()][0]
128 128 line.params = json.dumps(line_params)
129 129 line.save()
130 130
131 131 return self
132 132
133 133 def get_lines(self, **kwargs):
134 134 '''
135 135 Retrieve configuration lines
136 136 '''
137 137
138 138 return RCLine.objects.filter(rc_configuration=self.pk, **kwargs)
139 139
140 140
141 141 def clean_lines(self):
142 142 '''
143 143 '''
144 144
145 145 empty_line = RCLineType.objects.get(name='none')
146 146
147 147 for line in self.get_lines():
148 148 line.line_type = empty_line
149 149 line.params = '{}'
150 150 line.save()
151 151
152 152 def dict_to_parms(self, params, id=None):
153 153 '''
154 154 '''
155 155
156 156 if id:
157 157 data = Params(params).get_conf(id_conf=id)
158 158 else:
159 159 data = Params(params).get_conf(dtype='rc')
160 160
161 161 #print(data)
162 162 # self.name = data['name']
163 163 self.ipp = data['ipp']
164 164 self.ntx = data['ntx']
165 165 self.clock_in = data['clock_in']
166 166 self.clock_divider = data['clock_divider']
167 167 self.clock = data['clock']
168 168 self.time_before = data['time_before']
169 169 self.time_after = data['time_after']
170 170 self.sync = data['sync']
171 171 self.sampling_reference = data['sampling_reference']
172 172 self.total_units = self.ipp*self.ntx*self.km2unit
173 173 self.save()
174 174 self.clean_lines()
175 175
176 176 #print(params)
177 177
178 178 positions = {'tx':0, 'tr':0}
179 179 for i, id in enumerate(data['lines']):
180 180 line_data = params['lines']['byId'][id]
181 181 line_type = RCLineType.objects.get(name=line_data['line_type'])
182 182 if line_type.name == 'codes':
183 183 code = RCLineCode.objects.get(name=line_data['params']['code'])
184 184 line_data['params']['code'] = code.pk
185 185 if line_type.name == 'tx':
186 186 position = positions['tx']
187 187 positions['tx'] += 1
188 188 elif line_type.name == 'tr':
189 189 position = positions['tr']
190 190 positions['tr'] += 1
191 191 else:
192 192 position = 0
193 193 line, dum = RCLine.objects.update_or_create(
194 194 rc_configuration=self,
195 195 channel=i,
196 196 position=position,
197 197 defaults={
198 198 'line_type': line_type,
199 199 'params': json.dumps(line_data['params'])
200 200 }
201 201 )
202 202 # print(line,flush=True)
203 203
204 204 for i, line in enumerate(self.get_lines()):
205 205 line_params = json.loads(line.params)
206 206 print("accedimos a dict_to5",flush=True)
207 207 if 'TX_ref' in line_params:
208 208 if line_params['TX_ref'] in (0, '0'):
209 209 line_params['TX_ref'] = '0'
210 210 else:
211 211 ref_id = '{}'.format(line_params['TX_ref'])
212 212 ref_line = params['lines']['byId'][ref_id]
213 213 line_params['TX_ref'] = RCLine.objects.get(
214 214 rc_configuration=self,
215 215 params=json.dumps(ref_line['params'])
216 216 ).pk
217 217 line.params = json.dumps(line_params)
218 218 print(line.params)
219 219 line.save()
220 220 print("Fin de dict to param")
221 221
222 222 def get_delays(self):
223 223
224 224 pulses = [line.pulses_as_points() for line in self.get_lines()]
225 225 points = [tup for tups in pulses for tup in tups]
226 226 points = set([x for tup in points for x in tup])
227 227 points = list(points)
228 228 points.sort()
229 229
230 230 if points[0]!=0:
231 231 points.insert(0, 0)
232 232
233 233 return [points[i+1]-points[i] for i in range(len(points)-1)]
234 234
235 235
236 236 def get_pulses(self, binary=True):
237 237
238 238 pulses = [line.pulses_as_points() for line in self.get_lines()]
239 239 tuples = [tup for tups in pulses for tup in tups]
240 240 points = set([x for tup in tuples for x in tup])
241 241 points = list(points)
242 242 points.sort()
243 243 states = []
244 244 last = [0 for x in pulses]
245 245
246 246 for x in points:
247 247 dum = []
248 248 for i, tups in enumerate(pulses):
249 249 ups = [tup[0] for tup in tups if tup!=(0,0)]
250 250 dws = [tup[1] for tup in tups if tup!=(0,0)]
251 251 if x in ups:
252 252 dum.append(1)
253 253 elif x in dws:
254 254 dum.append(0)
255 255 else:
256 256 dum.append(last[i])
257 257 states.append(dum)
258 258 last = dum
259 259
260 260 if binary:
261 261 ret = []
262 262 for flips in states:
263 263 flips.reverse()
264 264 ret.append(int(''.join([str(x) for x in flips]), 2))
265 265 states = ret
266 266
267 267 return states[:-1]
268 268
269 269 def add_cmd(self, cmd):
270 270
271 271 if cmd in DAT_CMDS:
272 272 return (255, DAT_CMDS[cmd])
273 273
274 274 def add_data(self, value):
275 275
276 276 return (254, value-1)
277 277
278 278 def parms_to_binary(self, dat=True):
279 279 '''
280 280 Create "dat" stream to be send to CR
281 281 '''
282 282
283 283 data = bytearray()
284 284 # create header
285 285 data.extend(self.add_cmd('DISABLE'))
286 286 data.extend(self.add_cmd('CONTINUE'))
287 287 data.extend(self.add_cmd('RESTART'))
288 288
289 289 if self.control_sw:
290 290 data.extend(self.add_cmd('SW_ONE'))
291 291 else:
292 292 data.extend(self.add_cmd('SW_ZERO'))
293 293
294 294 if self.control_tx:
295 295 data.extend(self.add_cmd('TX_ONE'))
296 296 else:
297 297 data.extend(self.add_cmd('TX_ZERO'))
298 298
299 299 # write divider
300 300 data.extend(self.add_cmd('CLOCK_DIVIDER'))
301 301 data.extend(self.add_data(self.clock_divider))
302 302
303 303 # write delays
304 304 data.extend(self.add_cmd('DELAY_START'))
305 305 # first delay is always zero
306 306 data.extend(self.add_data(1))
307 307
308 308 delays = self.get_delays()
309 309
310 310 for delay in delays:
311 311 while delay>252:
312 312 data.extend(self.add_data(253))
313 313 delay -= 253
314 314 data.extend(self.add_data(int(delay)))
315 315
316 316 # write flips
317 317 data.extend(self.add_cmd('FLIP_START'))
318 318
319 319 states = self.get_pulses(binary=True)
320 320
321 321
322 322 last = 0
323 323 for flip, delay in zip(states, delays):
324 324 data.extend(self.add_data((flip^last)+1))
325 325 last = flip
326 326 while delay>252:
327 327 data.extend(self.add_data(1))
328 328 delay -= 253
329 329
330 330 # write sampling period
331 331 data.extend(self.add_cmd('SAMPLING_PERIOD'))
332 332 wins = self.get_lines(line_type__name='windows')
333 333 if wins:
334 334 win_params = json.loads(wins[0].params)['params']
335 335 if win_params:
336 336 dh = int(win_params[0]['resolution']*self.km2unit)
337 337 else:
338 338 dh = 1
339 339 else:
340 340 dh = 1
341 341 data.extend(self.add_data(dh))
342 342
343 343 # write enable
344 344 data.extend(self.add_cmd('ENABLE'))
345 345
346 346 if not dat:
347 347 return data
348 348
349 349 return '\n'.join(['{}'.format(x) for x in data])
350 350
351 351 def update_pulses(self):
352 352 contador = 0
353 353 for line in self.get_lines():
354 354 contador=contador+1
355 355 print(contador)
356 356 line.update_pulses()
357 357
358 358 def plot_pulses2(self, km=False):
359 359
360 360 import matplotlib
361 361 matplotlib.use('Agg')
362 362 import matplotlib.pyplot as plt
363 363 from bokeh.resources import CDN
364 364 from bokeh.embed import components
365 365 from bokeh.mpl import to_bokeh
366 366 from bokeh.models.tools import WheelZoomTool, ResetTool, PanTool, HoverTool, SaveTool
367 367
368 368 lines = self.get_lines()
369 369
370 370 N = len(lines)
371 371 npoints = self.total_units/self.km2unit if km else self.total_units
372 372 fig = plt.figure(figsize=(12, 2+N*0.5))
373 373 ax = fig.add_subplot(111)
374 374 labels = ['IPP']
375 375
376 376 for i, line in enumerate(lines):
377 377 labels.append(line.get_name(channel=True))
378 378 l = ax.plot((0, npoints),(N-i-1, N-i-1))
379 379 points = [(tup[0], tup[1]-tup[0]) for tup in line.pulses_as_points(km=km) if tup!=(0,0)]
380 380 ax.broken_barh(points, (N-i-1, 0.5),
381 381 edgecolor=l[0].get_color(), facecolor='none')
382 382
383 383 n = 0
384 384 f = ((self.ntx+50)/100)*5 if ((self.ntx+50)/100)*10>0 else 2
385 385 for x in np.arange(0, npoints, self.ipp if km else self.ipp*self.km2unit):
386 386 if n%f==0:
387 387 ax.text(x, N, '%s' % n, size=10)
388 388 n += 1
389 389
390 390 labels.reverse()
391 391 ax.set_yticks(range(len(labels)))
392 392 ax.set_yticklabels(labels)
393 393 ax.set_xlabel = 'Units'
394 394 plot = to_bokeh(fig, use_pandas=False)
395 395 plot.tools = [PanTool(dimensions="width"), WheelZoomTool(dimensions="width"), ResetTool(), SaveTool()]
396 396 plot.toolbar_location="above"
397 397
398 398 return components(plot, CDN)
399 399
400 400 def plot_pulses(self, km=False):
401 401
402 402 from bokeh.plotting import figure
403 403 from bokeh.resources import CDN
404 404 from bokeh.embed import components
405 405 from bokeh.models import FixedTicker, PrintfTickFormatter
406 406 from bokeh.models.tools import WheelZoomTool, ResetTool, PanTool, HoverTool, SaveTool
407 407 from bokeh.models.sources import ColumnDataSource
408 408
409 409 lines = self.get_lines().reverse()
410 410
411 411 N = len(lines)
412 412 npoints = self.total_units/self.km2unit if km else self.total_units
413 413 ipp = self.ipp if km else self.ipp*self.km2unit
414 414
415 415 hover = HoverTool(tooltips=[("Line", "@name"),
416 416 ("IPP", "@ipp"),
417 417 ("X", "@left")])
418 418
419 419 tools = [PanTool(dimensions="width"),
420 420 WheelZoomTool(dimensions="width"),
421 421 hover, SaveTool()]
422 422
423 423 plot = figure(width=1000,
424 424 height=40+N*50,
425 425 y_range = (0, N),
426 426 tools=tools,
427 427 toolbar_location='above',
428 428 toolbar_sticky=False,)
429 429
430 430 plot.xaxis.axis_label = 'Km' if km else 'Units'
431 431 plot.xaxis[0].formatter = PrintfTickFormatter(format='%d')
432 432 plot.yaxis.axis_label = 'Pulses'
433 433 plot.yaxis[0].ticker=FixedTicker(ticks=list(range(N)))
434 434 plot.yaxis[0].formatter = PrintfTickFormatter(format='Line %d')
435 435
436 436 for i, line in enumerate(lines):
437 437
438 438 points = [tup for tup in line.pulses_as_points(km=km) if tup!=(0,0)]
439 439
440 440 source = ColumnDataSource(data = dict(
441 441 bottom = [i for tup in points],
442 442 top = [i+0.5 for tup in points],
443 443 left = [tup[0] for tup in points],
444 444 right = [tup[1] for tup in points],
445 445 ipp = [int(tup[0]/ipp) for tup in points],
446 446 name = [line.get_name() for tup in points]
447 447 ))
448 448
449 449 plot.quad(
450 450 bottom = 'bottom',
451 451 top = 'top',
452 452 left = 'left',
453 453 right = 'right',
454 454 source = source,
455 455 fill_alpha = 0,
456 456 #line_color = 'blue',
457 457 )
458 458
459 459 plot.line([0, npoints], [i, i])#, color='blue')
460 460
461 461 return components(plot, CDN)
462 462
463 463 def request(self, cmd, method='get', **kwargs):
464 464
465 465 req = getattr(requests, method)(self.device.url(cmd), **kwargs)
466 466 payload = req.json()
467 467
468 468 return payload
469 469
470 470 def status_device(self):
471 471
472 472 try:
473 473 self.device.status = 0
474 474 payload = self.request('status')
475 475 if payload['status']=='enable':
476 476 self.device.status = 3
477 477 elif payload['status']=='disable':
478 478 self.device.status = 2
479 479 else:
480 480 self.device.status = 1
481 481 self.device.save()
482 482 self.message = 'RC status: {}'.format(payload['status'])
483 483 return False
484 484 except Exception as e:
485 485 if 'No route to host' not in str(e):
486 486 self.device.status = 4
487 487 self.device.save()
488 488 self.message = 'RC status: {}'.format(str(e))
489 489 return False
490 490
491 491 self.device.save()
492 492 return True
493 493
494 494 def reset_device(self):
495 495
496 496 try:
497 497 payload = self.request('reset', 'post')
498 498 if payload['reset']=='ok':
499 499 self.message = 'RC restarted OK'
500 500 self.device.status = 2
501 501 self.device.save()
502 502 else:
503 503 self.message = 'RC restart fail'
504 504 self.device.status = 4
505 505 self.device.save()
506 506 except Exception as e:
507 507 self.message = 'RC reset: {}'.format(str(e))
508 508 return False
509 509
510 510 return True
511 511
512 512 def stop_device(self):
513
513 # Se crea el modo ocupado para una vez inicia el STOP
514 self.device.status = 5
515 self.device.save()
516 # Por si se demora deteniendo, que su estado sea busy
514 517 try:
515 518 payload = self.request('stop', 'post')
516 519 self.message = 'RC stop: {}'.format(payload['stop'])
517 520 if payload['stop']=='ok':
518 521 self.device.status = 2
519 522 self.device.save()
520 523 else:
521 524 self.device.status = 4
522 525 self.device.save()
523 526 return False
524 527 except Exception as e:
525 528 if 'No route to host' not in str(e):
526 529 self.device.status = 4
527 530 else:
528 531 self.device.status = 0
529 532 self.message = 'RC stop: {}'.format(str(e))
530 533 self.device.save()
531 534 return False
532 535
533 536 return True
534 537
535 538 def start_device(self):
536 539
537 540 try:
538 541 payload = self.request('start', 'post')
539 542 self.message = 'RC start: {}'.format(payload['start'])
540 543 if payload['start']=='ok':
541 544 self.device.status = 3
542 545 self.device.save()
543 546 else:
544 547 return False
545 548 except Exception as e:
546 549 if 'No route to host' not in str(e):
547 550 self.device.status = 4
548 551 else:
549 552 self.device.status = 0
550 553 self.message = 'RC start: {}'.format(str(e))
551 554 self.device.save()
552 555 return False
553 556
554 557 return True
555 558
556 559 def write_device(self, raw=False):
557 560 print("write device",flush=True)
558 561
559 562 if not raw:
560 563 clock = RCClock.objects.get(rc_configuration=self)
561 564 if clock.mode:
562 565 data = {'default': clock.frequency}
563 566 else:
564 567 data = {'manual': [clock.multiplier, clock.divisor, clock.reference]}
565 568 payload = self.request('setfreq', 'post', data=json.dumps(data))
566 569 # print(payload)
567 570 if payload['command'] != 'ok':
568 571 self.message = 'RC write: {}'.format(payload['command'])
569 572 # print('RC write: {}'.format(payload['command']))
570 573 else:
571 574 self.message = payload['programming']
572 575 if payload['programming'] == 'fail':
573 576 self.message = 'RC write: error programming CGS chip'
574 577
575 578 values = []
576 579 for pulse, delay in zip(self.get_pulses(), self.get_delays()):
577 580 while delay > 65536:
578 581 values.append((pulse, 65535))
579 582 delay -= 65536
580 583 values.append((pulse, delay-1))
581 584 data = bytearray()
582 585 #reset
583 586 data.extend((128, 0))
584 587 #disable
585 588 data.extend((129, 0))
586 589 #SW switch
587 590 if self.control_sw:
588 591 data.extend((130, 2))
589 592 else:
590 593 data.extend((130, 0))
591 594 #divider
592 595 data.extend((131, self.clock_divider-1))
593 596 #enable writing
594 597 data.extend((139, 62))
595 598
596 599 last = 0
597 600 for tup in values:
598 601 vals = pack('<HH', last^tup[0], tup[1])
599 602 last = tup[0]
600 603 data.extend((133, vals[1], 132, vals[0], 133, vals[3], 132, vals[2]))
601 604
602 605 #enable
603 606 data.extend((129, 1))
604 607
605 608 if raw:
606 609 return b64encode(data)
607 610
608 611 #try:
609 612 payload = self.request('stop', 'post')
610 613 payload = self.request('reset', 'post')
611 614 #payload = self.request('divider', 'post', data={'divider': self.clock_divider-1})
612 615 #payload = self.request('write', 'post', data=b64encode(bytearray((139, 62))), timeout=20)
613 616 n = len(data)
614 617 x = 0
615 618 #while x < n:
616 619 payload = self.request('write', 'post', data=b64encode(data))
617 620 # x += 1024
618 621
619 622 if payload['write']=='ok':
620 623 self.device.status = 3
621 624 self.device.save()
622 625 self.message = 'RC configured and started'
623 626 # print('RC configured and started')
624 627 else:
625 628 self.device.status = 1
626 629 self.device.save()
627 630 self.message = 'RC write: {}'.format(payload['write'])
628 631 # print('RC write: {}'.format(payload['write']))
629 632 return False
630 633
631 634 #payload = self.request('start', 'post')
632 635
633 636 #except Exception as e:
634 637 # if 'No route to host' not in str(e):
635 638 # self.device.status = 4
636 639 # else:
637 640 # self.device.status = 0
638 641 # self.message = 'RC write: {}'.format(str(e))
639 642 # self.device.save()
640 643 # return False
641 644
642 645 return True
643 646
644 647
645 648 def get_absolute_url_import(self):
646 649 return reverse('url_import_rc_conf', args=[str(self.id)])
647 650
648 651
649 652 class RCLineCode(models.Model):
650 653
651 654 name = models.CharField(max_length=40)
652 655 bits_per_code = models.PositiveIntegerField(default=0)
653 656 number_of_codes = models.PositiveIntegerField(default=0)
654 657 codes = models.TextField(blank=True, null=True)
655 658
656 659 class Meta:
657 660 db_table = 'rc_line_codes'
658 661 ordering = ('name',)
659 662
660 663 def __str__(self):
661 664 return u'%s' % self.name
662 665
663 666
664 667 class RCLineType(models.Model):
665 668
666 669 name = models.CharField(choices=LINE_TYPES, max_length=40)
667 670 description = models.TextField(blank=True, null=True)
668 671 params = models.TextField(default='[]')
669 672
670 673 class Meta:
671 674 db_table = 'rc_line_types'
672 675
673 676 def __str__(self):
674 677 return u'%s - %s' % (self.name.upper(), self.get_name_display())
675 678
676 679
677 680 class RCLine(models.Model):
678 681
679 682 rc_configuration = models.ForeignKey('RCConfiguration', on_delete=models.CASCADE)
680 683 line_type = models.ForeignKey('RCLineType',on_delete=models.CASCADE)
681 684 channel = models.PositiveIntegerField(default=0)
682 685 position = models.PositiveIntegerField(default=0)
683 686 params = models.TextField(default='{}')
684 687 pulses = models.TextField(default='')
685 688
686 689 class Meta:
687 690 db_table = 'rc_lines'
688 691 ordering = ['channel']
689 692
690 693 def __str__(self):
691 694 # print("AAAA: ",self.rc_configuration,flush=True)
692 695 # ret = u'{}|{} - {}'.format(self.pk, self.get_name(),self.rc_configuration.name)
693 696 # return ret
694 697 if self.rc_configuration:
695 698 return u'{}|{} - {}'.format(self.pk, self.get_name(), self.rc_configuration.name)
696 699
697 700 def jsonify(self):
698 701
699 702 data = {}
700 703 data['params'] = json.loads(self.params)
701 704 data['id'] = '{}'.format(self.pk)
702 705 data['line_type'] = self.line_type.name
703 706 data['name'] = self.get_name()
704 707 if data['line_type']=='codes':
705 708 data['params']['code'] = RCLineCode.objects.get(pk=data['params']['code']).name
706 709
707 710 return data
708 711
709 712
710 713 def clone(self, **kwargs):
711 714
712 715 self.pk = None
713 716 self.id = None
714 717
715 718 for attr, value in kwargs.items():
716 719 setattr(self, attr, value)
717 720
718 721 self.save()
719 722
720 723 return self
721 724
722 725 def get_name(self, channel=False):
723 726
724 727 chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
725 728 s = ''
726 729
727 730 if self.line_type.name in ('tx',):
728 731 s = chars[self.position]
729 732 elif self.line_type.name in ('codes', 'windows', 'tr'):
730 733 if 'TX_ref' in json.loads(self.params):
731 734 pk = json.loads(self.params)['TX_ref']
732 735 if pk in (0, '0'):
733 736 s = ','.join(chars[l.position] for l in self.rc_configuration.get_lines(line_type__name='tx'))
734 737 else:
735 738 ref = RCLine.objects.get(pk=pk)
736 739 s = chars[ref.position]
737 740 s = '({})'.format(s)
738 741
739 742 s = '{}{}'.format(self.line_type.name.upper(), s)
740 743
741 744 if channel:
742 745 return '{} {}'.format(s, self.channel)
743 746 else:
744 747 return s
745 748
746 749 def get_lines(self, **kwargs):
747 750
748 751 return RCLine.objects.filter(rc_configuration=self.rc_configuration, **kwargs)
749 752
750 753 def pulses_as_array(self):
751 754
752 755 y = np.zeros(self.rc_configuration.total_units)
753 756
754 757 for tup in ast.literal_eval(self.pulses):
755 758 y[tup[0]:tup[1]] = 1
756 759
757 760 return y.astype(np.int8)
758 761
759 762 def pulses_as_points(self, km=False):
760 763
761 764 if km:
762 765 unit2km = 1/self.rc_configuration.km2unit
763 766 return [(tup[0]*unit2km, tup[1]*unit2km) for tup in ast.literal_eval(self.pulses)]
764 767 else:
765 768 return ast.literal_eval(self.pulses)
766 769
767 770 def get_win_ref(self, params, tx_id, km2unit):
768 771
769 772 ref = self.rc_configuration.sampling_reference
770 773 codes = [line for line in self.get_lines(line_type__name='codes') if int(json.loads(line.params)['TX_ref'])==int(tx_id)]
771 774
772 775 if codes:
773 776 tx_width = float(json.loads(RCLine.objects.get(pk=tx_id).params)['pulse_width'])*km2unit/len(json.loads(codes[0].params)['codes'][0])
774 777 else:
775 778 tx_width = float(json.loads(RCLine.objects.get(pk=tx_id).params)['pulse_width'])*km2unit
776 779
777 780 if ref=='first_baud':
778 781 return int(1 + round((tx_width + 1)/2 + params['first_height']*km2unit - params['resolution']*km2unit))
779 782 elif ref=='sub_baud':
780 783 return np.ceil(1 + params['first_height']*km2unit - params['resolution']*km2unit/2)
781 784 else:
782 785 return 0
783 786
784 787 def update_pulses(self):
785 788 '''
786 789 Update pulses field
787 790 '''
788 791
789 792 km2unit = self.rc_configuration.km2unit
790 793 us2unit = self.rc_configuration.us2unit
791 794 ipp = self.rc_configuration.ipp
792 795 ntx = int(self.rc_configuration.ntx)
793 796 ipp_u = int(ipp*km2unit)
794 797 total = ipp_u*ntx if self.rc_configuration.total_units==0 else self.rc_configuration.total_units
795 798 y = []
796 799
797 800 if self.line_type.name=='tr':
798 801 tr_params = json.loads(self.params)
799 802 #print(tr_params)
800 803 #print(tr_params['TX_ref'])
801 804 if tr_params['TX_ref'] in ('0', 0):
802 805 txs = self.get_lines(line_type__name='tx')
803 806 else:
804 807 txs = RCLine.objects.filter(pk=tr_params['TX_ref'])
805 808
806 809 for tx in txs:
807 810 params = json.loads(tx.params)
808 811
809 812 if float(params['pulse_width'])==0:
810 813 continue
811 814 delays = [float(d)*km2unit for d in params['delays'].split(',') if d]
812 815 width = float(params['pulse_width'])*km2unit+int(self.rc_configuration.time_before*us2unit)
813 816 before = 0
814 817 after = int(self.rc_configuration.time_after*us2unit)
815 818
816 819 y_tx = self.points(ntx, ipp_u, width,
817 820 delay=delays,
818 821 before=before,
819 822 after=after,
820 823 sync=self.rc_configuration.sync)
821 824
822 825 ranges = params['range'].split(',')
823 826
824 827 if len(ranges)>0 and ranges[0]!='0':
825 828 y_tx = self.mask_ranges(y_tx, ranges)
826 829
827 830 tr_ranges = tr_params['range'].split(',')
828 831
829 832 if len(tr_ranges)>0 and tr_ranges[0]!='0':
830 833 y_tx = self.mask_ranges(y_tx, tr_ranges)
831 834
832 835 y.extend(y_tx)
833 836
834 837 self.pulses = str(y)
835 838 y = self.array_to_points(self.pulses_as_array())
836 839
837 840 elif self.line_type.name=='tx':
838 841 params = json.loads(self.params)
839 842 delays = [float(d)*km2unit for d in params['delays'].split(',') if d]
840 843 width = float(params['pulse_width'])*km2unit
841 844
842 845 if width>0:
843 846 before = int(self.rc_configuration.time_before*us2unit)
844 847 after = 0
845 848
846 849 y = self.points(ntx, ipp_u, width,
847 850 delay=delays,
848 851 before=before,
849 852 after=after,
850 853 sync=self.rc_configuration.sync)
851 854
852 855 ranges = params['range'].split(',')
853 856
854 857 if len(ranges)>0 and ranges[0]!='0':
855 858 y = self.mask_ranges(y, ranges)
856 859
857 860 elif self.line_type.name=='flip':
858 861 n = float(json.loads(self.params)['number_of_flips'])
859 862 width = n*ipp*km2unit
860 863 y = self.points(int((ntx+1)/(2*n)), ipp_u*n*2, width)
861 864
862 865 elif self.line_type.name=='codes':
863 866 params = json.loads(self.params)
864 867 tx = RCLine.objects.get(pk=params['TX_ref'])
865 868 tx_params = json.loads(tx.params)
866 869 delays = [float(d)*km2unit for d in tx_params['delays'].split(',') if d]
867 870 f = int(float(tx_params['pulse_width'])*km2unit/len(params['codes'][0]))
868 871 codes = [(np.fromstring(''.join([s*f for s in code]), dtype=np.uint8)-48).astype(np.int8) for code in params['codes']]
869 872 codes = [self.array_to_points(code) for code in codes]
870 873 n = len(codes)
871 874
872 875 ranges = tx_params['range'].split(',')
873 876 if len(ranges)>0 and ranges[0]!='0':
874 877 dum = self.mask_ranges(tx.pulses_as_points(), ranges)
875 878 else:
876 879 dum = tx.pulses_as_points()
877 880
878 881 for i, tup in enumerate(dum):
879 882 if tup==(0,0): continue
880 883 code = codes[i%n]
881 884 y.extend([(c[0]+tup[0], c[1]+tup[0]) for c in code])
882 885
883 886 elif self.line_type.name=='sync':
884 887 params = json.loads(self.params)
885 888 n = ipp_u*ntx
886 889 if params['invert'] in ('1', 1):
887 890 y = [(n-1, n)]
888 891 else:
889 892 y = [(0, 1)]
890 893
891 894 elif self.line_type.name=='prog_pulses':
892 895 params = json.loads(self.params)
893 896 if int(params['periodic'])==0:
894 897 nntx = 1
895 898 nipp = ipp_u*ntx
896 899 else:
897 900 nntx = ntx
898 901 nipp = ipp_u
899 902
900 903 if 'params' in params and len(params['params'])>0:
901 904 for p in params['params']:
902 905 y_pp = self.points(nntx, nipp,
903 906 p['end']-p['begin'],
904 907 before=p['begin'])
905 908
906 909 y.extend(y_pp)
907 910
908 911 elif self.line_type.name=='windows':
909 912 params = json.loads(self.params)
910 913 if 'params' in params and len(params['params'])>0:
911 914 tx = RCLine.objects.get(pk=params['TX_ref'])
912 915 tx_params = json.loads(tx.params)
913 916 ranges = tx_params['range'].split(',')
914 917 for p in params['params']:
915 918 y_win = self.points(ntx, ipp_u,
916 919 p['resolution']*p['number_of_samples']*km2unit,
917 920 before=int(self.rc_configuration.time_before*us2unit)+p['first_height']*km2unit,
918 921 sync=self.rc_configuration.sync+self.get_win_ref(p, params['TX_ref'], km2unit))
919 922
920 923
921 924 if len(ranges)>0 and ranges[0]!='0':
922 925 y_win = self.mask_ranges(y_win, ranges)
923 926
924 927 y.extend(y_win)
925 928
926 929 elif self.line_type.name=='mix':
927 930 values = self.rc_configuration.parameters.split('-')
928 931 confs = [RCConfiguration.objects.get(pk=value.split('|')[0]) for value in values]
929 932 modes = [value.split('|')[1] for value in values]
930 933 ops = [value.split('|')[2] for value in values]
931 934 delays = [value.split('|')[3] for value in values]
932 935 masks = [value.split('|')[4] for value in values]
933 936 print("masks")
934 937 print(masks)
935 938 print('{:8b}'.format(int(masks[0])))
936 939 mask = list('{:8b}'.format(int(masks[0])))
937 940 print("mask")
938 941 print(mask)
939 942 mask.reverse()
940 943 print("mask reverse")
941 944 print(mask)
942 945 if mask[self.channel] in ('0', '', ' '):
943 946 y = np.zeros(confs[0].total_units, dtype=np.int8)
944 947 else:
945 948 y = confs[0].get_lines(channel=self.channel)[0].pulses_as_array()
946 949
947 950 for i in range(1, len(values)):
948 951 mask = list('{:8b}'.format(int(masks[i])))
949 952 mask.reverse()
950 953
951 954 if mask[self.channel] in ('0', '', ' '):
952 955 continue
953 956 Y = confs[i].get_lines(channel=self.channel)[0].pulses_as_array()
954 957 delay = float(delays[i])*km2unit
955 958
956 959 if modes[i]=='P':
957 960 if delay>0:
958 961 if delay<self.rc_configuration.ipp*km2unit and len(Y)==len(y):
959 962 y_temp = np.empty_like(Y)
960 963 y_temp[:delay] = 0
961 964 y_temp[delay:] = Y[:-delay]
962 965 elif delay+len(Y)>len(y):
963 966 y_new = np.zeros(delay+len(Y), dtype=np.int8)
964 967 y_new[:len(y)] = y
965 968 y = y_new
966 969 y_temp = np.zeros(delay+len(Y), dtype=np.int8)
967 970 y_temp[-len(Y):] = Y
968 971 elif delay+len(Y)==len(y):
969 972 y_temp = np.zeros(delay+len(Y))
970 973 y_temp[-len(Y):] = Y
971 974 elif delay+len(Y)<len(y):
972 975 y_temp = np.zeros(len(y), dtype=np.int8)
973 976 y_temp[delay:delay+len(Y)] = Y
974 977 else:
975 978 y_temp = Y.copy()
976 979
977 980 if ops[i]=='OR':
978 981 y = y | y_temp
979 982 elif ops[i]=='XOR':
980 983 y = y ^ y_temp
981 984 elif ops[i]=='AND':
982 985 y = y & y_temp
983 986 elif ops[i]=='NAND':
984 987 y = y & ~y_temp
985 988 else:
986 989 y = np.concatenate([y, Y])
987 990
988 991 total = len(y)
989 992 y = self.array_to_points(y)
990 993
991 994 else:
992 995 y = []
993 996
994 997 if self.rc_configuration.total_units != total:
995 998 self.rc_configuration.total_units = total
996 999 self.rc_configuration.save()
997 1000
998 1001 self.pulses = str(y)
999 1002 self.save()
1000 1003
1001 1004 @staticmethod
1002 1005 def array_to_points(X):
1003 1006
1004 1007 if X.size==0:
1005 1008 return []
1006 1009
1007 1010 d = X[1:]-X[:-1]
1008 1011
1009 1012 up = np.where(d==1)[0]
1010 1013 if X[0]==1:
1011 1014 up = np.concatenate((np.array([-1]), up))
1012 1015 up += 1
1013 1016
1014 1017 dw = np.where(d==-1)[0]
1015 1018 if X[-1]==1:
1016 1019 dw = np.concatenate((dw, np.array([len(X)-1])))
1017 1020 dw += 1
1018 1021
1019 1022 return [(tup[0], tup[1]) for tup in zip(up, dw)]
1020 1023
1021 1024 @staticmethod
1022 1025 def mask_ranges(Y, ranges):
1023 1026
1024 1027 y = [(0, 0) for __ in Y]
1025 1028
1026 1029 for index in ranges:
1027 1030 if '-' in index:
1028 1031 args = [int(a) for a in index.split('-')]
1029 1032 y[args[0]-1:args[1]] = Y[args[0]-1:args[1]]
1030 1033 else:
1031 1034 y[int(index)-1] = Y[int(index)-1]
1032 1035
1033 1036 return y
1034 1037
1035 1038 @staticmethod
1036 1039 def points(ntx, ipp, width, delay=[0], before=0, after=0, sync=0):
1037 1040
1038 1041 delays = len(delay)
1039 1042
1040 1043 Y = [(int(ipp*x+before+delay[x%delays]+sync), int(ipp*x+width+before+delay[x%delays]+after+sync)) for x in range(ntx)]
1041 1044
1042 1045 return Y
1043 1046
1044 1047 class RCClock(models.Model):
1045 1048
1046 1049 rc_configuration = models.ForeignKey('RCConfiguration', on_delete=models.CASCADE)
1047 1050 mode = models.BooleanField(default=True, choices=((True, 'Auto'), (False, 'Manual')))
1048 1051 multiplier = models.PositiveIntegerField(default=60)
1049 1052 divisor = models.PositiveIntegerField(default=10)
1050 1053 reference = models.PositiveSmallIntegerField(default=1, choices=((0, 'Internal (25MHz)'), (1, 'External (10MHz)')))
1051 1054 frequency = models.FloatField(default=60.0) No newline at end of file
General Comments 0
You need to be logged in to leave comments. Login now