216 lines
7.3 KiB
Python
216 lines
7.3 KiB
Python
|
#! /usr/bin/python3.7
|
||
|
"""
|
||
|
@file
|
||
|
mib_objects.py
|
||
|
@brief
|
||
|
Part of the Mission Information Base Exporter for the SOURCE project by KSat.
|
||
|
@details
|
||
|
Event exporter.
|
||
|
|
||
|
To use MySQLdb, run pip install mysqlclient or install in IDE.
|
||
|
On Windows, Build Tools installation might be necessary
|
||
|
@data
|
||
|
21.11.2019
|
||
|
"""
|
||
|
import re
|
||
|
import os
|
||
|
import shutil
|
||
|
import pprint
|
||
|
from utility.mib_csv_writer import CsvWriter
|
||
|
|
||
|
generateCpp = True
|
||
|
generateCsv = True
|
||
|
copyCppFile = True
|
||
|
moveCsvFile = True
|
||
|
cppFilename = "translateEvents.cpp"
|
||
|
csvFilename = "MIB_Events.csv"
|
||
|
cppCopyDestination = "../../config/objects/"
|
||
|
csvMoveDestination = "../"
|
||
|
fileSeparator = ";"
|
||
|
|
||
|
pp = pprint.PrettyPrinter(indent=0, width=250)
|
||
|
|
||
|
|
||
|
def main():
|
||
|
print("Parsing events: ")
|
||
|
listItems = parseOBSW()
|
||
|
handleFileExport(listItems)
|
||
|
print("")
|
||
|
|
||
|
|
||
|
def parseOBSW():
|
||
|
idSubsystemDefinitions = parseSubsystemDefinitionFile("../../config/tmtc/subsystemIdRanges.h")
|
||
|
tempList = parseSubsystemDefinitionFile("../../fsfw/events/fwSubsystemIdRanges.h")
|
||
|
idSubsystemDefinitions.update(tempList)
|
||
|
print(len(idSubsystemDefinitions))
|
||
|
# print ("Dictionary size is " + str(len(idInterfaceDefinitions)) )
|
||
|
# for entry in idSubsystemDefinitions:
|
||
|
# print(entry)
|
||
|
myHeaderList = getHeaderFileList("../../mission/")
|
||
|
myHeaderList = myHeaderList + getHeaderFileList("../../fsfw/")
|
||
|
myEventList = parseHeaderFiles(idSubsystemDefinitions, myHeaderList)
|
||
|
listItems = sorted(myEventList.items())
|
||
|
|
||
|
print("Found " + str(len(listItems)) + " entries:")
|
||
|
pp.pprint(listItems)
|
||
|
print(len(listItems))
|
||
|
return listItems
|
||
|
|
||
|
|
||
|
def handleFileExport(listItems):
|
||
|
csvWriter = CsvWriter(csvFilename)
|
||
|
if generateCpp:
|
||
|
print("Generating translation cpp file.")
|
||
|
writeTranslationFile(cppFilename, listItems)
|
||
|
if generateCpp and copyCppFile:
|
||
|
dst = shutil.copy2("../events/translateEvents.cpp", "../../config/events/")
|
||
|
print("CPP file was copied to " + dst)
|
||
|
if generateCsv:
|
||
|
print("Generating text export.")
|
||
|
exportToFile(csvFilename, listItems)
|
||
|
if generateCsv and moveCsvFile:
|
||
|
csvWriter.move_csv(csvMoveDestination)
|
||
|
|
||
|
|
||
|
# The output files are generated by putting the name of the output CPP file as first argument and the name of the
|
||
|
# csv or txt output as second argument in the Run Configuration.
|
||
|
# Config Parameters: translateEvents.cpp translateEvents.csv
|
||
|
def parseSubsystemDefinitionFile(filename):
|
||
|
file = open(filename, "r")
|
||
|
interfaces = dict()
|
||
|
for line in file.readlines():
|
||
|
match = re.search('([A-Z0-9_]*) = ([0-9]{1,2})', line)
|
||
|
if match:
|
||
|
interfaces.update({match.group(1): [match.group(2)]})
|
||
|
return interfaces
|
||
|
|
||
|
|
||
|
def returnNumberFromString(aString):
|
||
|
if aString.startswith('0x'):
|
||
|
return int(aString, 16)
|
||
|
elif aString.isdigit():
|
||
|
return int(aString)
|
||
|
else:
|
||
|
print('Error: Illegal number representation: ' + aString)
|
||
|
return 0
|
||
|
|
||
|
|
||
|
def convert(name):
|
||
|
singleStrings = name.split('_')
|
||
|
newString = ''
|
||
|
for oneString in singleStrings:
|
||
|
oneString = oneString.lower()
|
||
|
oneString = oneString.capitalize()
|
||
|
newString = newString + oneString
|
||
|
return newString
|
||
|
|
||
|
|
||
|
def buildCheckedString(firstPart, secondPart):
|
||
|
myStr = firstPart + convert(secondPart)
|
||
|
if len(myStr) > 16:
|
||
|
print("Error: Entry: " + myStr + " too long. Will truncate.")
|
||
|
myStr = myStr[0:14]
|
||
|
# else:
|
||
|
# print( "Entry: " + myStr + " is all right.")
|
||
|
return myStr
|
||
|
|
||
|
|
||
|
def cleanUpDescription(description):
|
||
|
description = description.lstrip('//!<>')
|
||
|
description = description.lstrip()
|
||
|
if description == '':
|
||
|
description = ' '
|
||
|
return description
|
||
|
|
||
|
|
||
|
def parseHeaderFiles(interfaceList, fileList):
|
||
|
dictionnary = dict()
|
||
|
totalCount = 0
|
||
|
count = 0
|
||
|
# noinspection PyUnusedLocal
|
||
|
currentId = 0
|
||
|
for fileName in fileList:
|
||
|
file = open(fileName, "r")
|
||
|
oldline = file.readline()
|
||
|
myId = 0
|
||
|
# print(file_name)
|
||
|
while True:
|
||
|
newline = file.readline()
|
||
|
if not newline:
|
||
|
break # EOF
|
||
|
if not oldline == '\n':
|
||
|
twolines = oldline + ' ' + newline.strip()
|
||
|
else:
|
||
|
twolines = ''
|
||
|
match1 = re.search('SUBSYSTEM_ID[\s]*=[\s]*SUBSYSTEM_ID::([A-Z_0-9]*);', twolines)
|
||
|
if match1:
|
||
|
currentId = interfaceList[match1.group(1)][0]
|
||
|
# print( "Current ID: " + str(currentId) )
|
||
|
myId = returnNumberFromString(currentId)
|
||
|
match = re.search('(//)?[\t ]*static const Event[\s]*([A-Z_0-9]*)[\s]*=[\s]*MAKE_EVENT\(([0-9]{1,2}),'
|
||
|
'[\s]*SEVERITY::([A-Z]*)\);[\t ]*(//!<)?([^\n]*)', twolines)
|
||
|
if match:
|
||
|
if match.group(1):
|
||
|
oldline = newline
|
||
|
continue
|
||
|
description = " "
|
||
|
if match.group(6):
|
||
|
description = cleanUpDescription(match.group(6))
|
||
|
stringToAdd = match.group(2)
|
||
|
fullId = (myId * 100) + returnNumberFromString(match.group(3))
|
||
|
severity = match.group(4)
|
||
|
if fullId in dictionnary:
|
||
|
print('duplicate Event ' + hex(fullId) + ' from ' + fileName + ' was already in ' +
|
||
|
dictionnary[fullId][3])
|
||
|
dictionnary.update({fullId: (stringToAdd, severity, description, fileName)})
|
||
|
count = count + 1
|
||
|
oldline = newline
|
||
|
if count > 0:
|
||
|
print("File " + fileName + " contained " + str(count) + " events.")
|
||
|
totalCount += count
|
||
|
count = 0
|
||
|
print("Total events: " + str(totalCount))
|
||
|
return dictionnary
|
||
|
|
||
|
|
||
|
def getHeaderFileList(base):
|
||
|
# print("getHeaderFileList called with" + base)
|
||
|
baseList = os.listdir(base)
|
||
|
fileList = []
|
||
|
for entry in baseList:
|
||
|
# Remove all hidden files:
|
||
|
if os.path.isdir(base + entry) and (entry[0] != ".") and (entry[0] != "_"):
|
||
|
fileList = fileList + getHeaderFileList(base + entry + "/")
|
||
|
if re.match("[^.]*\.h", entry) and os.path.isfile(base + entry):
|
||
|
fileList.append(base + entry)
|
||
|
return fileList
|
||
|
|
||
|
|
||
|
def exportToFile(filename, listOfEntries):
|
||
|
print('Exporting to file: ' + filename)
|
||
|
file = open(filename, "w")
|
||
|
for entry in listOfEntries:
|
||
|
file.write(str(entry[0]) + fileSeparator + entry[1][0] + fileSeparator + entry[1][1]
|
||
|
+ fileSeparator + entry[1][2] + fileSeparator + entry[1][3] + '\n')
|
||
|
file.close()
|
||
|
return
|
||
|
|
||
|
|
||
|
def writeTranslationFile(filename, listOfEntries):
|
||
|
outputfile = open(filename, "w")
|
||
|
definitions = ""
|
||
|
function = "const char * translateEvents(Event event){\n\tswitch((event&0xFFFF)){\n"
|
||
|
for entry in listOfEntries:
|
||
|
definitions += "const char *" + entry[1][0] + "_STRING = \"" + entry[1][0] + "\";\n"
|
||
|
function += "\t\tcase " + str(entry[0]) + ":\n\t\t\treturn " + entry[1][0] + "_STRING;\n"
|
||
|
function += '\t\tdefault:\n\t\t\treturn "UNKNOWN_EVENT";\n'
|
||
|
outputfile.write("/* Auto-generated event translation file. Contains "
|
||
|
+ str(len(listOfEntries)) + " translations. */\n")
|
||
|
outputfile.write("#include \"translateEvents.h\"\n\n")
|
||
|
outputfile.write(definitions + "\n" + function + "\t}\n\treturn 0;\n}\n")
|
||
|
outputfile.close()
|
||
|
|
||
|
|
||
|
if __name__ == "__main__":
|
||
|
main()
|