Skip to content

Commit

Permalink
doc: Add board catalog
Browse files Browse the repository at this point in the history
wip

Signed-off-by: Benjamin Cabé <[email protected]>
  • Loading branch information
kartben committed Oct 3, 2024
1 parent 1005a73 commit a4cca91
Show file tree
Hide file tree
Showing 5 changed files with 517 additions and 5 deletions.
326 changes: 326 additions & 0 deletions boards/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,335 @@ available under :zephyr_file:`doc/templates/board.tmpl`.
.. toctree::
:maxdepth: 2
:glob:
:hidden:

*/index

.. raw:: html

<style>
.filter-form {
display: flex;
flex-wrap: wrap;
gap: 10px;
margin-bottom: 20px;
padding: 10px;
border-radius: 8px;
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
}
.filter-form input[type="text"],
.filter-form input[type="number"],
.filter-form select {
padding: 10px;
border: 1px solid #ccc;
border-radius: 4px;
flex: 1 1 200px;
background-color: var(--input-background-color);
color: var(--body-color);
transition: all 0.3s ease;
}
.filter-form input[type="text"]:focus,
.filter-form input[type="number"]:focus,
.filter-form select:focus {
border-color: var(--input-focus-border-color);
}
.catalog {
display: flex;
flex-wrap: wrap;
gap: 20px;
justify-content: center;
/* Center the cards horizontally */
margin-top: 20px;
}
.board-card {
flex: 1 1 calc(33.3% - 20px);
/* Three cards per row */
max-width: calc(33.3% - 20px);
border: 1px solid #ddd;
border-radius: 8px;
padding: 20px;
background-color: var(--admonition-note-background-color);
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
display: flex;
flex-direction: column;
align-items: center;
/* Center card content */
transition: all 0.3s ease;
}
.board-card:hover {
box-shadow: 0 6px 12px rgba(0, 0, 0, 0.15);
/* Add hover effect for card */
transform: translateY(-5px);
/* Slight lift on hover */
}
.board-card img {
width: auto;
height: auto;
max-height: 180px;
margin-bottom: 15px;
border-radius: 4px;
display: block;
margin-left: auto;
margin-right: auto;
}
@media (max-width: 1024px) {
.board-card {
flex: 1 1 calc(50% - 20px);
max-width: calc(50% - 20px);
}
}
@media (max-width: 768px) {
.board-card {
flex: 1 1 calc(100% - 20px);
max-width: calc(100% - 20px);
}
.board-card img {
max-height: 120px;
}
}
.board-card h3 {
margin: 10px 0 5px;
text-align: center;
font-size: 18px;
font-weight: 500;
color: var(--body-color);
}
.board-card p {
margin: 5px 0;
text-align: center;
font-size: 14px;
color: var(--body-color);
}
</style>

<form class="filter-form">
<input type="text" id="name" placeholder="Name" style="flex-basis:600px">
<select id="arch">
<option value="">Select Architecture</option>
<!-- Architecture options will be populated dynamically -->
</select>
<select id="vendor">
<option value="">Select Vendor</option>
<!-- Vendor options will be populated dynamically -->
</select>
<input type="number" id="minRam" placeholder="Min RAM (KB)" />
<input type="number" id="minFlash" placeholder="Min Flash (KB)" />
</form>

<div id="number-of-matches" style="text-align: center;"></div>

<div class="catalog" id="catalog">
<!-- Board cards will be populated dynamically -->
</div>

