Files
platformio-core/scripts/docspregen.py

1220 lines
34 KiB
Python
Raw Permalink Normal View History

# Copyright (c) 2014-present PlatformIO <contact@platformio.org>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
2022-02-01 21:56:53 +02:00
import functools
import os
2022-02-01 21:56:53 +02:00
import sys
import tempfile
2022-04-01 14:29:38 +03:00
from urllib.parse import ParseResult, urlparse, urlunparse
2022-02-01 21:56:53 +02:00
sys.path.append("..")
2022-02-01 21:56:53 +02:00
import click # noqa: E402
2019-09-13 16:01:42 +03:00
2023-04-29 16:48:33 +03:00
from platformio import fs # noqa: E402
2022-02-01 21:56:53 +02:00
from platformio.package.manager.platform import PlatformPackageManager # noqa: E402
from platformio.platform.factory import PlatformFactory # noqa: E402
2019-09-13 16:01:42 +03:00
2018-10-04 01:33:15 +03:00
RST_COPYRIGHT = """.. Copyright (c) 2014-present PlatformIO <contact@platformio.org>
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
"""
SKIP_DEBUG_TOOLS = ["esp-bridge", "esp-builtin", "dfu"]
2022-08-01 13:06:12 +03:00
2023-04-29 16:48:33 +03:00
STATIC_FRAMEWORK_DATA = {
"arduino": {
"title": "Arduino",
"description": (
"Arduino Wiring-based Framework allows writing cross-platform software "
"to control devices attached to a wide range of Arduino boards to "
"create all kinds of creative coding, interactive objects, spaces "
"or physical experiences."
),
},
2023-07-28 14:34:59 +03:00
"cmsis": {
"title": "CMSIS",
"description": (
"Vendor-independent hardware abstraction layer for the Cortex-M processor series"
),
},
2023-04-29 16:48:33 +03:00
"freertos": {
"title": "FreeRTOS",
"description": (
"FreeRTOS is a real-time operating system kernel for embedded devices "
"that has been ported to 40 microcontroller platforms."
),
},
}
2022-02-01 15:38:15 +02:00
DOCS_ROOT_DIR = os.path.realpath(
os.path.join(os.path.dirname(os.path.realpath(__file__)), "..", "docs")
)
REGCLIENT = PlatformPackageManager().get_registry_client_instance()
2022-02-01 15:38:15 +02:00
def reg_package_url(type_, owner, name):
if type_ == "library":
type_ = "libraries"
else:
type_ += "s"
return f"https://registry.platformio.org/{type_}/{owner}/{name}"
2020-03-30 17:15:18 +03:00
def campaign_url(url, source="platformio.org", medium="docs"):
2019-09-13 16:01:42 +03:00
data = urlparse(url)
query = data.query
if query:
query += "&"
query += "utm_source=%s&utm_medium=%s" % (source, medium)
2019-09-13 16:01:42 +03:00
return urlunparse(
2020-08-26 14:51:53 +03:00
ParseResult(
data.scheme, data.netloc, data.path, data.params, query, data.fragment
)
)
2022-02-01 21:56:53 +02:00
def install_platforms():
print("Installing platforms...")
page = 1
pm = PlatformPackageManager()
while True:
2022-04-01 14:29:38 +03:00
result = REGCLIENT.list_packages(qualifiers=dict(types=["platform"]), page=page)
2022-02-01 21:56:53 +02:00
for item in result["items"]:
spec = "%s/%s" % (item["owner"]["username"], item["name"])
skip_conds = [
item["owner"]["username"] != "platformio",
item["tier"] == "community",
]
if all(skip_conds):
click.secho("Skip community platform: %s" % spec, fg="yellow")
continue
2022-04-01 14:29:38 +03:00
pm.install(spec, skip_dependencies=True)
2022-02-01 21:56:53 +02:00
page += 1
if not result["items"] or result["page"] * result["limit"] >= result["total"]:
break
@functools.cache
def get_frameworks():
items = {}
2023-04-29 16:48:33 +03:00
for platform in PlatformPackageManager().get_installed():
p = PlatformFactory.new(platform)
2022-02-01 21:56:53 +02:00
for name, options in (p.frameworks or {}).items():
2023-04-29 16:48:33 +03:00
if name in items:
2022-02-01 21:56:53 +02:00
continue
2023-04-29 16:48:33 +03:00
if name in STATIC_FRAMEWORK_DATA:
items[name] = dict(
name=name,
title=STATIC_FRAMEWORK_DATA[name]["title"],
description=STATIC_FRAMEWORK_DATA[name]["description"],
)
continue
title = options.get("title") or name.title()
description = options.get("description")
if "package" in options:
regdata = REGCLIENT.get_package(
"tool",
p.packages[options["package"]].get("owner", "platformio"),
options["package"],
)
title = regdata["title"] or title
description = regdata["description"]
items[name] = dict(name=name, title=title, description=description)
2022-02-01 21:56:53 +02:00
return sorted(items.values(), key=lambda item: item["name"])
2022-02-01 15:38:15 +02:00
def is_compat_platform_and_framework(platform, framework):
p = PlatformFactory.new(platform)
return framework in (p.frameworks or {}).keys()
2018-10-04 01:33:15 +03:00
def generate_boards_table(boards, skip_columns=None):
columns = [
2018-10-04 01:33:15 +03:00
("Name", ":ref:`board_{platform}_{id}`"),
("Platform", ":ref:`platform_{platform}`"),
("Debug", "{debug}"),
("MCU", "{mcu}"),
2019-09-13 16:01:42 +03:00
("Frequency", "{f_cpu}MHz"),
("Flash", "{rom}"),
("RAM", "{ram}"),
]
lines = []
2020-08-26 14:51:53 +03:00
lines.append(
"""
.. list-table::
:header-rows: 1
2020-08-26 14:51:53 +03:00
"""
)
# add header
2023-04-29 16:48:33 +03:00
for name, template in columns:
if skip_columns and name in skip_columns:
continue
2018-10-04 01:33:15 +03:00
prefix = " * - " if name == "Name" else " - "
lines.append(prefix + name)
2020-08-26 14:51:53 +03:00
for data in sorted(boards, key=lambda item: item["name"]):
has_onboard_debug = data.get("debug") and any(
t.get("onboard") for (_, t) in data["debug"]["tools"].items()
)
2018-10-04 01:33:15 +03:00
debug = "No"
if has_onboard_debug:
debug = "On-board"
2020-08-26 14:51:53 +03:00
elif data.get("debug"):
debug = "External"
2017-04-30 01:14:57 +03:00
2020-08-26 14:51:53 +03:00
variables = dict(
id=data["id"],
name=data["name"],
platform=data["platform"],
debug=debug,
mcu=data["mcu"].upper(),
f_cpu=int(data["fcpu"] / 1000000.0),
ram=fs.humanize_file_size(data["ram"]),
rom=fs.humanize_file_size(data["rom"]),
)
2023-04-29 16:48:33 +03:00
for name, template in columns:
if skip_columns and name in skip_columns:
continue
2018-10-04 01:33:15 +03:00
prefix = " * - " if name == "Name" else " - "
lines.append(prefix + template.format(**variables))
if lines:
lines.append("")
return lines
def generate_frameworks_contents(frameworks):
if not frameworks:
return []
lines = []
2020-08-26 14:51:53 +03:00
lines.append(
"""
Frameworks
----------
.. list-table::
:header-rows: 1
* - Name
2020-08-26 14:51:53 +03:00
- Description"""
)
2018-10-04 01:33:15 +03:00
known = set()
2022-02-01 21:56:53 +02:00
for framework in get_frameworks():
2020-08-26 14:51:53 +03:00
known.add(framework["name"])
if framework["name"] not in frameworks:
continue
2020-08-26 14:51:53 +03:00
lines.append(
"""
* - :ref:`framework_{name}`
2020-08-26 14:51:53 +03:00
- {description}""".format(
**framework
)
)
2019-09-13 16:01:42 +03:00
if set(frameworks) - known:
2020-08-26 14:51:53 +03:00
click.secho("Unknown frameworks %s " % (set(frameworks) - known), fg="red")
return lines
def generate_platforms_contents(platforms):
if not platforms:
return []
lines = []
2020-08-26 14:51:53 +03:00
lines.append(
"""
Platforms
---------
.. list-table::
:header-rows: 1
* - Name
2020-08-26 14:51:53 +03:00
- Description"""
)
for name in sorted(platforms):
2020-08-26 14:51:53 +03:00
p = PlatformFactory.new(name)
lines.append(
"""
* - :ref:`platform_{name}`
2020-08-26 14:51:53 +03:00
- {description}""".format(
name=p.name, description=p.description
)
)
return lines
2018-07-30 18:13:04 +03:00
def generate_debug_contents(boards, skip_board_columns=None, extra_rst=None):
2018-10-04 01:33:15 +03:00
if not skip_board_columns:
skip_board_columns = []
skip_board_columns.append("Debug")
lines = []
onboard_debug = [
2020-08-26 14:51:53 +03:00
b
for b in boards
if b.get("debug")
and any(t.get("onboard") for (_, t) in b["debug"]["tools"].items())
]
2020-08-26 14:51:53 +03:00
external_debug = [b for b in boards if b.get("debug") and b not in onboard_debug]
2018-07-30 18:13:04 +03:00
if not onboard_debug and not external_debug:
return lines
2020-08-26 14:51:53 +03:00
lines.append(
"""
Debugging
---------
:ref:`piodebug` - "1-click" solution for debugging with a zero configuration.
2018-07-30 18:13:04 +03:00
.. contents::
:local:
2020-08-26 14:51:53 +03:00
"""
)
2018-07-30 18:13:04 +03:00
if extra_rst:
lines.append(".. include:: %s" % extra_rst)
2020-08-26 14:51:53 +03:00
lines.append(
"""
Tools & Debug Probes
~~~~~~~~~~~~~~~~~~~~
2018-07-30 18:13:04 +03:00
Supported debugging tools are listed in "Debug" column. For more detailed
information, please scroll table by horizontal.
You can switch between debugging :ref:`debugging_tools` using
2018-10-04 01:33:15 +03:00
:ref:`projectconf_debug_tool` option in :ref:`projectconf`.
2018-07-30 18:13:04 +03:00
.. warning::
You will need to install debug tool drivers depending on your system.
Please click on compatible debug tool below for the further instructions.
2020-08-26 14:51:53 +03:00
"""
)
2018-07-30 18:13:04 +03:00
if onboard_debug:
2020-08-26 14:51:53 +03:00
lines.append(
"""
On-Board Debug Tools
2018-07-30 18:13:04 +03:00
^^^^^^^^^^^^^^^^^^^^
2018-10-04 01:33:15 +03:00
Boards listed below have on-board debug probe and **ARE READY** for debugging!
You do not need to use/buy external debug probe.
2020-08-26 14:51:53 +03:00
"""
)
lines.extend(
2020-08-26 14:51:53 +03:00
generate_boards_table(onboard_debug, skip_columns=skip_board_columns)
)
if external_debug:
2020-08-26 14:51:53 +03:00
lines.append(
"""
External Debug Tools
2018-07-30 18:13:04 +03:00
^^^^^^^^^^^^^^^^^^^^
Boards listed below are compatible with :ref:`piodebug` but **DEPEND ON**
2018-10-04 01:33:15 +03:00
external debug probe. They **ARE NOT READY** for debugging.
Please click on board name for the further details.
2020-08-26 14:51:53 +03:00
"""
)
lines.extend(
2020-08-26 14:51:53 +03:00
generate_boards_table(external_debug, skip_columns=skip_board_columns)
)
return lines
2022-02-01 15:38:15 +02:00
def generate_packages(platform, packages, is_embedded):
if not packages:
2015-08-03 12:33:37 +03:00
return
lines = []
2020-08-26 14:51:53 +03:00
lines.append(
"""
2015-08-03 12:33:37 +03:00
Packages
--------
2020-08-26 14:51:53 +03:00
"""
)
lines.append(
""".. list-table::
:header-rows: 1
* - Name
2020-08-26 14:51:53 +03:00
- Description"""
)
2022-02-01 15:38:15 +02:00
for name, options in dict(sorted(packages.items())).items():
2024-03-29 21:33:54 +02:00
if name == "toolchain-gccarmnoneeab": # aceinna typo fix
name = name + "i"
2022-02-01 15:38:15 +02:00
package = REGCLIENT.get_package(
"tool", options.get("owner", "platformio"), name
)
lines.append(
"""
2017-03-02 17:09:32 +02:00
* - `{name} <{url}>`__
2020-08-26 14:51:53 +03:00
- {description}""".format(
2022-02-01 15:38:15 +02:00
name=package["name"],
url=reg_package_url(
"tool", package["owner"]["username"], package["name"]
),
description=package["description"],
2020-08-26 14:51:53 +03:00
)
2022-02-01 15:38:15 +02:00
)
if is_embedded:
2020-08-26 14:51:53 +03:00
lines.append(
"""
.. warning::
**Linux Users**:
* Install "udev" rules :ref:`platformio_udev_rules`
2017-06-26 17:51:11 +03:00
* Raspberry Pi users, please read this article
`Enable serial port on Raspberry Pi <https://hallard.me/enable-serial-port-on-raspberry-pi/>`__.
2020-08-26 14:51:53 +03:00
"""
)
if platform == "teensy":
2020-08-26 14:51:53 +03:00
lines.append(
"""
2017-06-26 17:51:11 +03:00
**Windows Users:**
Teensy programming uses only Windows built-in HID
drivers. When Teensy is programmed to act as a USB Serial device,
Windows XP, Vista, 7 and 8 require `this serial driver
<http://www.pjrc.com/teensy/serial_install.exe>`_
is needed to access the COM port your program uses. No special driver
installation is necessary on Windows 10.
2020-08-26 14:51:53 +03:00
"""
)
else:
2020-08-26 14:51:53 +03:00
lines.append(
"""
2017-06-26 17:51:11 +03:00
**Windows Users:**
2017-06-26 17:51:11 +03:00
Please check that you have a correctly installed USB driver from board
manufacturer
2020-08-26 14:51:53 +03:00
"""
)
return "\n".join(lines)
2022-02-01 21:56:53 +02:00
def generate_platform(pkg, rst_dir):
owner = pkg.metadata.spec.owner
2022-02-01 21:56:53 +02:00
name = pkg.metadata.name
print("Processing platform: %s" % name)
2022-02-01 15:38:15 +02:00
compatible_boards = [
board
for board in PlatformPackageManager().get_installed_boards()
if name == board["platform"]
]
lines = []
2018-10-04 01:33:15 +03:00
lines.append(RST_COPYRIGHT)
2022-02-01 21:56:53 +02:00
2020-08-26 14:51:53 +03:00
p = PlatformFactory.new(name)
assert p.repository_url.endswith(".git")
github_url = p.repository_url[:-4]
registry_url = reg_package_url("platform", owner, name)
lines.append(".. _platform_%s:" % name)
lines.append("")
lines.append(p.title)
lines.append("=" * len(p.title))
lines.append("")
2022-02-01 21:56:53 +02:00
lines.append(":Registry:")
lines.append(" `%s <%s>`__" % (registry_url, registry_url))
lines.append(":Configuration:")
lines.append(" :ref:`projectconf_env_platform` = ``%s/%s``" % (owner, name))
lines.append("")
lines.append(p.description)
2020-08-26 14:51:53 +03:00
lines.append(
"""
For more detailed information please visit `vendor site <%s>`_."""
% campaign_url(p.homepage)
)
lines.append(
"""
.. contents:: Contents
:local:
:depth: 1
2020-08-26 14:51:53 +03:00
"""
)
#
# Extra
#
2022-02-01 15:38:15 +02:00
if os.path.isfile(os.path.join(rst_dir, "%s_extra.rst" % name)):
lines.append(".. include:: %s_extra.rst" % p.name)
#
# Examples
#
2020-08-26 14:51:53 +03:00
lines.append(
"""
Examples
--------
Examples are listed from `%s development platform repository <%s>`_:
2020-08-26 14:51:53 +03:00
"""
% (p.title, campaign_url("%s/tree/master/examples" % github_url))
)
2022-02-01 15:38:15 +02:00
examples_dir = os.path.join(p.get_dir(), "examples")
if os.path.isdir(examples_dir):
for eitem in os.listdir(examples_dir):
2022-02-01 15:38:15 +02:00
example_dir = os.path.join(examples_dir, eitem)
if not os.path.isdir(example_dir) or not os.listdir(example_dir):
continue
url = "%s/tree/master/examples/%s" % (github_url, eitem)
lines.append("* `%s <%s>`_" % (eitem, campaign_url(url)))
#
# Debugging
#
if compatible_boards:
lines.extend(
2018-07-30 18:13:04 +03:00
generate_debug_contents(
compatible_boards,
skip_board_columns=["Platform"],
2020-08-26 14:51:53 +03:00
extra_rst="%s_debug.rst" % name
2022-02-01 15:38:15 +02:00
if os.path.isfile(os.path.join(rst_dir, "%s_debug.rst" % name))
2020-08-26 14:51:53 +03:00
else None,
)
)
#
# Development version of dev/platform
#
2020-08-26 14:51:53 +03:00
lines.append(
"""
Stable and upstream versions
----------------------------
You can switch between `stable releases <{github_url}/releases>`__
of {title} development platform and the latest upstream version using
:ref:`projectconf_env_platform` option in :ref:`projectconf` as described below.
Stable
~~~~~~
.. code-block:: ini
; Latest stable version, NOT recommended
; Pin the version as shown below
[env:latest_stable]
platform = {name}
2023-01-04 18:40:04 +02:00
{board}
; Specific version
[env:custom_stable]
platform = {name}@x.y.z
2023-01-04 18:40:04 +02:00
{board}
Upstream
~~~~~~~~
.. code-block:: ini
[env:upstream_develop]
platform = {github_url}.git
2023-01-04 18:40:04 +02:00
{board}""".format(
name=p.name,
title=p.title,
github_url=github_url,
board="board = ...\n" if p.is_embedded() else "",
2020-08-26 14:51:53 +03:00
)
)
2015-08-03 12:33:37 +03:00
#
# Packages
#
2022-02-01 15:38:15 +02:00
_packages_content = generate_packages(name, p.packages, p.is_embedded())
2015-08-03 12:33:37 +03:00
if _packages_content:
lines.append(_packages_content)
2015-08-03 12:33:37 +03:00
#
# Frameworks
#
compatible_frameworks = []
2022-02-01 21:56:53 +02:00
for framework in get_frameworks():
2020-08-26 14:51:53 +03:00
if is_compat_platform_and_framework(name, framework["name"]):
compatible_frameworks.append(framework["name"])
lines.extend(generate_frameworks_contents(compatible_frameworks))
2015-08-03 12:33:37 +03:00
#
# Boards
#
if compatible_boards:
vendors = {}
for board in compatible_boards:
2020-08-26 14:51:53 +03:00
if board["vendor"] not in vendors:
vendors[board["vendor"]] = []
vendors[board["vendor"]].append(board)
2020-08-26 14:51:53 +03:00
lines.append(
"""
2015-08-03 12:33:37 +03:00
Boards
------
.. note::
* You can list pre-configured boards by :ref:`cmd_boards` command
2020-03-20 17:11:31 +02:00
* For more detailed ``board`` information please scroll the tables below by
horizontally.
2020-08-26 14:51:53 +03:00
"""
)
2015-08-03 12:33:37 +03:00
for vendor, boards in sorted(vendors.items()):
lines.append(str(vendor))
lines.append("~" * len(vendor))
2020-08-26 14:51:53 +03:00
lines.extend(generate_boards_table(boards, skip_columns=["Platform"]))
2015-08-03 12:33:37 +03:00
return "\n".join(lines)
def update_platform_docs():
2022-02-01 15:38:15 +02:00
platforms_dir = os.path.join(DOCS_ROOT_DIR, "platforms")
for pkg in PlatformPackageManager().get_installed():
2022-02-01 15:38:15 +02:00
rst_path = os.path.join(platforms_dir, "%s.rst" % pkg.metadata.name)
with open(rst_path, "w") as f:
2022-02-01 21:56:53 +02:00
f.write(generate_platform(pkg, platforms_dir))
def generate_framework(type_, framework, rst_dir=None):
print("Processing framework: %s" % type_)
compatible_platforms = [
pkg
for pkg in PlatformPackageManager().get_installed()
if is_compat_platform_and_framework(pkg.metadata.name, type_)
]
2022-02-01 15:38:15 +02:00
compatible_boards = [
board
for board in PlatformPackageManager().get_installed_boards()
if type_ in board["frameworks"]
]
lines = []
2018-10-04 01:33:15 +03:00
lines.append(RST_COPYRIGHT)
lines.append(".. _framework_%s:" % type_)
lines.append("")
lines.append(framework["title"])
lines.append("=" * len(framework["title"]))
lines.append("")
lines.append(":Configuration:")
lines.append(" :ref:`projectconf_env_framework` = ``%s``" % type_)
lines.append("")
lines.append(framework["description"])
2020-08-26 14:51:53 +03:00
lines.append(
"""
.. contents:: Contents
:local:
2020-08-26 14:51:53 +03:00
:depth: 1"""
)
# Extra
2022-02-01 15:38:15 +02:00
if os.path.isfile(os.path.join(rst_dir, "%s_extra.rst" % type_)):
lines.append(".. include:: %s_extra.rst" % type_)
2022-02-01 21:56:53 +02:00
if compatible_platforms:
# Platforms
2018-07-30 18:13:04 +03:00
lines.extend(
2022-02-01 21:56:53 +02:00
generate_platforms_contents(
[pkg.metadata.name for pkg in compatible_platforms]
2020-08-26 14:51:53 +03:00
)
)
# examples
2020-08-26 14:51:53 +03:00
lines.append(
"""
Examples
--------
2020-08-26 14:51:53 +03:00
"""
)
for pkg in compatible_platforms:
p = PlatformFactory.new(pkg)
2020-08-26 14:51:53 +03:00
lines.append(
"* `%s for %s <%s>`_"
% (
framework["title"],
p.title,
2020-08-26 14:51:53 +03:00
campaign_url("%s/tree/master/examples" % p.repository_url[:-4]),
)
)
2022-02-01 21:56:53 +02:00
#
# Debugging
#
if compatible_boards:
lines.extend(
2022-02-01 21:56:53 +02:00
generate_debug_contents(
compatible_boards,
extra_rst="%s_debug.rst" % type_
if os.path.isfile(os.path.join(rst_dir, "%s_debug.rst" % type_))
else None,
2020-08-26 14:51:53 +03:00
)
)
#
# Boards
#
if compatible_boards:
vendors = {}
for board in compatible_boards:
2020-08-26 14:51:53 +03:00
if board["vendor"] not in vendors:
vendors[board["vendor"]] = []
vendors[board["vendor"]].append(board)
lines.append(
"""
Boards
------
.. note::
* You can list pre-configured boards by :ref:`cmd_boards` command
2020-03-20 17:11:31 +02:00
* For more detailed ``board`` information please scroll the tables below by horizontally.
2020-08-26 14:51:53 +03:00
"""
)
for vendor, boards in sorted(vendors.items()):
lines.append(str(vendor))
lines.append("~" * len(vendor))
2018-10-04 01:33:15 +03:00
lines.extend(generate_boards_table(boards))
return "\n".join(lines)
def update_framework_docs():
2022-02-01 21:56:53 +02:00
frameworks_dir = os.path.join(DOCS_ROOT_DIR, "frameworks")
for framework in get_frameworks():
2020-08-26 14:51:53 +03:00
name = framework["name"]
2022-02-01 15:38:15 +02:00
rst_path = os.path.join(frameworks_dir, "%s.rst" % name)
with open(rst_path, "w") as f:
2018-07-30 18:13:04 +03:00
f.write(generate_framework(name, framework, frameworks_dir))
2018-10-04 01:33:15 +03:00
def update_boards():
2021-06-29 18:11:08 +03:00
print("Updating boards...")
2016-06-02 20:41:10 +03:00
lines = []
2018-10-04 01:33:15 +03:00
lines.append(RST_COPYRIGHT)
lines.append(".. _boards:")
2016-06-02 20:41:10 +03:00
lines.append("")
2018-10-04 01:33:15 +03:00
lines.append("Boards")
lines.append("======")
2016-06-02 20:41:10 +03:00
2020-08-26 14:51:53 +03:00
lines.append(
"""
2016-06-02 20:41:10 +03:00
Rapid Embedded Development, Continuous and IDE integration in a few
steps with PlatformIO thanks to built-in project generator for the most
popular embedded boards and IDEs.
2016-06-02 20:41:10 +03:00
.. note::
* You can list pre-configured boards by :ref:`cmd_boards` command
* For more detailed ``board`` information please scroll tables below by horizontal.
2020-08-26 14:51:53 +03:00
"""
)
2016-06-02 20:41:10 +03:00
2018-10-04 01:33:15 +03:00
platforms = {}
2022-02-01 15:38:15 +02:00
installed_boards = PlatformPackageManager().get_installed_boards()
for data in installed_boards:
2020-08-26 14:51:53 +03:00
platform = data["platform"]
2018-10-04 01:33:15 +03:00
if platform in platforms:
platforms[platform].append(data)
2016-06-02 20:41:10 +03:00
else:
2018-10-04 01:33:15 +03:00
platforms[platform] = [data]
2016-06-02 20:41:10 +03:00
2019-09-13 16:01:42 +03:00
for platform, boards in sorted(platforms.items()):
2020-08-26 14:51:53 +03:00
p = PlatformFactory.new(platform)
2018-10-04 01:33:15 +03:00
lines.append(p.title)
lines.append("-" * len(p.title))
2020-08-26 14:51:53 +03:00
lines.append(
"""
2018-10-04 01:33:15 +03:00
.. toctree::
:maxdepth: 1
2020-08-26 14:51:53 +03:00
"""
)
for board in sorted(boards, key=lambda item: item["name"]):
2018-10-04 01:33:15 +03:00
lines.append(" %s/%s" % (platform, board["id"]))
lines.append("")
2016-06-02 20:41:10 +03:00
2022-02-01 15:38:15 +02:00
emboards_rst = os.path.join(DOCS_ROOT_DIR, "boards", "index.rst")
2016-06-02 20:41:10 +03:00
with open(emboards_rst, "w") as f:
f.write("\n".join(lines))
2018-10-04 01:33:15 +03:00
# individual board page
2022-02-01 15:38:15 +02:00
for data in installed_boards:
rst_path = os.path.join(
2020-08-26 14:51:53 +03:00
DOCS_ROOT_DIR, "boards", data["platform"], "%s.rst" % data["id"]
)
2022-02-01 15:38:15 +02:00
if not os.path.isdir(os.path.dirname(rst_path)):
os.makedirs(os.path.dirname(rst_path))
2018-10-04 01:33:15 +03:00
update_embedded_board(rst_path, data)
def update_embedded_board(rst_path, board):
2020-08-26 14:51:53 +03:00
platform = PlatformFactory.new(board["platform"])
board_config = platform.board_config(board["id"])
2018-10-04 01:33:15 +03:00
board_manifest_url = platform.repository_url
assert board_manifest_url
if board_manifest_url.endswith(".git"):
board_manifest_url = board_manifest_url[:-4]
2020-08-26 14:51:53 +03:00
board_manifest_url += "/blob/master/boards/%s.json" % board["id"]
variables = dict(
id=board["id"],
name=board["name"],
platform=board["platform"],
platform_description=platform.description,
url=campaign_url(board["url"]),
mcu=board_config.get("build", {}).get("mcu", ""),
mcu_upper=board["mcu"].upper(),
f_cpu=board["fcpu"],
f_cpu_mhz=int(int(board["fcpu"]) / 1000000),
ram=fs.humanize_file_size(board["ram"]),
rom=fs.humanize_file_size(board["rom"]),
vendor=board["vendor"],
board_manifest_url=board_manifest_url,
upload_protocol=board_config.get("upload.protocol", ""),
)
2018-10-04 01:33:15 +03:00
lines = [RST_COPYRIGHT]
lines.append(".. _board_{platform}_{id}:".format(**variables))
lines.append("")
2020-08-26 14:51:53 +03:00
lines.append(board["name"])
lines.append("=" * len(board["name"]))
lines.append(
"""
2018-10-04 01:33:15 +03:00
.. contents::
Hardware
--------
2018-10-04 01:33:15 +03:00
Platform :ref:`platform_{platform}`: {platform_description}
2018-10-04 01:33:15 +03:00
.. list-table::
* - **Microcontroller**
- {mcu_upper}
* - **Frequency**
2019-09-13 16:01:42 +03:00
- {f_cpu_mhz:d}MHz
2018-10-04 01:33:15 +03:00
* - **Flash**
- {rom}
* - **RAM**
- {ram}
* - **Vendor**
- `{vendor} <{url}>`__
2020-08-26 14:51:53 +03:00
""".format(
**variables
)
)
2018-10-04 01:33:15 +03:00
#
# Configuration
#
2020-08-26 14:51:53 +03:00
lines.append(
"""
2018-10-04 01:33:15 +03:00
Configuration
-------------
Please use ``{id}`` ID for :ref:`projectconf_env_board` option in :ref:`projectconf`:
.. code-block:: ini
[env:{id}]
platform = {platform}
board = {id}
You can override default {name} settings per build environment using
``board_***`` option, where ``***`` is a JSON object path from
2018-10-04 01:33:15 +03:00
board manifest `{id}.json <{board_manifest_url}>`_. For example,
``board_build.mcu``, ``board_build.f_cpu``, etc.
2018-10-04 01:33:15 +03:00
.. code-block:: ini
[env:{id}]
platform = {platform}
board = {id}
; change microcontroller
board_build.mcu = {mcu}
; change MCU frequency
board_build.f_cpu = {f_cpu}L
2020-08-26 14:51:53 +03:00
""".format(
**variables
)
)
2018-10-04 01:33:15 +03:00
#
# Uploading
#
upload_protocols = board_config.get("upload.protocols", [])
if len(upload_protocols) > 1:
2020-08-26 14:51:53 +03:00
lines.append(
"""
2018-10-04 01:33:15 +03:00
Uploading
---------
2021-05-01 13:44:28 +03:00
%s supports the following uploading protocols:
2020-08-26 14:51:53 +03:00
"""
% board["name"]
)
2019-01-11 14:35:54 +02:00
for protocol in sorted(upload_protocols):
2018-10-04 01:33:15 +03:00
lines.append("* ``%s``" % protocol)
2020-08-26 14:51:53 +03:00
lines.append(
"""
Default protocol is ``%s``"""
% variables["upload_protocol"]
)
lines.append(
"""
2018-10-04 01:33:15 +03:00
You can change upload protocol using :ref:`projectconf_upload_protocol` option:
.. code-block:: ini
[env:{id}]
platform = {platform}
board = {id}
upload_protocol = {upload_protocol}
2020-08-26 14:51:53 +03:00
""".format(
**variables
)
)
2018-10-04 01:33:15 +03:00
#
# Debugging
#
lines.append("Debugging")
lines.append("---------")
2020-08-26 14:51:53 +03:00
if not board.get("debug"):
2018-10-04 01:33:15 +03:00
lines.append(
":ref:`piodebug` currently does not support {name} board.".format(
2020-08-26 14:51:53 +03:00
**variables
)
)
2018-10-04 01:33:15 +03:00
else:
default_debug_tool = board_config.get_debug_tool_name()
has_onboard_debug = any(
2020-08-26 14:51:53 +03:00
t.get("onboard") for (_, t) in board["debug"]["tools"].items()
)
lines.append(
"""
2018-10-04 01:33:15 +03:00
:ref:`piodebug` - "1-click" solution for debugging with a zero configuration.
.. warning::
You will need to install debug tool drivers depending on your system.
Please click on compatible debug tool below for the further
instructions and configuration information.
You can switch between debugging :ref:`debugging_tools` using
:ref:`projectconf_debug_tool` option in :ref:`projectconf`.
2020-08-26 14:51:53 +03:00
"""
)
2018-10-04 01:33:15 +03:00
if has_onboard_debug:
lines.append(
"{name} has on-board debug probe and **IS READY** for "
2020-08-26 14:51:53 +03:00
"debugging. You don't need to use/buy external debug probe.".format(
**variables
)
)
2018-10-04 01:33:15 +03:00
else:
lines.append(
"{name} does not have on-board debug probe and **IS NOT "
"READY** for debugging. You will need to use/buy one of "
2020-08-26 14:51:53 +03:00
"external probe listed below.".format(**variables)
)
lines.append(
"""
2018-10-04 01:33:15 +03:00
.. list-table::
:header-rows: 1
* - Compatible Tools
- On-board
2020-08-26 14:51:53 +03:00
- Default"""
)
2023-04-29 16:48:33 +03:00
for tool_name, tool_data in sorted(board["debug"]["tools"].items()):
2020-08-26 14:51:53 +03:00
lines.append(
2022-08-01 13:06:12 +03:00
""" * - {tool}
2018-10-04 01:33:15 +03:00
- {onboard}
- {default}""".format(
2022-08-01 13:06:12 +03:00
tool=f"``{tool_name}``"
if tool_name in SKIP_DEBUG_TOOLS
else f":ref:`debugging_tool_{tool_name}`",
2020-08-26 14:51:53 +03:00
onboard="Yes" if tool_data.get("onboard") else "",
default="Yes" if tool_name == default_debug_tool else "",
)
)
2018-10-04 01:33:15 +03:00
2020-08-26 14:51:53 +03:00
if board["frameworks"]:
lines.extend(generate_frameworks_contents(board["frameworks"]))
2018-10-04 01:33:15 +03:00
with open(rst_path, "w") as f:
f.write("\n".join(lines))
2016-06-02 20:41:10 +03:00
2017-04-29 01:42:23 +03:00
def update_debugging():
tool_to_platforms = {}
tool_to_boards = {}
2017-04-29 01:42:23 +03:00
vendors = {}
platforms = []
frameworks = []
2022-02-01 15:38:15 +02:00
for data in PlatformPackageManager().get_installed_boards():
2020-08-26 14:51:53 +03:00
if not data.get("debug"):
2017-04-29 01:42:23 +03:00
continue
2020-08-26 14:51:53 +03:00
for tool in data["debug"]["tools"]:
tool = str(tool)
if tool not in tool_to_platforms:
tool_to_platforms[tool] = []
2020-08-26 14:51:53 +03:00
tool_to_platforms[tool].append(data["platform"])
if tool not in tool_to_boards:
tool_to_boards[tool] = []
2020-08-26 14:51:53 +03:00
tool_to_boards[tool].append(data["id"])
2020-08-26 14:51:53 +03:00
platforms.append(data["platform"])
frameworks.extend(data["frameworks"])
vendor = data["vendor"]
2017-04-29 01:42:23 +03:00
if vendor in vendors:
vendors[vendor].append(data)
else:
vendors[vendor] = [data]
platforms = sorted(set(platforms))
frameworks = sorted(set(frameworks))
2017-04-29 01:42:23 +03:00
lines = [".. _debugging_platforms:"]
lines.extend(generate_platforms_contents(platforms))
lines.extend(generate_frameworks_contents(frameworks))
2017-04-29 01:42:23 +03:00
# Boards
2020-08-26 14:51:53 +03:00
lines.append(
"""
2017-04-29 01:42:23 +03:00
Boards
------
.. note::
For more detailed ``board`` information please scroll tables below by horizontal.
2020-08-26 14:51:53 +03:00
"""
)
2019-09-13 16:01:42 +03:00
for vendor, boards in sorted(vendors.items()):
2017-04-29 01:42:23 +03:00
lines.append(str(vendor))
lines.append("~" * len(vendor))
2018-10-04 01:33:15 +03:00
lines.extend(generate_boards_table(boards))
2017-04-29 01:42:23 +03:00
# save
2020-08-26 14:51:53 +03:00
with open(
2022-02-01 15:38:15 +02:00
os.path.join(fs.get_source_dir(), "..", "docs", "plus", "debugging.rst"), "r+"
2020-08-26 14:51:53 +03:00
) as fp:
content = fp.read()
2017-04-29 01:42:23 +03:00
fp.seek(0)
fp.truncate()
2020-08-26 14:51:53 +03:00
fp.write(
content[: content.index(".. _debugging_platforms:")] + "\n".join(lines)
)
2017-04-29 01:42:23 +03:00
# Debug tools
for tool, platforms in tool_to_platforms.items():
2022-02-01 15:38:15 +02:00
tool_path = os.path.join(DOCS_ROOT_DIR, "plus", "debug-tools", "%s.rst" % tool)
if not os.path.isfile(tool_path):
2022-08-01 13:06:12 +03:00
if tool in SKIP_DEBUG_TOOLS:
click.secho("Skipped debug tool `%s`" % tool, fg="yellow")
else:
click.secho("Unknown debug tool `%s`" % tool, fg="red")
2019-09-13 16:01:42 +03:00
continue
platforms = sorted(set(platforms))
lines = [".. begin_platforms"]
lines.extend(generate_platforms_contents(platforms))
tool_frameworks = []
for platform in platforms:
for framework in frameworks:
if is_compat_platform_and_framework(platform, framework):
tool_frameworks.append(framework)
lines.extend(generate_frameworks_contents(tool_frameworks))
2020-08-26 14:51:53 +03:00
lines.append(
"""
Boards
------
.. note::
For more detailed ``board`` information please scroll tables below by horizontal.
2020-08-26 14:51:53 +03:00
"""
)
lines.extend(
2018-10-04 01:33:15 +03:00
generate_boards_table(
2022-02-01 15:38:15 +02:00
[
b
for b in PlatformPackageManager().get_installed_boards()
if b["id"] in tool_to_boards[tool]
],
2020-08-26 14:51:53 +03:00
skip_columns=None,
)
)
with open(tool_path, "r+") as fp:
content = fp.read()
fp.seek(0)
fp.truncate()
2020-08-26 14:51:53 +03:00
fp.write(content[: content.index(".. begin_platforms")] + "\n".join(lines))
2017-04-29 01:42:23 +03:00
def update_project_examples():
platform_readme_tpl = """
# {title}: development platform for [PlatformIO](https://platformio.org)
{description}
* [Home](https://platformio.org/platforms/{name}) (home page in PlatformIO Registry)
2018-08-15 19:44:02 +03:00
* [Documentation](https://docs.platformio.org/page/platforms/{name}.html) (advanced usage, packages, boards, frameworks, etc.)
# Examples
{examples}
"""
framework_readme_tpl = """
# {title}: framework for [PlatformIO](https://platformio.org)
{description}
* [Home](https://platformio.org/frameworks/{name}) (home page in PlatformIO Registry)
2018-08-15 19:44:02 +03:00
* [Documentation](https://docs.platformio.org/page/frameworks/{name}.html)
# Examples
{examples}
"""
2022-02-01 15:38:15 +02:00
project_examples_dir = os.path.join(fs.get_source_dir(), "..", "examples")
framework_examples_md_lines = {}
embedded = []
desktop = []
for pkg in PlatformPackageManager().get_installed():
p = PlatformFactory.new(pkg)
github_url = p.repository_url[:-4]
# Platform README
2022-02-01 15:38:15 +02:00
platform_examples_dir = os.path.join(p.get_dir(), "examples")
examples_md_lines = []
2022-02-01 15:38:15 +02:00
if os.path.isdir(platform_examples_dir):
2020-04-08 22:34:04 +03:00
for item in sorted(os.listdir(platform_examples_dir)):
2022-02-01 15:38:15 +02:00
example_dir = os.path.join(platform_examples_dir, item)
if not os.path.isdir(example_dir) or not os.listdir(example_dir):
continue
url = "%s/tree/master/examples/%s" % (github_url, item)
examples_md_lines.append("* [%s](%s)" % (item, url))
2022-02-01 15:38:15 +02:00
readme_dir = os.path.join(project_examples_dir, "platforms", p.name)
if not os.path.isdir(readme_dir):
os.makedirs(readme_dir)
2022-02-01 15:38:15 +02:00
with open(os.path.join(readme_dir, "README.md"), "w") as fp:
fp.write(
platform_readme_tpl.format(
name=p.name,
title=p.title,
description=p.description,
2020-08-26 14:51:53 +03:00
examples="\n".join(examples_md_lines),
)
)
# Framework README
2022-02-01 21:56:53 +02:00
for framework in get_frameworks():
2020-08-26 14:51:53 +03:00
if not is_compat_platform_and_framework(p.name, framework["name"]):
continue
2020-08-26 14:51:53 +03:00
if framework["name"] not in framework_examples_md_lines:
framework_examples_md_lines[framework["name"]] = []
lines = []
lines.append("- [%s](%s)" % (p.title, github_url))
lines.extend(" %s" % line for line in examples_md_lines)
lines.append("")
2020-08-26 14:51:53 +03:00
framework_examples_md_lines[framework["name"]].extend(lines)
# Root README
line = "* [%s](%s)" % (p.title, "%s/tree/master/examples" % github_url)
if p.is_embedded():
embedded.append(line)
else:
desktop.append(line)
# Frameworks
frameworks = []
2022-02-01 21:56:53 +02:00
for framework in get_frameworks():
2020-10-29 18:09:08 +02:00
if framework["name"] not in framework_examples_md_lines:
continue
2022-02-01 15:38:15 +02:00
readme_dir = os.path.join(project_examples_dir, "frameworks", framework["name"])
if not os.path.isdir(readme_dir):
os.makedirs(readme_dir)
2022-02-01 15:38:15 +02:00
with open(os.path.join(readme_dir, "README.md"), "w") as fp:
fp.write(
framework_readme_tpl.format(
2020-08-26 14:51:53 +03:00
name=framework["name"],
title=framework["title"],
description=framework["description"],
examples="\n".join(framework_examples_md_lines[framework["name"]]),
)
)
url = campaign_url(
2018-08-15 19:44:02 +03:00
"https://docs.platformio.org/en/latest/frameworks/%s.html#examples"
2020-08-26 14:51:53 +03:00
% framework["name"],
source="github",
2020-08-26 14:51:53 +03:00
medium="examples",
)
frameworks.append("* [%s](%s)" % (framework["title"], url))
2022-02-01 15:38:15 +02:00
with open(os.path.join(project_examples_dir, "README.md"), "w") as fp:
2020-08-26 14:51:53 +03:00
fp.write(
"""# PlatformIO Project Examples
- [Development platforms](#development-platforms):
- [Embedded](#embedded)
- [Desktop](#desktop)
- [Frameworks](#frameworks)
## Development platforms
### Embedded
%s
### Desktop
%s
## Frameworks
%s
2020-08-26 14:51:53 +03:00
"""
% ("\n".join(embedded), "\n".join(desktop), "\n".join(frameworks))
)
def main():
2022-02-01 21:56:53 +02:00
with tempfile.TemporaryDirectory() as tmp_dir:
print("Core directory: %s" % tmp_dir)
os.environ["PLATFORMIO_CORE_DIR"] = tmp_dir
install_platforms()
update_platform_docs()
update_framework_docs()
update_boards()
update_debugging()
update_project_examples()
if __name__ == "__main__":
2022-02-01 21:56:53 +02:00
sys.exit(main())