"""Module holding Python representations of TC packets, TC header and the corresponding MIB tables.
This module takes care of creating a representation of TC commands from parsed sections of C-files and extracting
entries for MIB databases. These classes represent the TC commands only in the sense that they hold in a structured
form any possible information that could be found relating to that command including the entries in various MIB tables that
correspond to it.
"""
import mib_generator.construction.TC_packet_methods as pm
import mib_generator.data.warn as warn
import mib_generator.parsing.load as load
[docs]
class TC_packet:
"""Class representing a TC-packet/command and its various properties.
This class is an abstract representation of a TC command with all of its properties, entries and corresponding MIB tables.
It is created from passed :obj:`mib_generator.parsing.par_header.struct` and :obj:`TC_header` objects and and subsequently analysed using
included methods into the entries in various TC-side MIB tables.
Args:
h_structure (parsing.par_header.struct): An object corresponding to a description of this command found in the
:obj:`mib_generator.parsing.load.TcH` file (i.e. the TC ``.h`` file).
header (TC_header): A TC-header included at the start of the packet in which the command in question is send.
h_comment (parsing.par_methods.comment): A comment found in the :obj:`parsing.parsing.load.TcH` file which holds meta-information
about the command.
Attributes:
h_structure (parsing.par_header.struct): An object corresponding to a description of this command found in the
:obj:`mib_generator.parsing.load.TcH` file (i.e. the TC ``.h`` file).
h_comment (parsing.par_methods.comment): A comment found in the :obj:`parsing.parsing.load.TcH` file which holds meta-information
about the command.
header (TC_header): A TC-header included at the start of the packet in which the command in question is send.
h_entries (list): List of entries that relate to the header found inside the command definition. Each is an instance of
:obj:`mib_generator.parsing.par_header.misc_r`.
entries (list): List of entries that do not relate to the headerfound inside the command definition. Each is an instance
of :obj:`mib_generator.parsing.par_header.misc_r`.
size (int): Size of the command definition (joint size of all parameters in :attr:`entries`) in bytes.
positions (list): List of starting positions of :attr:`entries` in the command definition. Each entry is an integer representing an
offset from the start.
h_size (int): Size of the command definition (joint size of all parameters in :attr:`h_entries`) in bytes.
h_positions (list): List of starting positions of :attr:`h_entries` in the command definition. Each entry is an integer representing an
offset from the start.
parameters (list): List of indexes of all parameters in :attr:`entries` (i.e. those that aren't fixed areas). If entry is a parameter,
the corresponding field in this list has its index value, otherwise it is assigned -1.
ccf (dict): Dictionary corresponding to one line in MIB ccf table.
cpc (list): List of dictionaries each one corresponding to one line in MIB cpc table.
cdf (list): List of dictionaries each one corresponding to one line in MIB cdf table.
prf (list): List of dictionaries each one corresponding to one line in MIB prf table.
prv (list): List of dictionaries each one corresponding to one line in MIB prv table.
cvp (list): List of dictionaries each one corresponding to one line in MIB cvp table.
"""
def __init__(self, h_structure, header, h_comment):
self.h_structure = h_structure
self.h_comment = h_comment
self.header = header
self.h_entries, self.entries = pm.h_analysis(self.h_structure)
self.size, self.positions = pm.count_size(self.entries)
self.h_size, self.h_position = pm.count_size(self.h_entries)
self.parameters = pm.param_list(self.entries)
self.ccf = self.ccf_dictionary()
self.cpc = self.cpc_listdict()
self.cdf = self.cdf_listdict()
self.prf = self.prf_listdict()
self.prv = self.prv_listdict()
self.cvp = self.cvp_listdict()
[docs]
def ccf_dictionary(self):
"""Define elements for entry in ccf table.
Creates a dictionary where each key-value pair corresponds to an entry in one column of the ccf table (with the key being
the name of the column and value the entry to be filled in). Here the values are mostly general information extracted
from the comment in from of the command definition in the C-header file and such.
Returns:
dict: Dictionary which is one line in the MIB table. Assigned to :attr:`ccf`.
"""
diction = {}
try:
diction["CCF_CNAME"] = self.h_comment.entries["text_id"]
except:
diction["CCF_CNAME"] = ""
try:
diction["CCF_DESCR"] = self.h_comment.entries["desc"]
except:
diction["CCF_DESCR"] = ""
try:
if "Mnemonic" in self.h_comment.entries.keys():
diction["CCF_DESCR2"] = self.h_comment.entries["Mnemonic"]
elif "mnemonic" in self.h_comment.entries.keys():
diction["CCF_DESCR2"] = self.h_comment.entries["mnemonic"]
else:
diction["CCF_DESCR2"] = ""
except:
diction["CCF_DESCR2"] = ""
# diction["CCF_CTYPE"] = ""
# diction["CCF_CRITICAL"] = ""
diction["CCF_PKTID"] = self.header.tcp["TCP_ID"]
try:
diction["CCF_TYPE"] = self.h_comment.entries["service"]
diction["CCF_STYPE"] = self.h_comment.entries["sub"]
except:
diction["CCF_TYPE"] = ""
diction["CCF_STYPE"] = ""
try:
diction["CCF_APID"] = self.h_comment.entries["apid"]
except:
diction["CCF_APID"] = ""
diction["CCF_NPARS"] = len(self.entries)
# diction["CCF_PLAN"] = ""
# diction["CCF_EXEC"] = ""
# diction["CCF_ILSCOPE"] = ""
# diction["CCF_ILSTAGE"] = ""
# diction["CCF_SUBSYS"] = ""
# diction["CCF_HIPRI"] = ""
# diction["CCF_MAPID"] = ""
# diction["CCF_DEFSET"] = ""
# diction["CCF_RAPID"] = ""
# diction["CCF_ACK"] = ""
# diction["CCF_SUBSCHEDID"] = ""
return diction
[docs]
def cpc_listdict(self):
"""Define elements for entries in cpc table.
Creates a list of dictionaries in each of which a key-value pair corresponds to entry in one column of the cpc table (with
the key being the name of the column and value the entry to be filled in). Here for each parameter in the header, one row
(i.e. one entry in the list) is created, entries in which are extracted from comments around the given parameter, calculated
from type/general information, etc... It should be mentioned that not all entries in :attr:`etnries` are parameters since they
can be also fixed areas. Hence first, before the dictionary is created, a check is run for this.
Unusual case here is the range check ``"CPC_PRFREF"``. Normal here would be to directly associate it to some externally defined
calibration, but since that would be quite convoluted and ineffective for such simple task, it was decided to generate a random
placeholder name (rather than predefined one) to be put into the ``"CPC_PRFREF"`` entry and then generate the range check tables
as an attribute of this command class :attr:`prf` and :attr:`prv` (rather then as an external object as is the case with all
other calibrations).
Also, before entries for any parameter are calculated, a simple check is run inspecting whether the ``"base_par_index"`` defined
in the packet-level comment corresponds in length to the length of the numerical part of the parameter names to be generated (
this is defined in the config file). If not, a warning is raised.
Returns:
list: List of dictionaries which are to be lines in the MIB table. Assigned to :attr:`cpc`.
"""
entrydict = []
try:
if load.conf["nam"]["cpc"] < self.h_comment.entries["base_par_index"]:
warn.raises("WCTA", self.ccf["CCF_CNAME"])
except:
pass
for i in range(len(self.entries)):
if self.parameters[i] >= 0:
diction = {}
size = int(self.positions[i + 1] - self.positions[i])
try:
# all of this is for creation of the parameter name based on config settings.
if "nam" in load.conf.keys():
conf = load.conf["nam"]
no = "{:X}".format(
int(
str(self.h_comment.entries["base_par_index"])[
: int(conf["cpc"])
],
16,
)
+ i
)
if (
self.entries[i].comment
and "nature" in self.entries[i].comment[-1].entries.keys()
):
nat = self.entries[i].comment[-1].entries["nature"][:1]
else:
nat = conf["nat_cpc"]
else:
no = str(
"{:X}".format(
int(str(self.h_comment.entries["base_par_index"]), 16)
+ i
)
)
nat = ""
diction["CPC_PNAME"] = self.h_comment.entries["prefix"] + no + nat
except:
diction["CPC_PNAME"] = ""
try:
diction["CPC_DESCR"] = self.entries[i].comment[-1].entries["desc"]
except:
diction["CPC_DESCR"] = ""
diction["CPC_PTC"], diction["CPC_PFC"] = pm.getptcpcf(
self.entries[i], size
)
try:
if {"cal", "enum"} & self.entries[i].comment[-1].entries.keys():
diction["CPC_CATEG"] = "T"
else:
diction["CPC_CATEG"] = ""
except:
diction["CPC_CATEG"] = ""
if diction["CPC_CATEG"] == "T":
diction["CPC_DISPFMT"] = "A"
elif diction["CPC_PTC"] == 9:
diction["CPC_DISPFMT"] = "T"
elif diction["CPC_PTC"] == 10:
diction["CPC_DISPFMT"] = "D"
else:
diction["CPC_DISPFMT"] = "U"
# diction["CPC_RADIX"] = ""
try:
diction["CPC_UNIT"] = self.entries[i].comment[-1].entries["unit"]
except:
diction["CPC_UNIT"] = ""
if (
self.entries[i].comment
and {"min", "max"} & self.entries[i].comment[-1].entries.keys()
):
# generate pseudo-random name for the range check
diction["CPC_PRFREF"] = "RAN" + str(hash(diction["CPC_PNAME"]))[-7:]
else:
diction["CPC_PRFREF"] = ""
# diction["CPC_CCAREF"] = ""
if (
self.entries[i].comment
and "enum" in self.entries[i].comment[-1].entries.keys()
):
diction["CPC_PAFREF"] = self.entries[i].comment[-1].entries["enum"]
else:
diction["CPC_PAFREF"] = ""
# diction["CPC_INTER"] = ""
# diction["CPC_DEFVAL"] = ""
# diction["CPC_CORR"] = ""
# diction["CPC_OBTID"] = ""
try:
if "Mnemonic" in self.entries[i].comment[-1].entries.keys():
diction["CPC_DESCR2"] = (
self.entries[i].comment[-1].entries["Mnemonic"]
)
elif "mnemonic" in self.entries[i].comment[-1].entries.keys():
diction["CPC_DESCR2"] = (
self.entries[i].comment[-1].entries["mnemonic"]
)
else:
diction["CPC_DESCR2"] = ""
except:
diction["CPC_DESCR2"] = ""
# diction["CPC_ENDIAN"] = ""
entrydict.append(diction)
return entrydict
[docs]
def cdf_listdict(self):
"""Define elements for entries in cdf table.
Creates a list of dictionaries in each of which a key-value pair corresponds to entry in one column of the cdf table (with
the key being the name of the column and value the entry to be filled in). Here for each parameter in the header, one row
(i.e. one entry in the list) is created, entries in which are mostly deduced from the parameter's name or position/width.
Returns:
list: List of dictionaries which are to be lines in the MIB table. Assigned to :attr:`cdf`.
"""
entrydict = []
gr_size = pm.get_gr_sizes(self.entries)
for i in range(len(self.entries)):
size = int(self.positions[i + 1] - self.positions[i])
diction = {}
diction["CDF_CNAME"] = self.ccf["CCF_CNAME"]
if self.parameters[i] < 0:
diction["CDF_ELTYPE"] = "A"
else:
diction["CDF_ELTYPE"] = "E"
try:
diction["CDF_DESCR"] = self.entries[i].comment[-1].entries["desc"]
except:
diction["CDF_DESCR"] = ""
diction["CDF_ELLEN"] = size
diction["CDF_BIT"] = self.positions[i]
diction["CDF_GRPSIZE"] = gr_size[i]
if diction["CDF_ELTYPE"] in {"E", "F"}:
diction["CDF_PNAME"] = self.cpc[self.parameters[i]]["CPC_PNAME"]
else:
diction["CDF_PNAME"] = ""
# diction["CDF_INTER"] = ""
if diction["CDF_ELTYPE"] != "A":
try:
diction["CDF_VALUE"] = pm.evalu(
self.entries[i].comment[-1].entries["default"]
)
except:
diction["CDF_VALUE"] = ""
else:
try:
diction["CDF_VALUE"] = pm.evalu(
self.entries[i].comment[-1].entries["default"]
)
except:
diction["CDF_VALUE"] = 0
# diction["CDF_TMID"] = ""
entrydict.append(diction)
return entrydict
[docs]
def prf_listdict(self):
"""Define elements for entries in prf table.
Creates a list of dictionaries in each of which a key-value pair corresponds to entry in one column of the prf table (with
the key being the name of the column and value the entry to be filled in). Here it is first checked whether the given
parameter has a range associated to it and if so appropriate entries for name of the parameter and ad-hoc calibration
are generated.
For a reason why this table is here see :obj:`cpc_listdict`.
Returns:
list: List of dictionaries which are to be lines in the MIB table. Assigned to :attr:`prf`.
"""
entrydict = []
for i in range(len(self.entries)):
if self.parameters[i] >= 0 and self.cpc[self.parameters[i]]["CPC_PRFREF"]:
diction = {}
diction["PRF_NUMBR"] = self.cpc[self.parameters[i]]["CPC_PRFREF"]
# diction["PRF_DESCR"] = ""
# diction["PRFINTER"] = ""
# diction["PRF_DSPFMT"] = ""
# My code assumes that the bellow is decimal, but that is the default value anyways
# diction["PRF_RADIX"] = ""
diction["PRF_NRANGE"] = len(
{"min", "max"} & self.entries[i].comment[-1].entries.keys()
)
diction["PRF_UNIT"] = self.cpc[self.parameters[i]]["CPC_UNIT"]
entrydict.append(diction)
return entrydict
[docs]
def prv_listdict(self):
"""Define elements for entries in prv table.
Creates a list of dictionaries in each of which a key-value pair corresponds to entry in one column of the prv table (with
the key being the name of the column and value the entry to be filled in). Here it is first checked whether the given
parameter has a range associated to it and if so, the entries for the corresponding ad-hoc calibration are created.
For a reason why this table is here see :obj:`cpc_listdict`.
Returns:
list: List of dictionaries which are to be lines in the MIB table. Assigned to :attr:`prv`.
"""
entrydict = []
for i in range(len(self.entries)):
if self.parameters[i] >= 0 and self.cpc[self.parameters[i]]["CPC_PRFREF"]:
diction = {}
diction["PRV_NUMBR"] = self.cpc[self.parameters[i]]["CPC_PRFREF"]
try:
diction["PRV_MINVAL"] = pm.evalu(
self.entries[i].comment[-1].entries["min"]
)
except:
diction["PRV_MINVAL"] = 0
try:
diction["PRV_MAXVAL"] = pm.evalu(
self.entries[i].comment[-1].entries["max"]
)
if diction["PRV_MAXVAL"] == -1:
diction["PRV_MAXVAL"] = diction["PRV_MINVAL"]
except:
diction["PRV_MAXVAL"] = ""
entrydict.append(diction)
return entrydict
[docs]
def cvp_listdict(self):
"""Define elements for entries in cvp table.
Creates a list of dictionaries in each of which a key-value pair corresponds to entry in one column of the cvp table (with
the key being the name of the column and value the entry to be filled in). First checks whether there are verifications associated
to the given command and if so, creates an entry row to each one of them.
There are default values for verification which are applied automatically later for each command if no verification are specified here
(in which case the value of :attr:`cvp` will be ``None`` for now).
Returns:
list: List of dictionaries which are to be lines in the MIB table. Assigned to :attr:`cvp`.
"""
if self.h_structure.comment and "cvs" in self.h_comment.entries.keys():
entrydict = []
for i in self.h_comment.entries["cvs"]:
diction = {}
diction["CVP_TASK"] = self.ccf["CCF_CNAME"]
diction["CVP_TYPE"] = "C"
diction["CVP_CVSID"] = i
entrydict.append(diction)
return entrydict
else:
return None