Example #1
0
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())
Example #3
0
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
Example #7
0
 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
Example #8
0
    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)
Example #10
0
    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)))
Example #11
0
    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
        }
Example #12
0
    # 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}
Example #14
0
        # 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}