''' Calculate the IMA status from event file
The module provides states of MEX/IMA at a specified time.
The states include on/off, eeprom section, mode, deflection, or PACC.
These information are retrieved from so-called ASPERA event file.
http://aspera-3.irf.se/archive/commanding/pors/EV_ASPERA.MEX
This module is still alpha version, so that a big changes in
API may change in the future version.
Usage:
>>> import datetime
>>> state = get_status(datetime.datetime(2006, 12, 5, 15, 0, 0))
>>> print(state)
<ON:True/PAC:4.0/EEPR:0/MOD:24.0/DEF:True>
>>> print(state.on)
True
>>> print(state.pacc)
4.0
>>> print(state.eeprom)
0
>>> print(state.mode)
24.0
>>> print(state.deflector)
True
>>> print(get_status(datetime.datetime(2004, 1, 24, 10, 0, 0)))
<ON:False/PAC:False/EEPR:False/MOD:False/DEF:False>
>>> print(get_status(datetime.datetime(2003, 1, 1, 0, 0, 0)))
<ON:None/PAC:None/EEPR:None/MOD:None/DEF:None>
'''
import copy
import logging
import bisect
import warnings
from collections import OrderedDict
from irfpy.mexop import eventfile
[docs]def parse_eventfile():
logger = logging.getLogger('parse_eventfile')
# logger.setLevel(logging.INFO)
ef = eventfile.default_eventfile()
logger.debug(ef)
status = Status()
history = OrderedDict()
for l in ef.list:
cmd = l.cmdname
# logger.debug('%s %s' % (str(l), str(cmd)))
if cmd == 'AASF09A1':
status.on = True
status.eeprom = 0
status.hv = status.pacc = status.mode = status.deflector = None
status.deflector = True # As a default, deflector may be set to True.
elif cmd == 'AASF09B1':
status.on = True
status.eeprom = 1
status.hv = status.pacc = status.mode = status.deflector = None
status.deflector = True # As a default, deflector may be set to True.
elif cmd == 'AASF09C1':
status.on = True
status.eeprom = float(l.parameters['VAS04051']) + 1
status.hv = status.pacc = status.mode = status.deflector = None
status.deflector = True # As a default, deflector may be set to True.
elif cmd == 'AASF10A1' or cmd == 'AASF40D0': # IMA OFF, AS OFF
status = Status()
status.on = status.hv = status.pacc = status.mode = status.eeprom = status.deflector = False
elif cmd == 'AASF23E1': # IMA ENTRANCE REFERENCE
status.deflector = float(l.parameters['VAS05058'])
status.hv = True
elif cmd == 'AASF23I1': # IMA PACC
status.pacc = float(l.parameters['VAS05055'])
status.hv = True
elif cmd == 'AASF60A1': # IMA mode
status.mode = float(l.parameters['VAS05010'])
elif cmd == 'AASF40A0': # IMA HV activate
status.on = True
status.pacc = 4
status.eeprom = 16
status.mode = 24
elif cmd == 'AASF40B0': # IMA HV activate
status.hv = True
# status.pacc = 4 # TBC!!, Likely not with this command.
status.deflector = True # As a default, deflector may be set to True.
elif cmd == 'AASF40C0': # IMA HV disable
status.hv = False
elif cmd == 'AASF40K0': # IMA HV activate with PACC
status.hv = True
# status.pacc = 4 # TBC!!, Likely not with this command.
status.deflector = True # As a default, deflector may be set to True.
history[l.utc] = l, copy.copy(status)
logger.debug('%s %s' % (str(l), str(status)))
warnings.warn('Check the AASF40 command to MH/LK.')
return history
__parsed_event = None
''' Parsed event file.
'''
def __parse():
global __parsed_event
if __parsed_event is None:
__parsed_event = parse_eventfile()
[docs]class Status:
''' A status
'''
def __init__(self):
self.on = None
''' ON/OFF/Unknown.
True for ON, False for OFF, None for Unknown.
'''
self.hv = None
''' ON/OFF/Unknown.
True for ON, False for OFF, None for Unknown.
'''
self.pacc = None
''' PACC used
None for unknown (or default). 0-7.
'''
self.eeprom = None
''' EEPROM section to be booted.
None for unknown.
0 is booted from PROM. This is used in the first
period of the mission.
1-16 is booted from EEPROM. The exact page number is
to be decremented (0-15).
For example, if the operation command states the boot of
EEPROM=0, this attribute is set to 1.
This is the same behaviour in the IMA telemetry's standard header
(see VE-ASP-MA-0009, section 7.5, 8th byte 4-0 bit.)
'''
self.mode = None
''' Mode.
'''
self.deflector = None
''' Deflector, True=On, Number=reference or None=unknown.
'''
def __str__(self):
return '<ON:{0}/PAC:{2}/EEPR:{3}/MOD:{4}/DEF:{5}>'.format(
self.on,
self.hv,
self.pacc,
self.eeprom,
self.mode,
self.deflector,
)
def __repr__(self):
return self.__str__()
[docs]def get_status(t):
''' Return the :class:`Status` for given time
'''
__parse()
utcs = list(__parsed_event.keys())
idx = bisect.bisect(utcs, t) - 1
if idx < 0:
return Status() # before the datafile
logger = logging.getLogger('get_status')
# logger.setLevel(logging.INFO)
logger.debug('EVNT=%s CMD=%s' %
(str(__parsed_event[utcs[idx]][0]), str(__parsed_event[utcs[idx]][1])))
return __parsed_event[utcs[idx]][1] # Return the Status.
[docs]def isdb():
''' Return if the event file is available or not
'''
try:
__parse()
except IOError:
return False
return __parsed_event is not None
import unittest
import doctest
[docs]def doctests():
return unittest.TestSuite((
doctest.DocTestSuite(),
))
if __name__ == '__main__':
unittest.main(defaultTest='doctests')