|
|
from django.shortcuts import render, redirect, get_object_or_404, HttpResponse
|
|
|
from datetime import datetime
|
|
|
|
|
|
from django.db import models
|
|
|
from polymorphic.models import PolymorphicModel
|
|
|
|
|
|
from django.core.urlresolvers import reverse
|
|
|
|
|
|
|
|
|
CONF_STATES = (
|
|
|
(0, 'Disconnected'),
|
|
|
(1, 'Connected'),
|
|
|
(2, 'Running'),
|
|
|
)
|
|
|
|
|
|
EXP_STATES = (
|
|
|
(0,'Error'), #RED
|
|
|
(1,'Configured'), #BLUE
|
|
|
(2,'Running'), #GREEN
|
|
|
(3,'Waiting'), #YELLOW
|
|
|
(4,'Not Configured'), #WHITE
|
|
|
)
|
|
|
|
|
|
CONF_TYPES = (
|
|
|
(0, 'Active'),
|
|
|
(1, 'Historical'),
|
|
|
)
|
|
|
|
|
|
DEV_STATES = (
|
|
|
(0, 'No connected'),
|
|
|
(1, 'Connected'),
|
|
|
(2, 'Configured'),
|
|
|
(3, 'Running'),
|
|
|
)
|
|
|
|
|
|
DEV_TYPES = (
|
|
|
('', 'Select a device type'),
|
|
|
('rc', 'Radar Controller'),
|
|
|
('rc_mix', 'Radar Controller (Mix)'),
|
|
|
('dds', 'Direct Digital Synthesizer'),
|
|
|
('jars', 'Jicamarca Radar Acquisition System'),
|
|
|
('usrp', 'Universal Software Radio Peripheral'),
|
|
|
('cgs', 'Clock Generator System'),
|
|
|
('abs', 'Automatic Beam Switching'),
|
|
|
)
|
|
|
|
|
|
DEV_PORTS = {
|
|
|
'rc' : 2000,
|
|
|
'rc_mix': 2000,
|
|
|
'dds' : 2000,
|
|
|
'jars' : 2000,
|
|
|
'usrp' : 2000,
|
|
|
'cgs' : 8080,
|
|
|
'abs' : 8080
|
|
|
}
|
|
|
|
|
|
RADAR_STATES = (
|
|
|
(0, 'No connected'),
|
|
|
(1, 'Connected'),
|
|
|
(2, 'Configured'),
|
|
|
(3, 'Running'),
|
|
|
(4, 'Scheduled'),
|
|
|
)
|
|
|
# Create your models here.
|
|
|
|
|
|
class Location(models.Model):
|
|
|
|
|
|
name = models.CharField(max_length = 30)
|
|
|
description = models.TextField(blank=True, null=True)
|
|
|
|
|
|
class Meta:
|
|
|
db_table = 'db_location'
|
|
|
|
|
|
def __str__(self):
|
|
|
return u'%s' % self.name
|
|
|
|
|
|
def get_absolute_url(self):
|
|
|
return reverse('url_location', args=[str(self.id)])
|
|
|
|
|
|
|
|
|
class DeviceType(models.Model):
|
|
|
|
|
|
name = models.CharField(max_length = 10, choices = DEV_TYPES, default = 'rc')
|
|
|
description = models.TextField(blank=True, null=True)
|
|
|
|
|
|
class Meta:
|
|
|
db_table = 'db_device_types'
|
|
|
|
|
|
def __str__(self):
|
|
|
return u'%s' % self.get_name_display()
|
|
|
|
|
|
class Device(models.Model):
|
|
|
|
|
|
device_type = models.ForeignKey(DeviceType, on_delete=models.CASCADE)
|
|
|
location = models.ForeignKey(Location, on_delete=models.CASCADE)
|
|
|
|
|
|
name = models.CharField(max_length=40, default='')
|
|
|
ip_address = models.GenericIPAddressField(protocol='IPv4', default='0.0.0.0')
|
|
|
port_address = models.PositiveSmallIntegerField(default=2000)
|
|
|
description = models.TextField(blank=True, null=True)
|
|
|
status = models.PositiveSmallIntegerField(default=0, choices=DEV_STATES)
|
|
|
|
|
|
class Meta:
|
|
|
db_table = 'db_devices'
|
|
|
|
|
|
def __str__(self):
|
|
|
return u'[{}]: {}'.format(self.device_type.name.upper(),
|
|
|
self.name)
|
|
|
|
|
|
def get_status(self):
|
|
|
return self.status
|
|
|
|
|
|
@property
|
|
|
def status_color(self):
|
|
|
color = 'muted'
|
|
|
if self.status == 0:
|
|
|
color = "danger"
|
|
|
elif self.status == 1:
|
|
|
color = "warning"
|
|
|
elif self.status == 2:
|
|
|
color = "info"
|
|
|
elif self.status == 3:
|
|
|
color = "success"
|
|
|
|
|
|
return color
|
|
|
|
|
|
@property
|
|
|
def url(self):
|
|
|
|
|
|
return 'http://{}:{}/'.format(self.ip_address, self.port_address)
|
|
|
|
|
|
def get_absolute_url(self):
|
|
|
return reverse('url_device', args=[str(self.id)])
|
|
|
|
|
|
|
|
|
class Campaign(models.Model):
|
|
|
|
|
|
template = models.BooleanField(default=False)
|
|
|
name = models.CharField(max_length=60, unique=True)
|
|
|
start_date = models.DateTimeField(blank=True, null=True)
|
|
|
end_date = models.DateTimeField(blank=True, null=True)
|
|
|
tags = models.CharField(max_length=40)
|
|
|
description = models.TextField(blank=True, null=True)
|
|
|
experiments = models.ManyToManyField('Experiment', blank=True)
|
|
|
|
|
|
class Meta:
|
|
|
db_table = 'db_campaigns'
|
|
|
ordering = ('name',)
|
|
|
|
|
|
def __str__(self):
|
|
|
if self.template:
|
|
|
return u'{} (template)'.format(self.name)
|
|
|
else:
|
|
|
return u'{}'.format(self.name)
|
|
|
|
|
|
def parms_to_dict(self):
|
|
|
|
|
|
import json
|
|
|
|
|
|
parameters = {}
|
|
|
exp_parameters = {}
|
|
|
experiments = Experiment.objects.filter(campaign = self)
|
|
|
|
|
|
i=1
|
|
|
for experiment in experiments:
|
|
|
exp_parameters['experiment-'+str(i)] = json.loads(experiment.parms_to_dict())
|
|
|
i += 1
|
|
|
|
|
|
|
|
|
parameters['experiments'] = exp_parameters
|
|
|
parameters['end_date'] = self.end_date.strftime("%Y-%m-%d")
|
|
|
parameters['start_date'] = self.start_date.strftime("%Y-%m-%d")
|
|
|
parameters['campaign'] = self.__str__()
|
|
|
parameters['tags'] =self.tags
|
|
|
|
|
|
parameters = json.dumps(parameters, indent=2, sort_keys=False)
|
|
|
|
|
|
return parameters
|
|
|
|
|
|
def import_from_file(self, fp):
|
|
|
|
|
|
import os, json
|
|
|
|
|
|
parms = {}
|
|
|
|
|
|
path, ext = os.path.splitext(fp.name)
|
|
|
|
|
|
if ext == '.json':
|
|
|
parms = json.loads(fp.read())
|
|
|
|
|
|
return parms
|
|
|
|
|
|
def dict_to_parms(self, parms, CONF_MODELS):
|
|
|
|
|
|
experiments = Experiment.objects.filter(campaign = self)
|
|
|
configurations = Configuration.objects.filter(experiment = experiments)
|
|
|
|
|
|
if configurations:
|
|
|
for configuration in configurations:
|
|
|
configuration.delete()
|
|
|
|
|
|
if experiments:
|
|
|
for experiment in experiments:
|
|
|
experiment.delete()
|
|
|
|
|
|
for parms_exp in parms['experiments']:
|
|
|
location = Location.objects.get(name = parms['experiments'][parms_exp]['radar'])
|
|
|
new_exp = Experiment(
|
|
|
name = parms['experiments'][parms_exp]['experiment'],
|
|
|
location = location,
|
|
|
start_time = parms['experiments'][parms_exp]['start_time'],
|
|
|
end_time = parms['experiments'][parms_exp]['end_time'],
|
|
|
)
|
|
|
new_exp.save()
|
|
|
new_exp.dict_to_parms(parms['experiments'][parms_exp],CONF_MODELS)
|
|
|
new_exp.save()
|
|
|
|
|
|
self.name = parms['campaign']
|
|
|
self.start_date = parms['start_date']
|
|
|
self.end_date = parms['end_date']
|
|
|
self.tags = parms['tags']
|
|
|
self.experiments.add(new_exp)
|
|
|
self.save()
|
|
|
|
|
|
return self
|
|
|
|
|
|
def get_experiments_by_location(self):
|
|
|
|
|
|
ret = []
|
|
|
locations = set([e.location for e in self.experiments.all()])
|
|
|
for loc in locations:
|
|
|
dum = {}
|
|
|
dum['name'] = loc.name
|
|
|
dum['id'] = loc.pk
|
|
|
dum['experiments'] = [e for e in self.experiments.all() if e.location==loc]
|
|
|
ret.append(dum)
|
|
|
|
|
|
return ret
|
|
|
|
|
|
def get_absolute_url(self):
|
|
|
return reverse('url_campaign', args=[str(self.id)])
|
|
|
|
|
|
def get_absolute_url_edit(self):
|
|
|
return reverse('url_edit_campaign', args=[str(self.id)])
|
|
|
|
|
|
def get_absolute_url_export(self):
|
|
|
return reverse('url_export_campaign', args=[str(self.id)])
|
|
|
|
|
|
def get_absolute_url_import(self):
|
|
|
return reverse('url_import_campaign', args=[str(self.id)])
|
|
|
|
|
|
|
|
|
|
|
|
class RunningExperiment(models.Model):
|
|
|
radar = models.OneToOneField('Location', on_delete=models.CASCADE)
|
|
|
running_experiment = models.ManyToManyField('Experiment', blank = True)
|
|
|
status = models.PositiveSmallIntegerField(default=0, choices=RADAR_STATES)
|
|
|
|
|
|
|
|
|
class Experiment(models.Model):
|
|
|
|
|
|
template = models.BooleanField(default=False)
|
|
|
name = models.CharField(max_length=40, default='', unique=True)
|
|
|
location = models.ForeignKey('Location', null=True, blank=True, on_delete=models.CASCADE)
|
|
|
start_time = models.TimeField(default='00:00:00')
|
|
|
end_time = models.TimeField(default='23:59:59')
|
|
|
status = models.PositiveSmallIntegerField(default=0, choices=EXP_STATES)
|
|
|
|
|
|
class Meta:
|
|
|
db_table = 'db_experiments'
|
|
|
ordering = ('template', 'name')
|
|
|
|
|
|
def __str__(self):
|
|
|
if self.template:
|
|
|
return u'%s (template)' % (self.name)
|
|
|
else:
|
|
|
return u'%s' % (self.name)
|
|
|
|
|
|
@property
|
|
|
def radar_system(self):
|
|
|
return self.location
|
|
|
|
|
|
def clone(self, **kwargs):
|
|
|
|
|
|
confs = Configuration.objects.filter(experiment=self, type=0)
|
|
|
self.pk = None
|
|
|
self.name = '{} [{:%Y/%m/%d}]'.format(self.name, datetime.now())
|
|
|
for attr, value in kwargs.items():
|
|
|
setattr(self, attr, value)
|
|
|
|
|
|
self.save()
|
|
|
|
|
|
for conf in confs:
|
|
|
conf.clone(experiment=self, template=False)
|
|
|
|
|
|
return self
|
|
|
|
|
|
def get_status(self):
|
|
|
configurations = Configuration.objects.filter(experiment=self)
|
|
|
exp_status=[]
|
|
|
for conf in configurations:
|
|
|
exp_status.append(conf.status_device())
|
|
|
|
|
|
if not exp_status: #No Configuration
|
|
|
self.status = 4
|
|
|
self.save()
|
|
|
return
|
|
|
|
|
|
total = 1
|
|
|
for e_s in exp_status:
|
|
|
total = total*e_s
|
|
|
|
|
|
if total == 0: #Error
|
|
|
status = 0
|
|
|
elif total == (3**len(exp_status)): #Running
|
|
|
status = 2
|
|
|
else:
|
|
|
status = 1 #Configurated
|
|
|
|
|
|
self.status = status
|
|
|
self.save()
|
|
|
|
|
|
def status_color(self):
|
|
|
color = 'muted'
|
|
|
if self.status == 0:
|
|
|
color = "danger"
|
|
|
elif self.status == 1:
|
|
|
color = "info"
|
|
|
elif self.status == 2:
|
|
|
color = "success"
|
|
|
elif self.status == 3:
|
|
|
color = "warning"
|
|
|
|
|
|
return color
|
|
|
|
|
|
def get_absolute_url(self):
|
|
|
return reverse('url_experiment', args=[str(self.id)])
|
|
|
|
|
|
def parms_to_dict(self):
|
|
|
|
|
|
import json
|
|
|
|
|
|
configurations = Configuration.objects.filter(experiment=self)
|
|
|
conf_parameters = {}
|
|
|
parameters={}
|
|
|
|
|
|
for configuration in configurations:
|
|
|
if 'cgs' in configuration.device.device_type.name:
|
|
|
conf_parameters['cgs'] = configuration.parms_to_dict()
|
|
|
if 'dds' in configuration.device.device_type.name:
|
|
|
conf_parameters['dds'] = configuration.parms_to_dict()
|
|
|
if 'rc' in configuration.device.device_type.name:
|
|
|
conf_parameters['rc'] = configuration.parms_to_dict()
|
|
|
if 'jars' in configuration.device.device_type.name:
|
|
|
conf_parameters['jars'] = configuration.parms_to_dict()
|
|
|
if 'usrp' in configuration.device.device_type.name:
|
|
|
conf_parameters['usrp'] = configuration.parms_to_dict()
|
|
|
if 'abs' in configuration.device.device_type.name:
|
|
|
conf_parameters['abs'] = configuration.parms_to_dict()
|
|
|
|
|
|
parameters['configurations'] = conf_parameters
|
|
|
parameters['end_time'] = self.end_time.strftime("%H:%M:%S")
|
|
|
parameters['start_time'] = self.start_time.strftime("%H:%M:%S")
|
|
|
parameters['radar'] = self.radar_system.name
|
|
|
parameters['experiment'] = self.name
|
|
|
parameters = json.dumps(parameters, indent=2)
|
|
|
|
|
|
return parameters
|
|
|
|
|
|
def import_from_file(self, fp):
|
|
|
|
|
|
import os, json
|
|
|
|
|
|
parms = {}
|
|
|
|
|
|
path, ext = os.path.splitext(fp.name)
|
|
|
|
|
|
if ext == '.json':
|
|
|
parms = json.loads(fp.read().decode('utf-8'))
|
|
|
|
|
|
return parms
|
|
|
|
|
|
def dict_to_parms(self, parms, CONF_MODELS):
|
|
|
|
|
|
configurations = Configuration.objects.filter(experiment=self)
|
|
|
|
|
|
if configurations:
|
|
|
for configuration in configurations:
|
|
|
configuration.delete()
|
|
|
|
|
|
for conf_type in parms['configurations']:
|
|
|
#--For ABS Device:
|
|
|
#--For USRP Device:
|
|
|
#--For JARS Device:
|
|
|
if conf_type == 'jars':
|
|
|
device = get_object_or_404(Device, pk=parms['configurations']['jars']['device_id'])
|
|
|
DevConfModel = CONF_MODELS[conf_type]
|
|
|
confjars_form = DevConfModel(
|
|
|
experiment = self,
|
|
|
name = 'JARS',
|
|
|
device=device,
|
|
|
)
|
|
|
confjars_form.dict_to_parms(parms['configurations']['jars'])
|
|
|
confjars_form.save()
|
|
|
#--For RC Device:
|
|
|
if conf_type == 'rc':
|
|
|
device = get_object_or_404(Device, pk=parms['configurations']['rc']['device_id'])
|
|
|
DevConfModel = CONF_MODELS[conf_type]
|
|
|
confrc_form = DevConfModel(
|
|
|
experiment = self,
|
|
|
name = 'RC',
|
|
|
device=device,
|
|
|
)
|
|
|
confrc_form.dict_to_parms(parms['configurations']['rc'])
|
|
|
confrc_form.save()
|
|
|
#--For DDS Device:
|
|
|
if conf_type == 'dds':
|
|
|
device = get_object_or_404(Device, pk=parms['configurations']['dds']['device_id'])
|
|
|
DevConfModel = CONF_MODELS[conf_type]
|
|
|
confdds_form = DevConfModel(
|
|
|
experiment = self,
|
|
|
name = 'DDS',
|
|
|
device=device,
|
|
|
)
|
|
|
confdds_form.dict_to_parms(parms['configurations']['dds'])
|
|
|
confdds_form.save()
|
|
|
#--For CGS Device:
|
|
|
if conf_type == 'cgs':
|
|
|
device = get_object_or_404(Device, pk=parms['configurations']['cgs']['device_id'])
|
|
|
DevConfModel = CONF_MODELS[conf_type]
|
|
|
confcgs_form = DevConfModel(
|
|
|
experiment = self,
|
|
|
name = 'CGS',
|
|
|
device=device,
|
|
|
)
|
|
|
confcgs_form.dict_to_parms(parms['configurations']['cgs'])
|
|
|
confcgs_form.save()
|
|
|
|
|
|
location = Location.objects.get(name = parms['radar'])
|
|
|
self.name = parms['experiment']
|
|
|
self.location = location
|
|
|
self.start_time = parms['start_time']
|
|
|
self.end_time = parms['end_time']
|
|
|
self.save()
|
|
|
|
|
|
return self
|
|
|
|
|
|
def get_absolute_url_edit(self):
|
|
|
return reverse('url_edit_experiment', args=[str(self.id)])
|
|
|
|
|
|
def get_absolute_url_import(self):
|
|
|
return reverse('url_import_experiment', args=[str(self.id)])
|
|
|
|
|
|
def get_absolute_url_export(self):
|
|
|
return reverse('url_export_experiment', args=[str(self.id)])
|
|
|
|
|
|
|
|
|
class Configuration(PolymorphicModel):
|
|
|
|
|
|
template = models.BooleanField(default=False)
|
|
|
|
|
|
name = models.CharField(verbose_name="Configuration Name", max_length=40, default='')
|
|
|
|
|
|
experiment = models.ForeignKey('Experiment', verbose_name='Experiment', null=True, blank=True, on_delete=models.CASCADE)
|
|
|
device = models.ForeignKey('Device', verbose_name='Device', null=True, on_delete=models.CASCADE)
|
|
|
|
|
|
type = models.PositiveSmallIntegerField(default=0, choices=CONF_TYPES)
|
|
|
|
|
|
created_date = models.DateTimeField(auto_now_add=True)
|
|
|
programmed_date = models.DateTimeField(auto_now=True)
|
|
|
|
|
|
parameters = models.TextField(default='{}')
|
|
|
|
|
|
message = ""
|
|
|
|
|
|
class Meta:
|
|
|
db_table = 'db_configurations'
|
|
|
|
|
|
def __str__(self):
|
|
|
|
|
|
device = '{}:'.format(self.device.device_type.name.upper())
|
|
|
|
|
|
if 'mix' in [f.name for f in self._meta.get_fields()]:
|
|
|
if self.mix:
|
|
|
device = '{} MIXED:'.format(self.device.device_type.name.upper())
|
|
|
|
|
|
if self.template:
|
|
|
return u'{} {} (template)'.format(device, self.name)
|
|
|
else:
|
|
|
return u'{} {}'.format(device, self.name)
|
|
|
|
|
|
def clone(self, **kwargs):
|
|
|
|
|
|
self.pk = None
|
|
|
self.id = None
|
|
|
for attr, value in kwargs.items():
|
|
|
setattr(self, attr, value)
|
|
|
|
|
|
self.save()
|
|
|
|
|
|
return self
|
|
|
|
|
|
def parms_to_dict(self):
|
|
|
|
|
|
parameters = {}
|
|
|
|
|
|
for key in self.__dict__.keys():
|
|
|
parameters[key] = getattr(self, key)
|
|
|
|
|
|
return parameters
|
|
|
|
|
|
def parms_to_text(self):
|
|
|
|
|
|
raise NotImplementedError("This method should be implemented in %s Configuration model" %str(self.device.device_type.name).upper())
|
|
|
|
|
|
|
|
|
def parms_to_binary(self):
|
|
|
|
|
|
raise NotImplementedError("This method should be implemented in %s Configuration model" %str(self.device.device_type.name).upper())
|
|
|
|
|
|
|
|
|
def dict_to_parms(self, parameters):
|
|
|
|
|
|
if type(parameters) != type({}):
|
|
|
return
|
|
|
|
|
|
for key in parameters.keys():
|
|
|
setattr(self, key, parameters[key])
|
|
|
|
|
|
def export_to_file(self, format="json"):
|
|
|
|
|
|
import json
|
|
|
|
|
|
content_type = ''
|
|
|
|
|
|
if format == 'text':
|
|
|
content_type = 'text/plain'
|
|
|
filename = '%s_%s.%s' %(self.device.device_type.name, self.name, self.device.device_type.name)
|
|
|
content = self.parms_to_text()
|
|
|
|
|
|
if format == 'binary':
|
|
|
content_type = 'application/octet-stream'
|
|
|
filename = '%s_%s.bin' %(self.device.device_type.name, self.name)
|
|
|
content = self.parms_to_binary()
|
|
|
|
|
|
if not content_type:
|
|
|
content_type = 'application/json'
|
|
|
filename = '%s_%s.json' %(self.device.device_type.name, self.name)
|
|
|
content = json.dumps(self.parms_to_dict(), indent=2)
|
|
|
|
|
|
fields = {'content_type':content_type,
|
|
|
'filename':filename,
|
|
|
'content':content
|
|
|
}
|
|
|
|
|
|
return fields
|
|
|
|
|
|
def import_from_file(self, fp):
|
|
|
|
|
|
import os, json
|
|
|
|
|
|
parms = {}
|
|
|
|
|
|
path, ext = os.path.splitext(fp.name)
|
|
|
|
|
|
if ext == '.json':
|
|
|
parms = json.load(fp)
|
|
|
|
|
|
return parms
|
|
|
|
|
|
def status_device(self):
|
|
|
|
|
|
raise NotImplementedError("This method should be implemented in %s Configuration model" %str(self.device.device_type.name).upper())
|
|
|
|
|
|
|
|
|
def stop_device(self):
|
|
|
|
|
|
raise NotImplementedError("This method should be implemented in %s Configuration model" %str(self.device.device_type.name).upper())
|
|
|
|
|
|
|
|
|
def start_device(self):
|
|
|
|
|
|
raise NotImplementedError("This method should be implemented in %s Configuration model" %str(self.device.device_type.name).upper())
|
|
|
|
|
|
|
|
|
def write_device(self, parms):
|
|
|
|
|
|
raise NotImplementedError("This method should be implemented in %s Configuration model" %str(self.device.device_type.name).upper())
|
|
|
|
|
|
|
|
|
def read_device(self):
|
|
|
|
|
|
raise NotImplementedError("This method should be implemented in %s Configuration model" %str(self.device.device_type.name).upper())
|
|
|
|
|
|
|
|
|
def get_absolute_url(self):
|
|
|
return reverse('url_%s_conf' % self.device.device_type.name, args=[str(self.id)])
|
|
|
|
|
|
def get_absolute_url_edit(self):
|
|
|
return reverse('url_edit_%s_conf' % self.device.device_type.name, args=[str(self.id)])
|
|
|
|
|
|
def get_absolute_url_import(self):
|
|
|
return reverse('url_import_dev_conf', args=[str(self.id)])
|
|
|
|
|
|
def get_absolute_url_export(self):
|
|
|
return reverse('url_export_dev_conf', args=[str(self.id)])
|
|
|
|
|
|
def get_absolute_url_write(self):
|
|
|
return reverse('url_write_dev_conf', args=[str(self.id)])
|
|
|
|
|
|
def get_absolute_url_read(self):
|
|
|
return reverse('url_read_dev_conf', args=[str(self.id)])
|
|
|
|
|
|
def get_absolute_url_start(self):
|
|
|
return reverse('url_start_dev_conf', args=[str(self.id)])
|
|
|
|
|
|
def get_absolute_url_stop(self):
|
|
|
return reverse('url_stop_dev_conf', args=[str(self.id)])
|
|
|
|
|
|
def get_absolute_url_status(self):
|
|
|
return reverse('url_status_dev_conf', args=[str(self.id)])
|
|
|
|