def parse_database(database_filename): try: from lxml import etree except ImportError: LOG.warning( "Install the 'lxml' Python package to speed up CAN database parsing" ) try: # Python 2.5 import xml.etree.cElementTree as etree except ImportError: try: # Python 2.5 import xml.etree.ElementTree as etree except ImportError: try: # normal cElementTree install import cElementTree as etree except ImportError: try: # normal ElementTree install import elementtree.ElementTree as etree except ImportError: fatal_error( "Failed to import ElementTree from any known place" ) return etree.parse(database_filename)
def main(): """Main Routine @todo dump last print to a filename or pipe instead.""" configure_logging() arguments = parse_options() search_paths = arguments.search_paths or [] search_paths.insert(0, DEFAULT_SEARCH_PATH) message_sets = arguments.message_sets or [] if arguments.super_set is not None: super_set_data = load_json_from_search_path(arguments.super_set, arguments.search_paths) super_set_message_sets = super_set_data.get('message_sets', []) if len(super_set_message_sets) == 0: LOG.warning("Superset '%s' has no message sets" % super_set_data.get('name', 'unknown')) message_sets.extend(super_set_message_sets) generator = CodeGenerator(search_paths) for filename in message_sets: message_set = JsonMessageSet.parse(filename, search_paths=search_paths, skip_disabled_mappings=True) if not message_set.validate_messages() or not message_set.validate_name(): fatal_error("unable to generate code") generator.message_sets.append(message_set) # TODO dump to a filename or pipe instead print(generator.build_source())
def main(): configure_logging() arguments = parse_options() search_paths = arguments.search_paths or [] search_paths.insert(0, DEFAULT_SEARCH_PATH) message_sets = arguments.message_sets or [] if arguments.super_set is not None: super_set_data = load_json_from_search_path(arguments.super_set, arguments.search_paths) super_set_message_sets = super_set_data.get('message_sets', []) if len(super_set_message_sets) == 0: LOG.warning("Superset '%s' has no message sets" % super_set_data.get('name', 'unknown')) message_sets.extend(super_set_message_sets) if arguments.py: generator = CodeGeneratorPython(search_paths) else: generator = CodeGenerator(search_paths) for filename in message_sets: message_set = JsonMessageSet.parse(filename, search_paths=search_paths, skip_disabled_mappings=True) if not message_set.validate_messages() or not message_set.validate_name(): fatal_error("unable to generate code") generator.message_sets.append(message_set) # TODO dump to a filename or pipe instead print(generator.build_source())
def _parse_buses(cls, data): buses = {} for bus_name, bus_data in data.get('buses', {}).items(): buses[bus_name] = CanBus(name=bus_name, **bus_data) if buses[bus_name].speed is None: fatal_error("Bus %s is missing the 'speed' attribute" % bus_name) return buses
def merge_message(self, data): self.bus_name = self.bus_name or data.get('bus', None) message_attributes = dir(self) message_attributes = [ a.replace('bus_name', 'bus') for a in message_attributes ] data_attributes = list(data.keys()) extra_attributes = set(data_attributes) - set(message_attributes) if extra_attributes: fatal_error('ERROR: Message %s has unrecognized attributes: %s' % (data.get('id'), ', '.join(extra_attributes))) if getattr(self, 'message_set'): self.bus = self.message_set.lookup_bus(name=self.bus_name) if not self.bus.valid(): self.enabled = False msg = "" if self.bus is None: msg = "Bus '%s' is invalid, only %s are defined" % ( self.bus_name, list(self.message_set.valid_buses())) else: msg = "Bus '%s' is disabled" % self.bus_name LOG.warning("%s - message 0x%x will be disabled" % (msg, self.id)) self.id = self.id or data.get('id') self.name = self.name or data.get('name', None) self.bit_numbering_inverted = (self.bit_numbering_inverted or data.get( 'bit_numbering_inverted', None)) self.max_frequency = data.get('max_frequency', self.max_frequency) if self.max_frequency is None: self.max_frequency = self.bus.max_message_frequency self.max_signal_frequency = data.get('max_signal_frequency', self.max_signal_frequency) self.force_send_changed = data.get('force_send_changed', self.force_send_changed) self.force_send_changed_signals = data.get( 'force_send_changed_signals', self.force_send_changed_signals) self.handlers.extend(data.get('handlers', [])) if 'handler' in data: # Support deprecated single 'handler' field self.handlers.append(data.get('handler')) LOG.warning("The 'handler' attribute on the message " + "%s is deprecated but will still work for " % self.name + "now - the replacement is a 'handlers' array") if self.enabled is None: self.enabled = data.get('enabled', True) else: self.enabled = data.get('enabled', self.enabled) if 'signals' in data: self.merge_signals(data['signals'])
def _parse_buses(cls, data): buses = {} for bus_name, bus_data in data.get('buses', {}).items(): buses[bus_name] = CanBus(name=bus_name, default_raw_can_mode=data.get('raw_can_mode', "off"), default_max_message_frequency=data.get('max_message_frequency', 0), **bus_data) if buses[bus_name].speed is None: fatal_error("Bus %s is missing the 'speed' attribute" % bus_name) return buses
def __init__(self, database_name, tree, all_messages): self.messages = {} for message_id, message in all_messages.items(): numeric_message_id = int(message_id, 0) query = "./Node/TxMessage[ID=\"0x%s\"]" # Search for both lower and upper case hex for attr_value in ["%X", "%x"]: node = tree.find(query % (attr_value % numeric_message_id)) if node is not None: break if node is None: LOG.warning("Unable to find message ID 0x%x in %s" % ( numeric_message_id, database_name)) else: if 'signals' not in message: fatal_error("This message object is missing a " "top-level 'signals' field: %s" % message) self.messages[numeric_message_id] = XMLBackedMessage.from_xml_node( node, message_id, message['signals'])
def parse_database(database_filename): try: from lxml import etree except ImportError: LOG.warning("Install the 'lxml' Python package to speed up CAN database parsing") try: # Python 2.5 import xml.etree.cElementTree as etree except ImportError: try: # Python 2.5 import xml.etree.ElementTree as etree except ImportError: try: # normal cElementTree install import cElementTree as etree except ImportError: try: # normal ElementTree install import elementtree.ElementTree as etree except ImportError: fatal_error("Failed to import ElementTree from any known place") return etree.parse(database_filename)
def merge_signal(self, data): self.name = data.get('name', self.name) self.enabled = data.get('enabled', self.enabled) self.generic_name = data.get('generic_name', self.name) self.bit_position = data.get('bit_position', self.bit_position) self.bit_size = data.get('bit_size', self.bit_size) self.factor = data.get('factor', self.factor) self.offset = data.get('offset', self.offset) self.min_value = data.get('min_value', self.min_value) self.max_value = data.get('max_value', self.max_value) # Kind of nasty, but we want to avoid actually setting one of the # implicit handlers on the object (and then later on, assuming that it # was set explicitly) self.decoder = data.get('decoder', getattr(self, '_decoder', None)) self.writable = data.get('writable', self.writable) self.encoder = data.get('encoder', self.encoder) self.send_same = data.get('send_same', self.send_same) self.force_send_changed = data.get('force_send_changed', self.force_send_changed) self.ignore = data.get('ignore', self.ignore) self.max_frequency = data.get('max_frequency', self.max_frequency) self.bit_numbering_inverted = data.get('bit_numbering_inverted') if 'send_frequency' in data: LOG.warning("The 'send_frequency' attribute in the signal " + "%s is deprecated and has no effect " % self.generic_name + " - see the replacement, max_frequency") signal_attributes = dir(self) data_attributes = list(data.keys()) extra_attributes = set(data_attributes) - set(signal_attributes) if extra_attributes: fatal_error( 'ERROR: Signal %s in %s has unrecognized attributes: %s' % (self.name, self.message.name, ', '.join(extra_attributes)))
def _parse_mappings(self, data, search_paths, skip_disabled_mappings): all_messages = [] all_diagnostic_messages = [] all_commands = [] all_extra_sources = set() all_initializers = [] all_loopers = [] for mapping in data.get('mappings', []): if 'mapping' not in mapping: fatal_error("Mapping is missing the mapping file path") mapping_enabled = mapping.get('enabled', True) if not mapping_enabled: LOG.warning("Mapping '%s' is disabled" % mapping['mapping']) if skip_disabled_mappings: continue LOG.warning("Adding mapping '%s'" % mapping['mapping']) bus_name = mapping.get('bus', None) if bus_name is None: LOG.warning("No default bus associated with '%s' mapping" % mapping['mapping']) elif bus_name not in self.buses: fatal_error("Bus '%s' (from mapping %s) is not defined" % (bus_name, mapping['mapping'])) elif not self.buses[bus_name].valid(): LOG.warning("Mapping '%s' is disabled because bus '%s' " % (mapping['mapping'], bus_name) + "is not associated with a CAN controller") mapping['enabled'] = False if skip_disabled_mappings: continue mapping_data = load_json_from_search_path(mapping['mapping'], search_paths) commands = mapping_data.get('commands', []) for command in commands: command.setdefault('enabled', mapping_enabled) all_commands.extend(commands) diagnostic_messages = mapping_data.get('diagnostic_messages', []) for message in diagnostic_messages: message.setdefault('bus', bus_name) message.setdefault('enabled', mapping_enabled) all_diagnostic_messages.extend(diagnostic_messages) if mapping_enabled: all_initializers.extend(mapping_data.get('initializers', [])) all_loopers.extend(mapping_data.get('loopers', [])) all_extra_sources.update( set(mapping_data.get('extra_sources', set()))) messages = mapping_data.get('messages', {}) if len(messages) == 0: LOG.warning("Mapping file '%s' doesn't define any messages" % mapping['mapping']) if 'database' in mapping: database_filename, database_tree = self._parse_database( find_file(mapping['database'], search_paths)) messages = merge( merge_database_into_mapping(database_filename, database_tree, messages).get('messages', {}), messages) if mapping.get('bit_numbering_inverted', None) is None: LOG.warning( "The bit number inversion setting is undefined " "for the mapping '%s', but it " % mapping['mapping'] + "is database-backed - assuming inverted") for message in list(messages.values()): message.setdefault('bit_numbering_inverted', True) for message_id, message in list(messages.items()): message['id'] = message_id message.setdefault('bus', bus_name) message.setdefault('enabled', mapping_enabled) all_messages.extend(list(messages.values())) return { 'messages': all_messages, 'commands': all_commands, 'diagnostic_messages': all_diagnostic_messages, 'initializers': all_initializers, 'extra_sources': all_extra_sources, 'loopers': all_loopers }
# Python 2.5 import xml.etree.cElementTree as etree except ImportError: try: # Python 2.5 import xml.etree.ElementTree as etree except ImportError: try: # normal cElementTree install import cElementTree as etree except ImportError: try: # normal ElementTree install import elementtree.ElementTree as etree except ImportError: fatal_error("Failed to import ElementTree from any known place") class Network(object): """Represents all the messages on a single bus in an XML-backed database.""" def __init__(self, database_name, tree, all_messages): self.messages = {} for message_id, message in all_messages.items(): message_id = int(message_id, 0) query = "./Node/TxMessage[ID=\"0x%s\"]" # Search for both lower and upper case hex for attr_value in ["%X", "%x"]: node = tree.find(query % (attr_value % message_id)) if node is not None:
def _parse_mappings(self, data, search_paths, skip_disabled_mappings): all_messages = [] all_commands = [] all_extra_sources = set() all_initializers = [] all_loopers = [] for mapping in data.get('mappings', []): if 'mapping' not in mapping: fatal_error("Mapping is missing the mapping file path") mapping_enabled = mapping.get('enabled', True) if not mapping_enabled: LOG.warning("Mapping '%s' is disabled" % mapping['mapping']) if skip_disabled_mappings: continue LOG.warning("Adding mapping '%s'" % mapping['mapping']) bus_name = mapping.get('bus', None) if bus_name is None: LOG.warning("No default bus associated with '%s' mapping" % mapping['mapping']) elif bus_name not in self.buses: fatal_error("Bus '%s' (from mapping %s) is not defined" % (bus_name, mapping['mapping'])) elif not self.buses[bus_name].valid(): LOG.warning("Mapping '%s' is disabled because bus '%s' " % ( mapping['mapping'], bus_name) + "is not associated with a CAN controller") mapping['enabled'] = False if skip_disabled_mappings: continue mapping_data = load_json_from_search_path(mapping['mapping'], search_paths) commands = mapping_data.get('commands', []) if not mapping_enabled: for command in commands: command['enabled'] = False all_commands.extend(commands) if mapping_enabled: all_initializers.extend(mapping_data.get('initializers', [])) all_loopers.extend(mapping_data.get('loopers', [])) all_extra_sources.update( set(mapping_data.get('extra_sources', set()))) messages = mapping_data.get('messages', {}) if len(messages) == 0: LOG.warning("Mapping file '%s' doesn't define any messages" % mapping['mapping']) if 'database' in mapping: database_filename, database_tree = self._parse_database( find_file(mapping['database'], search_paths)) messages = merge(merge_database_into_mapping(database_filename, database_tree, messages).get('messages', {}), messages) if mapping.get('bit_numbering_inverted', None) is None: LOG.warning("The bit number inversion setting is undefined " "for the mapping '%s', but it " % mapping['mapping'] + "is database-backed - assuming inverted") for message in messages.values(): message.setdefault('bit_numbering_inverted', True) for message_id, message in messages.items(): message['id'] = message_id message.setdefault('bus', bus_name) message.setdefault('enabled', mapping_enabled) all_messages.extend(messages.values()) return {'messages': all_messages, 'commands': all_commands, 'initializers': all_initializers, 'extra_sources': all_extra_sources, 'loopers': all_loopers}
# Python 2.5 import xml.etree.cElementTree as etree except ImportError: try: # Python 2.5 import xml.etree.ElementTree as etree except ImportError: try: # normal cElementTree install import cElementTree as etree except ImportError: try: # normal ElementTree install import elementtree.ElementTree as etree except ImportError: fatal_error( "Failed to import ElementTree from any known place") class Network(object): """Represents all the messages on a single bus in an XML-backed database.""" def __init__(self, database_name, tree, all_messages): self.messages = {} for message_id, message in all_messages.items(): message_id = int(message_id, 0) query = "./Node/TxMessage[ID=\"0x%s\"]" # Search for both lower and upper case hex for attr_value in ["%X", "%x"]: node = tree.find(query % (attr_value % message_id)) if node is not None: break
def _parse_mappings(self, data, search_paths, skip_disabled_mappings): all_messages = [] all_commands = [] all_extra_sources = set() all_initializers = [] all_loopers = [] for mapping in data.get('mappings', []): if 'mapping' not in mapping: fatal_error("Mapping is missing the mapping file path") mapping_enabled = mapping.get('enabled', True) if not mapping_enabled: LOG.warning("Mapping '%s' is disabled" % mapping['mapping']) if skip_disabled_mappings: continue bus_name = mapping.get('bus', None) if bus_name is None: LOG.warning("No default bus associated with '%s' mapping" % mapping['mapping']) elif bus_name not in self.buses: fatal_error("Bus '%s' (from mapping %s) is not defined" % (bus_name, mapping['mapping'])) mapping_data = load_json_from_search_path(mapping['mapping'], search_paths) commands = mapping_data.get('commands', []) if not mapping_enabled: for command in commands: command['enabled'] = False all_commands.extend(commands) if mapping_enabled: all_initializers.extend(mapping_data.get('initializers', [])) all_loopers.extend(mapping_data.get('loopers', [])) all_extra_sources.update( set(mapping_data.get('extra_sources', set()))) messages = mapping_data.get('messages', []) if len(messages) == 0: LOG.warning("Mapping file '%s' doesn't define any messages" % mapping['mapping']) if 'database' in mapping: messages = merge(merge_database_into_mapping( find_file(mapping['database'], search_paths), messages)['messages'], messages) for message_id, message in messages.items(): message['id'] = message_id message.setdefault('bus', bus_name) message.setdefault('enabled', mapping_enabled) all_messages.extend(messages.values()) return {'messages': all_messages, 'commands': all_commands, 'initializers': all_initializers, 'extra_sources': all_extra_sources, 'loopers': all_loopers}