From 8f04a011d48a7ae3cab3db7e4f75677d2586f714 Mon Sep 17 00:00:00 2001 From: Erwan Gouriou Date: Fri, 9 Nov 2018 14:51:34 +0100 Subject: [PATCH 01/18] scripts/dts/extract: reg.py: Flatten reg instead of props Flatten reg instead of props Signed-off-by: Erwan Gouriou --- scripts/dts/extract/reg.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/dts/extract/reg.py b/scripts/dts/extract/reg.py index 5836d504df0e0..f40c07f578155 100644 --- a/scripts/dts/extract/reg.py +++ b/scripts/dts/extract/reg.py @@ -45,8 +45,8 @@ def populate_edts(self, node_address): # Newer versions of dtc might have the reg propertly look like # reg = <1 2>, <3 4>; # So we need to flatten the list in that case - if isinstance(props[0], list): - props = [item for sublist in props for item in sublist] + if isinstance(reg[0], list): + reg = [item for sublist in reg for item in sublist] (nr_address_cells, nr_size_cells) = get_addr_size_cells(node_address) From d41bf05c103fd9f7e68ace76f2c2ddee72544cd9 Mon Sep 17 00:00:00 2001 From: Erwan Gouriou Date: Thu, 18 Oct 2018 15:24:18 +0200 Subject: [PATCH 02/18] scripts/dts: provide edts sanity check scripts Validate generated etds.json against a reference edts file. Script first checks edts structure then content of various elements and finally devices parameters values. This last step is done using a specific method for ref_edts parameter extraction so we can verify behavior of edtsdatabase class extraction function. Signed-off-by: Erwan Gouriou --- scripts/dts_sanity/edts_ref.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/dts_sanity/edts_ref.json b/scripts/dts_sanity/edts_ref.json index e051924d4f117..07d646b4e8fec 100644 --- a/scripts/dts_sanity/edts_ref.json +++ b/scripts/dts_sanity/edts_ref.json @@ -534,4 +534,4 @@ "unique_id": "REFSOC_SPI_44000000_REFSOC_SENSOR_SPI_0" } } -} \ No newline at end of file +} From 21fe1cf1892f22906d88ba88bcac86a5479f199c Mon Sep 17 00:00:00 2001 From: Bobby Noelte Date: Wed, 28 Feb 2018 10:37:23 +0100 Subject: [PATCH 03/18] scripts: codegen: add inline code generation Codegen is a file generation tool. It uses pieces of Python code in the source file as generators to generate whatever text is needed. If a source file is added by zephyr_sources_codegen(..) or zephyr_sources_codegen_ifdef(..) codegen will be executed and the generated file stored to the build directory. Compilation will run on the generated file only. Codegen is based on Cog. All files taken from Cog are modified. The files are marked by the Cog author's copyright: Copyright 2004-2016, Ned Batchelder. http://nedbatchelder.com/code/cog SPDX-License-Identifier: MIT Origin: https://pypi.python.org/pypi/cogapp Status: 2.5.1 Description: A code generator for executing Python snippets in source files. Dependencies: python URL: https://pypi.python.org/pypi/cogapp commit: 2.5.1 Maintained-by: External License: MIT License Link: URL: https://pypi.python.org/pypi/cogapp Signed-off-by: Bobby Noelte --- CMakeLists.txt | 7 + cmake/extensions.cmake | 193 ++++++++++ scripts/codegen/cmake.py | 191 ++++++++++ scripts/codegen/codegen.py | 630 ++++++++++++++++++++++++++++++++ scripts/codegen/config.py | 56 +++ scripts/codegen/edts.py | 31 ++ scripts/codegen/error.py | 68 ++++ scripts/codegen/filereader.py | 20 + scripts/codegen/generic.py | 51 +++ scripts/codegen/guard.py | 16 + scripts/codegen/importmodule.py | 37 ++ scripts/codegen/include.py | 67 ++++ scripts/codegen/log.py | 41 +++ scripts/codegen/options.py | 139 +++++++ scripts/codegen/output.py | 19 + scripts/codegen/redirectable.py | 31 ++ scripts/codegen/whiteutils.py | 72 ++++ scripts/codegen/zephyr.py | 12 + scripts/gen_code.py | 13 + 19 files changed, 1694 insertions(+) create mode 100644 scripts/codegen/cmake.py create mode 100644 scripts/codegen/codegen.py create mode 100644 scripts/codegen/config.py create mode 100644 scripts/codegen/edts.py create mode 100644 scripts/codegen/error.py create mode 100644 scripts/codegen/filereader.py create mode 100644 scripts/codegen/generic.py create mode 100644 scripts/codegen/guard.py create mode 100644 scripts/codegen/importmodule.py create mode 100644 scripts/codegen/include.py create mode 100644 scripts/codegen/log.py create mode 100644 scripts/codegen/options.py create mode 100644 scripts/codegen/output.py create mode 100644 scripts/codegen/redirectable.py create mode 100644 scripts/codegen/whiteutils.py create mode 100644 scripts/codegen/zephyr.py create mode 100755 scripts/gen_code.py diff --git a/CMakeLists.txt b/CMakeLists.txt index a282b51163b77..01f6c65254291 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -413,6 +413,13 @@ add_subdirectory(subsys) add_subdirectory(drivers) add_subdirectory(tests) +# Add all generated zephyr sources in the same context as the zephyr library +# is created. Assure all sub directories that might invoke code generation +# are processed before. +get_property(zephyr_generated_sources GLOBAL PROPERTY zephyr_generated_sources_property) +set_source_files_properties(${zephyr_generated_sources} PROPERTIES GENERATED 1) +target_sources(zephyr PRIVATE ${zephyr_generated_sources}) + set(syscall_macros_h ${ZEPHYR_BINARY_DIR}/include/generated/syscall_macros.h) add_custom_target(syscall_macros_h_target DEPENDS ${syscall_macros_h}) diff --git a/cmake/extensions.cmake b/cmake/extensions.cmake index 5d50d9ea45094..38b75b4317c7f 100644 --- a/cmake/extensions.cmake +++ b/cmake/extensions.cmake @@ -304,6 +304,192 @@ macro(get_property_and_add_prefix result target property prefix) endforeach() endmacro() +# 1.3 generate_inc_* + +# These functions are useful if there is a need to generate a file +# that can be included into the application at build time. The file +# can also be compressed automatically when embedding it. +# +# See tests/application_development/gen_inc_file for an example of +# usage. +function(generate_inc_file + source_file # The source file to be converted to hex + generated_file # The generated file + ) + add_custom_command( + OUTPUT ${generated_file} + COMMAND + ${PYTHON_EXECUTABLE} + ${ZEPHYR_BASE}/scripts/file2hex.py + ${ARGN} # Extra arguments are passed to file2hex.py + --file ${source_file} + > ${generated_file} # Does pipe redirection work on Windows? + DEPENDS ${source_file} + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + ) +endfunction() + +function(generate_inc_file_for_gen_target + target # The cmake target that depends on the generated file + source_file # The source file to be converted to hex + generated_file # The generated file + gen_target # The generated file target we depend on + # Any additional arguments are passed on to file2hex.py + ) + generate_inc_file(${source_file} ${generated_file} ${ARGN}) + + # Ensure 'generated_file' is generated before 'target' by creating a + # dependency between the two targets + + add_dependencies(${target} ${gen_target}) +endfunction() + +function(get_unique_generated_target_name + generated_file # The generated file + generated_target_name # the unique name + ) + string(RANDOM LENGTH 8 random_chars) + get_filename_component(basename ${generated_file} NAME) + string(REPLACE "." "_" basename ${basename}) + string(REPLACE "@" "_" basename ${basename}) + set(generated_target_name "gen_${basename}_${random_chars}" PARENT_SCOPE) +endfunction() + +function(generate_inc_file_for_target + target # The cmake target that depends on the generated file + source_file # The source file to be converted to hex + generated_file # The generated file + # Any additional arguments are passed on to file2hex.py + ) + # Ensure 'generated_file' is generated before 'target' by creating a + # 'custom_target' for it and setting up a dependency between the two + # targets + get_unique_generated_target_name(${generated_file} generated_target_name) + add_custom_target(${generated_target_name} DEPENDS ${generated_file}) + generate_inc_file_for_gen_target(${target} ${source_file} ${generated_file} + ${generated_target_name} ${ARGN}) +endfunction() + +function(target_sources_codegen + target # The cmake target that depends on the generated file + ) + set(options) + set(oneValueArgs) + set(multiValueArgs CODEGEN_DEFINES DEPENDS) + cmake_parse_arguments(CODEGEN "${options}" "${oneValueArgs}" + "${multiValueArgs}" ${ARGN}) + # prepend -D to all defines + string(REGEX REPLACE "([^;]+)" "-D;\\1" + CODEGEN_CODEGEN_DEFINES "${CODEGEN_CODEGEN_DEFINES}") + # Get all the files that make up codegen for dependency + file(GLOB CODEGEN_SOURCES + ${ZEPHYR_BASE}/scripts/dts/edtsdevice.py + ${ZEPHYR_BASE}/scripts/dts/edtsdatabase.py + ${ZEPHYR_BASE}/scripts/codegen/*.py + ${ZEPHYR_BASE}/scripts/gen_code.py) + + message(STATUS "Will generate for target ${target}") + # Generated file must be generated to the current binary directory. + # Otherwise this would trigger CMake issue #14633: + # https://gitlab.kitware.com/cmake/cmake/issues/14633 + foreach(arg ${CODEGEN_UNPARSED_ARGUMENTS}) + if(IS_ABSOLUTE ${arg}) + set(template_file ${arg}) + get_filename_component(generated_file_name ${arg} NAME) + set(generated_file ${CMAKE_CURRENT_BINARY_DIR}/${generated_file_name}) + else() + set(template_file ${CMAKE_CURRENT_SOURCE_DIR}/${arg}) + set(generated_file ${CMAKE_CURRENT_BINARY_DIR}/${arg}) + endif() + get_filename_component(template_dir ${template_file} DIRECTORY) + + if(IS_DIRECTORY ${template_file}) + message(FATAL_ERROR "target_sources_codegen() was called on a directory") + endif() + + # Generate file from template + message(STATUS " from '${template_file}'") + message(STATUS " to '${generated_file}'") + add_custom_command( + COMMENT "CodeGen ${generated_file}" + OUTPUT ${generated_file} + MAIN_DEPENDENCY ${template_file} + DEPENDS + ${CODEGEN_DEPENDS} + ${CODEGEN_SOURCES} + COMMAND + ${PYTHON_EXECUTABLE} + ${ZEPHYR_BASE}/scripts/gen_code.py + ${CODEGEN_CODEGEN_DEFINES} + -D "PROJECT_NAME=${PROJECT_NAME}" + -D "PROJECT_SOURCE_DIR=${PROJECT_SOURCE_DIR}" + -D "PROJECT_BINARY_DIR=${PROJECT_BINARY_DIR}" + -D "CMAKE_SOURCE_DIR=${CMAKE_SOURCE_DIR}" + -D "CMAKE_BINARY_DIR=${CMAKE_BINARY_DIR}" + -D "CMAKE_CURRENT_SOURCE_DIR=${CMAKE_CURRENT_SOURCE_DIR}" + -D "CMAKE_CURRENT_BINARY_DIR=${CMAKE_CURRENT_BINARY_DIR}" + -D "CMAKE_CURRENT_LIST_DIR=${CMAKE_CURRENT_LIST_DIR}" + -D "CMAKE_FILES_DIRECTORY=${CMAKE_FILES_DIRECTORY}" + -D "CMAKE_PROJECT_NAME=${CMAKE_PROJECT_NAME}" + -D "CMAKE_SYSTEM=${CMAKE_SYSTEM}" + -D "CMAKE_SYSTEM_NAME=${CMAKE_SYSTEM_NAME}" + -D "CMAKE_SYSTEM_VERSION=${CMAKE_SYSTEM_VERSION}" + -D "CMAKE_SYSTEM_PROCESSOR=${CMAKE_SYSTEM_PROCESSOR}" + -D "CMAKE_C_COMPILER=${CMAKE_C_COMPILER}" + -D "CMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}" + -D "CMAKE_COMPILER_IS_GNUCC=${CMAKE_COMPILER_IS_GNUCC}" + -D "CMAKE_COMPILER_IS_GNUCXX=${CMAKE_COMPILER_IS_GNUCXX}" + -D "GENERATED_DTS_BOARD_H=${GENERATED_DTS_BOARD_H}" + -D "GENERATED_DTS_BOARD_CONF=${GENERATED_DTS_BOARD_CONF}" + -D "GENERATED_EDTS=${GENERATED_EDTS}" + --input "${template_file}" + --output "${generated_file}" + --log "${CMAKE_BINARY_DIR}/${CMAKE_FILES_DIRECTORY}/CodeGen.log" + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + ) + if("${target}" STREQUAL "zephyr") + # zephyr is special + get_unique_generated_target_name(${generated_file} generated_target_name) + add_custom_target(${generated_target_name} DEPENDS ${generated_file}) + add_dependencies(zephyr ${generated_target_name}) + # Remember all the files that are generated for zephyr. + # target_sources(zephyr PRIVATE ${zephyr_generated_sources}) + # is executed in the top level CMakeFile.txt context. + get_property(zephyr_generated_sources GLOBAL PROPERTY zephyr_generated_sources_property) + list(APPEND zephyr_generated_sources ${generated_file}) + set_property(GLOBAL PROPERTY zephyr_generated_sources_property "${zephyr_generated_sources}") + # Add template directory to include path to allow includes with + # relative path in generated file to work + zephyr_include_directories(${template_dir}) + else() + target_sources(${target} PRIVATE ${generated_file}) + # Add template directory to include path to allow includes with + # relative path in generated file to work + target_include_directories(${target} PRIVATE ${template_dir}) + endif() + endforeach() +endfunction() + +function(zephyr_sources_codegen) + target_sources_codegen(zephyr ${ARGN}) +endfunction() + +function(zephyr_sources_codegen_ifdef feature_toggle) + if(${${feature_toggle}}) + zephyr_sources_codegen(${ARGN}) + endif() +endfunction() + +function(zephyr_library_sources_codegen) + target_sources_codegen(${ZEPHYR_CURRENT_LIBRARY} ${ARGN}) +endfunction() + +function(zephyr_library_sources_codegen_ifdef feature_toggle) + if(${${feature_toggle}}) + zephyr_library_sources_codegen(${ARGN}) + endif() +endfunction() + # 1.2 zephyr_library_* # # Zephyr libraries use CMake's library concept and a set of @@ -357,6 +543,13 @@ macro(zephyr_library_named name) # This is a macro because we need add_library() to be executed # within the scope of the caller. set(ZEPHYR_CURRENT_LIBRARY ${name}) + + if("${name}" STREQUAL "zephyr") + # We have to mark all the generated files "GENERATED" in this context + get_property(zephyr_generated_files GLOBAL PROPERTY zephyr_generated_files_property) + set_source_files_properties(${zephyr_generated_files} PROPERTIES GENERATED 1) + endif() + add_library(${name} STATIC "") zephyr_append_cmake_library(${name}) diff --git a/scripts/codegen/cmake.py b/scripts/codegen/cmake.py new file mode 100644 index 0000000000000..eedc0be56c07f --- /dev/null +++ b/scripts/codegen/cmake.py @@ -0,0 +1,191 @@ +# Copyright (c) 2018 Open Source Foundries Limited. +# Copyright (c) 2018 Bobby Noelte. +# +# SPDX-License-Identifier: Apache-2.0 +# +# CMakeCacheEntry and CMakeCache are taken from scripts/zephyr_run.py. +# + +import os +import sys +import re +from collections import OrderedDict +from pathlib import Path + + +class CMakeCacheEntry: + '''Represents a CMake cache entry. + This class understands the type system in a CMakeCache.txt, and + converts the following cache types to Python types: + Cache Type Python type + ---------- ------------------------------------------- + FILEPATH str + PATH str + STRING str OR list of str (if ';' is in the value) + BOOL bool + INTERNAL str OR list of str (if ';' is in the value) + ---------- ------------------------------------------- + ''' + + # Regular expression for a cache entry. + # + # CMake variable names can include escape characters, allowing a + # wider set of names than is easy to match with a regular + # expression. To be permissive here, use a non-greedy match up to + # the first colon (':'). This breaks if the variable name has a + # colon inside, but it's good enough. + CACHE_ENTRY = re.compile( + r'''(?P.*?) # name + :(?PFILEPATH|PATH|STRING|BOOL|INTERNAL) # type + =(?P.*) # value + ''', re.X) + + @classmethod + def _to_bool(cls, val): + # Convert a CMake BOOL string into a Python bool. + # + # "True if the constant is 1, ON, YES, TRUE, Y, or a + # non-zero number. False if the constant is 0, OFF, NO, + # FALSE, N, IGNORE, NOTFOUND, the empty string, or ends in + # the suffix -NOTFOUND. Named boolean constants are + # case-insensitive. If the argument is not one of these + # constants, it is treated as a variable." + # + # https://cmake.org/cmake/help/v3.0/command/if.html + val = val.upper() + if val in ('ON', 'YES', 'TRUE', 'Y'): + return True + elif val in ('OFF', 'NO', 'FALSE', 'N', 'IGNORE', 'NOTFOUND', ''): + return False + elif val.endswith('-NOTFOUND'): + return False + else: + try: + v = int(val) + return v != 0 + except ValueError as exc: + raise ValueError('invalid bool {}'.format(val)) from exc + + @classmethod + def from_line(cls, line, line_no): + # Comments can only occur at the beginning of a line. + # (The value of an entry could contain a comment character). + if line.startswith('//') or line.startswith('#'): + return None + + # Whitespace-only lines do not contain cache entries. + if not line.strip(): + return None + + m = cls.CACHE_ENTRY.match(line) + if not m: + return None + + name, type_, value = (m.group(g) for g in ('name', 'type', 'value')) + if type_ == 'BOOL': + try: + value = cls._to_bool(value) + except ValueError as exc: + args = exc.args + ('on line {}: {}'.format(line_no, line),) + raise ValueError(args) from exc + elif type_ == 'STRING' or type_ == 'INTERNAL': + # If the value is a CMake list (i.e. is a string which + # contains a ';'), convert to a Python list. + if ';' in value: + value = value.split(';') + + return CMakeCacheEntry(name, value) + + def __init__(self, name, value): + self.name = name + self.value = value + + def __str__(self): + fmt = 'CMakeCacheEntry(name={}, value={})' + return fmt.format(self.name, self.value) + + +class CMakeCache: + '''Parses and represents a CMake cache file.''' + + def __init__(self, cache_file): + self.load(cache_file) + + def load(self, cache_file): + entries = [] + with open(str(cache_file), 'r') as cache: + for line_no, line in enumerate(cache): + entry = CMakeCacheEntry.from_line(line, line_no) + if entry: + entries.append(entry) + self._entries = OrderedDict((e.name, e) for e in entries) + + def get(self, name, default=None): + entry = self._entries.get(name) + if entry is not None: + return entry.value + else: + return default + + def get_list(self, name, default=None): + if default is None: + default = [] + entry = self._entries.get(name) + if entry is not None: + value = entry.value + if isinstance(value, list): + return value + elif isinstance(value, str): + return [value] + else: + msg = 'invalid value {} type {}' + raise RuntimeError(msg.format(value, type(value))) + else: + return default + + def __getitem__(self, name): + return self._entries[name].value + + def __setitem__(self, name, entry): + if not isinstance(entry, CMakeCacheEntry): + msg = 'improper type {} for value {}, expecting CMakeCacheEntry' + raise TypeError(msg.format(type(entry), entry)) + self._entries[name] = entry + + def __delitem__(self, name): + del self._entries[name] + + def __iter__(self): + return iter(self._entries.values()) + + +class CMakeMixin(object): + __slots__ = [] + + _cmake_cache = None + + def cmake_variable(self, variable_name, default=""): + variable_value = self.options.defines.get(variable_name, default) + if variable_value == "": + raise self._get_error_exception( + "CMake variable '{}' not defined.".format(variable_name), 1) + return variable_value + + def cmake_cache_variable(self, variable_name, default=""): + if self._cmake_cache is None: + cache_file = self.cmake_variable("CMAKE_BINARY_DIR") + cache_file = Path(cache_file).joinpath("CMakeCache.txt") + if not cache_file.is_file(): + raise self._get_error_exception( + "CMake cache file '{}' does not exist or is no file.". + format(cache_file), 1) + self._cmake_cache = CMakeCache(cache_file) + try: + return self._cmake_cache.get(variable_name) + except: + if default == "": + raise self._get_error_exception( + "CMake variable '{}' not defined in cache file.". + format(variable_name), 1) + return default + diff --git a/scripts/codegen/codegen.py b/scripts/codegen/codegen.py new file mode 100644 index 0000000000000..296ae8101d66a --- /dev/null +++ b/scripts/codegen/codegen.py @@ -0,0 +1,630 @@ +# Copyright 2004-2016, Ned Batchelder. +# http://nedbatchelder.com/code/cog +# Copyright (c) 2018 Bobby Noelte. +# +# SPDX-License-Identifier: MIT + +import sys +import os +import imp +import inspect +import re +from traceback import TracebackException + +from .whiteutils import * +from .filereader import NumberedFileReader +from .options import Options, OptionsMixin +from .generic import GenericMixin +from .guard import GuardMixin +from .config import ConfigMixin +from .cmake import CMakeMixin +from .zephyr import ZephyrMixin +from .edts import EDTSMixin +from .include import IncludeMixin +from .log import LogMixin +from .error import ErrorMixin, Error +from .output import OutputMixin +from .importmodule import ImportMixin +from .redirectable import Redirectable, RedirectableMixin + +class CodeGenerator(OptionsMixin, GenericMixin, ConfigMixin, + CMakeMixin, ZephyrMixin, EDTSMixin, GuardMixin, + IncludeMixin, LogMixin, ErrorMixin, OutputMixin, + ImportMixin, RedirectableMixin): + + code_start_marker = b'@code{.codegen}' + code_end_marker = b'@endcode{.codegen}' + code_insert_marker = b'@code{.codeins}@endcode' + + def __init__(self, processor, globals={}, + output_file=None, snippet_file = None): + self._stdout = sys.stdout + self._stderr = sys.stderr + self._outstring = '' + # code snippet markers and lines + self._start_marker = self.code_start_marker.decode('utf-8') + self._end_marker = self.code_end_marker.decode('utf-8') + self._insert_marker = self.code_insert_marker.decode('utf-8') + self.markers = [] + self.lines = [] + # The processor that is using this generator + self.processor = processor + self.options = processor.options + # All generators of a file usually work on the same global namespace + self.generator_globals = globals + self._output_file = output_file + # The file that contains the snippet + self._snippet_file = snippet_file + # The snippet this generator works on + self._snippet = None + # the snippet start offset in original file + self._snippet_offset = None + # the tab size in the snippet + self._snippet_tabsize = 8 + # the current evaluation start offset in the original file + # may be different to snippet offset during evaluation + self._eval_offset = None + # the previous output + self._previous = '' + + def line_is_start_marker(self, s): + return self._start_marker in s + + def line_is_end_marker(self, s): + return self._end_marker in s and not self.line_is_insert_marker(s) + + def line_is_insert_marker(self, s): + return self._insert_marker in s + + def parse_start_marker(self, l, snippet_offset): + self._snippet_offset = snippet_offset + self._eval_offset = snippet_offset + self.markers.append(l.expandtabs(self._snippet_tabsize)) + + def parse_end_marker(self, l): + self.markers.append(l.expandtabs(self._snippet_tabsize)) + + def parse_line(self, l, single_line_snippet=False): + l = l.expandtabs(self._snippet_tabsize).strip('\n') + if single_line_snippet: + # single line snippets contain the markers - remove them + beg = l.find(self._start_marker) + end = l.find(self._end_marker) + if beg > end: + self.lines.append(l) + self.error("Codegen code markers inverted", + frame_index = -2) + else: + l = l[beg+len(self._start_marker):end].strip() + self.lines.append(l) + + def _out(self, output='', dedent=False, trimblanklines=False): + if trimblanklines and ('\n' in output): + lines = output.split('\n') + if lines[0].strip() == '': + del lines[0] + if lines and lines[-1].strip() == '': + del lines[-1] + output = '\n'.join(lines)+'\n' + if dedent: + output = reindentBlock(output) + self._outstring += output + + ## + # @brief Re-indent a code block. + # + # Take a block of text as a string or list of lines. + # Remove any common prefix and whitespace indentation. + # Re-indent using new_indent + # + # @param lines + # @param common_prefix + # @param new_indent + # @return indented code block as a single string. + def _reindent_code(self, lines, common_prefix = '', new_indent=''): + if not isinstance(lines, list): + lines = lines.split('\n') + # remove common prefix + code_lines = [] # all code lines + code_no_white_lines = [] # code lines excluding white space lines + for line in lines: + line = line.expandtabs() + if common_prefix: + line = line.replace(common_prefix, '', 1) + code_lines.append(line) + if line and not line.isspace(): + code_no_white_lines.append(line) + # remove common white space and re-indent + out_lines = [] + common_white = os.path.commonprefix(code_no_white_lines) + common_white = re.search(r'\s*', common_white).group(0) + for line in code_lines: + if common_white: + line = line.replace(common_white, '', 1) + if line and new_indent: + line = new_indent + line + out_lines.append(line) + return '\n'.join(out_lines) + + ## + # @brief Extract the executable Python code from the generator. + # + def _get_code(self, fname, snippet_offset): + # If the markers and lines all have the same prefix + # (end-of-line comment chars, for example), + # then remove it from all the lines. + common_prefix = os.path.commonprefix(self.markers + self.lines) + if not common_prefix: + # there may be a prefix error + # just do some heuristics + if fname.endswith( + ('.h', '.hxx', '.c', '.cpp', '.cxx')): + # assume C/C++ comments + for line in (self.markers + self.lines): + if line.strip().startswith('*'): + common_prefix = '*' + break + elif line.strip().startswith('//'): + common_prefix = '//' + break + if common_prefix: + # there should be a common prefix -> error + lines = list() # lines with correct prefix + for lineno, line in enumerate(self.lines): + if not line.strip().startswith(common_prefix): + print("Codegen: Comment prefix may miss in codegen snippet (+{}) in '{}'.".format( + snippet_offset, fname)) + line_start = lineno - 5 + if line_start < 0: + line_start = 0 + line_end = lineno + 5 + if line_end > len(self.lines): + line_end = len(self.lines) + for i in range(line_start, line_end): + snippet_lineno = i + 2 + input_lineno = snippet_offset + snippet_lineno + print("#{} (+{}, line {}): {}".format( + input_lineno, snippet_offset, snippet_lineno, self.lines[i])) + else: + lines.append(line) + if len(lines) >= int(len(self.lines) / 2): + common_prefix = os.path.commonprefix(lines) + print("Codegen: Assuming comment prefix '{}' for codegen snippet (+{}) in '{}'.".format( + common_prefix, snippet_offset, fname)) + else: + common_prefix = '' + if common_prefix: + self.markers = [ line.replace(common_prefix, '', 1) for line in self.markers ] + code = self._reindent_code(self.lines, common_prefix) + return code + + # Make sure the "codegen" (alias cog) module has our state. + def _set_module_state(self): + restore_state = {} + module_states = self.processor.module_states + module = self.processor.cogmodule + # General module values + restore_state['inFile'] = getattr(module, 'inFile', None) + module.inFile = self._snippet_file + restore_state['outFile'] = getattr(module, 'outFile', None) + module.outFile = self._output_file + restore_state['firstLineNum'] = getattr(module, 'firstLineNum', None) + module.firstLineNum = self._snippet_offset + restore_state['previous'] = getattr(module, 'previous', None) + module.previous = self._previous + # CodeGenerator access + restore_state['options'] = getattr(module, 'options', None) + module.options = self.options + restore_state['Error'] = getattr(module, 'Error', None) + module.Error = self._get_error_exception + # Look for the Mixin classes + for base_cls in inspect.getmro(CodeGenerator): + if "Mixin" in base_cls.__name__: + for member_name, member_value in inspect.getmembers(base_cls): + if member_name.startswith('_'): + continue + if inspect.isroutine(member_value): + restore_state[member_name] = \ + getattr(module, member_name, None) + setattr(module, member_name, + getattr(self, member_name)) + module_states.append(restore_state) + + def _restore_module_state(self): + module_states = self.processor.module_states + module = self.processor.cogmodule + restore_state = module_states.pop() + # General module values + module.inFile = restore_state['inFile'] + module.outFile = restore_state['outFile'] + module.firstLineNum = restore_state['firstLineNum'] + module.previous = restore_state['previous'] + # CodeGenerator access + module.options = restore_state['options'] + module.Error = restore_state['Error'] + # Look for the Mixin classes + for base_cls in inspect.getmro(CodeGenerator): + if "Mixin" in base_cls.__name__: + for member_name, member_value in inspect.getmembers(base_cls): + if member_name.startswith('_'): + continue + if inspect.isroutine(member_value): + setattr(module, member_name, restore_state[member_name]) + + ## + # @brief snippet id to be used in logging and error reporting + # + # Accounts for extra lines added during evaluation + # + def _get_snippet_id(self): + return "+{}".format(self._eval_offset) + + ## + # @brief get snippet line number from evaluation line number + # + # Accounts for extra lines added during evaluation + # + # @param eval_lineno line number as reported from python code eval + def _get_snippet_lineno(self, eval_lineno): + return int(eval_lineno) + self._eval_offset - self._snippet_offset + + def _list_snippet(self): + if not self._snippet: + return None + listing = "" + for i, line in enumerate(self._snippet.splitlines()): + eval_lineno = i + 2 + input_lineno = self._eval_offset + eval_lineno + if i > 0: + listing += "\n" + listing += "#{} ({}, line {}): {}".format( + input_lineno, self._get_snippet_id(), eval_lineno, line) + return listing + + def _list_lines(self): + if len(self.lines) == 0: + return None + listing = "" + for i, line in enumerate(self.lines): + eval_lineno = i + 2 + input_lineno = self._eval_offset + eval_lineno + if i > 0: + listing += "\n" + listing += "#{} ({}, line {}): {}".format( + input_lineno, self._get_snippet_id(), eval_lineno, line) + return listing + + ## + # @brief evaluate + # + def evaluate(self): + self._snippet = self._get_code(self._snippet_file, self._snippet_offset) + if not self._snippet: + return '' + + # we add an extra line 'import codegen' + # to snippet so account for that + self._eval_offset = self._snippet_offset - 1 + + # In Python 2.2, the last line has to end in a newline. + eval_code = "import codegen\n" + self._snippet + "\n" + eval_fname = "{} {}".format(self._snippet_file, self._get_snippet_id()) + + try: + code = compile(eval_code, eval_fname, 'exec') + except: + exc_type, exc_value, exc_tb = sys.exc_info() + exc_traceback = TracebackException(exc_type, exc_value, exc_tb) + self.error( + "compile exception '{}' within snippet in {}".format( + exc_value, self._snippet_file), + frame_index = -2, + snippet_lineno = exc_traceback.lineno) + + # Make sure the "codegen" (alias cog) module has our state. + self._set_module_state() + + self._outstring = '' + try: + eval(code, self.generator_globals) + except: + exc_type, exc_value, exc_tb = sys.exc_info() + if exc_type is Error: + # Exception raise by CodeGen means + raise + # Not raised by Codegen means - add some info + print("Codegen: eval exception within codegen snippet ({}) in {}".format( + self._get_snippet_id(), self._snippet_file)) + for i, line in enumerate(self._snippet.splitlines()): + eval_lineno = i + 2 + input_lineno = self._eval_offset + eval_lineno + print("#{} ({}, line {}): {}".format(input_lineno, self._get_snippet_id(), eval_lineno, line)) + raise + finally: + self._restore_module_state() + + # We need to make sure that the last line in the output + # ends with a newline, or it will be joined to the + # end-output line, ruining cog's idempotency. + if self._outstring and self._outstring[-1] != '\n': + self._outstring += '\n' + + # end of evaluation - no extra offset anymore + self._eval_offset = self._snippet_offset + + # figure out the right whitespace prefix for the output + prefOut = whitePrefix(self.markers) + self._previous = reindentBlock(self._outstring, prefOut) + return self._previous + +## +# @brief The code generation processor +# +class CodeGen(Redirectable): + + def __init__(self): + Redirectable.__init__(self) + # Stack of module states + self.module_states = [] + self.options = Options() + # assure codegen module is installed + self._install_codegen_module() + + ## + # @brief Is this a trailing line after an end spec marker. + # + # @todo Make trailing end spec line detection dependent on + # type of text or file type. + # + # @param s line + # + def _is_end_spec_trailer(self, s): + return '*/' in s + + def _install_codegen_module(self): + """ Magic mumbo-jumbo so that imported Python modules + can say "import codegen" and get our state. + + Make us the module, and not our parent cog. + """ + self.cogmodule = imp.new_module('codegen') + self.cogmodule.path = [] + sys.modules['codegen'] = self.cogmodule + + def openOutputFile(self, fname): + """ Open an output file, taking all the details into account. + """ + opts = {} + mode = "w" + opts['encoding'] = self.options.sEncoding + if self.options.bNewlines: + opts['newline'] = "\n" + fdir = os.path.dirname(fname) + if os.path.dirname(fdir) and not os.path.exists(fdir): + os.makedirs(fdir) + return open(fname, mode, **opts) + + def openInputFile(self, fname): + """ Open an input file. """ + if fname == "-": + return sys.stdin + else: + opts = {} + opts['encoding'] = self.options.sEncoding + return open(fname, "r", **opts) + + ## + # @brief Process an input file object to an output file object. + # + # May be called recursively + # + # @param fIn input file object, or file name + # @param fOut output file object, or file name + # @param fname [optional] + # @param globals [optional] + # + def process_file(self, fIn, fOut, fname=None, globals=None): + + fInToClose = fOutToClose = None + # Convert filenames to files. + if isinstance(fIn, (str, bytes)): + # Open the input file. + sFileIn = fIn + fIn = fInToClose = self.openInputFile(fIn) + elif hasattr(fIn, 'name'): + sFileIn = fIn.name + else: + sFileIn = fname or '' + if isinstance(fOut, (str, bytes)): + # Open the output file. + sFileOut = fOut + fOut = fOutToClose = self.openOutputFile(fOut) + elif hasattr(fOut, 'name'): + sFileOut = fOut.name + else: + sFileOut = fname or '' + + try: + fIn = NumberedFileReader(fIn) + + bSawCog = False + + # The globals dict we will use for this file. + if globals is None: + globals = {} + # list of include files that are guarded against inclusion + globals['_guard_include'] = [] + + # If there are any global defines, put them in the globals. + globals.update(self.options.defines) + + # global flag for code generation + globals['_generate_code'] = True + + # loop over generator chunks + l = fIn.readline() + gen = None + while l and globals['_generate_code']: + + if gen is None: + # have a generator ready + # for marker check and error reporting + gen = CodeGenerator(self, globals, sFileOut, str(sFileIn)) + gen.setOutput(stdout=self._stdout) + + # Find the next spec begin + while l and not gen.line_is_start_marker(l): + if gen.line_is_end_marker(l): + gen._snippet_offset = fIn.linenumber() + gen.error("Unexpected '%s'" % gen._end_marker, + frame_index=-1, snippet_lineno=0) + if gen.line_is_insert_marker(l): + gen._snippet_offset = fIn.linenumber() + gen.error("Unexpected '%s'" % gen._insert_marker, + frame_index=-1, snippet_lineno=0) + fOut.write(l) + l = fIn.readline() + if not l: + break + if not self.options.bDeleteCode: + fOut.write(l) + + # l is the begin spec + firstLineNum = fIn.linenumber() + # Start parsing the inline code spec + # Assure a new generator is in use + gen = CodeGenerator(self, globals, sFileOut, str(sFileIn)) + gen.setOutput(stdout=self._stdout) + gen.parse_start_marker(l, firstLineNum) + + gen.log('s{}: process {} #{}'.format(len(self.module_states), sFileIn, firstLineNum)) + # If the spec begin is also a spec end, then process the single + # line of code inside. + if gen.line_is_end_marker(l): + gen.parse_line(l, True) + # next line + l = fIn.readline() + else: + # Deal with an ordinary code block. + l = fIn.readline() + + # Get all the lines in the spec + while l and not gen.line_is_end_marker(l): + gen.parse_line(l) + if gen.line_is_start_marker(l): + gen.error("Code followed by unexpected '%s'" % gen._start_marker, + frame_index = -2, + snippet_lineno = fIn.linenumber() - firstLineNum) + if gen.line_is_insert_marker(l): + gen.error("Code followed by unexpected '%s'" % gen._insert_marker, + frame_index = -2, + snippet_lineno = fIn.linenumber() - firstLineNum) + if not self.options.bDeleteCode: + fOut.write(l) + l = fIn.readline() + if not l: + gen.error("Codegen block begun but never ended.", + frame_index = -2, snippet_lineno = 0) + # write out end spec line + if not self.options.bDeleteCode: + fOut.write(l) + gen.parse_end_marker(l) + # next line - may be trailing end spec line + l = fIn.readline() + if self._is_end_spec_trailer(l) and not gen.line_is_insert_marker(l): + fOut.write(l) + l = fIn.readline() + + # Eat all the lines in the output section. + while l and not gen.line_is_insert_marker(l): + if gen.line_is_start_marker(l): + gen.error("Unexpected '%s'" % gen._start_marker, + frame_index = -2, + snippet_lineno = fIn.linenumber() - firstLineNum) + if gen.line_is_end_marker(l): + gen.error("Unexpected '%s'" % gen._end_marker, + frame_index = -2, + snippet_lineno = fIn.linenumber() - firstLineNum) + l = fIn.readline() + + if not l: + # We reached end of file before we found the end output line. + gen.error("Missing '%s' before end of file." % gen._insert_marker, + frame_index = -2, + snippet_lineno = fIn.linenumber() - firstLineNum) + + # Write the output of the spec to be the new output if we're + # supposed to generate code. + if not self.options.bNoGenerate: + sGen = gen.evaluate() + fOut.write(sGen) + if not globals['_generate_code']: + # generator code snippet stopped code generation + break + + bSawCog = True + + if not self.options.bDeleteCode: + fOut.write(l) + l = fIn.readline() + + if not bSawCog and self.options.bWarnEmpty: + self.warning("no codegen code found in %s" % sFileIn) + finally: + if fInToClose: + fInToClose.close() + if fOutToClose: + fOutToClose.close() + + def saveIncludePath(self): + self.savedInclude = self.options.includePath[:] + self.savedSysPath = sys.path[:] + + def restoreIncludePath(self): + self.options.includePath = self.savedInclude + self.cogmodule.path = self.options.includePath + sys.path = self.savedSysPath + + def addToIncludePath(self, includePath): + self.cogmodule.path.extend(includePath) + sys.path.extend(includePath) + + ## + # @brief process one file through CodeGen + # + # @param sFile file name + # + def _process_one_file(self, sFile): + """ Process one filename through cog. + """ + + self.saveIncludePath() + bNeedNewline = False + + try: + self.addToIncludePath(self.options.includePath) + # Since we know where the input file came from, + # push its directory onto the include path. + self.addToIncludePath([os.path.dirname(sFile)]) + + # How we process the file depends on where the output is going. + if self.options.sOutputName: + self.process_file(sFile, self.options.sOutputName, sFile) + else: + self.process_file(sFile, self.stdout, sFile) + finally: + self.restoreIncludePath() + + def callableMain(self, argv): + """ All of command-line codegen, but in a callable form. + This is used by main. + argv is the equivalent of sys.argv. + """ + argv = argv[1:] + + self.options.parse_args(argv) + + if self.options.input_file is None: + raise FileNotFoundError("No files to process") + + self._process_one_file(self.options.input_file) diff --git a/scripts/codegen/config.py b/scripts/codegen/config.py new file mode 100644 index 0000000000000..02c45f7a68ca3 --- /dev/null +++ b/scripts/codegen/config.py @@ -0,0 +1,56 @@ +# Copyright (c) 2018 Bobby Noelte. +# +# SPDX-License-Identifier: Apache-2.0 + +import os +import sys +import shlex +from pathlib import Path + +class ConfigMixin(object): + __slots__ = [] + + _autoconf = None + _autoconf_filename = None + + def _autoconf_assure(self): + if self._autoconf is None: + autoconf_file = self.cmake_variable("PROJECT_BINARY_DIR", None) + if autoconf_file is None: + raise self._get_error_exception( + "CMake variable PROJECT_BINARY_DIR not defined to codegen.", 2) + autoconf_file = Path(autoconf_file).joinpath('include/generated/autoconf.h') + if not autoconf_file.is_file(): + raise self._get_error_exception( + "Generated configuration {} not found/ no access.". + format(autoconf_file), 2) + autoconf = {} + with open(str(autoconf_file)) as autoconf_fd: + for line in autoconf_fd: + if not line.startswith('#'): + continue + if " " not in line: + continue + key, value = shlex.split(line)[1:] + autoconf[key] = value + self._autoconf = autoconf + self._autoconf_filename = str(autoconf_file) + + def config_property(self, property_name, default=""): + self._autoconf_assure() + property_value = self._autoconf.get(property_name, default) + if property_value == "": + raise self._get_error_exception( + "Config property '{}' not defined.".format(property_name), 1) + return property_value + + ## + # @brief Get all config properties. + # + # The property names are the ones autoconf.conf. + # + # @return A dictionary of config properties. + # + def config_properties(self): + self._autoconf_assure() + return self._autoconf diff --git a/scripts/codegen/edts.py b/scripts/codegen/edts.py new file mode 100644 index 0000000000000..7a1eaa63ad9d6 --- /dev/null +++ b/scripts/codegen/edts.py @@ -0,0 +1,31 @@ +# Copyright (c) 2018 Bobby Noelte. +# +# SPDX-License-Identifier: Apache-2.0 + +from pathlib import Path +from dts.edtsdatabase import EDTSDatabase + +class EDTSMixin(object): + __slots__ = [] + + _edts = None + + def _edts_assure(self): + if self._edts is None: + edts_file = self.cmake_variable("GENERATED_EDTS") + edts_file = Path(edts_file) + if not edts_file.is_file(): + raise self._get_error_exception( + "Generated extended device tree database file '{}' not found/ no access.". + format(edts_file), 2) + self._edts = EDTSDatabase() + self._edts.load(str(edts_file)) + + ## + # @brief Get the extended device tree database. + # + # @return Extended device tree database. + # + def edts(self): + self._edts_assure() + return self._edts diff --git a/scripts/codegen/error.py b/scripts/codegen/error.py new file mode 100644 index 0000000000000..56cf4ddb2a6b5 --- /dev/null +++ b/scripts/codegen/error.py @@ -0,0 +1,68 @@ +# Copyright (c) 2018 Bobby Noelte. +# +# SPDX-License-Identifier: Apache-2.0 + +import inspect +from pathlib import Path + +class Error(Exception): + pass + +class ErrorMixin(object): + __slots__ = [] + + ## + # @brief Get code generation error exception + # + # @note only for 'raise codegen.Error(msg)' in snippet + # + # @param msg exception message + # @param frame_index [optional] call frame index + # @param snippet_lineno [optional] line number within snippet + # @return code generation exception object + # + def _get_error_exception(self, msg, frame_index = 0, + snippet_lineno = 0): + if frame_index >= 0: + # There are frames to get data from + frame_index += 1 + frame = inspect.currentframe() + try: + while frame_index > 0: + frame = frame.f_back + frame_index -= 1 + (filename, snippet_lineno, function, code_context, index) = \ + inspect.getframeinfo(frame) + except: + pass + finally: + del frame + input_lineno = self._snippet_offset + self._get_snippet_lineno(snippet_lineno) + error_msg = "{} #{} ({}, line {}): {}".format( + Path(self._snippet_file).name, + input_lineno, self._get_snippet_id(), + snippet_lineno, msg) + listing = self._list_snippet() + if listing: + error_msg = listing + '\n' + error_msg + else: + listing = self._list_lines() + if listing: + error_msg= listing + '\n' + error_msg + return Error(error_msg) + + ## + # @brief Raise Error exception. + # + # Extra information is added that maps the python snippet + # line seen by the Python interpreter to the line of the file + # that inlines the python snippet. + # + # @param msg [optional] exception message + # @param frame_index [optional] call frame index + # @param snippet_lineno [optional] line number within snippet + # + def error(self, msg = 'Error raised by codegen generator.', + frame_index = 0, snippet_lineno = 0): + frame_index += 1 + raise self._get_error_exception(msg, frame_index, snippet_lineno) diff --git a/scripts/codegen/filereader.py b/scripts/codegen/filereader.py new file mode 100644 index 0000000000000..c567a5ca24dfc --- /dev/null +++ b/scripts/codegen/filereader.py @@ -0,0 +1,20 @@ +# Copyright 2004-2016, Ned Batchelder. +# Copyright (c) 2018 Bobby Noelte. +# +# SPDX-License-Identifier: MIT + +class NumberedFileReader: + """ A decorator for files that counts the readline()'s called. + """ + def __init__(self, f): + self.f = f + self.n = 0 + + def readline(self): + l = self.f.readline() + if l: + self.n += 1 + return l + + def linenumber(self): + return self.n diff --git a/scripts/codegen/generic.py b/scripts/codegen/generic.py new file mode 100644 index 0000000000000..07e89bcaeed57 --- /dev/null +++ b/scripts/codegen/generic.py @@ -0,0 +1,51 @@ +# Copyright (c) 2018 Bobby Noelte. +# +# SPDX-License-Identifier: Apache-2.0 + +from pathlib import Path + +class GenericMixin(object): + __slots__ = [] + + @staticmethod + def path_walk(top, topdown = False, followlinks = False): + """ + See Python docs for os.walk, exact same behavior but it yields Path() + instances instead + + Form: http://ominian.com/2016/03/29/os-walk-for-pathlib-path/ + """ + names = list(top.iterdir()) + + dirs = (node for node in names if node.is_dir() is True) + nondirs = (node for node in names if node.is_dir() is False) + + if topdown: + yield top, dirs, nondirs + + for name in dirs: + if followlinks or name.is_symlink() is False: + for x in path_walk(name, topdown, followlinks): + yield x + + if topdown is not True: + yield top, dirs, nondirs + + # + # @param marker Marker as b'my-marker' + # + @staticmethod + def template_files(top, marker, suffix='.c'): + sources = [] + for path, directory_names, file_names in CodeGen.path_walk(top): + sources.extend([x for x in file_names if x.suffix == suffix]) + + templates = [] + for source_file in sources: + if os.stat(source_file).st_size == 0: + continue + with open(source_file, 'rb', 0) as source_file_fd: + s = mmap.mmap(source_file_fd.fileno(), 0, access=mmap.ACCESS_READ) + if s.find(marker) != -1: + templates.append(source_file) + return templates diff --git a/scripts/codegen/guard.py b/scripts/codegen/guard.py new file mode 100644 index 0000000000000..0cf8a11a22eb6 --- /dev/null +++ b/scripts/codegen/guard.py @@ -0,0 +1,16 @@ +# Copyright (c) 2018 Bobby Noelte. +# +# SPDX-License-Identifier: Apache-2.0 + +class GuardMixin(object): + __slots__ = [] + + + def outl_guard_config(self, property_name): + is_config = self.config_property(property_name, 0) + self.outl("#if {} // Guard({}) {}".format( + is_config, is_config, property_name)) + + def outl_unguard_config(self, property_name): + is_config = self.config_property(property_name, 0) + self.outl("#endif // Guard({}) {}".format(is_config, property_name)) diff --git a/scripts/codegen/importmodule.py b/scripts/codegen/importmodule.py new file mode 100644 index 0000000000000..3f4e632059d9e --- /dev/null +++ b/scripts/codegen/importmodule.py @@ -0,0 +1,37 @@ +# Copyright (c) 2018 Bobby Noelte. +# +# SPDX-License-Identifier: Apache-2.0 + +import sys +import os +import importlib +from pathlib import Path + +class ImportMixin(object): + __slots__ = [] + + ## + # @brief Import a CodeGen module. + # + # Import a module from the codegen/modules package. + # + # @param name Module to import. Specified without any path. + # + def import_module(self, name): + try: + module_file = self.zephyr_path().joinpath( + "scripts/codegen/modules/{}.py".format(name)).resolve() + except FileNotFoundError: + # Python 3.4/3.5 will throw this exception + # Python >= 3.6 will not throw this exception + module_file = self.zephyr_path().joinpath( + "scripts/codegen/modules/{}.py".format(name)) + if not module_file.is_file(): + raise self._get_error_exception( + "Module file '{}' of module '{}' does not exist or is no file.". + format(module_file, name), 1) + sys.path.append(os.path.dirname(str(module_file))) + module = importlib.import_module(name) + sys.path.pop() + self.generator_globals[name] = module + diff --git a/scripts/codegen/include.py b/scripts/codegen/include.py new file mode 100644 index 0000000000000..54ea51d48eba9 --- /dev/null +++ b/scripts/codegen/include.py @@ -0,0 +1,67 @@ +# Copyright (c) 2018 Bobby Noelte. +# +# SPDX-License-Identifier: Apache-2.0 + +from pathlib import Path +import io + +from .error import Error + +class IncludeMixin(object): + __slots__ = [] + + def out_include(self, include_file): + try: + input_file = Path(include_file).resolve() + except FileNotFoundError: + # Python 3.4/3.5 will throw this exception + # Python >= 3.6 will not throw this exception + input_file = Path(include_file) + if not input_file.is_file(): + # don't resolve upfront + input_file = Path(include_file) + # try to find the file in the templates directory + expanded_file_path = self.zephyr_path().joinpath( + "scripts/codegen/templates") + if 'templates' in input_file.parts: + templates_seen = False + else: + # assume the path starts after templates + templates_seen = True + # append the remaining part behind templates + for part in input_file.parts: + if templates_seen: + expanded_file_path = expanded_file_path.joinpath(part) + elif part is 'templates': + templates_seen = True + if expanded_file_path.is_file(): + input_file = expanded_file_path + if not input_file.is_file(): + raise self._get_error_exception( + "Include file '{}' does not exist or is no file.". + format(input_file), 1) + if str(input_file) in self.generator_globals['_guard_include']: + self.log('------- include guarded {} - multiple inclusion of include file.'. + format(str(input_file))) + else: + output_fd = io.StringIO() + # delete inline code in included files + delete_code = self.processor.options.bDeleteCode + self.processor.options.bDeleteCode = True + self.log('------- include start {}'.format(input_file)) + self.processor.process_file(str(input_file), output_fd, + globals=self.generator_globals) + self.log(output_fd.getvalue()) + self.log('------- include end {}'.format(input_file)) + self.processor.options.bDeleteCode = delete_code + self.out(output_fd.getvalue()) + + def guard_include(self): + if self._snippet_file in self.generator_globals['_guard_include']: + # This should never happen + raise self._get_error_exception( + "Multiple inclusion of guarded include file '{}'.". + format(self._snippet_file), 1) + self.log('------- include guard {}'.format(self._snippet_file)) + self.generator_globals['_guard_include'].append(self._snippet_file) + diff --git a/scripts/codegen/log.py b/scripts/codegen/log.py new file mode 100644 index 0000000000000..7ee81bad6ac6e --- /dev/null +++ b/scripts/codegen/log.py @@ -0,0 +1,41 @@ +# Copyright (c) 2018 Bobby Noelte. +# +# SPDX-License-Identifier: Apache-2.0 + +from pathlib import Path + +class LogMixin(object): + __slots__ = [] + + _log_fd = None + + def log(self, message, message_type=None, end="\n", logonly=True): + if self._log_fd is None: + if self.options.log_file is not None: + log_file = Path(self.options.log_file) + if not log_file.is_file(): + # log file will be created + # add preamble + preamble = "My preamble\n{}".format(message) + self._log_fd = open(str(log_file), 'a') + if message_type is None: + message_type = '' + else: + message_type = message_type+': ' + if self._log_fd is not None: + for line in message.splitlines(): + self._log_fd.write("{}{}{}".format(message_type, line, end)) + if not logonly: + print(message_type+message, file=self._stderr, end=end) + + def msg(self, s): + self.log(s, message_type='message', logonly=False) + + def warning(self, s): + self.log(s, message_type='warning', logonly=False) + + def prout(self, s, end="\n"): + self.log(s, message_type=None, end=end, logonly=False) + + def prerr(self, s, end="\n"): + self.log(s, message_type='error', end=end, logonly=False) diff --git a/scripts/codegen/options.py b/scripts/codegen/options.py new file mode 100644 index 0000000000000..312509353852d --- /dev/null +++ b/scripts/codegen/options.py @@ -0,0 +1,139 @@ +# Copyright 2004-2016, Ned Batchelder. +# http://nedbatchelder.com/code/cog +# Copyright (c) 2018 Bobby Noelte. +# +# SPDX-License-Identifier: MIT + +import os +import argparse + +class Options(object): + + @staticmethod + def is_valid_directory(parser, arg): + if not os.path.isdir(arg): + parser.error('The directory {} does not exist!'.format(arg)) + else: + # File directory so return the directory + return arg + + @staticmethod + def is_valid_file(parser, arg): + if not os.path.isfile(arg): + parser.error('The file {} does not exist!'.format(arg)) + else: + # File exists so return the file + return arg + + def __init__(self): + # Defaults for argument values. + self.args = [] + self.includePath = [] + self.defines = {} + self.bNoGenerate = False + self.sOutputName = None + self.bWarnEmpty = False + self.bDeleteCode = False + self.bNewlines = False + self.sEncoding = "utf-8" + self.verbosity = 2 + + self._parser = argparse.ArgumentParser( + description='Generate code with inlined Python code.') + self._parser.add_argument('-d', '--delete-code', + dest='bDeleteCode', action='store_true', + help='Delete the generator code from the output file.') + self._parser.add_argument('-D', '--define', nargs=1, metavar='DEFINE', + dest='defines', action='append', + help='Define a global string available to your generator code.') + self._parser.add_argument('-e', '--warn-empty', + dest='bWarnEmpty', action='store_true', + help='Warn if a file has no generator code in it.') + self._parser.add_argument('-U', '--unix-newlines', + dest='bNewlines', action='store_true', + help='Write the output with Unix newlines (only LF line-endings).') + self._parser.add_argument('-I', '--include', nargs=1, metavar='DIR', + dest='includePath', action='append', + type=lambda x: self.is_valid_directory(self._parser, x), + help='Add DIR to the list of directories for data files and modules.') + self._parser.add_argument('-n', '--encoding', nargs=1, + dest='sEncoding', action='store', metavar='ENCODING', + type=lambda x: self.is_valid_file(self._parser, x), + help='Use ENCODING when reading and writing files.') + self._parser.add_argument('-i', '--input', nargs=1, metavar='FILE', + dest='input_file', action='store', + type=lambda x: self.is_valid_file(self._parser, x), + help='Get the input from FILE.') + self._parser.add_argument('-o', '--output', nargs=1, metavar='FILE', + dest='sOutputName', action='store', + help='Write the output to FILE.') + self._parser.add_argument('-l', '--log', nargs=1, metavar='FILE', + dest='log_file', action='store', + help='Log to FILE.') + + def __str__(self): + sb = [] + for key in self.__dict__: + sb.append("{key}='{value}'".format(key=key, value=self.__dict__[key])) + return ', '.join(sb) + + def __repr__(self): + return self.__str__() + + + def __eq__(self, other): + """ Comparison operator for tests to use. + """ + return self.__dict__ == other.__dict__ + + def clone(self): + """ Make a clone of these options, for further refinement. + """ + return copy.deepcopy(self) + + def parse_args(self, argv): + args = self._parser.parse_args(argv) + # set options + self.bDeleteCode = args.bDeleteCode + self.bWarnEmpty = args.bWarnEmpty + self.bNewlines = args.bNewlines + if args.includePath is None: + self.includePath = [] + else: + self.includePath = args.includePath + self.sEncoding = args.sEncoding + if args.input_file is None: + self.input_file = None + else: + self.input_file = args.input_file[0] + if args.sOutputName is None: + self.sOutputName = None + else: + self.sOutputName = args.sOutputName[0] + if args.log_file is None: + self.log_file = None + else: + self.log_file = args.log_file[0] + self.defines = {} + if args.defines is not None: + for define in args.defines: + d = define[0].split('=') + if len(d) > 1: + value = d[1] + else: + value = None + self.defines[d[0]] = value + + def addToIncludePath(self, dirs): + """ Add directories to the include path. + """ + dirs = dirs.split(os.pathsep) + self.includePath.extend(dirs) + + + +class OptionsMixin(object): + __slots__ = [] + + def option(self, option_name): + return getattr(self.options, option_name) diff --git a/scripts/codegen/output.py b/scripts/codegen/output.py new file mode 100644 index 0000000000000..647002b3ed53f --- /dev/null +++ b/scripts/codegen/output.py @@ -0,0 +1,19 @@ +# Copyright (c) 2018 Bobby Noelte. +# +# SPDX-License-Identifier: Apache-2.0 + + +class OutputMixin(object): + __slots__ = [] + + def msg(self, s): + self.prout("Message: "+s) + + def out(self, sOut='', dedent=False, trimblanklines=False): + self._out(sOut, dedent, trimblanklines) + + def outl(self, sOut='', **kw): + """ The cog.outl function. + """ + self._out(sOut, **kw) + self._out('\n') diff --git a/scripts/codegen/redirectable.py b/scripts/codegen/redirectable.py new file mode 100644 index 0000000000000..3cdc49b25e5f2 --- /dev/null +++ b/scripts/codegen/redirectable.py @@ -0,0 +1,31 @@ +# Copyright 2004-2016, Ned Batchelder. +# Copyright (c) 2018 Bobby Noelte. +# +# SPDX-License-Identifier: MIT + +import sys + +class RedirectableMixin(object): + __slots__ = [] + + def setOutput(self, stdout=None, stderr=None): + """ Assign new files for standard out and/or standard error. + """ + if stdout: + self._stdout = stdout + if stderr: + self._stderr = stderr + + def prout(self, s, end="\n"): + print(s, file=self._stdout, end=end) + + def prerr(self, s, end="\n"): + print(s, file=self._stderr, end=end) + + +class Redirectable(RedirectableMixin): + """ An object with its own stdout and stderr files. + """ + def __init__(self): + self._stdout = sys.stdout + self._stderr = sys.stderr diff --git a/scripts/codegen/whiteutils.py b/scripts/codegen/whiteutils.py new file mode 100644 index 0000000000000..2a128e4ab88f7 --- /dev/null +++ b/scripts/codegen/whiteutils.py @@ -0,0 +1,72 @@ +# Copyright 2004-2016, Ned Batchelder. +# http://nedbatchelder.com/code/cog +# Copyright (c) 2018 Bobby Noelte. +# +# SPDX-License-Identifier: MIT + +import re + +def b(s): + return s.encode("latin-1") + +def whitePrefix(strings): + """ Determine the whitespace prefix common to all non-blank lines + in the argument list. + """ + # Remove all blank lines from the list + strings = [s for s in strings if s.strip() != ''] + + if not strings: return '' + + # Find initial whitespace chunk in the first line. + # This is the best prefix we can hope for. + pat = r'\s*' + if isinstance(strings[0], (bytes, )): + pat = pat.encode("utf8") + prefix = re.match(pat, strings[0]).group(0) + + # Loop over the other strings, keeping only as much of + # the prefix as matches each string. + for s in strings: + for i in range(len(prefix)): + if prefix[i] != s[i]: + prefix = prefix[:i] + break + return prefix + +def reindentBlock(lines, newIndent=''): + """ Take a block of text as a string or list of lines. + Remove any common whitespace indentation. + Re-indent using newIndent, and return it as a single string. + """ + sep, nothing = '\n', '' + if isinstance(lines, (bytes, )): + sep, nothing = b('\n'), b('') + if isinstance(lines, (str, bytes)): + lines = lines.split(sep) + oldIndent = whitePrefix(lines) + outLines = [] + for l in lines: + if oldIndent: + l = l.replace(oldIndent, nothing, 1) + if l and newIndent: + l = newIndent + l + outLines.append(l) + return sep.join(outLines) + +def commonPrefix(strings): + """ Find the longest string that is a prefix of all the strings. + """ + if not strings: + return '' + prefix = strings[0] + for s in strings: + if len(s) < len(prefix): + prefix = prefix[:len(s)] + if not prefix: + return '' + for i in range(len(prefix)): + if prefix[i] != s[i]: + prefix = prefix[:i] + break + return prefix diff --git a/scripts/codegen/zephyr.py b/scripts/codegen/zephyr.py new file mode 100644 index 0000000000000..3366b2643ba87 --- /dev/null +++ b/scripts/codegen/zephyr.py @@ -0,0 +1,12 @@ +# Copyright (c) 2018 Bobby Noelte. +# +# SPDX-License-Identifier: Apache-2.0 + +from pathlib import Path + +class ZephyrMixin(object): + __slots__ = [] + + @staticmethod + def zephyr_path(): + return Path(__file__).resolve().parents[2] diff --git a/scripts/gen_code.py b/scripts/gen_code.py new file mode 100755 index 0000000000000..36719134ef740 --- /dev/null +++ b/scripts/gen_code.py @@ -0,0 +1,13 @@ +#!/usr/bin/env python3 +# +# Copyright (c) 2018 Bobby Noelte. +# +# SPDX-License-Identifier: Apache-2.0 + +import sys + +from codegen.codegen import CodeGen + +if __name__ == '__main__': + ret = CodeGen().callableMain(sys.argv) + sys.exit(ret) From 6ec24a9f0595c9e505a41bfe23d26e907081416f Mon Sep 17 00:00:00 2001 From: Bobby Noelte Date: Sat, 10 Mar 2018 15:45:54 +0100 Subject: [PATCH 04/18] doc: codegen: add inline code generation documentation Document the inline code generation tool codegen and its integration in the CMake build process. Signed-off-by: Bobby Noelte --- doc/contribute/contribute_guidelines.rst | 24 +- doc/subsystems/codegen/build.rst | 29 +++ doc/subsystems/codegen/codegen.rst | 90 ++++++++ doc/subsystems/codegen/codegen_principle.png | Bin 0 -> 39747 bytes .../codegen/codegen_principle_access.png | Bin 0 -> 58311 bytes .../codegen/codegen_principle_import.png | Bin 0 -> 113795 bytes .../codegen/codegen_principle_include.png | Bin 0 -> 113376 bytes doc/subsystems/codegen/functions.rst | 216 ++++++++++++++++++ doc/subsystems/codegen/index.rst | 27 +++ doc/subsystems/codegen/principle.rst | 48 ++++ doc/subsystems/subsystems.rst | 1 + 11 files changed, 434 insertions(+), 1 deletion(-) create mode 100644 doc/subsystems/codegen/build.rst create mode 100644 doc/subsystems/codegen/codegen.rst create mode 100644 doc/subsystems/codegen/codegen_principle.png create mode 100644 doc/subsystems/codegen/codegen_principle_access.png create mode 100644 doc/subsystems/codegen/codegen_principle_import.png create mode 100644 doc/subsystems/codegen/codegen_principle_include.png create mode 100644 doc/subsystems/codegen/functions.rst create mode 100644 doc/subsystems/codegen/index.rst create mode 100644 doc/subsystems/codegen/principle.rst diff --git a/doc/contribute/contribute_guidelines.rst b/doc/contribute/contribute_guidelines.rst index c362bb3a05d0e..d044cc556059a 100644 --- a/doc/contribute/contribute_guidelines.rst +++ b/doc/contribute/contribute_guidelines.rst @@ -326,8 +326,11 @@ On Linux systems, you can install uncrustify with For Windows installation instructions see the `sourceforge listing for uncrustify `_. +Best coding practises +********************* + Coding Style -************ +============ Use these coding guidelines to ensure that your development complies with the project's style and naming conventions. @@ -363,6 +366,25 @@ it to contain: set -e exec exec git diff --cached | ${ZEPHYR_BASE}/scripts/checkpatch.pl - +Keep the code simple +==================== + +Keep the code as simple as possible. + +Code-generation preprocessing tools provide a convenient way to +simplify some repetitive or parameterized coding tasks. While Zephyr +development allows use of such tools, we recommend keeping this +use to a minimum and when it provides an appropriate and simple +coding solution that follows these rules: + +* Use code generation - by preprocessor, :ref:`codegen`, or other - only for + problems that cannot be solved in the source language. +* Limit code generation to declarative data. Avoid generating control logic + whenever possible. +* Use the preprocessor for code generation as the primary tool. +* Use :ref:`codegen` only if the preprocessor can not provide a simple solution. +* Use CMake only if :ref:`codegen` can not be used. + .. _Contribution workflow: Contribution Workflow diff --git a/doc/subsystems/codegen/build.rst b/doc/subsystems/codegen/build.rst new file mode 100644 index 0000000000000..4ecc1ccf359b8 --- /dev/null +++ b/doc/subsystems/codegen/build.rst @@ -0,0 +1,29 @@ +.. + Copyright (c) 2018 Bobby Noelte + SPDX-License-Identifier: Apache-2.0 + +.. _codegen_build: + +Code Generation in the Build Process +#################################### + +Code generation has to be invoked as part of the build process. Zephyr uses +`CMake `_ as the tool to manage building the project. + +A file that contains inline code generation has to be added to the project +by one of the following commands in a :file:`CMakeList.txt` file. + +.. function:: zephyr_sources_codegen(codegen_file.c [CODEGEN_DEFINES defines..] [DEPENDS target.. file..]) + +.. function:: zephyr_sources_codegen_ifdef(ifguard codegen_file.c [CODEGEN_DEFINES defines..] [DEPENDS target.. file..]) + +.. function:: zephyr_library_sources_codegen(codegen_file.c [CODEGEN_DEFINES defines..] [DEPENDS target.. file..]) + +.. function:: zephyr_library_sources_codegen_ifdef(ifguard codegen_file.c [CODEGEN_DEFINES defines..] [DEPENDS target.. file..]) + +The arguments given by the ``CODEGEN_DEFINES`` keyword have to be of the form +``define_name=define_value``. The arguments become globals in the python +snippets and can be accessed by ``define_name``. + +Dependencies given by the ``DEPENDS`` key word are added to the dependencies +of the generated file. diff --git a/doc/subsystems/codegen/codegen.rst b/doc/subsystems/codegen/codegen.rst new file mode 100644 index 0000000000000..cc7b1bb3eed38 --- /dev/null +++ b/doc/subsystems/codegen/codegen.rst @@ -0,0 +1,90 @@ +.. + Copyright (c) 2004-2015 Ned Batchelder + SPDX-License-Identifier: MIT + Copyright (c) 2018 Bobby Noelte + SPDX-License-Identifier: Apache-2.0 + +.. _codegen_intro: + +Introduction +############ + +Python snippets that are inlined in a source file are used as code generators. +The tool to scan the source file for the Python snippets and process them is +Codegen. Codegen and part of this documentation is based on +`Cog `_ from Ned Batchelder. + +The processing of source files is controlled by the CMake extension functions: +zephyr_sources_codegen(..) or zephyr_library_sources_codegen(..). The generated +source files are added to the Zephyr sources. During build the source files are +processed by Codegen and the generated source files are written to the CMake +binary directory. + +The inlined Python snippets can contain any Python code, they are regular +Python scripts. All Python snippets in a source file and all Python snippets of +included template files are treated as a python script with a common set of +global Python variables. Global data created in one snippet can be used in +another snippet that is processed later on. This feature could be used, for +example, to customize included template files. + +An inlined Python snippet can always access the codegen module. The codegen +module encapsulates and provides all the functions to retrieve information +(options, device tree properties, CMake variables, config properties) and to +output the generated code. + +Codegen transforms files in a very simple way: it finds chunks of Python code +embedded in them, executes the Python code, and places its output combined with +the original file into the generated file. The original file can contain +whatever text you like around the Python code. It will usually be source code. + +For example, if you run this file through Codegen: + +:: + + /* This is my C file. */ + ... + /** + * @code{.codegen} + * fnames = ['DoSomething', 'DoAnotherThing', 'DoLastThing'] + * for fn in fnames: + * codegen.outl("void %s();" % fn) + * @endcode{.codegen} + */ + /** @code{.codeins}@endcode */ + ... + +it will come out like this: + +:: + + /* This is my C file. */ + ... + /** + * @code{.codegen} + * fnames = ['DoSomething', 'DoAnotherThing', 'DoLastThing'] + * for fn in fnames: + * codegen.outl("void %s();" % fn) + * @endcode{.codegen} + */ + void DoSomething(); + void DoAnotherThing(); + void DoLastThing(); + /** @code{.codeins}@endcode */ + ... + +Lines with ``@code{.codegen}`` or ``@code{.codeins}@endcode`` are marker lines. +The lines between ``@code{.codegen}`` and ``@endcode{.codegen}`` are the +generator Python code. The lines between ``@endcode{.codegen}`` and +``@code{.codeins}@endcode`` are the output from the generator. + +When Codegen runs, it discards the last generated Python output, executes the +generator Python code, and writes its generated output into the file. All text +lines outside of the special markers are passed through unchanged. + +The Codegen marker lines can contain any text in addition to the marker tokens. +This makes it possible to hide the generator Python code from the source file. + +In the sample above, the entire chunk of Python code is a C comment, so the +Python code can be left in place while the file is treated as C code. + + diff --git a/doc/subsystems/codegen/codegen_principle.png b/doc/subsystems/codegen/codegen_principle.png new file mode 100644 index 0000000000000000000000000000000000000000..b1f340731f3ac5359ca3172bef4418819f341c3c GIT binary patch literal 39747 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­S(zu8l|~{ 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 literal 0 HcmV?d00001 diff --git a/doc/subsystems/codegen/codegen_principle_import.png b/doc/subsystems/codegen/codegen_principle_import.png new file mode 100644 index 0000000000000000000000000000000000000000..e8c681833a0b989682641b38837b0eabd18503ee GIT binary patch literal 113795 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 literal 0 HcmV?d00001 diff --git a/doc/subsystems/codegen/codegen_principle_include.png b/doc/subsystems/codegen/codegen_principle_include.png new file mode 100644 index 0000000000000000000000000000000000000000..1b58b41dd0098937282effbbbdad593cbb90cb10 GIT binary patch literal 113376 zcmc$Gc|4Tu`*x*hu~f2eY2lGAyR1cre_3b#JUuGa0qK2CeCLTEs&h!D6rMD$tsiJa*_Y@$_22fI-;2aN zZS(!}yU&r;qkXTwdf%ycLXz2YYCPHNWYn;uj^*WF?JP664IEvll*2m9o^Ggcioax> zOIR~PE zi8QH}q%Fx0$1-uJjL8CO$UOx1Iw@+Y%b|w#;YgEhGfF|L68l$ld7TUeo?i$BOJubE zG=3mw?$z^j*4xRh~ZL(DNjT**BdXZdg|ugMV|Db zT8l93?P5sbp@=lD*ndQmRp0uw(6F~2TNyY1LyXu;{dx?mYMcw%$!tkrT;sJXdTgkN z@~TZ#PAZ<>POSIp)ns}&OONkgj} zvpcPU)SvmJcX)R=?Zk2N^4U`g>eT6dDis$j%{USyH>Z+3@3+#9=kc~>hQ7WECZ(N- z%~Y*?Nc`kj!ry84T;KVqqat-?SHNn0JoUF_&Lf)EvGPBX$Y?$!{AhkRKDGaVN7?uU z8%#H*bZ9C*cG5|piEMi_#?O0oI9wuTGU)>1B(xEZHt(cXlD4c?5jN-fB`}T|cO*uh zK8kliz0$0Y!5=g6UYKd(Qg6J912J+J@E-=9 z!zxR@i@$%54!y$uf?J&Hf^=)7JYh_h#XD1W3z+UG*dTS8h3r)3 zc#9ant(@Gou3K?90-ER{zA*gry|wj=?4p%LijnKTpX$#XOiD+m#$f54RCdNSUmd!o zx{H>w&$&4vE@>aKI~gg?w%HOrlf&rx7Pr>Jt6B#h_C_f%l9Un{_76gL@9rMMwG4F~5~15c4+I zXLstf{rDCMTyq2j@%_oic01-Y+VKMQ!z!0vi7t?z+wm^Zb2~`3g%%vi#hxO?uY!wO z5@R(OuOfVtKN??*xy*c0{D-}Fw}fwdROQraC?a3bT2*)fVtVMrkNc%(7jh-}bW0p^$}N^5eiMNwxD(#l`q|->5?vU5P@XMfy z<4X&w9?Msz>dM!KgQm6O9rn?-E%H-gs#I=EH^dg>#k1|E>&ZPXtic1%qLXq<TJDu4R=P9fuPoS1Ia0P2r;3qkNP& zaw%_S8b^pOp!~b5d3Ve@`1JV&E+tx9ckQk6lW}$z>Est$DRNv-X1_{RX(|bT_I!U5 z@B3~2BVcPTE?|rk$x;IGffVilKU|ibi*N{-)=$Te<{-3y*K+MR`t6SNQEVOgJuS?> zHoE(yT*%p_g%*bMn!~Pv@x}RZT;eawK9jrT=5IKkhnUZ4STp0zr03%*KdVzz%d#Mb z3?x~Uh>}8diHUS0eYSV&-pEuvTO6qr%&qWOvGCwOgp*iuebcYjvp3RkO`^!&EK#pr zx`*5eI&nDM^C?X7M%J7>@m+Fl;ttkgFIXKJI(FR(<7>)^o%IL)xS_WIF7D(NeCLLh#rmsxc$(q3lF%HTQ8w7=y{9e^ z14;xMOn~1i&_xzi{9xbRZ`-$S({btW+cMf>F%-@HI!U8gf)v2ky~?>ayMgi?zu-p- zq<0sc_$PbcT^OoQ)y2VD0|!!VXxMCSGFZ5AbkW*sr3RG9?!r71 z^9C0+B`Stu%WyQB3Rt!MY!w-IVb#TD;AW|6g+B1AH^x3yyaf5n8>hL0#(9mg@9jw0 zpVcZ590t9QT50FjJOw+K-Pzqe7d8=FKJ}zgG~)VF2GAkkIXMcw;2UzYl+0%YzjSyQ zRJ1fE9Lb9z_zx9pQaMhX6MvchW4X|_H_>H$DPy`dkONWc?dYHi+G z{7IFimD`m^VVu@zvo|HRIcmB&a@>Pa1py5%Q|(zKxl=jaq6?HG{%1A6Ea^7h7v}X$Le_cs28>$i z-J|7WvpQZ8^|`mSdh5Ahn8aw&g#<3w&Nn=`a+<`FM}pm?qh)GaJ~zD7X>Cmv=&-)W zCW08eCZ$Cyp}o0P_2c$Ry?@eF<+ii@wj2CP?d<#K3nyq?8ccDQVcdkQ+dx-w@vJ`+ zi7xd;(|FpiBdXL_(tfTu*FR$0Xq;^F8j^tNmwl+7Uw)k!@1o;D=9%~hM(J*gO*p;v zJ0mFwyOZ}x&WcX&X17;*Vy4bU&%LxKGb}t$cZKK1N%5KonXQqDn0>ajTrqePETPXT!Rf~=ak^JPWBi}%g>f!# zZar`(^}+U$Nbt#vlkLaxv(kMn)zQUg&}1AgMX1R7^se zm}8>!M7DMjW*>-)r$jvuxAtl?UjrITA=CJqF`0}OfY@<9cK3-h6u?V>OaZ{B=ijp^ z&;=N8Anu{ZclLjGN3R7@&FdY}6i~pbR)9V$Xs(8k&v{8HAcJ=(1GCK+u_b*ff7ZpXU(G!ajcs&e`D z9KG#j1-c-5@|!%MJ!e;J$ZOWan$`@`7eO35Z|Sv*XYfPdKnMU}RBFicKVfFeUqD@CZwD8+Fd zN5QKHsky2J{!!{MFZimimW`9zTHP|u?wkrBG;;LG8HC^0L7U`zp*XmPmr!9^N)hLN z|FgVqtk(XbRByR3Pgmb~>bOx;UJ|lT zc2K0v{*tCtqGf$tY>48CqeX~XXDW-Tb@PZq=9yTo0R!Zfu7fPi-8?baIEUJR-9
    -l*D@vOM^Bdyaf7 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%0D0U!BWog$rw3Imfzj7JFLAu>XCO8O1Oh35%8; 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 z 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%0Au^XI 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%0AmtB0Jqj`dcm$cgLUcJEihqmQcSw#8UWLeRD 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 W+gab&uK2Lvo#zcq^z%+Tg#9l`RerDl literal 0 HcmV?d00001 diff --git a/doc/subsystems/codegen/functions.rst b/doc/subsystems/codegen/functions.rst new file mode 100644 index 0000000000000..45b56c1ab39e2 --- /dev/null +++ b/doc/subsystems/codegen/functions.rst @@ -0,0 +1,216 @@ +.. + Copyright (c) 2004-2015 Ned Batchelder + SPDX-License-Identifier: MIT + Copyright (c) 2018 Bobby Noelte + SPDX-License-Identifier: Apache-2.0 + +.. _codegen_functions: + +Code Generation Functions +######################### + +A module called ``codegen`` provides the core functions for inline +code generation. It encapsulates all the functions to retrieve information +(options, device tree properties, CMake variables, config properties) and +to output the generated code. + +.. contents:: + :depth: 2 + :local: + :backlinks: top + +The ``codegen`` module is automatically imported by all code snippets. No +explicit import is necessary. + +Output +------ + +.. function:: codegen.out(sOut=’’ [, dedent=False][, trimblanklines=False]) + + Writes text to the output. + + :param sOut: The string to write to the output. + :param dedent: If dedent is True, then common initial white space is + removed from the lines in sOut before adding them to the + output. + :param trimblanklines: If trimblanklines is True, + then an initial and trailing blank line are removed + from sOut before adding them to the output. + + ``dedent`` and ``trimblanklines`` make it easier to use + multi-line strings, and they are only are useful for multi-line strings: + + :: + + codegen.out(""" + These are lines I + want to write into my source file. + """, dedent=True, trimblanklines=True) + +.. function:: codegen.outl + + Same as codegen.out, but adds a trailing newline. + +.. attribute:: codegen.inFile + + An attribute, the path of the input file. + +.. attribute:: codegen.outFile + + An attribute, the path of the output file. + +.. attribute:: codegen.firstLineNum + + An attribute, the line number of the first line of Python code in the + generator. This can be used to distinguish between two generators in the + same input file, if needed. + +.. attribute:: codegen.previous + + An attribute, the text output of the previous run of this generator. This + can be used for whatever purpose you like, including outputting again with + codegen.out() + +The codegen module also provides a set of convenience functions: + + +Code generation module import +----------------------------- + +.. function:: codegen.module_import(module_name) + + Import a module from the codegen/modules package. + + After import the module's functions and variables can be accessed by + module_name.func() and module_name.var. + + :param module_name: Module to import. Specified without any path. + + See :ref:`codegen_modules` for the available modules. + +Template file inclusion +----------------------- + +.. function:: codegen.out_include(include_file) + + Write the text from include_file to the output. The :file:`include_file` + is processed by Codegen. Inline code generation in ``include_file`` + can access the globals defined in the ``including source file`` before + inclusion. The ``including source file`` can access the globals defined in + the ``include_file`` (after inclusion). + + :param include_file: path of include file, either absolute path or relative + to current directory or relative to templates directory + (e.g. 'templates/drivers/simple_tmpl.c') + + See :ref:`codegen_templates` for the templates in the Codegen templates + folders. + +.. function:: codegen.guard_include() + + Prevent the current file to be included by ``codegen.out_include()`` + when called the next time. + +Configuration property access +----------------------------- + +.. function:: codegen.config_property(property_name [, default=""]) + + Get the value of a configuration property from :file:`autoconf.h`. If + ``property_name`` is not given in :file:`autoconf.h` the default value is + returned. + +CMake variable access +--------------------- + +.. function:: codegen.cmake_variable(variable_name [, default=""]) + + Get the value of a CMake variable. If variable_name is not provided to + Codegen by CMake the default value is returned. The following variables + are provided to Codegen: + + - "PROJECT_NAME" + - "PROJECT_SOURCE_DIR" + - "PROJECT_BINARY_DIR" + - "CMAKE_SOURCE_DIR" + - "CMAKE_BINARY_DIR" + - "CMAKE_CURRENT_SOURCE_DIR" + - "CMAKE_CURRENT_BINARY_DIR" + - "CMAKE_CURRENT_LIST_DIR" + - "CMAKE_FILES_DIRECTORY" + - "CMAKE_PROJECT_NAME" + - "CMAKE_SYSTEM" + - "CMAKE_SYSTEM_NAME" + - "CMAKE_SYSTEM_VERSION" + - "CMAKE_SYSTEM_PROCESSOR" + - "CMAKE_C_COMPILER" + - "CMAKE_CXX_COMPILER" + - "CMAKE_COMPILER_IS_GNUCC" + - "CMAKE_COMPILER_IS_GNUCXX" + - "GENERATED_DTS_BOARD_H" + - "GENERATED_DTS_BOARD_CONF" + +.. function:: codegen.cmake_cache_variable(variable_name [, default=""]) + + Get the value of a CMake variable from CMakeCache.txt. If variable_name + is not given in CMakeCache.txt the default value is returned. + +Extended device tree database access +------------------------------------ + +.. function:: codegen.edts() + + Get the extended device tree database. + + :return: extended device tree database + +Guarding chunks of source code +------------------------------ + +.. function:: codegen.outl_guard_config(property_name) + + Write a guard (#if [guard]) C preprocessor directive to output. + + If there is a configuration property of the given name the property value + is used as guard value, otherwise it is set to 0. + + :param property_name: Name of the configuration property. + +.. function:: codegen.outl_unguard_config(property_name) + + Write an unguard (#endif) C preprocessor directive to output. + + This is the closing command for codegen.outl_guard_config(). + + :param property_name: Name of the configuration property. + +Error handling +-------------- + +.. function:: codegen.error(msg='Error raised by codegen.' [, frame_index=0] [, snippet_lineno=0]) + + Raise a codegen.Error exception. + + Instead of raising standard python errors, codegen generators can use + this function. Extra information is added that maps the python snippet + line seen by the Python interpreter to the line of the file that inlines + the python snippet. + + :param msg: Exception message. + :param frame_index: Call frame index. The call frame offset of the function + calling codegen.error(). Zero if directly called in a + snippet. Add one for every level of function call. + :param snippet_lineno: Line number within snippet. + +Logging +------- + +.. function:: codegen.log(message [, message_type=None] [, end="\n"] [, logonly=True]) + +.. function:: codegen.msg(msg) + + Prints msg to stdout with a “Message: ” prefix. + +.. function:: codegen.prout(s [, end="\n"]) + +.. function:: codegen.prerr(s [, end="\n"]) diff --git a/doc/subsystems/codegen/index.rst b/doc/subsystems/codegen/index.rst new file mode 100644 index 0000000000000..7432af384c4c4 --- /dev/null +++ b/doc/subsystems/codegen/index.rst @@ -0,0 +1,27 @@ +.. + Copyright (c) 2018 Bobby Noelte + SPDX-License-Identifier: Apache-2.0 + +.. _codegen: + +Inline Code Generation +###################### + +For some repetitive or parameterized coding tasks, it's convenient to +use a code generating tool to build C code fragments, instead of writing +(or editing) that source code by hand. Such a tool can also access CMake build +parameters and device tree information to generate source code automatically +tailored and tuned to a specific project configuration. + +The Zephyr project supports a code generating tool that processes embedded +Python "snippets" inlined in your source files. It can be used, for example, +to generate source code that creates and fills data structures, adapts +programming logic, creates configuration-specific code fragments, and more. + +.. toctree:: + :maxdepth: 1 + + codegen + functions + build + principle diff --git a/doc/subsystems/codegen/principle.rst b/doc/subsystems/codegen/principle.rst new file mode 100644 index 0000000000000..4fa4a0b3d2700 --- /dev/null +++ b/doc/subsystems/codegen/principle.rst @@ -0,0 +1,48 @@ +.. + Copyright (c) 2018 Bobby Noelte + SPDX-License-Identifier: Apache-2.0 + +.. _codegen_principle: + +Code Generation Principle +######################### + +How code generation works in Zephyr. + +.. contents:: + :depth: 2 + :local: + :backlinks: top + +Principle +--------- + +.. image:: codegen_principle.png + :width: 500px + :align: center + :alt: Principle + +Inclusion of other inline code +------------------------------ + +.. image:: codegen_principle_include.png + :width: 500px + :align: center + :alt: Include other inline code + +Access to Zephyr data +--------------------- + +.. image:: codegen_principle_access.png + :width: 500px + :align: center + :alt: Access Zephyr data + +Import of Python modules +------------------------ + +.. image:: codegen_principle_import.png + :width: 500px + :align: center + :alt: Import Python modules + diff --git a/doc/subsystems/subsystems.rst b/doc/subsystems/subsystems.rst index 64a659b48d9c9..8f444e8be6859 100644 --- a/doc/subsystems/subsystems.rst +++ b/doc/subsystems/subsystems.rst @@ -11,6 +11,7 @@ to applications. bluetooth/bluetooth.rst c_library + codegen/index dfu logging/index tracing/index From 81dca4e663f8b87d8f60cefbff35aa013a0a76ab Mon Sep 17 00:00:00 2001 From: Bobby Noelte Date: Fri, 1 Jun 2018 07:56:23 +0200 Subject: [PATCH 05/18] scripts: codegen: add generic module modules/devicedeclare.py: Device declaration functions. Signed-off-by: Bobby Noelte --- cmake/extensions.cmake | 2 + scripts/codegen/modules/__init__.py | 1 + scripts/codegen/modules/devicedeclare.py | 392 +++++++++++++++++++++++ 3 files changed, 395 insertions(+) create mode 100644 scripts/codegen/modules/__init__.py create mode 100644 scripts/codegen/modules/devicedeclare.py diff --git a/cmake/extensions.cmake b/cmake/extensions.cmake index 38b75b4317c7f..9aaa908eda65c 100644 --- a/cmake/extensions.cmake +++ b/cmake/extensions.cmake @@ -385,6 +385,8 @@ function(target_sources_codegen file(GLOB CODEGEN_SOURCES ${ZEPHYR_BASE}/scripts/dts/edtsdevice.py ${ZEPHYR_BASE}/scripts/dts/edtsdatabase.py + ${ZEPHYR_BASE}/scripts/codegen/modules/*.py + ${ZEPHYR_BASE}/scripts/codegen/templates/drivers/*.py ${ZEPHYR_BASE}/scripts/codegen/*.py ${ZEPHYR_BASE}/scripts/gen_code.py) diff --git a/scripts/codegen/modules/__init__.py b/scripts/codegen/modules/__init__.py new file mode 100644 index 0000000000000..270dcebaa5f4e --- /dev/null +++ b/scripts/codegen/modules/__init__.py @@ -0,0 +1 @@ +from .modules import * diff --git a/scripts/codegen/modules/devicedeclare.py b/scripts/codegen/modules/devicedeclare.py new file mode 100644 index 0000000000000..0332ff81f497a --- /dev/null +++ b/scripts/codegen/modules/devicedeclare.py @@ -0,0 +1,392 @@ +# Copyright (c) 2018 Linaro Limited +# Copyright (c) 2018 Bobby Noelte +# +# SPDX-License-Identifier: Apache-2.0 + +import pprint +import re +import codegen + +from string import Template + +_device_and_api_init_tmpl = \ + 'DEVICE_AND_API_INIT( \\\n' + \ + '\t${device-name}, \\\n' + \ + '\t"${driver-name}", \\\n' + \ + '\t${device-init}, \\\n' + \ + '\t&${device-data}, \\\n' + \ + '\t&${device-config-info}, \\\n' + \ + '\t${device-level}, \\\n' + \ + '\t${device-prio}, \\\n' + \ + '\t&${device-api});' + +## +# Aliases for EDTS property paths. +_property_path_aliases = [ + ('reg/0/address/0', 'reg/address'), + ('reg/0/size/0', 'reg/size'), +] + +## +# @brief Get device name +# +# Device name is generated from +# - device compatible +# - bus master address if the device is connected to a bus master +# - device address +# - parent device address if the device does not have a device address +def _device_name(device_id): + device = codegen.edts().get_device_by_device_id(device_id) + device_name = device.get_property('compatible/0', None) + if device_name is None: + codegen.error("No compatible property for device id '{}'." + .format(device_id)) + + bus_master_device_id = device.get_property('bus/master', None) + if bus_master_device_id is not None: + bus_master_device = codegen.edts().get_device_by_device_id(bus_master_device_id) + reg = bus_master_device.get_property('reg') + try: + # use always the first key to get first address inserted into dict + # because reg_index may be number or name + # reg//address/ : address + for reg_index in reg: + for address_index in reg[reg_index]['address']: + bus = reg[reg_index]['address'][address_index] + device_name += '_' + hex(bus)[2:].zfill(8) + break + break + except: + # this device is missing the register directive + codegen.error("No bus master register address property for device id '{}'." + .format(bus_master_device_id)) + + reg = device.get_property('reg', None) + if reg is None: + # no reg property - take the reg property of the parent device + parent_device_id = device.get_property('parent-device', None) + if parent_device_id: + parent_device = codegen.edts().get_device_by_device_id(parent_device_id) + reg = parent_device.get_property(parent_device_id, 'reg', None) + device_address = None + if reg is not None: + try: + # use always the first key to get first address inserted into dict + # because reg_index may be number or name + # reg//address/ : address + for reg_index in reg: + for address_index in reg[reg_index]['address']: + address = reg[reg_index]['address'][address_index] + device_address = hex(address)[2:].zfill(8) + break + break + except: + # this device is missing the register directive + pass + if device_address is None: + # use label instead of address + device_address = device.get_property('label','') + # Warn about missing reg property + codegen.log("No register address property for device id '{}'." + .format(device_id), "warning", "\n") + device_name += '_' + device_address + + device_name = device_name.replace("-", "_"). \ + replace(",", "_"). \ + replace(";", "_"). \ + replace("@", "_"). \ + replace("#", "_"). \ + replace("&", "_"). \ + replace("/", "_"). \ + lower() + return device_name + +class _DeviceLocalTemplate(Template): + # pattern is ${} + # never starts with / + # extend default pattern by '-' '/' ',' + idpattern = r'[_a-z][_a-z0-9\-/,]*' + + +class _DeviceGlobalTemplate(Template): + # pattern is ${:} + # device ID is the same as node address + # always starts with / + # extend default pattern by '-', '@', '/', ':' + idpattern = r'/[_a-z0-9\-/,@:]*' + +## +# @brief Substitude values in device template +# +def _device_template_substitute(template, device_id, preset={}): + # substitute device local placeholders ${}, config, ... + mapping = {} + # add preset mapping + mapping.update(preset) + # add device properties from device tree + device = codegen.edts().get_device_by_device_id(device_id) + mapping.update(device.properties_flattened()) + # add specific device declaration vars/ constants + mapping['device-name'] = mapping.get('device-name', + _device_name(device_id)) + mapping['driver-name'] = mapping.get('driver-name', + device.get_property('label').strip('"')) + mapping['device-data'] = mapping.get('device-data', + "{}_data".format(mapping['device-name']).lower()) + mapping['device-config-info'] = mapping.get('device-config-info', + "{}_config".format(mapping['device-name']).lower()) + mapping['device-config-irq'] = mapping.get('device-config-irq', + "{}_config_irq".format(mapping['device-name']).lower()) + substituted = _DeviceLocalTemplate(template).safe_substitute(mapping) + + # substitute device global placeholders ${:} + # + # we need a second substitude to allow for device indirections + # ${${}:} + mapping = {} + for device_id in codegen.edts()['devices']: + path_prefix = device_id + ':' + device = codegen.edts().get_device_by_device_id(device_id) + mapping.update(device.properties_flattened(path_prefix)) + # add specific device declaration vars/ constants + try: + mapping[path_prefix + 'device-name'] = _device_name(device_id) + mapping[path_prefix + 'driver-name'] = \ + codegen.edts().device_property(device_id, 'label').strip('"') + except: + # will be obvious if any of this is needed, just skip here + pass + + # add aliases to mapping + aliases_mapping = {} + for property_path, property_value in mapping.items(): + for alias_property_path, alias in _property_path_aliases: + if property_path.endswith(alias_property_path): + property_path = property_path[:-len(alias_property_path)] \ + + alias + aliases_mapping[property_path] = property_value + mapping.update(aliases_mapping) + + substituted = _DeviceGlobalTemplate(substituted).safe_substitute(mapping) + + return substituted + + +# +# @return True if device is declared, False otherwise +def device_declare_single(device_config, + driver_name, + device_init, + device_level, + device_prio, + device_api, + device_info, + device_defaults = {}): + device_configured = codegen.config_property(device_config, '') + if device_configured == '' or device_configured[-1] == '0': + # Not configured - do not generate + # + # The generation decision must be taken by codegen here + # (vs. #define CONFIG_xxx) to cope with the following situation: + # + # If config is not set the device may also be not activated in the + # device tree. No device tree info is available in this case. + # An attempt to generate code without the DTS info + # will lead to an exception for a valid situation. + codegen.outl("/* !!! '{}' not configured !!! */".format(driver_name)) + return False + + device_id = codegen.edts().get_device_id_by_label(driver_name) + if device_id is None: + # this should not happen + raise codegen.Error("Did not find driver name '{}'.".format(driver_name)) + + # Presets for mapping this device data to template + preset = device_defaults + preset['device-init'] = device_init + preset['device-level'] = device_level + preset['device-prio'] = device_prio + preset['device-api'] = device_api + preset['device-config'] = device_config + preset['driver-name'] = driver_name.strip('"') + + # + # device info + if device_info: + device_info = _device_template_substitute(device_info, device_id, + preset) + codegen.outl(device_info) + # + # device init + codegen.outl(_device_template_substitute(_device_and_api_init_tmpl, + device_id, preset)) + return True + +## +# @param device_configs +# A list of configuration variables for device instantiation. +# (e.g. ['CONFIG_SPI_0', 'CONFIG_SPI_1']) +# @param driver_names +# A list of driver names for device instantiation. The list shall be ordered +# as the list of device configs. +# (e.g. ['SPI_0', 'SPI_1']) +# @param device_inits +# A list of device initialisation functions or a one single function. The +# list shall be ordered as the list of device configs. +# (e.g. 'spi_stm32_init') +# @param device_levels +# A list of driver initialisation levels or one single level definition. The +# list shall be ordered as the list of device configs. +# (e.g. 'PRE_KERNEL_1') +# @param device_prios +# A list of driver initialisation priorities or one single priority +# definition. The list shall be ordered as the list of device configs. +# (e.g. 32) +# @param device_api +# Identifier of the device api. +# (e.g. 'spi_stm32_driver_api') +# @param device_info +# Device info template for device driver config, data and interrupt +# initialisation. +# @param device_defaults +# Device default property values. `device_defaults` is a dictionary of +# property path : property value. +# +def device_declare_multi(device_configs, + driver_names, + device_inits, + device_levels, + device_prios, + device_api, + device_info, + device_defaults = {}): + devices_declared = [] + for i, device_config in enumerate(device_configs): + driver_name = driver_names[i] + if isinstance(device_inits, str): + device_init = device_inits + else: + try: + device_init = device_inits[i] + except: + device_init = device_inits + if isinstance(device_levels, str): + device_level = device_levels + else: + try: + device_level = device_levels[i] + except: + device_level = device_levels + if isinstance(device_prios, str): + device_prio = device_prios + else: + try: + device_prio = device_prios[i] + except: + device_prio = device_prios + + device_declared = device_declare_single(device_config, + driver_name, + device_init, + device_level, + device_prio, + device_api, + device_info, + device_defaults) + devices_declared.append(str(device_declared)) + + if 'True' not in devices_declared: + err = "No active device found for {} = {} and {}.".format( + ', '.join(device_configs), ', '.join(devices_declared), + ', '.join(driver_names)) + codegen.log(err) + raise codegen.Error(err) + + +def _device_generate_struct(type_of_struct, _struct): + if _struct is None and type_of_struct == 'config': + return 'static const int ${device-config-info}[] = {};\n' + elif _struct is None and type_of_struct == 'data': + return 'static int ${device-data}[] = {};\n' + + struct = "" + # convert _struct into a list. Struct might have only one element + if type(_struct) is str: + _struct = [_struct] + else: + _struct = list(_struct) + + if type_of_struct == 'config': + struct += 'static const struct {} ${{device-config-info}} = {{\n'.format(_struct[0]) + elif type_of_struct == 'data': + struct += 'static struct {} ${{device-data}} = {{\n'.format(_struct[0]) + else: + msg("Not expected") + + if len(_struct) > 1: + struct += _struct[1] + + struct += '};\n\n' + return struct + + +def _device_generate_irq_bootstrap(irq_names, irq_flag, irq_func): + irq_bootstrap_info = \ + '#ifdef {}\n'.format(irq_flag) + \ + 'DEVICE_DECLARE(${device-name});\n' + \ + 'static void ${device-config-irq}(struct device *dev)\n' + \ + '{\n' + for index, irq_name in enumerate(irq_names): + irq_name = irq_names[index] + irq_num = '${{get_property(\'interrupts/{}/irq\')}}'.format(index) + irq_prio = '${{get_property(\'interrupts/{}/priority\')}}'.format(index) + irq_bootstrap_info += \ + '\tIRQ_CONNECT({},\n'.format(irq_num) + \ + '\t\t{},\n'.format(irq_prio) + if len(irq_names) == 1 and irq_name == '0': + # Only one irq and no name associated. Keep it simple name + irq_bootstrap_info += '\t\t{},\n'.format(irq_func) + else: + irq_bootstrap_info += '\t\t{}_{},\n'.format(irq_func, irq_name) + irq_bootstrap_info += \ + '\t\tDEVICE_GET(${device-name}),\n' + \ + '\t\t0);\n' + \ + '\tirq_enable({});\n\n'.format(irq_num) + irq_bootstrap_info += \ + '}\n' + \ + '#endif /* {} */\n\n'.format(irq_flag) + return irq_bootstrap_info + + +def device_declare(compatibles, init_prio_flag, kernel_level, irq_func, + init_func, api, data_struct, config_struct): + + config_struct = _device_generate_struct('config', config_struct) + data_struct = _device_generate_struct('data', data_struct) + if api is None: + api = "(*(const int *)0)" + + for device_id in codegen.edts().get_device_ids_by_compatible(compatibles): + device_info = "" + device = codegen.edts().get_device_by_device_id(device_id) + driver_name = device.get_property('label') + device_config = "CONFIG_{}".format(driver_name.strip('"')) + interrupts = device.get_property('interrupts', None) + if interrupts is not None: + try: + irq_names = list(interrupts[dev]['name'] for dev in interrupts) + except: + irq_names = list(interrupts) + + device_info += _device_generate_irq_bootstrap( + irq_names, irq_func['irq_flag'], irq_func['irq_func']) + device_info += config_struct + device_info += data_struct + + device_declare_single(device_config, + driver_name, + init_func, + kernel_level, + init_prio_flag, + api, + device_info) From bad906abb8a001b741136a6fc7977e9bbb5e6e42 Mon Sep 17 00:00:00 2001 From: Bobby Noelte Date: Fri, 1 Jun 2018 18:44:03 +0200 Subject: [PATCH 06/18] doc: codegen: add modules and templates doc Document the modules that can be imported and the templates that can be included by inline code generation. Signed-off-by: Bobby Noelte --- doc/subsystems/codegen/index.rst | 2 + doc/subsystems/codegen/modules.rst | 322 +++++++++++++++++++++++++++ doc/subsystems/codegen/templates.rst | 37 +++ 3 files changed, 361 insertions(+) create mode 100644 doc/subsystems/codegen/modules.rst create mode 100644 doc/subsystems/codegen/templates.rst diff --git a/doc/subsystems/codegen/index.rst b/doc/subsystems/codegen/index.rst index 7432af384c4c4..129749e02530d 100644 --- a/doc/subsystems/codegen/index.rst +++ b/doc/subsystems/codegen/index.rst @@ -23,5 +23,7 @@ programming logic, creates configuration-specific code fragments, and more. codegen functions + modules + templates build principle diff --git a/doc/subsystems/codegen/modules.rst b/doc/subsystems/codegen/modules.rst new file mode 100644 index 0000000000000..3a53d5d8ad5e2 --- /dev/null +++ b/doc/subsystems/codegen/modules.rst @@ -0,0 +1,322 @@ +.. + Copyright (c) 2018 Bobby Noelte + SPDX-License-Identifier: Apache-2.0 + +.. _codegen_modules: + +Code Generation Modules +####################### + +Code generation modules provide supporting functions for code generation. + +.. contents:: + :depth: 2 + :local: + :backlinks: top + +Modules have to be imported to gain access to the module's functions +and variables. + + :: + + /* This file uses modules. */ + ... + /** + * @code{.codegen} + * codegen.import_module('my_special_module') + * my_special_module.do_everything(): + * @endcode{.codegen} + */ + /** @code{.codeins}@endcode */ + ... + +Device declare module +********************* + +:: + + codegen.import_module('devicedeclare') + +The devicedeclare module provides functions to generate driver device +instantiations. + +Driver info templates +--------------------- + +The device declaration functions work on templates that feature placeholder +substitution. + +Device instance property placeholders: + +- ${device-name}: device instance name. + Name is generated by the declaration function. +- ${driver-name}: device instance driver name. + Name is taken from the device tree node property 'label'. +- ${device-data}: device instance data structure name. + Name is generated by the declaration function. +- ${device-config-info}: device instance configuration structure name. + Name is generated by the declaration function. +- ${device-config-irq}: device instance interrupt configuration function name. + Name is generated by the declaration function. + +Device instance device tree property placeholders: + +* ${[path to DTS property]}: device instance device tree node property. + The property path supports every node property that is documented in the + node yaml bindings. It also supports yaml heuristics, like 'bus-master' and + will use documented '"#cells"'. + +Device tree property placeholders: + +- ${[device id]:[path to DTS property]}: device node property value. + The device node property is defined by the property path of the device + given by the device id. + The device id is usually also taken from a DTS property e.g. + ${${clocks/0/provider}:device-name}. + +KConfig configuration parameter placeholders: + +- ${CONFIG_[configuration parameter]}: KConfig configuration parameter value. + +Declaration of device instances +------------------------------- + +.. function:: devicedeclare.device_declare(compatibles, init_prio_flag, kernel_level, irq_func, init_func, api, data_struct, config_struct) + + Generate device instances code for all devices activated ('status' = 'ok') + in the board device tree file matching the provided compatibles. + + Most of the parameters aim at filling the DEVICE_AND_API_INIT macro. + Other parameters are there to help code generation to fit driver specifics. + + Instance code will only be generated if the Kconfig variable is set. The + variable name is build with the device node label name (e.g: CONFIG_I2C_1). + + :param compatibles: List of compatibles supported by the driver + (e.g. ['st,stm32-spi-fifo', 'st,stm32-spi']) + :param init_prio_flag: Flag for driver activation priority + (e.g. CONFIG_KERNEL_INIT_PRIORITY_DEVICE) + :param kernel_level: Flag for driver activation priority (e.g. POST_KERNEL) + :param irq_func: Two elements python dict providing driver isr function + prefix (e.g. 'irq_func' \: 'stm32_i2c_isr') and flag to be + used for driver IRQ code control + (e.g. 'irq_flag' \: 'CONFIG_I2C_STM32_INTERRUPT'). + If irq_func is 'None', no IRQ code is generated. + 'device_declare' will generate as much IRQ code as + declared by device node. + If the 'interrupts-names' property is provided in the node, + isr names will be generated using matching values as + function postfixes. + :param init_func: Name of the driver init function (e.g. 'i2c_stm32_init'). + :param api: Name of the driver api structure (e.g. 'api_funcs'). + :param data_struct: Two elements python list providing elements for driver + '_data' structure generation. + :param config_struct: Two elements python list providing elements for driver + '_config' structure generation. + +'data_struct' and 'config_struct' will be processed the same way: + +* First element (e.g. 'i2c_stm32_config') should be the structure name. +* Second element is a 'c' template code between triple double quotes (""" """). + It should provide the expected code to be generated for the structure. + For instance: + +.. code-block:: python + + """ + .i2c = (I2C_TypeDef *)${reg/0/address/0}, + .pclken = { + .enr = ${clocks/0/bits}, + .bus = ${clocks/0/bus}, + }, + #ifdef CONFIG_I2C_STM32_INTERRUPT + .irq_config_func = st_stm32_i2c_v1_${node_index}_config_irq, + #endif + .bitrate = ${clock-frequency}, + """ + +If the second element of 'data_struct' or 'config_struct' list is not provided, +an empty structure is generated. + +Finally, for the above depicted example, 'device_declare' will generate, +for device instance 'I2C1': + +.. code-block:: c + + #ifdef CONFIG_I2C_STM32_INTERRUPT + DEVICE_DECLARE(st_stm32_i2c_v1_i2c_1); + static void st_stm32_i2c_v1_i2c_1_config_irq(struct device *dev) + { + IRQ_CONNECT(31, + 0, + stm32_i2c_isr_event, + DEVICE_GET(st_stm32_i2c_v1_i2c_1), + 0); + irq_enable(31); + IRQ_CONNECT(32, + 0, + stm32_i2c_isr_error, + DEVICE_GET(st_stm32_i2c_v1_i2c_1), + 0); + irq_enable(32); + } + #endif /* CONFIG_I2C_STM32_INTERRUPT */ + + static const struct i2c_stm32_config st_stm32_i2c_v1_i2c_1_config = { + .i2c = (I2C_TypeDef *)0x40005400, + .pclken = { + .enr = 131072, + .bus = 2, + }, + #ifdef CONFIG_I2C_STM32_INTERRUPT + .irq_config_func = st_stm32_i2c_v1_i2c_1_config_irq, + #endif + .bitrate = 400000, + }; + + static struct i2c_stm32_data st_stm32_i2c_v1_i2c_1_data = {}; + + DEVICE_AND_API_INIT(st_stm32_i2c_v1_i2c_1, + "I2C_1", + i2c_stm32_init, + &st_stm32_i2c_v1_i2c_1_data, + &st_stm32_i2c_v1_i2c_1_config, + POST_KERNEL, + CONFIG_KERNEL_INIT_PRIORITY_DEVICE, + &api_funcs); + +Raw declaration of a single device instance +------------------------------------------- + +.. function:: devicedeclare.device_declare_single(device_config, driver_name, device_init, device_levels device_prio, device_api, device_info) + + Generate device instances code for a device instance that: + + - matches the driver name and that + - is activated ('status' = 'ok') in the board device tree file and that is + - configured by Kconfig. + + The ``device_declare_single`` function enables a detailed control of the + device info definition. It's primary use is for complex device instance + initialisation that can not be accomplished by ``device_declare``. + + :param device_config: + Configuration variables for device instantiation. + (e.g. 'CONFIG_SPI_0') + :param driver_name: + Driver name for device instantiation. + (e.g. 'SPI_0') + :param device_init: + Device initialisation function. + (e.g. 'spi_stm32_init') + :param device_level: + Driver initialisation level. + (e.g. 'PRE_KERNEL_1') + :param device_prios: + Driver initialisation priority definition. + (e.g. 32) + :param device_api: + Identifier of the device api. + (e.g. 'spi_stm32_driver_api') + :param device_info: + Device info template for device driver config, data and interrupt + initialisation. + :param device_defaults: + Default property values. + (e.g. { 'label' : 'My default label' }) + +Raw declaration of multiple device instances +-------------------------------------------- + +.. function:: devicedeclare.device_declare_multi(device_configs, driver_names, device_inits, device_levels, device_prios, device_api, device_info) + + Generate device instances code for all device instances that: + + - match the driver names and that + - are activated ('status' = 'ok') in the board device tree file and that are + - configured by Kconfig. + + The ``device_declare_multi`` function enables a detailed control of the + device info definition. It's primary use is for complex device instance + initialisation that can not be accomplished by ``device_declare``. + + :param device_configs: + A list of configuration variables for device instantiation. + (e.g. ['CONFIG_SPI_0', 'CONFIG_SPI_1']) + :param driver_names: + A list of driver names for device instantiation. The list shall be + ordered the same way as the list of device configs. + (e.g. ['SPI_0', 'SPI_1']) + :param device_inits: + A list of device initialisation functions or a one single function. + The list shall be ordered as the list of device configs. + (e.g. 'spi_stm32_init') + :param device_levels: + A list of driver initialisation levels or one single level definition. + The list shall be ordered as the list of device configs. + (e.g. 'PRE_KERNEL_1') + :param device_prios: + A list of driver initialisation priorities or one single priority + definition. The list shall be ordered as the list of device configs. + (e.g. 32) + :param device_api: + Identifier of the device api. + (e.g. 'spi_stm32_driver_api') + :param device_info: + Device info template for device driver config, data and interrupt + initialisation. + :param device_defaults: + Default property values. + (e.g. { 'label' : 'My default label' }) + +Example: + +.. code-block:: C + + /** + * @code{.codegen} + * codegen.import_module('devicedeclare') + * + * device_configs = ['CONFIG_SPI_{}'.format(x) for x in range(1, 4)] + * driver_names = ['SPI_{}'.format(x) for x in range(1, 4)] + * device_inits = 'spi_stm32_init' + * device_levels = 'POST_KERNEL' + * device_prios = 'CONFIG_SPI_INIT_PRIORITY' + * device_api = 'spi_stm32_driver_api' + * device_info = \ + * """ + * #if CONFIG_SPI_STM32_INTERRUPT + * DEVICE_DECLARE(${device-name}); + * static void ${device-config-irq}(struct device *dev) + * { + * IRQ_CONNECT(${interrupts/0/irq}, ${interrupts/0/priority}, \\ + * spi_stm32_isr, \\ + * DEVICE_GET(${device-name}), 0); + * irq_enable(${interrupts/0/irq}); + * } + * #endif + * static const struct spi_stm32_config ${device-config-info} = { + * .spi = (SPI_TypeDef *)${reg/0/address/0}, + * .pclken.bus = ${clocks/0/bus}, + * .pclken.enr = ${clocks/0/bits}, + * #if CONFIG_SPI_STM32_INTERRUPT + * .config_irq = ${device-config-irq}, + * #endif + * }; + * static struct spi_stm32_data ${device-data} = { + * SPI_CONTEXT_INIT_LOCK(${device-data}, ctx), + * SPI_CONTEXT_INIT_SYNC(${device-data}, ctx), + * }; + * """ + * + * devicedeclare.device_declare_multi( \ + * device_configs, + * driver_names, + * device_inits, + * device_levels, + * device_prios, + * device_api, + * device_info) + * @endcode{.codegen} + */ + /** @code{.codeins}@endcode */ diff --git a/doc/subsystems/codegen/templates.rst b/doc/subsystems/codegen/templates.rst new file mode 100644 index 0000000000000..da9f3a5ad12b8 --- /dev/null +++ b/doc/subsystems/codegen/templates.rst @@ -0,0 +1,37 @@ +.. + Copyright (c) 2018 Bobby Noelte + SPDX-License-Identifier: Apache-2.0 + +.. _codegen_templates: + +Code Generation Templates +######################### + +Code generation templates provide sopisticated code generation functions. + +.. contents:: + :depth: 2 + :local: + :backlinks: top + +Templates have to be included to gain access to the template's functions +and variables. + + :: + + /* This file uses templates. */ + ... + /** + * @code{.codegen} + * template_in_var = 1 + * codegen.out_include('templates/template_tmpl.c') + * if template_out_var not None: + * codegen.outl("int x = %s;" % template_out_var) + * @endcode{.codegen} + */ + /** @code{.codeins}@endcode */ + ... + + + + From 5fa50b4f8c61cd7dc1a0493fb8637278ac2c2340 Mon Sep 17 00:00:00 2001 From: Erwan Gouriou Date: Thu, 25 Oct 2018 18:04:05 +0200 Subject: [PATCH 07/18] cmake: extensions.cmake: Update codegen sequence When a file.c gets added in cmake with zephyr_library_sources_codegen_ifdef,matching file_devices.c will be generated by codegen using file_devices.c.in template file. Signed-off-by: Erwan Gouriou --- cmake/extensions.cmake | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/cmake/extensions.cmake b/cmake/extensions.cmake index 9aaa908eda65c..6bea301213fe2 100644 --- a/cmake/extensions.cmake +++ b/cmake/extensions.cmake @@ -395,15 +395,16 @@ function(target_sources_codegen # Otherwise this would trigger CMake issue #14633: # https://gitlab.kitware.com/cmake/cmake/issues/14633 foreach(arg ${CODEGEN_UNPARSED_ARGUMENTS}) + get_filename_component(generated_file_name ${arg} NAME_WE) if(IS_ABSOLUTE ${arg}) set(template_file ${arg}) - get_filename_component(generated_file_name ${arg} NAME) - set(generated_file ${CMAKE_CURRENT_BINARY_DIR}/${generated_file_name}) + set(generated_file ${CMAKE_CURRENT_BINARY_DIR}/${generated_file_name}_devices.c) else() - set(template_file ${CMAKE_CURRENT_SOURCE_DIR}/${arg}) - set(generated_file ${CMAKE_CURRENT_BINARY_DIR}/${arg}) + set(template_file ${CMAKE_CURRENT_SOURCE_DIR}/${generated_file_name}_devices.c.in) + set(generated_file ${CMAKE_CURRENT_BINARY_DIR}/${generated_file_name}_devices.c) endif() get_filename_component(template_dir ${template_file} DIRECTORY) + get_filename_component(generated_dir ${generated_file} DIRECTORY) if(IS_DIRECTORY ${template_file}) message(FATAL_ERROR "target_sources_codegen() was called on a directory") @@ -412,13 +413,7 @@ function(target_sources_codegen # Generate file from template message(STATUS " from '${template_file}'") message(STATUS " to '${generated_file}'") - add_custom_command( - COMMENT "CodeGen ${generated_file}" - OUTPUT ${generated_file} - MAIN_DEPENDENCY ${template_file} - DEPENDS - ${CODEGEN_DEPENDS} - ${CODEGEN_SOURCES} + execute_process( COMMAND ${PYTHON_EXECUTABLE} ${ZEPHYR_BASE}/scripts/gen_code.py @@ -464,7 +459,9 @@ function(target_sources_codegen # relative path in generated file to work zephyr_include_directories(${template_dir}) else() - target_sources(${target} PRIVATE ${generated_file}) + zephyr_include_directories(${generated_dir}) + target_sources(${target} PRIVATE ${arg}) + # Add template directory to include path to allow includes with # relative path in generated file to work target_include_directories(${target} PRIVATE ${template_dir}) From 3fab258516306c714b9cd3fe8c10cf7bd9e9e420 Mon Sep 17 00:00:00 2001 From: Erwan Gouriou Date: Wed, 1 Aug 2018 11:08:59 +0200 Subject: [PATCH 08/18] drivers/spi: stm32: use codegen driver instantiation Replace device instances code by codegen solution. Since there are 2 compatibles for STM32 SPI, declare both compatibles in device_declare API. Signed-off-by: Erwan Gouriou --- drivers/spi/CMakeLists.txt | 2 +- drivers/spi/spi_ll_stm32.c | 119 +------------------------- drivers/spi/spi_ll_stm32_devices.c.in | 41 +++++++++ 3 files changed, 43 insertions(+), 119 deletions(-) create mode 100644 drivers/spi/spi_ll_stm32_devices.c.in diff --git a/drivers/spi/CMakeLists.txt b/drivers/spi/CMakeLists.txt index c626a1409c329..7c8b1bf48d7d5 100644 --- a/drivers/spi/CMakeLists.txt +++ b/drivers/spi/CMakeLists.txt @@ -2,7 +2,7 @@ zephyr_library() zephyr_library_sources_ifdef(CONFIG_SPI_DW spi_dw.c) zephyr_library_sources_ifdef(CONFIG_SPI_INTEL spi_intel.c) -zephyr_library_sources_ifdef(CONFIG_SPI_STM32 spi_ll_stm32.c) +zephyr_library_sources_codegen_ifdef(CONFIG_SPI_STM32 spi_ll_stm32.c) zephyr_library_sources_ifdef(CONFIG_SPI_MCUX_DSPI spi_mcux_dspi.c) zephyr_library_sources_ifdef(CONFIG_SPI_MCUX_LPSPI spi_mcux_lpspi.c) zephyr_library_sources_ifdef(CONFIG_SPI_SAM spi_sam.c) diff --git a/drivers/spi/spi_ll_stm32.c b/drivers/spi/spi_ll_stm32.c index 8290297f6c895..addffa67d5540 100644 --- a/drivers/spi/spi_ll_stm32.c +++ b/drivers/spi/spi_ll_stm32.c @@ -477,121 +477,4 @@ static int spi_stm32_init(struct device *dev) return 0; } -#ifdef CONFIG_SPI_1 - -#ifdef CONFIG_SPI_STM32_INTERRUPT -static void spi_stm32_irq_config_func_1(struct device *port); -#endif - -static const struct spi_stm32_config spi_stm32_cfg_1 = { - .spi = (SPI_TypeDef *) CONFIG_SPI_1_BASE_ADDRESS, - .pclken = { -#ifdef CONFIG_SOC_SERIES_STM32F0X - .enr = LL_APB1_GRP2_PERIPH_SPI1, - .bus = STM32_CLOCK_BUS_APB1_2 -#else - .enr = LL_APB2_GRP1_PERIPH_SPI1, - .bus = STM32_CLOCK_BUS_APB2 -#endif - }, -#ifdef CONFIG_SPI_STM32_INTERRUPT - .irq_config = spi_stm32_irq_config_func_1, -#endif -}; - -static struct spi_stm32_data spi_stm32_dev_data_1 = { - SPI_CONTEXT_INIT_LOCK(spi_stm32_dev_data_1, ctx), - SPI_CONTEXT_INIT_SYNC(spi_stm32_dev_data_1, ctx), -}; - -DEVICE_AND_API_INIT(spi_stm32_1, CONFIG_SPI_1_NAME, &spi_stm32_init, - &spi_stm32_dev_data_1, &spi_stm32_cfg_1, - POST_KERNEL, CONFIG_SPI_INIT_PRIORITY, - &api_funcs); - -#ifdef CONFIG_SPI_STM32_INTERRUPT -static void spi_stm32_irq_config_func_1(struct device *dev) -{ - IRQ_CONNECT(CONFIG_SPI_1_IRQ, CONFIG_SPI_1_IRQ_PRI, - spi_stm32_isr, DEVICE_GET(spi_stm32_1), 0); - irq_enable(CONFIG_SPI_1_IRQ); -} -#endif - -#endif /* CONFIG_SPI_1 */ - -#ifdef CONFIG_SPI_2 - -#ifdef CONFIG_SPI_STM32_INTERRUPT -static void spi_stm32_irq_config_func_2(struct device *port); -#endif - -static const struct spi_stm32_config spi_stm32_cfg_2 = { - .spi = (SPI_TypeDef *) CONFIG_SPI_2_BASE_ADDRESS, - .pclken = { - .enr = LL_APB1_GRP1_PERIPH_SPI2, - .bus = STM32_CLOCK_BUS_APB1 - }, -#ifdef CONFIG_SPI_STM32_INTERRUPT - .irq_config = spi_stm32_irq_config_func_2, -#endif -}; - -static struct spi_stm32_data spi_stm32_dev_data_2 = { - SPI_CONTEXT_INIT_LOCK(spi_stm32_dev_data_2, ctx), - SPI_CONTEXT_INIT_SYNC(spi_stm32_dev_data_2, ctx), -}; - -DEVICE_AND_API_INIT(spi_stm32_2, CONFIG_SPI_2_NAME, &spi_stm32_init, - &spi_stm32_dev_data_2, &spi_stm32_cfg_2, - POST_KERNEL, CONFIG_SPI_INIT_PRIORITY, - &api_funcs); - -#ifdef CONFIG_SPI_STM32_INTERRUPT -static void spi_stm32_irq_config_func_2(struct device *dev) -{ - IRQ_CONNECT(CONFIG_SPI_2_IRQ, CONFIG_SPI_2_IRQ_PRI, - spi_stm32_isr, DEVICE_GET(spi_stm32_2), 0); - irq_enable(CONFIG_SPI_2_IRQ); -} -#endif - -#endif /* CONFIG_SPI_2 */ - -#ifdef CONFIG_SPI_3 - -#ifdef CONFIG_SPI_STM32_INTERRUPT -static void spi_stm32_irq_config_func_3(struct device *port); -#endif - -static const struct spi_stm32_config spi_stm32_cfg_3 = { - .spi = (SPI_TypeDef *) CONFIG_SPI_3_BASE_ADDRESS, - .pclken = { - .enr = LL_APB1_GRP1_PERIPH_SPI3, - .bus = STM32_CLOCK_BUS_APB1 - }, -#ifdef CONFIG_SPI_STM32_INTERRUPT - .irq_config = spi_stm32_irq_config_func_3, -#endif -}; - -static struct spi_stm32_data spi_stm32_dev_data_3 = { - SPI_CONTEXT_INIT_LOCK(spi_stm32_dev_data_3, ctx), - SPI_CONTEXT_INIT_SYNC(spi_stm32_dev_data_3, ctx), -}; - -DEVICE_AND_API_INIT(spi_stm32_3, CONFIG_SPI_3_NAME, &spi_stm32_init, - &spi_stm32_dev_data_3, &spi_stm32_cfg_3, - POST_KERNEL, CONFIG_SPI_INIT_PRIORITY, - &api_funcs); - -#ifdef CONFIG_SPI_STM32_INTERRUPT -static void spi_stm32_irq_config_func_3(struct device *dev) -{ - IRQ_CONNECT(CONFIG_SPI_3_IRQ, CONFIG_SPI_3_IRQ_PRI, - spi_stm32_isr, DEVICE_GET(spi_stm32_3), 0); - irq_enable(CONFIG_SPI_3_IRQ); -} -#endif - -#endif /* CONFIG_SPI_3 */ +#include diff --git a/drivers/spi/spi_ll_stm32_devices.c.in b/drivers/spi/spi_ll_stm32_devices.c.in new file mode 100644 index 0000000000000..0f7d17579550c --- /dev/null +++ b/drivers/spi/spi_ll_stm32_devices.c.in @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2018 Linaro Limited + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @code{.codegen} + * codegen.import_module('devicedeclare') + * + * device_data = ( 'spi_stm32_data', + * """ + * SPI_CONTEXT_INIT_LOCK(${device-name}_data, ctx), + * SPI_CONTEXT_INIT_SYNC(${device-name}_data, ctx), + * """ + * ) + * + * + * device_config = ( 'spi_stm32_config', + * """ + * .spi = (SPI_TypeDef *)${reg/0/address}, + * .pclken.bus = ${clocks/0/bus}, + * .pclken.enr = ${clocks/0/bits}, + * #ifdef CONFIG_SPI_STM32_INTERRUPT + * .irq_config = ${device-name}_config_irq, + * #endif + * """) + * + * devicedeclare.device_declare(['st,stm32-spi', 'st,stm32-spi-fifo'], + * 'CONFIG_SPI_INIT_PRIORITY', + * 'POST_KERNEL', + * {'irq_func':'spi_stm32_isr','irq_flag': 'CONFIG_SPI_STM32_INTERRUPT'}, + * 'spi_stm32_init', + * 'api_funcs', + * device_data, + * device_config + * ) + * + * @endcode{.codegen} + */ +/** @code{.codeins}@endcode */ From 362c376337dbb86b50687c5263ff508b5c4bfde3 Mon Sep 17 00:00:00 2001 From: Erwan Gouriou Date: Wed, 1 Aug 2018 11:11:28 +0200 Subject: [PATCH 09/18] drivers/i2c: stm32: use codegen driver instantiation Replace device instances code by codegen solution. Since there are 2 compatibles for STM32 i2c, specify 2 different compatibles are supported by the driver Change the isr name, with isr name as postfix (instead being in the middle of the function name) in order to make it easier to be generated. Signed-off-by: Erwan Gouriou --- drivers/i2c/CMakeLists.txt | 11 +- drivers/i2c/i2c_ll_stm32.c | 180 +------------------------- drivers/i2c/i2c_ll_stm32.h | 6 +- drivers/i2c/i2c_ll_stm32_devices.c.in | 38 ++++++ drivers/i2c/i2c_ll_stm32_v1.c | 4 +- drivers/i2c/i2c_ll_stm32_v2.c | 7 +- 6 files changed, 51 insertions(+), 195 deletions(-) create mode 100644 drivers/i2c/i2c_ll_stm32_devices.c.in diff --git a/drivers/i2c/CMakeLists.txt b/drivers/i2c/CMakeLists.txt index 6eff42c950ffa..c3f4b42f0c255 100644 --- a/drivers/i2c/CMakeLists.txt +++ b/drivers/i2c/CMakeLists.txt @@ -18,14 +18,9 @@ zephyr_library_sources_ifdef(CONFIG_I2C_SBCON i2c_sbcon.c) zephyr_library_sources_ifdef(CONFIG_I2C_NIOS2 i2c_nios2.c) zephyr_library_sources_ifdef(CONFIG_I2C_GECKO i2c_gecko.c) -zephyr_library_sources_ifdef(CONFIG_I2C_STM32_V1 - i2c_ll_stm32_v1.c - i2c_ll_stm32.c - ) -zephyr_library_sources_ifdef(CONFIG_I2C_STM32_V2 - i2c_ll_stm32_v2.c - i2c_ll_stm32.c - ) +zephyr_library_sources_codegen_ifdef(CONFIG_I2C_STM32 i2c_ll_stm32.c) +zephyr_library_sources_ifdef(CONFIG_I2C_STM32_V1 i2c_ll_stm32_v1.c) +zephyr_library_sources_ifdef(CONFIG_I2C_STM32_V2 i2c_ll_stm32_v2.c) zephyr_library_sources_ifdef(CONFIG_USERSPACE i2c_handlers.c) diff --git a/drivers/i2c/i2c_ll_stm32.c b/drivers/i2c/i2c_ll_stm32.c index 9757d1e0d5ce8..a82b2069321bd 100644 --- a/drivers/i2c/i2c_ll_stm32.c +++ b/drivers/i2c/i2c_ll_stm32.c @@ -211,182 +211,4 @@ static int i2c_stm32_init(struct device *dev) return 0; } -#ifdef CONFIG_I2C_1 - -#ifdef CONFIG_I2C_STM32_INTERRUPT -static void i2c_stm32_irq_config_func_1(struct device *port); -#endif - -static const struct i2c_stm32_config i2c_stm32_cfg_1 = { - .i2c = (I2C_TypeDef *)CONFIG_I2C_1_BASE_ADDRESS, - .pclken = { - .enr = CONFIG_I2C_1_CLOCK_BITS, - .bus = CONFIG_I2C_1_CLOCK_BUS, - }, -#ifdef CONFIG_I2C_STM32_INTERRUPT - .irq_config_func = i2c_stm32_irq_config_func_1, -#endif - .bitrate = CONFIG_I2C_1_BITRATE, -}; - -static struct i2c_stm32_data i2c_stm32_dev_data_1; - -DEVICE_AND_API_INIT(i2c_stm32_1, CONFIG_I2C_1_NAME, &i2c_stm32_init, - &i2c_stm32_dev_data_1, &i2c_stm32_cfg_1, - POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEVICE, - &api_funcs); - -#ifdef CONFIG_I2C_STM32_INTERRUPT -static void i2c_stm32_irq_config_func_1(struct device *dev) -{ -#ifdef CONFIG_I2C_STM32_COMBINED_INTERRUPT - IRQ_CONNECT(CONFIG_I2C_1_COMBINED_IRQ, CONFIG_I2C_1_COMBINED_IRQ_PRI, - stm32_i2c_combined_isr, DEVICE_GET(i2c_stm32_1), 0); - irq_enable(CONFIG_I2C_1_COMBINED_IRQ); -#else - IRQ_CONNECT(CONFIG_I2C_1_EVENT_IRQ, CONFIG_I2C_1_EVENT_IRQ_PRI, - stm32_i2c_event_isr, DEVICE_GET(i2c_stm32_1), 0); - irq_enable(CONFIG_I2C_1_EVENT_IRQ); - - IRQ_CONNECT(CONFIG_I2C_1_ERROR_IRQ, CONFIG_I2C_1_ERROR_IRQ_PRI, - stm32_i2c_error_isr, DEVICE_GET(i2c_stm32_1), 0); - irq_enable(CONFIG_I2C_1_ERROR_IRQ); -#endif -} -#endif - -#endif /* CONFIG_I2C_1 */ - -#ifdef CONFIG_I2C_2 - -#ifdef CONFIG_I2C_STM32_INTERRUPT -static void i2c_stm32_irq_config_func_2(struct device *port); -#endif - -static const struct i2c_stm32_config i2c_stm32_cfg_2 = { - .i2c = (I2C_TypeDef *)CONFIG_I2C_2_BASE_ADDRESS, - .pclken = { - .enr = CONFIG_I2C_2_CLOCK_BITS, - .bus = CONFIG_I2C_2_CLOCK_BUS, - }, -#ifdef CONFIG_I2C_STM32_INTERRUPT - .irq_config_func = i2c_stm32_irq_config_func_2, -#endif - .bitrate = CONFIG_I2C_2_BITRATE, -}; - -static struct i2c_stm32_data i2c_stm32_dev_data_2; - -DEVICE_AND_API_INIT(i2c_stm32_2, CONFIG_I2C_2_NAME, &i2c_stm32_init, - &i2c_stm32_dev_data_2, &i2c_stm32_cfg_2, - POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEVICE, - &api_funcs); - -#ifdef CONFIG_I2C_STM32_INTERRUPT -static void i2c_stm32_irq_config_func_2(struct device *dev) -{ -#ifdef CONFIG_I2C_STM32_COMBINED_INTERRUPT - IRQ_CONNECT(CONFIG_I2C_2_COMBINED_IRQ, CONFIG_I2C_2_COMBINED_IRQ_PRI, - stm32_i2c_combined_isr, DEVICE_GET(i2c_stm32_2), 0); - irq_enable(CONFIG_I2C_2_COMBINED_IRQ); -#else - IRQ_CONNECT(CONFIG_I2C_2_EVENT_IRQ, CONFIG_I2C_2_EVENT_IRQ_PRI, - stm32_i2c_event_isr, DEVICE_GET(i2c_stm32_2), 0); - irq_enable(CONFIG_I2C_2_EVENT_IRQ); - - IRQ_CONNECT(CONFIG_I2C_2_ERROR_IRQ, CONFIG_I2C_2_ERROR_IRQ_PRI, - stm32_i2c_error_isr, DEVICE_GET(i2c_stm32_2), 0); - irq_enable(CONFIG_I2C_2_ERROR_IRQ); -#endif -} -#endif - -#endif /* CONFIG_I2C_2 */ - -#ifdef CONFIG_I2C_3 - -#ifndef I2C3_BASE -#error "I2C_3 is not available on the platform that you selected" -#endif /* I2C3_BASE */ - -#ifdef CONFIG_I2C_STM32_INTERRUPT -static void i2c_stm32_irq_config_func_3(struct device *port); -#endif - -static const struct i2c_stm32_config i2c_stm32_cfg_3 = { - .i2c = (I2C_TypeDef *)CONFIG_I2C_3_BASE_ADDRESS, - .pclken = { - .enr = CONFIG_I2C_3_CLOCK_BITS, - .bus = CONFIG_I2C_3_CLOCK_BUS, - }, -#ifdef CONFIG_I2C_STM32_INTERRUPT - .irq_config_func = i2c_stm32_irq_config_func_3, -#endif - .bitrate = CONFIG_I2C_3_BITRATE, -}; - -static struct i2c_stm32_data i2c_stm32_dev_data_3; - -DEVICE_AND_API_INIT(i2c_stm32_3, CONFIG_I2C_3_NAME, &i2c_stm32_init, - &i2c_stm32_dev_data_3, &i2c_stm32_cfg_3, - POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEVICE, - &api_funcs); - -#ifdef CONFIG_I2C_STM32_INTERRUPT -static void i2c_stm32_irq_config_func_3(struct device *dev) -{ - IRQ_CONNECT(CONFIG_I2C_3_EVENT_IRQ, CONFIG_I2C_3_EVENT_IRQ_PRI, - stm32_i2c_event_isr, DEVICE_GET(i2c_stm32_3), 0); - irq_enable(CONFIG_I2C_3_EVENT_IRQ); - - IRQ_CONNECT(CONFIG_I2C_3_ERROR_IRQ, CONFIG_I2C_3_ERROR_IRQ_PRI, - stm32_i2c_error_isr, DEVICE_GET(i2c_stm32_3), 0); - irq_enable(CONFIG_I2C_3_ERROR_IRQ); -} -#endif - -#endif /* CONFIG_I2C_3 */ - -#ifdef CONFIG_I2C_4 - -#ifndef I2C4_BASE -#error "I2C_4 is not available on the platform that you selected" -#endif /* I2C4_BASE */ - -#ifdef CONFIG_I2C_STM32_INTERRUPT -static void i2c_stm32_irq_config_func_4(struct device *port); -#endif - -static const struct i2c_stm32_config i2c_stm32_cfg_4 = { - .i2c = (I2C_TypeDef *)CONFIG_I2C_4_BASE_ADDRESS, - .pclken = { - .enr = CONFIG_I2C_4_CLOCK_BITS, - .bus = CONFIG_I2C_4_CLOCK_BUS, - }, -#ifdef CONFIG_I2C_STM32_INTERRUPT - .irq_config_func = i2c_stm32_irq_config_func_4, -#endif - .bitrate = CONFIG_I2C_4_BITRATE, -}; - -static struct i2c_stm32_data i2c_stm32_dev_data_4; - -DEVICE_AND_API_INIT(i2c_stm32_4, CONFIG_I2C_4_NAME, &i2c_stm32_init, - &i2c_stm32_dev_data_4, &i2c_stm32_cfg_4, - POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEVICE, - &api_funcs); - -#ifdef CONFIG_I2C_STM32_INTERRUPT -static void i2c_stm32_irq_config_func_4(struct device *dev) -{ - IRQ_CONNECT(CONFIG_I2C_4_EVENT_IRQ, CONFIG_I2C_4_EVENT_IRQ_PRI, - stm32_i2c_event_isr, DEVICE_GET(i2c_stm32_4), 0); - irq_enable(CONFIG_I2C_4_EVENT_IRQ); - - IRQ_CONNECT(CONFIG_I2C_4_ERROR_IRQ, CONFIG_I2C_4_ERROR_IRQ_PRI, - stm32_i2c_error_isr, DEVICE_GET(i2c_stm32_4), 0); - irq_enable(CONFIG_I2C_4_ERROR_IRQ); -} -#endif - -#endif /* CONFIG_I2C_4 */ +#include diff --git a/drivers/i2c/i2c_ll_stm32.h b/drivers/i2c/i2c_ll_stm32.h index 528064f56d9ba..3d9d764dbffe2 100644 --- a/drivers/i2c/i2c_ll_stm32.h +++ b/drivers/i2c/i2c_ll_stm32.h @@ -55,10 +55,10 @@ s32_t stm32_i2c_msg_read(struct device *dev, struct i2c_msg *msg, u8_t *flg, s32_t stm32_i2c_configure_timing(struct device *dev, u32_t clk); int i2c_stm32_runtime_configure(struct device *dev, u32_t config); -void stm32_i2c_event_isr(void *arg); -void stm32_i2c_error_isr(void *arg); +void stm32_i2c_isr_event(void *arg); +void stm32_i2c_isr_error(void *arg); #ifdef CONFIG_I2C_STM32_COMBINED_INTERRUPT -void stm32_i2c_combined_isr(void *arg); +void stm32_i2c_isr_combined(void *arg); #endif #ifdef CONFIG_I2C_SLAVE diff --git a/drivers/i2c/i2c_ll_stm32_devices.c.in b/drivers/i2c/i2c_ll_stm32_devices.c.in new file mode 100644 index 0000000000000..9b660f6084b8c --- /dev/null +++ b/drivers/i2c/i2c_ll_stm32_devices.c.in @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2018 Linaro Ltd + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @code{.codegen} + * codegen.import_module('devicedeclare') + * + * device_data = ('i2c_stm32_data') + * + * device_config = ('i2c_stm32_config', + * """ + * .i2c = (I2C_TypeDef *)${reg/0/address}, + * .pclken = { + * .enr = ${clocks/0/bits}, + * .bus = ${clocks/0/bus}, + * }, + * #ifdef CONFIG_I2C_STM32_INTERRUPT + * .irq_config_func = ${device-name}_config_irq, + * #endif + * .bitrate = ${clock-frequency}, + * """) + * + * devicedeclare.device_declare(['st,stm32-i2c-v1','st,stm32-i2c-v2'], + * 'CONFIG_KERNEL_INIT_PRIORITY_DEVICE', + * 'POST_KERNEL', + * {'irq_func':'stm32_i2c_isr','irq_flag': 'CONFIG_I2C_STM32_INTERRUPT'}, + * 'i2c_stm32_init', + * 'api_funcs', + * device_data, + * device_config + * ) + * + * @endcode{.codegen} + */ +/** @code{.codeins}@endcode */ diff --git a/drivers/i2c/i2c_ll_stm32_v1.c b/drivers/i2c/i2c_ll_stm32_v1.c index 085af54cd9dd4..90133efecc1da 100644 --- a/drivers/i2c/i2c_ll_stm32_v1.c +++ b/drivers/i2c/i2c_ll_stm32_v1.c @@ -171,7 +171,7 @@ static inline void handle_btf(I2C_TypeDef *i2c, struct i2c_stm32_data *data) } } -void stm32_i2c_event_isr(void *arg) +void stm32_i2c_isr_event(void *arg) { const struct i2c_stm32_config *cfg = DEV_CFG((struct device *)arg); struct i2c_stm32_data *data = DEV_DATA((struct device *)arg); @@ -192,7 +192,7 @@ void stm32_i2c_event_isr(void *arg) } } -void stm32_i2c_error_isr(void *arg) +void stm32_i2c_isr_error(void *arg) { const struct i2c_stm32_config *cfg = DEV_CFG((struct device *)arg); struct i2c_stm32_data *data = DEV_DATA((struct device *)arg); diff --git a/drivers/i2c/i2c_ll_stm32_v2.c b/drivers/i2c/i2c_ll_stm32_v2.c index a01acd8b788a9..a732ef07d82ff 100644 --- a/drivers/i2c/i2c_ll_stm32_v2.c +++ b/drivers/i2c/i2c_ll_stm32_v2.c @@ -343,7 +343,7 @@ static int stm32_i2c_error(struct device *dev) } #ifdef CONFIG_I2C_STM32_COMBINED_INTERRUPT -void stm32_i2c_combined_isr(void *arg) +void stm32_i2c_isr_combined(void *arg) { struct device *dev = (struct device *) arg; @@ -354,14 +354,14 @@ void stm32_i2c_combined_isr(void *arg) } #else -void stm32_i2c_event_isr(void *arg) +void stm32_i2c_isr_event(void *arg) { struct device *dev = (struct device *) arg; stm32_i2c_event(dev); } -void stm32_i2c_error_isr(void *arg) +void stm32_i2c_isr_error(void *arg) { struct device *dev = (struct device *) arg; @@ -467,6 +467,7 @@ int stm32_i2c_msg_read(struct device *dev, struct i2c_msg *msg, } #else /* !CONFIG_I2C_STM32_INTERRUPT */ + static inline void msg_done(struct device *dev, unsigned int current_msg_flags) { const struct i2c_stm32_config *cfg = DEV_CFG(dev); From 2c16942dbda1b8e3d6c648fc973140ff80a88f92 Mon Sep 17 00:00:00 2001 From: Erwan Gouriou Date: Tue, 4 Sep 2018 14:59:29 +0200 Subject: [PATCH 10/18] scripts/codegen: Remove CONFIG flag check from device generation To align with requirement about split of responsibility between Kconfig and device tree, don't condition instance code generation on matching CONFIG flag value. Codegen should generate the code configured in device tree. Kconfig is responible for its final compilation. This way codegen is independant from Kconfig and could be executed before it. Reported misconfiguration should not be possible if a 'compatible' check is done beforehand. Signed-off-by: Erwan Gouriou --- scripts/codegen/modules/devicedeclare.py | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/scripts/codegen/modules/devicedeclare.py b/scripts/codegen/modules/devicedeclare.py index 0332ff81f497a..aa5d14461aa0d 100644 --- a/scripts/codegen/modules/devicedeclare.py +++ b/scripts/codegen/modules/devicedeclare.py @@ -183,18 +183,8 @@ def device_declare_single(device_config, device_info, device_defaults = {}): device_configured = codegen.config_property(device_config, '') - if device_configured == '' or device_configured[-1] == '0': - # Not configured - do not generate - # - # The generation decision must be taken by codegen here - # (vs. #define CONFIG_xxx) to cope with the following situation: - # - # If config is not set the device may also be not activated in the - # device tree. No device tree info is available in this case. - # An attempt to generate code without the DTS info - # will lead to an exception for a valid situation. - codegen.outl("/* !!! '{}' not configured !!! */".format(driver_name)) - return False + + codegen.outl('\n#ifdef {}\n'.format(device_config)) device_id = codegen.edts().get_device_id_by_label(driver_name) if device_id is None: @@ -220,6 +210,10 @@ def device_declare_single(device_config, # device init codegen.outl(_device_template_substitute(_device_and_api_init_tmpl, device_id, preset)) + + codegen.outl('') + codegen.outl('#endif /* {} */\n'.format(device_config)) + return True ## From d617e192f803675019d881ddfeb5b2062acfb45f Mon Sep 17 00:00:00 2001 From: Erwan Gouriou Date: Thu, 25 Oct 2018 11:25:20 +0200 Subject: [PATCH 11/18] scripts/dts: edtsdatabase.py: provide alternate path for edtsdevice Depending on the caller, edtsdatabase should import EDTSDevice class from edtsdevice or dts.edtsdevice. Signed-off-by: Erwan Gouriou --- scripts/dts/edtsdatabase.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/scripts/dts/edtsdatabase.py b/scripts/dts/edtsdatabase.py index 83666b37d8680..9aa1be84a609b 100755 --- a/scripts/dts/edtsdatabase.py +++ b/scripts/dts/edtsdatabase.py @@ -11,7 +11,10 @@ import argparse import json import pprint -from edtsdevice import EDTSDevice +try: + from dts.edtsdevice import EDTSDevice +except: + from edtsdevice import EDTSDevice ## # @brief ETDS Database consumer From f3c94b690aabb5ff5be4e2d78f75bfe9ff801702 Mon Sep 17 00:00:00 2001 From: Erwan Gouriou Date: Thu, 8 Nov 2018 15:18:22 +0100 Subject: [PATCH 12/18] scripts/codegen: devicedeclare: use EDTSDevice API to access EDTS In codegen devicedeclare module, use EDTSDevice API to access EDTS data. To simplify things, 'device-name' derivates (device-data, device-config-info and device-config-irq) are reworked to use unique_id field. Signed-off-by: Erwan Gouriou --- drivers/i2c/i2c_ll_stm32_devices.c.in | 10 +++---- drivers/spi/spi_ll_stm32_devices.c.in | 12 ++++---- scripts/codegen/modules/devicedeclare.py | 35 ++++++++++++++++++++++-- 3 files changed, 43 insertions(+), 14 deletions(-) diff --git a/drivers/i2c/i2c_ll_stm32_devices.c.in b/drivers/i2c/i2c_ll_stm32_devices.c.in index 9b660f6084b8c..2f9ded950de35 100644 --- a/drivers/i2c/i2c_ll_stm32_devices.c.in +++ b/drivers/i2c/i2c_ll_stm32_devices.c.in @@ -12,15 +12,15 @@ * * device_config = ('i2c_stm32_config', * """ - * .i2c = (I2C_TypeDef *)${reg/0/address}, + * .i2c = (I2C_TypeDef *)${get_reg_addr()}, * .pclken = { - * .enr = ${clocks/0/bits}, - * .bus = ${clocks/0/bus}, + * .enr = ${get_property('clocks/0/bits')}, + * .bus = ${get_property('clocks/0/bus')}, * }, * #ifdef CONFIG_I2C_STM32_INTERRUPT - * .irq_config_func = ${device-name}_config_irq, + * .irq_config_func = ${get_unique_id()}_config_irq, * #endif - * .bitrate = ${clock-frequency}, + * .bitrate = ${get_property('clock-frequency')}, * """) * * devicedeclare.device_declare(['st,stm32-i2c-v1','st,stm32-i2c-v2'], diff --git a/drivers/spi/spi_ll_stm32_devices.c.in b/drivers/spi/spi_ll_stm32_devices.c.in index 0f7d17579550c..f276466d4f01c 100644 --- a/drivers/spi/spi_ll_stm32_devices.c.in +++ b/drivers/spi/spi_ll_stm32_devices.c.in @@ -10,19 +10,19 @@ * * device_data = ( 'spi_stm32_data', * """ - * SPI_CONTEXT_INIT_LOCK(${device-name}_data, ctx), - * SPI_CONTEXT_INIT_SYNC(${device-name}_data, ctx), + * SPI_CONTEXT_INIT_LOCK(${get_unique_id()}_data, ctx), + * SPI_CONTEXT_INIT_SYNC(${get_unique_id()}_data, ctx), * """ * ) * * * device_config = ( 'spi_stm32_config', * """ - * .spi = (SPI_TypeDef *)${reg/0/address}, - * .pclken.bus = ${clocks/0/bus}, - * .pclken.enr = ${clocks/0/bits}, + * .spi = (SPI_TypeDef *)${get_reg_addr()}, + * .pclken.bus = ${get_property('clocks/0/bus')}, + * .pclken.enr = ${get_property('clocks/0/bits')}, * #ifdef CONFIG_SPI_STM32_INTERRUPT - * .irq_config = ${device-name}_config_irq, + * .irq_config = ${get_unique_id()}_config_irq, * #endif * """) * diff --git a/scripts/codegen/modules/devicedeclare.py b/scripts/codegen/modules/devicedeclare.py index aa5d14461aa0d..17d338b15deb4 100644 --- a/scripts/codegen/modules/devicedeclare.py +++ b/scripts/codegen/modules/devicedeclare.py @@ -107,6 +107,11 @@ class _DeviceLocalTemplate(Template): # extend default pattern by '-' '/' ',' idpattern = r'[_a-z][_a-z0-9\-/,]*' +class _DeviceCustomTemplate(Template): + # pattern is ${} + # never starts with / + # extend default pattern by '-' '/' ',', '(', ')' + idpattern = r'[_a-z][_a-z0-9\-/,()\']*' class _DeviceGlobalTemplate(Template): # pattern is ${:} @@ -115,10 +120,31 @@ class _DeviceGlobalTemplate(Template): # extend default pattern by '-', '@', '/', ':' idpattern = r'/[_a-z0-9\-/,@:]*' + +## +# @brief Substitude values in device template +# +def _device_custom_template_substitute(template, device_id): + + class CustomMapping: + def __getitem__(self, key): + # Need to play with device so it could be visible in eval() + bogus = device.get_unique_id() + cmd = 'device' + '.' + key + return eval(cmd) + + # add device properties from device tree + device = codegen.edts().get_device_by_device_id(device_id) + + substituted = _DeviceCustomTemplate(template).safe_substitute(CustomMapping()) + + return substituted + ## # @brief Substitude values in device template # def _device_template_substitute(template, device_id, preset={}): + # substitute device local placeholders ${}, config, ... mapping = {} # add preset mapping @@ -132,11 +158,11 @@ def _device_template_substitute(template, device_id, preset={}): mapping['driver-name'] = mapping.get('driver-name', device.get_property('label').strip('"')) mapping['device-data'] = mapping.get('device-data', - "{}_data".format(mapping['device-name']).lower()) + "{}_data".format(device.get_unique_id())) mapping['device-config-info'] = mapping.get('device-config-info', - "{}_config".format(mapping['device-name']).lower()) + "{}_config".format(device.get_unique_id())) mapping['device-config-irq'] = mapping.get('device-config-irq', - "{}_config_irq".format(mapping['device-name']).lower()) + "{}_config_irq".format(device.get_unique_id())) substituted = _DeviceLocalTemplate(template).safe_substitute(mapping) # substitute device global placeholders ${:} @@ -205,6 +231,7 @@ def device_declare_single(device_config, if device_info: device_info = _device_template_substitute(device_info, device_id, preset) + device_info = _device_custom_template_substitute(device_info, device_id) codegen.outl(device_info) # # device init @@ -357,6 +384,7 @@ def device_declare(compatibles, init_prio_flag, kernel_level, irq_func, config_struct = _device_generate_struct('config', config_struct) data_struct = _device_generate_struct('data', data_struct) + if api is None: api = "(*(const int *)0)" @@ -374,6 +402,7 @@ def device_declare(compatibles, init_prio_flag, kernel_level, irq_func, device_info += _device_generate_irq_bootstrap( irq_names, irq_func['irq_flag'], irq_func['irq_func']) + device_info += config_struct device_info += data_struct From 55c15fbb5418d12ffacc3c15c5b4817facc63b16 Mon Sep 17 00:00:00 2001 From: Erwan Gouriou Date: Fri, 9 Nov 2018 14:53:20 +0100 Subject: [PATCH 13/18] drivers/i2c: stm32: Split v1 and v2 compatibles templates This change is only to demonstrate how we could declare common template for a driver compatible with 2 compatible variants. Signed-off-by: Erwan Gouriou --- drivers/i2c/i2c_ll_stm32_devices.c.in | 31 ++++++++++++++++++++++++--- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/drivers/i2c/i2c_ll_stm32_devices.c.in b/drivers/i2c/i2c_ll_stm32_devices.c.in index 2f9ded950de35..4db899ccf8f83 100644 --- a/drivers/i2c/i2c_ll_stm32_devices.c.in +++ b/drivers/i2c/i2c_ll_stm32_devices.c.in @@ -4,13 +4,15 @@ * SPDX-License-Identifier: Apache-2.0 */ +/* Split configs for compat v1 and v2 to demonstrate multi-compat ability */ + /** * @code{.codegen} * codegen.import_module('devicedeclare') * * device_data = ('i2c_stm32_data') * - * device_config = ('i2c_stm32_config', + * device_config_v1 = ('i2c_stm32_config', * """ * .i2c = (I2C_TypeDef *)${get_reg_addr()}, * .pclken = { @@ -23,14 +25,37 @@ * .bitrate = ${get_property('clock-frequency')}, * """) * - * devicedeclare.device_declare(['st,stm32-i2c-v1','st,stm32-i2c-v2'], + * device_config_v2 = ('i2c_stm32_config', + * """ + * .i2c = (I2C_TypeDef *)${get_reg_addr()}, + * .pclken = { + * .enr = ${get_property('clocks/0/bits')}, + * .bus = ${get_property('clocks/0/bus')}, + * }, + * #ifdef CONFIG_I2C_STM32_INTERRUPT + * .irq_config_func = ${get_unique_id()}_config_irq, + * #endif + * .bitrate = ${get_property('clock-frequency')}, + * """) + * + * devicedeclare.device_declare('st,stm32-i2c-v1', + * 'CONFIG_KERNEL_INIT_PRIORITY_DEVICE', + * 'POST_KERNEL', + * {'irq_func':'stm32_i2c_isr','irq_flag': 'CONFIG_I2C_STM32_INTERRUPT'}, + * 'i2c_stm32_init', + * 'api_funcs', + * device_data, + * device_config_v1 + * ) + * + * devicedeclare.device_declare('st,stm32-i2c-v2', * 'CONFIG_KERNEL_INIT_PRIORITY_DEVICE', * 'POST_KERNEL', * {'irq_func':'stm32_i2c_isr','irq_flag': 'CONFIG_I2C_STM32_INTERRUPT'}, * 'i2c_stm32_init', * 'api_funcs', * device_data, - * device_config + * device_config_v2 * ) * * @endcode{.codegen} From d87631896258a31c0f59241e9e3b1c37ae7c9b0b Mon Sep 17 00:00:00 2001 From: Erwan Gouriou Date: Mon, 12 Nov 2018 09:19:53 +0100 Subject: [PATCH 14/18] scripts/dts/codegen: devicedeclare: fix for parents and controllers Update devicedecmare to work with parents and controllers. Since they now can be returned thanks to EDTSDevice methods returning EDTSDevice Object, remove the additional code to do this treatment inside devicedeclare. Add support for '.' inside pattern _DeviceCustomTemplate to enable treatment of such partens: get_controller('irq-gpios/0').get_property('label') Signed-off-by: Erwan Gouriou --- scripts/codegen/modules/devicedeclare.py | 42 +++++++++++++----------- 1 file changed, 22 insertions(+), 20 deletions(-) diff --git a/scripts/codegen/modules/devicedeclare.py b/scripts/codegen/modules/devicedeclare.py index 17d338b15deb4..a7bcbc03994f3 100644 --- a/scripts/codegen/modules/devicedeclare.py +++ b/scripts/codegen/modules/devicedeclare.py @@ -42,24 +42,24 @@ def _device_name(device_id): codegen.error("No compatible property for device id '{}'." .format(device_id)) - bus_master_device_id = device.get_property('bus/master', None) - if bus_master_device_id is not None: - bus_master_device = codegen.edts().get_device_by_device_id(bus_master_device_id) - reg = bus_master_device.get_property('reg') - try: - # use always the first key to get first address inserted into dict - # because reg_index may be number or name - # reg//address/ : address - for reg_index in reg: - for address_index in reg[reg_index]['address']: - bus = reg[reg_index]['address'][address_index] - device_name += '_' + hex(bus)[2:].zfill(8) - break - break - except: - # this device is missing the register directive - codegen.error("No bus master register address property for device id '{}'." - .format(bus_master_device_id)) + # bus_master_device_id = device.get_property('bus/master', None) + # if bus_master_device_id is not None: + # bus_master_device = codegen.edts().get_device_by_device_id(bus_master_device_id) + # reg = bus_master_device.get_property('reg') + # try: + # # use always the first key to get first address inserted into dict + # # because reg_index may be number or name + # # reg//address/ : address + # for reg_index in reg: + # for address_index in reg[reg_index]['address']: + # bus = reg[reg_index]['address'][address_index] + # device_name += '_' + hex(bus)[2:].zfill(8) + # break + # break + # except: + # # this device is missing the register directive + # codegen.error("No bus master register address property for device id '{}'." + # .format(bus_master_device_id)) reg = device.get_property('reg', None) if reg is None: @@ -110,8 +110,8 @@ class _DeviceLocalTemplate(Template): class _DeviceCustomTemplate(Template): # pattern is ${} # never starts with / - # extend default pattern by '-' '/' ',', '(', ')' - idpattern = r'[_a-z][_a-z0-9\-/,()\']*' + # extend default pattern by '-' '/' ',', '(', ')', '.' + idpattern = r'[_a-z][_a-z0-9\-/,()\'.]*' class _DeviceGlobalTemplate(Template): # pattern is ${:} @@ -394,6 +394,8 @@ def device_declare(compatibles, init_prio_flag, kernel_level, irq_func, driver_name = device.get_property('label') device_config = "CONFIG_{}".format(driver_name.strip('"')) interrupts = device.get_property('interrupts', None) + + if interrupts is not None: try: irq_names = list(interrupts[dev]['name'] for dev in interrupts) From 4fb3dd80b66b3e8a3fbb8d23dc56015a93969536 Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Fri, 9 Nov 2018 11:23:36 -0600 Subject: [PATCH 15/18] scripts/dts: add initial cut at get_parent() Needs error checking, and handling of different 'types' (interrupt, gpio, etc). Signed-off-by: Kumar Gala --- scripts/dts/edtsdatabase.py | 2 +- scripts/dts/edtsdevice.py | 13 +++++++++++-- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/scripts/dts/edtsdatabase.py b/scripts/dts/edtsdatabase.py index 9aa1be84a609b..f881e0c35c839 100755 --- a/scripts/dts/edtsdatabase.py +++ b/scripts/dts/edtsdatabase.py @@ -95,7 +95,7 @@ def get_device_id_by_label(self, label): # @return (dict)device def get_device_by_device_id(self, device_id): try: - return EDTSDevice(self._edts['devices'][device_id]) + return EDTSDevice(self._edts['devices'], device_id) except: return None diff --git a/scripts/dts/edtsdevice.py b/scripts/dts/edtsdevice.py index 1929ede118e3f..e4cb95c144e29 100755 --- a/scripts/dts/edtsdevice.py +++ b/scripts/dts/edtsdevice.py @@ -5,8 +5,9 @@ # class EDTSDevice: - def __init__(self, device): - self.device = device + def __init__(self, devices, dev_id): + self.all = devices + self.device = devices[dev_id] ## # @brief Get device tree property value for the device of the given device id. @@ -128,3 +129,11 @@ def get_irq_prop_types(self): # @return device unique id string def get_unique_id(self): return self.get_property('unique_id') + + def get_parent(self, parent_type='bus'): + parent_device_id = '' + + for comp in self.device['device-id'].split('/')[1:-1]: + parent_device_id += '/' + comp + + return EDTSDevice(self.all, parent_device_id) From 91e81be6d6113786f0894f67cc1df2e55a759903 Mon Sep 17 00:00:00 2001 From: Erwan Gouriou Date: Mon, 12 Nov 2018 10:40:25 +0100 Subject: [PATCH 16/18] scripts/dts: edtsdevice: Method to get controller EDTSDevice object Add get_controller that return controller EDTSDevice Object Signed-off-by: Erwan Gouriou --- scripts/dts/edtsdevice.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/scripts/dts/edtsdevice.py b/scripts/dts/edtsdevice.py index e4cb95c144e29..28f3ff36c2a26 100755 --- a/scripts/dts/edtsdevice.py +++ b/scripts/dts/edtsdevice.py @@ -130,6 +130,22 @@ def get_irq_prop_types(self): def get_unique_id(self): return self.get_property('unique_id') + def get_controller(self, property_path): + device_id = self.device['device-id'] + property_value = self.device + property_path_elems = property_path.strip("'").split('/') + # This method is made to find a controller after given path + # we expect only ditcs in the path and ['controller'] at the end. + for elem_index, key in enumerate(property_path_elems): + if isinstance(property_value, dict): + property_value = property_value.get(key, None) + controller = property_value.get('controller', None) + + # How to return a meaningfull error here? + # if controller is None: + + return EDTSDevice(self.all, controller) + def get_parent(self, parent_type='bus'): parent_device_id = '' From 64617de60777f7488e92eb4b08f5278d96cd5571 Mon Sep 17 00:00:00 2001 From: Erwan Gouriou Date: Wed, 4 Jul 2018 17:48:47 +0200 Subject: [PATCH 17/18] drivers/sensors: lsm6dsl: Generate driver instantiation [DNM] Update driver to support code generation. Note that this driver change is not functional but done to provide example on how to demonstrate several possibilities of device_declare api: -access bus-master information (implicit in device tree, build thanks to yaml) -access irq/cs gpios and pin information -For a single driver specify 2 types of config struct and build them depending on the compatible present in the board Remove from build_all test to pass CI Signed-off-by: Erwan Gouriou --- boards/arm/96b_argonkey/96b_argonkey.dts | 1 + drivers/sensor/lsm6dsl/CMakeLists.txt | 2 +- drivers/sensor/lsm6dsl/lsm6dsl.c | 19 +++---- drivers/sensor/lsm6dsl/lsm6dsl.h | 10 ++++ drivers/sensor/lsm6dsl/lsm6dsl_devices.c.in | 53 +++++++++++++++++++ drivers/sensor/lsm6dsl/lsm6dsl_i2c.c | 10 ++-- drivers/sensor/lsm6dsl/lsm6dsl_spi.c | 1 + dts/bindings/sensor/st,lsm6dsl-spi.yaml | 5 ++ tests/drivers/build_all/sensors_i_z.conf | 2 +- .../build_all/sensors_trigger_i_z.conf | 2 +- 10 files changed, 85 insertions(+), 20 deletions(-) create mode 100644 drivers/sensor/lsm6dsl/lsm6dsl_devices.c.in diff --git a/boards/arm/96b_argonkey/96b_argonkey.dts b/boards/arm/96b_argonkey/96b_argonkey.dts index 873dcc35456e9..105ca86d85f58 100644 --- a/boards/arm/96b_argonkey/96b_argonkey.dts +++ b/boards/arm/96b_argonkey/96b_argonkey.dts @@ -63,6 +63,7 @@ compatible = "st,lsm6dsl-spi"; reg = <1>; spi-max-frequency = <1000000>; + cs-gpios = <&gpioc 2 0>; irq-gpios = <&gpiob 1 0>; label = "LSM6DSL_SPI"; }; diff --git a/drivers/sensor/lsm6dsl/CMakeLists.txt b/drivers/sensor/lsm6dsl/CMakeLists.txt index b42cba8f09e0f..57823a9354a5f 100644 --- a/drivers/sensor/lsm6dsl/CMakeLists.txt +++ b/drivers/sensor/lsm6dsl/CMakeLists.txt @@ -1,6 +1,6 @@ zephyr_library() -zephyr_library_sources_ifdef(CONFIG_LSM6DSL lsm6dsl.c) +zephyr_library_sources_codegen_ifdef(CONFIG_LSM6DSL lsm6dsl.c) zephyr_library_sources_ifdef(CONFIG_LSM6DSL_SPI lsm6dsl_spi.c) zephyr_library_sources_ifdef(CONFIG_LSM6DSL_I2C lsm6dsl_i2c.c) zephyr_library_sources_ifdef(CONFIG_LSM6DSL_TRIGGER lsm6dsl_trigger.c) diff --git a/drivers/sensor/lsm6dsl/lsm6dsl.c b/drivers/sensor/lsm6dsl/lsm6dsl.c index 8a71f516016ed..3f4bcdfb3564f 100644 --- a/drivers/sensor/lsm6dsl/lsm6dsl.c +++ b/drivers/sensor/lsm6dsl/lsm6dsl.c @@ -772,13 +772,6 @@ static int lsm6dsl_init_chip(struct device *dev) return 0; } -static struct lsm6dsl_config lsm6dsl_config = { -#ifdef CONFIG_LSM6DSL_SPI - .comm_master_dev_name = CONFIG_LSM6DSL_SPI_MASTER_DEV_NAME, -#else - .comm_master_dev_name = CONFIG_LSM6DSL_I2C_MASTER_DEV_NAME, -#endif -}; static int lsm6dsl_init(struct device *dev) { @@ -795,6 +788,12 @@ static int lsm6dsl_init(struct device *dev) #ifdef CONFIG_LSM6DSL_SPI lsm6dsl_spi_init(dev); #else + data->i2c_addr = config->i2c_slave_addr; + if (!data->i2c_addr) { + SYS_LOG_DBG("I2C slave address not provided"); + return -EINVAL; + } + lsm6dsl_i2c_init(dev); #endif @@ -821,8 +820,4 @@ static int lsm6dsl_init(struct device *dev) } -static struct lsm6dsl_data lsm6dsl_data; - -DEVICE_AND_API_INIT(lsm6dsl, CONFIG_LSM6DSL_DEV_NAME, lsm6dsl_init, - &lsm6dsl_data, &lsm6dsl_config, POST_KERNEL, - CONFIG_SENSOR_INIT_PRIORITY, &lsm6dsl_api_funcs); +#include diff --git a/drivers/sensor/lsm6dsl/lsm6dsl.h b/drivers/sensor/lsm6dsl/lsm6dsl.h index 3aee094d59083..08cd252767d53 100644 --- a/drivers/sensor/lsm6dsl/lsm6dsl.h +++ b/drivers/sensor/lsm6dsl/lsm6dsl.h @@ -605,6 +605,15 @@ struct lsm6dsl_config { char *comm_master_dev_name; +#ifdef CONFIG_LSM6DSL_SPI + char *irq_gpio_port; + u32_t irq_gpio_pin; + char *cs_gpio_port; + u32_t cs_gpio_pin; + u32_t frequency; +#else + u16_t i2c_slave_addr; +#endif }; struct lsm6dsl_data; @@ -622,6 +631,7 @@ struct lsm6dsl_transfer_function { struct lsm6dsl_data { struct device *comm_master; + u16_t i2c_addr; int accel_sample_x; int accel_sample_y; int accel_sample_z; diff --git a/drivers/sensor/lsm6dsl/lsm6dsl_devices.c.in b/drivers/sensor/lsm6dsl/lsm6dsl_devices.c.in new file mode 100644 index 0000000000000..db5597dfd52b3 --- /dev/null +++ b/drivers/sensor/lsm6dsl/lsm6dsl_devices.c.in @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2018 Linaro Limited + * + * SPDX-License-Identifier: Apache-2.0 + */ + + + +/** + * @code{.codegen} + * codegen.import_module('devicedeclare') + * + * device_data = ('lsm6dsl_data') + * + * device_config_spi = ('lsm6dsl_config', + * """ + * .comm_master_dev_name = "${get_parent().get_property('label')}", + * .irq_gpio_port = "${get_controller('irq-gpios/0').get_property('label')}", + * .irq_gpio_pin = ${get_property('irq-gpios/0/pin')}, + * .cs_gpio_port = "${get_controller('cs-gpios/0').get_property('label')}", + * .cs_gpio_pin = ${get_property('cs-gpios/0/pin')}, + * .frequency = ${get_property('spi-max-frequency')}, + * """) + * + * device_config_i2c = ('lsm6dsl_config', + * """ + * .comm_master_dev_name = "${get_parent().get_property('label')}", + * .i2c_slave_addr = ${get_reg_addr()} + * """) + * + * devicedeclare.device_declare('st,lsm6dsl-spi', + * 'CONFIG_SENSOR_INIT_PRIORITY', + * 'POST_KERNEL', + * None, + * 'lsm6dsl_init', + * 'lsm6dsl_api_funcs', + * device_data, + * device_config_spi + * ) + * + * devicedeclare.device_declare('st,lsm6dsl', + * 'CONFIG_SENSOR_INIT_PRIORITY', + * 'POST_KERNEL', + * None, + * 'lsm6dsl_init', + * 'lsm6dsl_api_funcs', + * device_data, + * device_config_i2c + * ) + * + * @endcode{.codegen} + */ +/** @code{.codeins}@endcode */ diff --git a/drivers/sensor/lsm6dsl/lsm6dsl_i2c.c b/drivers/sensor/lsm6dsl/lsm6dsl_i2c.c index a23b7e2e67970..221a99045c2ae 100644 --- a/drivers/sensor/lsm6dsl/lsm6dsl_i2c.c +++ b/drivers/sensor/lsm6dsl/lsm6dsl_i2c.c @@ -7,13 +7,13 @@ * SPDX-License-Identifier: Apache-2.0 */ + #include #include #include #include "lsm6dsl.h" -static u16_t lsm6dsl_i2c_slave_addr = CONFIG_LSM6DSL_I2C_ADDR; #define LOG_LEVEL CONFIG_SENSOR_LOG_LEVEL LOG_MODULE_DECLARE(LSM6DSL); @@ -21,28 +21,28 @@ LOG_MODULE_DECLARE(LSM6DSL); static int lsm6dsl_i2c_read_data(struct lsm6dsl_data *data, u8_t reg_addr, u8_t *value, u8_t len) { - return i2c_burst_read(data->comm_master, lsm6dsl_i2c_slave_addr, + return i2c_burst_read(data->comm_master, data->i2c_addr, reg_addr, value, len); } static int lsm6dsl_i2c_write_data(struct lsm6dsl_data *data, u8_t reg_addr, u8_t *value, u8_t len) { - return i2c_burst_write(data->comm_master, lsm6dsl_i2c_slave_addr, + return i2c_burst_write(data->comm_master, data->i2c_addr, reg_addr, value, len); } static int lsm6dsl_i2c_read_reg(struct lsm6dsl_data *data, u8_t reg_addr, u8_t *value) { - return i2c_reg_read_byte(data->comm_master, lsm6dsl_i2c_slave_addr, + return i2c_reg_read_byte(data->comm_master, data->i2c_addr, reg_addr, value); } static int lsm6dsl_i2c_update_reg(struct lsm6dsl_data *data, u8_t reg_addr, u8_t mask, u8_t value) { - return i2c_reg_update_byte(data->comm_master, lsm6dsl_i2c_slave_addr, + return i2c_reg_update_byte(data->comm_master, data->i2c_addr, reg_addr, mask, value); } diff --git a/drivers/sensor/lsm6dsl/lsm6dsl_spi.c b/drivers/sensor/lsm6dsl/lsm6dsl_spi.c index eba7143d2d2f1..ed16ac8d9383e 100644 --- a/drivers/sensor/lsm6dsl/lsm6dsl_spi.c +++ b/drivers/sensor/lsm6dsl/lsm6dsl_spi.c @@ -7,6 +7,7 @@ * SPDX-License-Identifier: Apache-2.0 */ + #include #include #include "lsm6dsl.h" diff --git a/dts/bindings/sensor/st,lsm6dsl-spi.yaml b/dts/bindings/sensor/st,lsm6dsl-spi.yaml index 3a1e20b0db241..a26d44d63bf03 100644 --- a/dts/bindings/sensor/st,lsm6dsl-spi.yaml +++ b/dts/bindings/sensor/st,lsm6dsl-spi.yaml @@ -22,4 +22,9 @@ properties: type: compound category: required generation: define, use-prop-name + + cs-gpios: + type: compound + category: required + generation: define, use-prop-name ... diff --git a/tests/drivers/build_all/sensors_i_z.conf b/tests/drivers/build_all/sensors_i_z.conf index f0cb73bed6b1c..caa3fe6cad77d 100644 --- a/tests/drivers/build_all/sensors_i_z.conf +++ b/tests/drivers/build_all/sensors_i_z.conf @@ -15,7 +15,7 @@ CONFIG_LPS25HB=y CONFIG_LSM303DLHC_ACCEL=y CONFIG_LSM303DLHC_MAGN=y CONFIG_LSM6DS0=y -CONFIG_LSM6DSL=y +CONFIG_LSM6DSL=n CONFIG_LSM9DS0_GYRO=y CONFIG_LSM9DS0_MFD=y CONFIG_MAX30101=y diff --git a/tests/drivers/build_all/sensors_trigger_i_z.conf b/tests/drivers/build_all/sensors_trigger_i_z.conf index dd8bf8e39bb43..2713ac8249549 100644 --- a/tests/drivers/build_all/sensors_trigger_i_z.conf +++ b/tests/drivers/build_all/sensors_trigger_i_z.conf @@ -12,7 +12,7 @@ CONFIG_LIS2MDL=y CONFIG_LIS2MDL_TRIGGER_OWN_THREAD=y CONFIG_LIS3DH=y CONFIG_LIS3DH_TRIGGER_OWN_THREAD=y -CONFIG_LSM6DSL=y +CONFIG_LSM6DSL=n CONFIG_LSM6DSL_TRIGGER_OWN_THREAD=y CONFIG_LSM9DS0_GYRO=y CONFIG_LSM9DS0_GYRO_TRIGGERS=y From 043c929021060ccbf94506b8cd87ffcdc806777c Mon Sep 17 00:00:00 2001 From: Erwan Gouriou Date: Tue, 20 Nov 2018 11:48:01 +0100 Subject: [PATCH 18/18] boards: 96b_argonkey: Add LSM6DSL I2C sensor for codegen demo [DNM] Do Not Merge: Add LSM6DSL I2C sensor Signed-off-by: Erwan Gouriou --- boards/arm/96b_argonkey/96b_argonkey.dts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/boards/arm/96b_argonkey/96b_argonkey.dts b/boards/arm/96b_argonkey/96b_argonkey.dts index 105ca86d85f58..6662593a84811 100644 --- a/boards/arm/96b_argonkey/96b_argonkey.dts +++ b/boards/arm/96b_argonkey/96b_argonkey.dts @@ -76,6 +76,13 @@ &i2c1 { status = "ok"; clock-frequency = ; + + /* ST Microelectronics LSM6DSL accel/gyro sensor */ + lsm6dsl@1 { + compatible = "st,lsm6dsl"; + reg = <1>; + label = "LSM6DSL_I2C"; + }; }; &i2c2 {