Source code for PyICe.xml_registers.datasheet_indesign.datasheet_registers_xml

'''
Adobe Indesign (Datasheet) Register Table and Hyperlink Generator
=================================================================
'''

import sys
import os
import xml.etree.ElementTree as ET
import csv
from PyICe import lab_utils

[docs]class inDesignOutput(object): '''shared methods between XML conversion program and CSV conversion program''' def __init__(self, source_revision="", source_date=""): self.xml_declaration = '<?xml version="1.0" standalone="no"?>\n' file_path = os.path.abspath(__file__) dtd_path = "/".join(file_path.replace("\\", "/").split("/")[:-1] + ["link_inserter/register_map_InDesign.dtd"]) self.doctype = '<!DOCTYPE register_map SYSTEM "{}">\n'.format(dtd_path) #ETree.register_namespace(prefix, uri) self.table = ET.Element("register_map") # self.table = ET.SubElement(self.xml_out, "Table", attrib={'content':'register_map'}) self.table.set("xmlns:aid", "http://ns.adobe.com/AdobeInDesign/4.0/") # self.table.set("xmlns:aid5", "http://ns.adobe.com/AdobeInDesign/5.0/") self.table.set("aid:table", "table") # self.table.set("aid:trows","1") self.table.set("aid:tcols","6") self.table.set("revision",source_revision) self.table.set("date",source_date) # self.table.set("revision","$Revision: $") # self.table.set("date","$Date: $") self.trows = 0 id_element = {'symbol_name':'header', 'command_code':'header', 'access':'header', 'default':'header', 'subordinate':'header', 'presets':'header'} id_cell = {'aid:table':'cell', 'aid:theader':'', 'aid:crows':'1', 'aid:ccols':'1'} self.add_symbol("Symbol Name","Command Code","Access","Bit Range","Default","Description","",id_element,id_cell) def add_symbol(self, symbol_name, command_code, access, bit_range, default, description, presets, id_element = None, id_cell = None, subordinate = False): if id_element is None: id_element = {'symbol_name':symbol_name, 'command_code':command_code, 'access':access, 'default':default, 'subordinate':str(subordinate), 'presets':presets} if id_cell is None: id_cell = {'aid:table':'cell', 'aid:crows':'1', 'aid:ccols':'1'} if subordinate: command_code = '' access = '' #symbol_name = ' ' + symbol_name id_cell['aid:ccolwidth']='80' #symbol_name column width symbol_name_tag = ET.SubElement(ET.SubElement(self.table, "Cell", attrib = id_cell), "symbol_name", attrib = id_element).text = symbol_name id_cell['aid:ccolwidth']='45' #command_code column width command_code_tag = ET.SubElement(ET.SubElement(self.table, "Cell", attrib = id_cell), "command_code", attrib = id_element).text = command_code id_cell['aid:ccolwidth']='35' #access column width access_tag = ET.SubElement(ET.SubElement(self.table, "Cell", attrib = id_cell), "access", attrib = id_element).text = access id_cell['aid:ccolwidth']='35' #bit_range column width bit_range_tag = ET.SubElement(ET.SubElement(self.table, "Cell", attrib = id_cell), "bit_range", attrib = id_element).text = bit_range id_cell['aid:ccolwidth']='35' #default column width default_tag = ET.SubElement(ET.SubElement(self.table, "Cell", attrib = id_cell), "default", attrib = id_element).text = default id_cell['aid:ccolwidth']='285' #description column width description_tag = ET.SubElement(ET.SubElement(self.table, "Cell", attrib = id_cell), "description", attrib = id_element).text = description self.trows += 1 def add_xml_revision(self, revision_string): #aid:pstyle could maybe be used to right-align text instead of javascript? revision_tag = ET.SubElement(ET.SubElement(self.table, "Cell", attrib = {'aid:table':'cell', 'aid:crows':'1', 'aid:ccols':'6', 'aid:ccolwidth':'515'}), "revision").text = revision_string self.trows += 1
[docs] def bit_range_str(self, size=None, lsb=None, msb=None): '''specify two of the three arguments to convert symbol size description to string output format''' if size is None: lsb = int(lsb) msb = int(msb) size = msb-lsb+1 if lsb is None: msb = int(msb) size = int(size) lsb = msb-size+1 if msb is None: lsb = int(lsb) size = int(size) msb = lsb+size-1 else: msb = int(msb) lsb = int(lsb) size = int(size) assert msb == lsb+size-1 if size == 1: return "[{}]".format(lsb) else: return "[{}:{}]".format(msb, lsb)
[docs] def access_str(self, readable, writable): '''convert readable and writable booleans to string output format''' if readable and writable: return "R/W" elif readable: return "R" elif writable: return "W" else: return ""
def write(self, xmlfilename): self.table.set("aid:trows","{}".format(self.trows)) with open(xmlfilename, 'w') as f: f.write(self.xml_declaration) f.write(self.doctype) ET.ElementTree(self.table).write(f, encoding='utf-8')
class xml_converter(inDesignOutput): def __init__(self, xmlfilename, use_case, access_list): self.xml = ET.parse(xmlfilename) self.root = self.xml.getroot() self.chip = self.root.find('.//chip') self.use = self.root.find('./use[@name="{}"]'.format(use_case)) source_revision = self.root.attrib['revision'].strip().strip("$").strip() #remove SVN escape to avoid re-writing source version information. source_date = self.root.attrib['date'].strip().strip("$").strip() inDesignOutput.__init__(self, source_revision, source_date) self.categories = [] for category in self.use.findall('category'): self.categories.append(category.text) self.access_list = access_list self._make_regtable() self.add_xml_revision('{} {}'.format(source_revision,source_date)) def _make_regtable(self): for command_code in self.chip.findall('./command_code'): cc_val = command_code.attrib['value'] bit_fields_tmp = command_code.findall('./bit_field') bit_fields = [] for bit_field in bit_fields_tmp: if bit_field.attrib['category'] in self.categories: bit_fields.append(bit_field) if not len(bit_fields): continue #REGISTER ACCESS read = False write = False for xmlaccess in command_code.findall('./access'): for access in self.access_list: if xmlaccess.attrib["mode"] == access and xmlaccess.attrib["type"] == "read": read = True if xmlaccess.attrib["mode"] == access and xmlaccess.attrib["type"] == "write": write = True access_mode = self.access_str(read, write) #COMPUTE WHOLE-REGISTER DEFAULT try: reg_default = 0 for bf in bit_fields: reg_default += lab_utils.str2num(bf.find("./default").text) << lab_utils.str2num(bf.attrib['offset']) reg_default = str(reg_default) except: reg_default = "N/A" #COMPUTE WHOLE-REGISTER BIT-RANGE reg_lsb = None reg_msb = None for bf in bit_fields: bf_lsb = lab_utils.str2num(bf.attrib['offset']) bf_msb = bf_lsb + lab_utils.str2num(bf.attrib['size']) - 1 if bf_msb > reg_msb: reg_msb = bf_msb if bf_lsb < reg_lsb or reg_lsb is None: reg_lsb = bf_lsb reg_bit_range = self.bit_range_str(lsb=reg_lsb, msb=reg_msb) #CHECK REGISTER DESCRIPTION if command_code.find("./description") is not None: reg_description = command_code.find("./description").text else: reg_description = "" #no description! if len(bit_fields) == 1: #Special case of single bit_field register subordinate = False else: self.add_symbol(symbol_name = command_code.attrib['name'], command_code = cc_val, access = access_mode, bit_range = reg_bit_range, default = reg_default, description = reg_description, presets = '', id_element=None, id_cell=None, subordinate = False) subordinate = True for bit_field in bit_fields: presets = [] presets_attrib = '' for preset in bit_field.findall('./preset'): presets.append("{} = {}".format(preset.attrib['name'], preset.attrib['value'])) presets_attrib += '{},'.format(preset.attrib['name']) presets_attrib = presets_attrib[:-1] # dump last comma. bit_range = self.bit_range_str(lsb=bit_field.attrib['offset'], size= bit_field.attrib['size']) if bit_field.find("./default") is not None: default = bit_field.find("./default").text #default_cell else: default = "N/A" #default_cell description = bit_field.find("./description").text if len(presets) == 1: description += "\nEnum: {}".format(presets[0]) elif len(presets) >= 1: description += "\nEnums: " for preset in presets: description += "\t{},\n".format(preset) description = description[:-2] # remove last comma self.add_symbol(symbol_name = bit_field.attrib['name'], command_code = cc_val, access = access_mode, bit_range = bit_range, default = default, description = description, presets = presets_attrib, id_element=None, id_cell=None, subordinate = subordinate)
[docs]class csv_converter(inDesignOutput): '''converts csv input file to appropriate XML format for import to InDesign Expects 6 columns to be ordered: SYMBOL_NAME, COMMAND_CODE, ACCESS ex(R/W), BIT_RANGE ex(15:0), DEFAULT, DESCRIPTION ''' def __init__(self, csvfilename, **kwargs): inDesignOutput.__init__(self) with open(csvfilename, 'rb') as csvfile: csvreader = csv.reader(csvfile, **kwargs) #pass delimiter, quotechar, escapechar, lineterminator, etc here if necessary (https://docs.python.org/2/library/csv.html#csv-fmt-params) for row in csvreader: self.add_symbol(symbol_name = row[0], #converter functions available above to help form access, bit_range strings! command_code = row[1], access = row[2], bit_range = row[3], default = row[4], description = row[5], presets = '', id_element = None, id_cell = None, subordinate = None) self.add_xml_revision("CSV revision placeholder")
if __name__ == '__main__': # Get Variables import os try: DESIGN = '{}'.format(os.environ['DESIGN']) except: raise Exception('ERROR: DESIGN variable not defined!') try: REG_XML = '{}'.format(os.environ['REG_XML']) except: raise Exception('ERROR: REG_XML variable not defined!') try: SYN_INDESIGN = '{}'.format(os.environ['SYN_INDESIGN']) except: raise Exception('ERROR: SYN_INDESIGN variable not defined!') try: DATASHEET_XML_USE = '{}'.format(os.environ['DATASHEET_XML_USE']) except: raise Exception('ERROR: DATASHEET_XML_USE variable not defined!') try: access = '{}'.format(os.environ['DATASHEET_XML_ACCESS']) access = access.replace(' ', '') DATASHEET_XML_ACCESS = access.split(',') except: raise Exception('ERROR: DATASHEET_XML_ACCESS variable not defined!') datasheet_xml = xml_converter ( xmlfilename = './{}'.format(REG_XML) , use_case = DATASHEET_XML_USE , access_list = DATASHEET_XML_ACCESS ) datasheet_xml.write('{}/{}_indesign.xml'.format(SYN_INDESIGN, DESIGN)) datasheet_xml.write('{}/{}_indesign.xml_temp'.format(SYN_INDESIGN, DESIGN)) # Don't use --format with xmllint, Adobe inDesign wants 'linearized' output, no extra spaces. # print # print "**********************************************************************************************" # print "* InDesign requires linearized output (no extra white-space) - use notepad++ XMLTools plugin *" # print "**********************************************************************************************" # print