<script>
function formatSize(sizeInKB) {
function smartRound(num) {
return num.toLocaleString('en-US', { minimumFractionDigits: 0, maximumFractionDigits: 2 });
}
if (sizeInKB >= 1024 * 1024) {
return smartRound(sizeInKB / (1024 * 1024)) + " GB";
} else if (sizeInKB >= 1024) {
return smartRound(sizeInKB / 1024) + " MB";
} else {
return smartRound(sizeInKB) + " KB";
}
}
document.addEventListener("DOMContentLoaded", function () {
let data;
// Guess path to the board catalog JSON file based on the download link on this page
const boardCatalogLink = document.querySelector("a.reference.download.internal[href$='.json']");
// Fetch the JSON data
fetch(boardCatalogLink.href)
.then((response) => response.json())
.then((jsonData) => {
data = jsonData;
const archs = new Set();
const vendors = new Set();
Object.values(data).forEach((board) => {
if (board.arch) {
archs.add(board.arch);
}
if (board.vendor) {
vendors.add(board.vendor);
}
});
archToHumanReadable = {
"arc": "Synopsys DesignWare ARC",
"arm": "ARM",
"arm64": "ARM 64",
"mips": "MIPS",
"nios2": "Altera Nios II",
"posix": "POSIX",
"riscv": "RISC-V",
"sparc": "SPARC",
"x86": "x86",
"xtensa": "Xtensa"
};
// Populate architecture select, sorted alphabetically by human-readable name
const archSelect = document.getElementById("arch");
Array.from(archs)
.sort((a, b) => archToHumanReadable[a].localeCompare(archToHumanReadable[b], undefined, { sensitivity: "base" }))
.forEach((arch) => {
const option = document.createElement("option");
option.value = arch;
option.textContent = archToHumanReadable[arch];
archSelect.appendChild(option);
});
// Populate vendor select, sorted alphabetically
const vendorSelect = document.getElementById("vendor");
Array.from(vendors)
.sort((a, b) => a.localeCompare(b, undefined, { sensitivity: "base" }))
.forEach((vendor) => {
const option = document.createElement("option");
option.value = vendor;
option.textContent = vendor;
vendorSelect.appendChild(option);
});
generateBoardCards(data);
updateBoardCount();
const form = document.querySelector(".filter-form");
form.addEventListener("input", function () {
filterBoards(data);
});
});
});
function generateBoardCards(data) {
const catalog = document.getElementById("catalog");
catalog.innerHTML = ""; // Clear existing content
// sort boards alphabetically
Object.values(data)
.sort((a, b) => a.name.localeCompare(b.name, undefined, { sensitivity: "base" }))
.forEach((board) => {
const boardCard = document.createElement("div");
boardCard.className = "board-card";
// Set data attributes for filtering
boardCard.setAttribute("data-arch", (board.arch || "").toLowerCase());
boardCard.setAttribute("data-vendor", (board.vendor || "").toLowerCase());
boardCard.setAttribute("data-ram", board.ram || "0");
boardCard.setAttribute("data-flash", board.flash || "0");
// Create image
const img = document.createElement("img");
if (board.image) {
img.src = board.image.replace("/Users/kartben/zephyrproject/zephyr/", "/");
} else {
img.src = "https://via.placeholder.com/200";
}
img.alt = "Board Image";
boardCard.appendChild(img);
// Board name
const h3 = document.createElement("h3");
h3.textContent = board.name || "Unknown Board";
boardCard.appendChild(h3);
basicInfoPara = document.createElement("p");
// Architecture
const pArch = document.createTextNode("Architecture: ");
pArch.textContent += (board.arch || "N/A");
basicInfoPara.appendChild(pArch);
basicInfoPara.appendChild(document.createElement("br"));
// RAM
const pRAM = document.createTextNode("RAM: ");
pRAM.textContent += board.ram ? formatSize(board.ram) : "N/A";
basicInfoPara.appendChild(pRAM);
basicInfoPara.appendChild(document.createElement("br"));
// Flash
const pFlash = document.createTextNode("Flash: ");
pFlash.textContent += board.flash ? formatSize(board.flash) : "N/A";
basicInfoPara.appendChild(pFlash);
boardCard.appendChild(basicInfoPara);
// clicking on the boards card should open the board's README, that can be found at
// ./<vendor>/<board_name>/README.rst
boardCard.addEventListener("click", function () {
window.open(`../${board.dir}/doc/index.html`, "_self");
});
document.getElementById("catalog").appendChild(boardCard);
});
}
function updateBoardCount() {
const boards = document.getElementsByClassName("board-card");
const visibleBoards = Array.from(boards).filter((board) => board.style.display !== "none").length;
const totalBoards = boards.length;
document.getElementById("number-of-matches").textContent = `Showing ${visibleBoards} of ${totalBoards} boards`;
}
function filterBoards(data) {
const nameInput = document.getElementById("name").value.toLowerCase();
const archSelect = document.getElementById("arch").value.toLowerCase();
const vendorSelect = document.getElementById("vendor").value.toLowerCase();
const minRam = parseInt(document.getElementById("minRam").value, 10) || 0;
const minFlash = parseInt(document.getElementById("minFlash").value, 10) || 0;
console.log(archSelect);
const boards = document.getElementsByClassName("board-card");
Array.from(boards).forEach(function (board) {
const boardName = board.querySelector("h3").textContent.toLowerCase();
const boardArch = board.getAttribute("data-arch").toLowerCase();
const boardVendor = board.getAttribute("data-vendor").toLowerCase();
const boardRam = parseInt(board.getAttribute("data-ram"), 10);
const boardFlash = parseInt(board.getAttribute("data-flash"), 10);
let matches = true;
if (nameInput && !boardName.includes(nameInput)) matches = false;
if (archSelect && !boardArch.includes(archSelect)) matches = false;
if (vendorSelect && boardVendor !== vendorSelect) matches = false;
if (boardRam < minRam) matches = false;
if (boardFlash < minFlash) matches = false;
if (matches) {
board.style.display = "block";
} else {
board.style.display = "none";
}
});
updateBoardCount();
}
</script>

