diff --git a/docs/conf_common.py b/docs/conf_common.py index 7075a1e50..213c03d87 100644 --- a/docs/conf_common.py +++ b/docs/conf_common.py @@ -34,7 +34,7 @@ suppress_warnings = ['image.nonlocal_uri'] # If your documentation needs a minimal Sphinx version, state it here. # needs_sphinx = '1.0' - +idf_target = '' # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. @@ -61,6 +61,7 @@ extensions = ['breathe', 'idf_extensions.kconfig_reference', 'idf_extensions.run_doxygen', 'idf_extensions.gen_idf_tools_links', + 'idf_extensions.format_idf_target', # from https://github.com/pfalcon/sphinx_selective_exclude 'sphinx_selective_exclude.eager_only', @@ -131,7 +132,13 @@ def update_exclude_patterns(tags): 'api-guides/esp-ble-mesh/**', 'api-guides/ulp-legacy.rst', 'api-guides/unit-tests-legacy.rst', + 'api-guides/jtag-debugging/configure-wrover.rst', 'api-reference/bluetooth/**', + 'api-reference/system/himem.rst', + 'hw-reference/get-started-devkitc.rst', + 'hw-reference/get-started-ethernet-kit.rst', + 'hw-reference/get-started-pico-kit.rst', + 'hw-reference/get-started-wrover-kit.rst', 'get-started-legacy/**', 'gnu-make-legacy.rst']: exclude_patterns.append(e) @@ -337,11 +344,12 @@ texinfo_documents = [ # texinfo_no_detailmenu = False + # Override RTD CSS theme to introduce the theme corrections # https://github.com/rtfd/sphinx_rtd_theme/pull/432 def setup(app): app.add_stylesheet('theme_overrides.css') - + app.add_config_value('idf_target', '', 'env') # Breathe extension variables (depend on build_dir) # note: we generate into xml_in and then copy_if_modified to xml dir app.config.breathe_projects = {"esp32-idf": os.path.join(app.config.build_dir, "xml_in/")} diff --git a/docs/idf_extensions/build_system/__init__.py b/docs/idf_extensions/build_system/__init__.py index f1e2e0913..e990633c5 100644 --- a/docs/idf_extensions/build_system/__init__.py +++ b/docs/idf_extensions/build_system/__init__.py @@ -39,20 +39,19 @@ def setup(app): except KeyError: idf_path = os.path.realpath(os.path.join(os.path.dirname(__file__), '..')) + app.add_config_value('docs_root', os.path.join(idf_path, "docs"), 'env') app.add_config_value('idf_path', idf_path, 'env') - app.add_config_value('idf_target', 'esp32', 'env') app.add_config_value('build_dir', build_dir, 'env') # not actually an IDF thing app.add_event('idf-info') - # Attaching the generate event to env-get-outdated is a bit of a hack, # we want this to run early in the docs build but unclear exactly when - app.connect('env-get-outdated', generate_idf_info) + app.connect('config-inited', generate_idf_info) return {'parallel_read_safe': True, 'parallel_write_safe': True, 'version': '0.1'} -def generate_idf_info(app, env, added, changed, removed): +def generate_idf_info(app, config): print("Running CMake on dummy project to get build info...") build_dir = os.path.dirname(app.doctreedir.rstrip(os.sep)) cmake_build_dir = os.path.join(build_dir, "build_dummy_project") @@ -66,7 +65,7 @@ def generate_idf_info(app, env, added, changed, removed): project_path] if not os.path.exists(os.path.join(cmake_build_dir, "CMakeCache.txt")): # if build directory not created yet, run a reconfigure pass over it - print("Starting new dummy IDF project...") + print("Starting new dummy IDF project... w") subprocess.check_call(idf_py + ["set-target", app.config.idf_target]) else: print("Re-running CMake on the existing IDF project in {}".format(cmake_build_dir)) diff --git a/docs/idf_extensions/format_idf_target.py b/docs/idf_extensions/format_idf_target.py new file mode 100644 index 000000000..8a2204f44 --- /dev/null +++ b/docs/idf_extensions/format_idf_target.py @@ -0,0 +1,94 @@ +import re + +TARGET_NAMES = {'esp32': 'ESP32', 'esp32s2': 'ESP32-S2'} +TOOLCHAIN_NAMES = {'esp32': 'esp', 'esp32s2': 'esp32s2'} +CONFIG_PREFIX = {'esp32': 'ESP32', 'esp32s2': 'ESP32S2'} + +TRM_URL = {'esp32': 'https://www.espressif.com/sites/default/files/documentation/esp32_technical_reference_manual_en.pdf', + 'esp32s2': 'https://www.espressif.com/sites/default/files/documentation/esp32-s2_technical_reference_manual_en.pdf'} + +class StringSubstituter: + """ Allows for string substitution of target related strings + before any markup is parsed + + Supports the following replacements (examples shown is for target=esp32s2): + {IDF_TARGET_NAME}, replaced with the current target name, e.g. ESP32-S2 Beta + {IDF_TARGET_PATH_NAME}, replaced with the path name, e.g. esp32s2 + {IDF_TARGET_TOOLCHAIN_NAME}, replaced with the toolchain name, e.g. esp32s2 + {IDF_TARGET_CFG_PREFIX}, replaced with the prefix used for config parameters, e.g. ESP32S2 + {IDF_TARGET_TRM_URL}, replaced with the url to the technical reference manual + + Also supports defines of local (single rst file) with the format: + {IDF_TARGET_TX_PIN:default="IO3",esp32="IO4",esp32s2="IO5"} + + This will define a replacement of the tag {IDF_TARGET_TX_PIN} in the current rst-file, see e.g. uart.rst for example + + """ + RE_PATTERN = re.compile(r'^\s*{IDF_TARGET_(\w+?):(.+?)}', re.MULTILINE) + + def __init__(self): + self.substitute_strings = {} + self.local_sub_strings = {} + + def add_pair(self, tag, replace_value): + self.substitute_strings[tag] = replace_value + + def init_sub_strings(self, app, config): + self.target_name = config.idf_target + + self.add_pair("{IDF_TARGET_NAME}", TARGET_NAMES[config.idf_target]) + self.add_pair("{IDF_TARGET_PATH_NAME}", config.idf_target) + self.add_pair("{IDF_TARGET_TOOLCHAIN_NAME}", TOOLCHAIN_NAMES[config.idf_target]) + self.add_pair("{IDF_TARGET_CFG_PREFIX}", CONFIG_PREFIX[config.idf_target]) + self.add_pair("{IDF_TARGET_TRM_URL}", TRM_URL[config.idf_target]) + + def add_local_subs(self, matches): + + for sub_def in matches: + if len(sub_def) != 2: + raise ValueError("IDF_TARGET_X substitution define invalid, val={}".format(sub_def)) + + tag = "{" + "IDF_TARGET_{}".format(sub_def[0]) + "}" + + match_default = re.match(r'^\s*default(\s*)=(\s*)\"(.*?)\"', sub_def[1]) + + if match_default is None: + # There should always be a default value + raise ValueError("No default value in IDF_TARGET_X substitution define, val={}".format(sub_def)) + + match_target = re.match(r'^.*{}(\s*)=(\s*)\"(.*?)\"'.format(self.target_name), sub_def[1]) + + if match_target is None: + sub_value = match_default.groups()[2] + else: + sub_value = match_target.groups()[2] + + self.local_sub_strings[tag] = sub_value + + def substitute(self, app, docname, source): + # Add any new local tags that matches the reg.ex. + sub_defs = re.findall(self.RE_PATTERN, source[0]) + + if len(sub_defs) is not 0: + self.add_local_subs(sub_defs) + + # Remove the tag defines + source[0] = re.sub(self.RE_PATTERN,'', source[0]) + + for key in self.local_sub_strings: + source[0] = source[0].replace(key, self.local_sub_strings[key]) + + self.local_sub_strings = {} + + for key in self.substitute_strings: + source[0] = source[0].replace(key, self.substitute_strings[key]) + + +def setup(app): + sub = StringSubstituter() + + # Config values not available when setup is called + app.connect('config-inited', sub.init_sub_strings) + app.connect('source-read', sub.substitute) + + return {'parallel_read_safe': True, 'parallel_write_safe': True, 'version': '0.1'}