:download:`Raw board catalog <_catalog/board_catalog.json>`.

.. _boards-shields:

Shields
Expand Down
29 changes: 27 additions & 2 deletions doc/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ set(SPHINXOPTS "-j auto -W --keep-going -T" CACHE STRING "Default Sphinx Options
set(SPHINXOPTS_EXTRA "" CACHE STRING "Extra Sphinx Options (added to defaults)")
set(LATEXMKOPTS "-halt-on-error -no-shell-escape" CACHE STRING "Default latexmk options")
set(DT_TURBO_MODE OFF CACHE BOOL "Enable DT turbo mode")
set(BOARDS_TURBO_MODE OFF CACHE BOOL "Enable Boards turbo mode")
set(DOC_TAG "development" CACHE STRING "Documentation tag")
set(DTS_ROOTS "${ZEPHYR_BASE}" CACHE STRING "DT bindings root folders")

Expand Down Expand Up @@ -146,6 +147,30 @@ add_custom_target(

set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${GEN_DEVICETREE_REST_SCRIPT})

#-------------------------------------------------------------------------------
# boards catalog

set(GEN_BOARDS_CATALOG_SCRIPT ${CMAKE_CURRENT_LIST_DIR}/_scripts/gen_boards_catalog.py)

set(GEN_BOARDS_ARGS)
if(BOARDS_TURBO_MODE)
list(APPEND GEN_BOARDS_ARGS --turbo-mode)
endif()

add_custom_target(
boards-catalog
COMMAND ${CMAKE_COMMAND} -E env
PYTHONPATH=${ZEPHYR_BASE}/scripts/dts/python-devicetree/src${SEP}$ENV{PYTHONPATH}:${ZEPHYR_BASE}/scripts
ZEPHYR_BASE=${ZEPHYR_BASE}
${PYTHON_EXECUTABLE} ${GEN_BOARDS_CATALOG_SCRIPT}
${GEN_BOARDS_ARGS}
${DOCS_SRC_DIR}/boards/_catalog
VERBATIM
USES_TERMINAL
COMMENT "Generating Boards catalog documentation..."
)


#-------------------------------------------------------------------------------
# html

Expand All @@ -172,7 +197,7 @@ set_target_properties(
ADDITIONAL_CLEAN_FILES "${DOCS_SRC_DIR};${DOCS_HTML_DIR};${DOCS_DOCTREE_DIR}"
)

add_dependencies(html devicetree)
add_dependencies(html devicetree boards-catalog)

#-------------------------------------------------------------------------------
# html-live
Expand Down Expand Up @@ -202,7 +227,7 @@ set_target_properties(
ADDITIONAL_CLEAN_FILES "${DOCS_SRC_DIR};${DOCS_HTML_DIR};${DOCS_DOCTREE_DIR}"
)

add_dependencies(html-live devicetree)
add_dependencies(html-live devicetree boards-catalog)
#-------------------------------------------------------------------------------
# pdf

Expand Down
Loading

0 comments on commit a4cca91

Please sign in to comment.