<!DOCTYPE html>
<html lang="zh-CN">
<head>
? ? <meta charset="UTF-8">
? ? <meta name="viewport" content="width=device-width, initial-scale=1.0">
? ? <title>Zephyr設備初始化機制交互式解析</title>
? ? <script src="https://cdn.tailwindcss.com"></script>
? ? <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
? ? <!-- Chosen Palette: Soft Tech -->
? ? <!-- Application Structure Plan: The application is designed around a central, interactive, vertical flowchart representing the Zephyr boot sequence. This visual anchor (hub) allows users to immediately form a mental model of the process. Instead of a linear report, content is organized into thematic sections (spokes) that are revealed dynamically when a user clicks on a corresponding stage in the flowchart. This hub-and-spoke model promotes non-linear exploration, which is ideal for a technical audience that may want to quickly jump to specific topics like initialization priorities or dependency issues. Key data points, such as initialization priorities, are visualized using a bar chart to make abstract numbers tangible. This structure was chosen to transform a dense, text-based report into an engaging and intuitive learning tool, prioritizing user understanding and exploration over simply reproducing the source document's layout. -->
? ? <!-- Visualization & Content Choices:?
? ? ? ? - Report Info: Zephyr Boot Sequence -> Goal: Organize/Change -> Viz: Vertical HTML/CSS flowchart -> Interaction: Click to navigate to content sections -> Justification: Provides a high-level map and acts as the main navigation, guiding the user's journey.
? ? ? ? - Report Info: DEVICE_DEFINE macro -> Goal: Inform/Organize -> Viz: Code block + HTML table -> Interaction: Click button to toggle table visibility -> Justification: Clearly separates code from its explanation, reducing initial clutter.
? ? ? ? - Report Info: Initialization Levels -> Goal: Compare/Inform -> Viz: HTML table -> Interaction: Highlight active level based on flowchart selection -> Justification: Table is ideal for comparison; highlighting adds context.
? ? ? ? - Report Info: Initialization Priorities -> Goal: Compare/Relationships -> Viz: Chart.js Bar Chart -> Interaction: Highlight specific driver priority -> Justification: A chart visualizes relative numerical order far more effectively than text, making priority conflicts easier to understand.
? ? ? ? - Report Info: Dependency/Future Issues -> Goal: Organize/Inform -> Viz: Interactive accordion cards -> Interaction: Click to expand/collapse -> Justification: Breaks down complex problems into digestible chunks, encouraging engagement without overwhelming the user.
? ? ? ? - Library/Method: Chart.js for canvas-based charts, Vanilla JS for all interactions (toggles, navigation), Tailwind CSS for layout and styling. -->
? ? <!-- CONFIRMATION: NO SVG graphics used. NO Mermaid JS used. -->
? ? <style>
? ? ? ? body {
? ? ? ? ? ? font-family: 'Inter', 'Helvetica Neue', 'Helvetica', 'Arial', 'sans-serif';
? ? ? ? }
? ? ? ? .nav-link.active {
? ? ? ? ? ? background-color: #e0f2fe; /* sky-100 */
? ? ? ? ? ? color: #0c4a6e; /* sky-900 */
? ? ? ? ? ? font-weight: 600;
? ? ? ? ? ? border-left-color: #0ea5e9; /* sky-500 */
? ? ? ? }
? ? ? ? .content-section {
? ? ? ? ? ? display: none;
? ? ? ? }
? ? ? ? .content-section.active {
? ? ? ? ? ? display: block;
? ? ? ? }
? ? ? ? .flow-line {
? ? ? ? ? ? width: 2px;
? ? ? ? ? ? background-color: #cbd5e1; /* slate-300 */
? ? ? ? ? ? height: 1.5rem;
? ? ? ? ? ? margin-left: calc(0.75rem - 1px);
? ? ? ? }
? ? ? ? .flow-dot {
? ? ? ? ? ? width: 0.75rem;
? ? ? ? ? ? height: 0.75rem;
? ? ? ? ? ? background-color: #94a3b8; /* slate-400 */
? ? ? ? ? ? border-radius: 9999px;
? ? ? ? }
? ? ? ? .nav-link.active .flow-dot {
? ? ? ? ? ? background-color: #0ea5e9; /* sky-500 */
? ? ? ? }
? ? ? ? .accordion-content {
? ? ? ? ? ? max-height: 0;
? ? ? ? ? ? overflow: hidden;
? ? ? ? ? ? transition: max-height 0.3s ease-out;
? ? ? ? }
? ? </style>
</head>
<body class="bg-slate-50 text-slate-700">
? ? <main class="container mx-auto p-4 md:p-8">
? ? ? ? <header class="text-center mb-10">
? ? ? ? ? ? <h1 class="text-3xl md:text-4xl font-bold text-slate-900 mb-2">Zephyr設備初始化機制交互式解析</h1>
? ? ? ? ? ? <p class="text-lg text-slate-600">一份將復雜的技術報告轉化為可探索體驗的交互式應用</p>
? ? ? ? </header>
? ? ? ? <div class="flex flex-col md:flex-row gap-8">
? ? ? ? ? ? <!-- Sticky Navigation -->
? ? ? ? ? ? <aside class="md:w-1/4 lg:w-1/5 md:sticky top-8 self-start">
? ? ? ? ? ? ? ? <h2 class="text-lg font-semibold text-slate-800 mb-4">系統啟動流程</h2>
? ? ? ? ? ? ? ? <nav id="boot-sequence-nav" class="flex flex-col items-start">
? ? ? ? ? ? ? ? ? ? <!-- Nav items will be dynamically generated here -->
? ? ? ? ? ? ? ? </nav>
? ? ? ? ? ? </aside>
? ? ? ? ? ? <!-- Content Panel -->
? ? ? ? ? ? <div id="content-panel" class="md:w-3/4 lg:w-4/5 min-h-screen">
? ? ? ? ? ? ? ? <!-- Content sections will be dynamically generated here -->
? ? ? ? ? ? </div>
? ? ? ? </div>
? ? </main>
? ? <footer class="text-center p-6 mt-12 border-t border-slate-200">
? ? ? ? <p class="text-sm text-slate-500">基于 Zephyr RTOS 設備模型報告構建 | 旨在促進理解與探索</p>
? ? </footer>
? ? <script>
? ? ? ? document.addEventListener('DOMContentLoaded', () => {
? ? ? ? ? ? const navContainer = document.getElementById('boot-sequence-nav');
? ? ? ? ? ? const contentContainer = document.getElementById('content-panel');
? ? ? ? ? ? const contentData = [
? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? id: 'intro',
? ? ? ? ? ? ? ? ? ? title: '報告引言',
? ? ? ? ? ? ? ? ? ? content: `
? ? ? ? ? ? ? ? ? ? ? ? <h3 class="text-2xl font-bold text-slate-800 mb-4">深入理解Zephyr的自動化設備初始化</h3>
? ? ? ? ? ? ? ? ? ? ? ? <p class="mb-4 text-slate-600 leading-relaxed">在像Zephyr這樣的實時操作系統中,確保所有硬件設備在主應用程序開始前都已正確初始化是至關重要的。本應用的源報告深入探討了Zephyr的設備模型,特別是<code>DEVICE_DEFINE</code>宏如何將一個設備(如DSP)的初始化函數(例如<code>dsp_acts_init</code>)無縫集成到系統啟動流程中。這個過程是高度自動化的,旨在簡化開發,但其背后依賴于一個由初始化級別、優先級和“鏈接器魔法”構成的復雜系統。</p>
? ? ? ? ? ? ? ? ? ? ? ? <p class="mb-6 text-slate-600 leading-relaxed">本交互式應用旨在揭開這一過程的神秘面紗。您可以通過左側的啟動流程圖進行導航,逐步探索從設備定義到內核調用其初始化函數的完整路徑。我們將通過可視化的方式,幫助您理解其中的關鍵概念、潛在的依賴問題以及Zephyr社區為應對這些挑戰而提出的未來演進方向。</p>
? ? ? ? ? ? ? ? ? ? ? ? <div class="bg-sky-50 border-l-4 border-sky-400 p-4 rounded-r-lg">
? ? ? ? ? ? ? ? ? ? ? ? ? ? <p class="text-sky-800"><strong>如何使用:</strong> 點擊左側“系統啟動流程”中的任意階段,右側將顯示對應的詳細解析。請從“設備定義”開始您的探索之旅!</p>
? ? ? ? ? ? ? ? ? ? ? ? </div>
? ? ? ? ? ? ? ? ? ? `
? ? ? ? ? ? ? ? },
? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? id: 'device-define',
? ? ? ? ? ? ? ? ? ? title: '1. 設備定義: DEVICE_DEFINE',
? ? ? ? ? ? ? ? ? ? content: `
? ? ? ? ? ? ? ? ? ? ? ? <h3 class="text-2xl font-bold text-slate-800 mb-4">一切的起點:<code>DEVICE_DEFINE</code> 宏</h3>
? ? ? ? ? ? ? ? ? ? ? ? <p class="mb-4 text-slate-600 leading-relaxed">在Zephyr中,一個設備驅動程序的生命周期始于<code>DEVICE_DEFINE</code>宏。這個宏是Zephyr設備模型的核心,它在編譯時靜態地創建一個設備實例,并將其初始化函數注冊到系統的啟動序列中。這使得內核能夠在啟動時自動發現并初始化所有已定義的設備,而無需開發者手動調用任何初始化代碼。</p>
? ? ? ? ? ? ? ? ? ? ? ? <p class="mb-6 text-slate-600 leading-relaxed">下面是源報告中分析的<code>dsp_acts</code>設備的定義示例。這個宏的每個參數都扮演著至關重要的角色,共同構成了設備在系統中的完整畫像。</p>
? ? ? ? ? ? ? ? ? ? ? ? <div class="bg-gray-900 rounded-lg p-4 my-6 text-white text-sm font-mono overflow-x-auto">
? ? ? ? ? ? ? ? ? ? ? ? ? ? <pre><code>DEVICE_DEFINE(dsp_acts, CONFIG_DSP_NAME,
? ? ? ? ? ? ? dsp_acts_init, NULL, &dsp_data, &dsp_acts_config,
? ? ? ? ? ? ? POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEVICE, &dsp_drv_api);</code></pre>
? ? ? ? ? ? ? ? ? ? ? ? </div>
? ? ? ? ? ? ? ? ? ? ? ? <div id="param-table-container" class="border border-slate-200 rounded-lg p-6">
? ? ? ? ? ? ? ? ? ? ? ? ? ? <h4 class="text-xl font-semibold text-slate-800 mb-4">參數詳解</h4>
? ? ? ? ? ? ? ? ? ? ? ? ? ? <p class="mb-4 text-slate-600">下表詳細解釋了<code>DEVICE_DEFINE</code>宏的每個參數及其在<code>dsp_acts</code>示例中的具體值,這些參數共同決定了設備的身份、行為和初始化時機。</p>
? ? ? ? ? ? ? ? ? ? ? ? ? ? <div class="overflow-x-auto">
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? <table class="w-full text-left border-collapse">
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? <thead class="bg-slate-100">
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? <tr>
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? <th class="p-3 font-semibold text-slate-700 border-b border-slate-200">參數</th>
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? <th class="p-3 font-semibold text-slate-700 border-b border-slate-200">描述</th>
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? <th class="p-3 font-semibold text-slate-700 border-b border-slate-200"><code>dsp_acts</code> 示例值</th>
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? </tr>
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? </thead>
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? <tbody>
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? <tr class="hover:bg-slate-50">
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? <td class="p-3 border-b border-slate-200 font-mono text-sky-700">init_fn</td>
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? <td class="p-3 border-b border-slate-200">設備初始化函數指針,由內核在啟動時調用。</td>
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? <td class="p-3 border-b border-slate-200 font-mono">dsp_acts_init</td>
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? </tr>
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? <tr class="hover:bg-slate-50">
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? <td class="p-3 border-b border-slate-200 font-mono text-sky-700">data</td>
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? <td class="p-3 border-b border-slate-200">指向設備運行時可變數據結構體的指針(存-在RAM中)。</td>
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? <td class="p-3 border-b border-slate-200 font-mono">&dsp_data</td>
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? </tr>
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? <tr class="hover:bg-slate-50">
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? <td class="p-3 border-b border-slate-200 font-mono text-sky-700">config</td>
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? <td class="p-3 border-b border-slate-200">指向設備只讀配置數據結構體的指針(存在ROM中)。</td>
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? <td class="p-3 border-b border-slate-200 font-mono">&dsp_acts_config</td>
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? </tr>
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? <tr class="hover:bg-slate-50">
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? <td class="p-3 border-b border-slate-200 font-mono text-sky-700">level</td>
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? <td class="p-3 border-b border-slate-200">初始化發生的系統級別。</td>
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? <td class="p-3 border-b border-slate-200 font-mono">POST_KERNEL</td>
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? </tr>
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? <tr class="hover:bg-slate-50">
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? <td class="p-3 border-b border-slate-200 font-mono text-sky-700">prio</td>
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? <td class="p-3 border-b border-slate-200">在指定級別內的初始化優先級 (0-99)。</td>
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? <td class="p-3 border-b border-slate-200 font-mono">CONFIG_KERNEL_INIT_PRIORITY_DEVICE</td>
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? </tr>
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? <tr class="hover:bg-slate-50">
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? <td class="p-3 border-b border-slate-200 font-mono text-sky-700">api</td>
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? <td class="p-3 border-b border-slate-200">指向設備API函數指針集合的指針,提供抽象接口。</td>
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? <td class="p-3 border-b border-slate-200 font-mono">&dsp_drv_api</td>
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? </tr>
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? </tbody>
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? </table>
? ? ? ? ? ? ? ? ? ? ? ? ? ? </div>
? ? ? ? ? ? ? ? ? ? ? ? </div>
? ? ? ? ? ? ? ? ? ? `
? ? ? ? ? ? ? ? },
? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? id: 'init-levels',
? ? ? ? ? ? ? ? ? ? title: '2. 初始化級別 (Level)',
? ? ? ? ? ? ? ? ? ? content: `
? ? ? ? ? ? ? ? ? ? ? ? <h3 class="text-2xl font-bold text-slate-800 mb-4">時機至關重要:初始化級別</h3>
? ? ? ? ? ? ? ? ? ? ? ? <p class="mb-4 text-slate-600 leading-relaxed">Zephyr的啟動過程被劃分為幾個明確的階段或“級別”。<code>DEVICE_DEFINE</code>宏中的<code>level</code>參數決定了設備的初始化函數將在哪個階段被執行。這是一個粗粒度的排序機制,確保了系統資源按邏輯順序準備就緒。</p>
? ? ? ? ? ? ? ? ? ? ? ? <p class="mb-6 text-slate-600 leading-relaxed"><code>dsp_acts</code>設備被配置在<code>POST_KERNEL</code>級別進行初始化。這是一個非常關鍵的選擇,因為它意味著初始化將在Zephyr內核完全啟動、所有內核服務(如線程、信號量、內存管理)都可用之后進行。這為驅動程序提供了安全使用內核功能的保障。</p>
? ? ? ? ? ? ? ? ? ? ? ? <div class="overflow-x-auto border border-slate-200 rounded-lg p-6">
? ? ? ? ? ? ? ? ? ? ? ? ? ? <h4 class="text-xl font-semibold text-slate-800 mb-4">Zephyr 系統初始化級別詳解</h4>
? ? ? ? ? ? ? ? ? ? ? ? ? ? ?<table class="w-full text-left border-collapse">
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? <thead class="bg-slate-100">
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? <tr>
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? <th class="p-3 font-semibold text-slate-700 border-b border-slate-200">級別</th>
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? <th class="p-3 font-semibold text-slate-700 border-b border-slate-200">描述</th>
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? <th class="p-3 font-semibold text-slate-700 border-b border-slate-200">典型用途</th>
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? </tr>
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? </thead>
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? <tbody>
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? <tr class="hover:bg-slate-50">
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? <td class="p-3 border-b border-slate-200 font-mono">EARLY</td>
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? <td class="p-3 border-b border-slate-200">極早期,在C代碼環境準備好后立即執行。</td>
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? <td class="p-3 border-b border-slate-200">SoC或架構特定的底層初始化。</td>
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? </tr>
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? <tr class="hover:bg-slate-50">
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? <td class="p-3 border-b border-slate-200 font-mono">PRE_KERNEL_1 / 2</td>
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? <td class="p-3 border-b border-slate-200">內核服務可用之前。</td>
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? <td class="p-3 border-b border-slate-200">不依賴內核服務的早期驅動初始化。</td>
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? </tr>
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? <tr class="bg-sky-100 font-semibold text-sky-900">
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? <td class="p-3 border-b border-slate-200 font-mono">POST_KERNEL</td>
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? <td class="p-3 border-b border-slate-200">內核已啟動并活躍,所有內核原語可用。</td>
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? <td class="p-3 border-b border-slate-200">大部分設備驅動和系統服務(如本例的DSP、藍牙棧)。</td>
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? </tr>
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? <tr class="hover:bg-slate-50">
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? <td class="p-3 border-b border-slate-200 font-mono">APPLICATION</td>
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? <td class="p-3 border-b border-slate-200">在<code>main()</code>函數執行之前。</td>
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? <td class="p-3 border-b border-slate-200">應用程序特定的初始化。</td>
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? </tr>
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? </tbody>
? ? ? ? ? ? ? ? ? ? ? ? ? ? </table>
? ? ? ? ? ? ? ? ? ? ? ? </div>
? ? ? ? ? ? ? ? ? ? `
? ? ? ? ? ? ? ? },
? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? id: 'priority',
? ? ? ? ? ? ? ? ? ? title: '3. 初始化優先級 (Priority)',
? ? ? ? ? ? ? ? ? ? content: `
? ? ? ? ? ? ? ? ? ? ? ? <h3 class="text-2xl font-bold text-slate-800 mb-4">精細控制:初始化優先級</h3>
? ? ? ? ? ? ? ? ? ? ? ? <p class="mb-4 text-slate-600 leading-relaxed">在同一個初始化級別內,可能存在數十個設備和系統服務需要初始化。為了管理它們之間的順序,特別是處理依賴關系,Zephyr引入了優先級(priority)機制。這是一個從0到99的數字,數字越小,優先級越高,越早被執行。</p>
? ? ? ? ? ? ? ? ? ? ? ? <p class="mb-6 text-slate-600 leading-relaxed"><code>dsp_acts</code>設備的優先級被設置為<code>CONFIG_KERNEL_INIT_PRIORITY_DEVICE</code>,這是一個Kconfig選項,默認值通常為50。這個選擇決定了它在<code>POST_KERNEL</code>級別中與其他設備(如PINMUX、I2C控制器等)的相對初始化順序。正確的優先級設置對于避免“雞生蛋,蛋生雞”式的依賴問題至關重要。</p>
? ? ? ? ? ? ? ? ? ? ? ? <div class="border border-slate-200 rounded-lg p-6">
? ? ? ? ? ? ? ? ? ? ? ? ? ? <h4 class="text-xl font-semibold text-slate-800 mb-4">POST_KERNEL 級別內常見優先級對比</h4>
? ? ? ? ? ? ? ? ? ? ? ? ? ? <p class="mb-4 text-slate-600">下圖通過一個條形圖直觀地展示了<code>POST_KERNEL</code>級別中一些常見驅動的初始化優先級。您可以看到,像PINMUX(引腳復用)這樣的基礎服務通常具有更高的優先級(數值更小),以確保它們在依賴它們的設備(如我們的DSP)之前準備就M就緒。</p>
? ? ? ? ? ? ? ? ? ? ? ? ? ? <div class="chart-container relative h-96 max-h-[400px] w-full max-w-3xl mx-auto">
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? <canvas id="priorityChart"></canvas>
? ? ? ? ? ? ? ? ? ? ? ? ? ? </div>
? ? ? ? ? ? ? ? ? ? ? ? </div>
? ? ? ? ? ? ? ? ? ? `
? ? ? ? ? ? ? ? },
? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? id: 'linker-magic',
? ? ? ? ? ? ? ? ? ? title: '4. 鏈接器魔法與調用',
? ? ? ? ? ? ? ? ? ? content: `
? ? ? ? ? ? ? ? ? ? ? ? <h3 class="text-2xl font-bold text-slate-800 mb-4">幕后英雄:鏈接器</h3>
? ? ? ? ? ? ? ? ? ? ? ? <p class="mb-4 text-slate-600 leading-relaxed">我們已經定義了設備、級別和優先級,但系統究竟是如何找到并按正確順序調用<code>dsp_acts_init</code>函數的呢?答案在于“鏈接器魔法”。當編譯器處理<code>DEVICE_DEFINE</code>宏時,它會生成一個包含初始化函數指針和設備信息的小結構體(<code>init_entry</code>)。</p>
? ? ? ? ? ? ? ? ? ? ? ? <p class="mb-6 text-slate-600 leading-relaxed">然后,鏈接器腳本會將所有這些<code>init_entry</code>結構體收集起來,并將它們放入一個特殊的內存區域(鏈接器章節)。最關鍵的是,鏈接器會根據每個入口的初始化級別和優先級對它們進行排序。這樣,在最終的固件鏡像中,就形成了一個預先排好序的初始化函數指針數組。</p>
? ? ? ? ? ? ? ? ? ? ? ? <div class="bg-slate-100 rounded-lg p-6">
? ? ? ? ? ? ? ? ? ? ? ? ? ? <h4 class="text-xl font-semibold text-slate-800 mb-4">最終調用路徑</h4>
? ? ? ? ? ? ? ? ? ? ? ? ? ? <ol class="list-decimal list-inside space-y-3 text-slate-700">
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? <li><strong>定義與注冊:</strong> <code>DEVICE_DEFINE</code> 創建一個包含 <code>dsp_acts_init</code> 函數指針的 <code>init_entry</code>。</li>
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? <li><strong>收集與排序:</strong> 鏈接器將這個 <code>init_entry</code> 和其他所有入口放入一個特定內存段,并根據級別和優先級排序。</li>
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? <li><strong>內核遍歷:</strong> 系統啟動時,內核中的一個函數(如 <code>z_sys_init_runlevel</code>)會遍歷這個排好序的數組。</li>
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? <li><strong>執行調用:</strong> 當遍歷到 <code>dsp_acts</code> 對應的入口時,內核會調用 <code>dsp_acts_init</code> 函數,并將指向 <code>dsp_acts</code> 設備實例的指針作為參數傳入。</li>
? ? ? ? ? ? ? ? ? ? ? ? ? ? </ol>
? ? ? ? ? ? ? ? ? ? ? ? </div>
? ? ? ? ? ? ? ? ? ? `
? ? ? ? ? ? ? ? },
? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? id: 'dependencies',
? ? ? ? ? ? ? ? ? ? title: '5. 依賴問題與演進',
? ? ? ? ? ? ? ? ? ? content: `
? ? ? ? ? ? ? ? ? ? ? ? <h3 class="text-2xl font-bold text-slate-800 mb-4">挑戰與未來:依賴管理</h3>
? ? ? ? ? ? ? ? ? ? ? ? <p class="mb-6 text-slate-600 leading-relaxed">盡管Zephyr的初始化系統很強大,但它并非完美無缺。當前基于優先級的依賴管理機制將保證正確順序的責任完全交給了開發者。如果依賴關系復雜或未被完全理解,就很容易導致難以調試的運行時錯誤。源報告中強調了幾個關鍵挑戰以及社區正在探索的解決方案。</p>
? ? ? ? ? ? ? ? ? ? ? ??
? ? ? ? ? ? ? ? ? ? ? ? <div class="space-y-4 accordion-container">
? ? ? ? ? ? ? ? ? ? ? ? ? ? <div class="accordion-item border border-slate-200 rounded-lg">
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? <button class="accordion-header w-full flex justify-between items-center p-4 text-left font-semibold text-slate-800 bg-slate-100 hover:bg-slate-200 transition-colors">
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? <span>挑戰:隱式依賴與優先級沖突</span>
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? <svg class="w-5 h-5 transform transition-transform" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"></path></svg>
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? </button>
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? <div class="accordion-content">
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? <div class="p-4 border-t border-slate-200 text-slate-600">
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? <p><strong>問題:</strong> 系統本身不追蹤設備間的依賴關系。例如,一個EEPROM驅動可能依賴I2C總線,但如果I2C驅動的初始化優先級(數字更大)低于EEPROM驅動,EEPROM在嘗試獲取I2C總線句柄時將失敗,導致系統故障。</p>
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? <p class="mt-2"><strong>影響:</strong> 這種手動管理方式是脆弱的,特別是在大型、復雜的項目中,依賴關系可能跨越多個子系統,使得正確的優先級設置變得異常困難。</p>
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? </div>
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? </div>
? ? ? ? ? ? ? ? ? ? ? ? ? ? </div>
? ? ? ? ? ? ? ? ? ? ? ? ? ? <div class="accordion-item border border-slate-200 rounded-lg">
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? <button class="accordion-header w-full flex justify-between items-center p-4 text-left font-semibold text-slate-800 bg-slate-100 hover:bg-slate-200 transition-colors">
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? <span>演進方向一:延遲初始化 (Deferred Init)</span>
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? <svg class="w-5 h-5 transform transition-transform" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"></path></svg>
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? </button>
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? <div class="accordion-content">
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? <div class="p-4 border-t border-slate-200 text-slate-600">
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?<p><strong>方案:</strong> 允許某些設備在啟動時不自動初始化。應用程序可以在運行時,當條件成熟時(例如,電源已穩定、所需資源已可用),手動調用其初始化函數。</p>
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?<p class="mt-2"><strong>優勢:</strong> 這對于需要動態電源管理的設備或共享資源的場景非常有用,提供了更大的靈活性,避免了在不適宜的時候強制初始化。</p>
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? </div>
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? </div>
? ? ? ? ? ? ? ? ? ? ? ? ? ? </div>
? ? ? ? ? ? ? ? ? ? ? ? ? ? <div class="accordion-item border border-slate-200 rounded-lg">
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? <button class="accordion-header w-full flex justify-between items-center p-4 text-left font-semibold text-slate-800 bg-slate-100 hover:bg-slate-200 transition-colors">
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? <span>演進方向二:利用Devicetree序數</span>
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? <svg class="w-5 h-5 transform transition-transform" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"></path></svg>
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? </button>
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? <div class="accordion-content">
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? <div class="p-4 border-t border-slate-200 text-slate-600">
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? <p><strong>方案:</strong> 探索使用設備樹(Devicetree)來更明確地聲明設備間的依賴關系。構建系統可以解析這些依賴,并自動生成正確的初始化順序,而不是依賴開發者手動設置的數字優先級。</p>
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? <p class="mt-2"><strong>優勢:</strong> 將依賴管理從命令式(手動設置優先級)轉變為聲明式(聲明依賴關系),這是一種更健壯、更不易出錯的方法,可以大大提高系統的可靠性和可維護性。</p>
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? </div>
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? </div>
? ? ? ? ? ? ? ? ? ? ? ? ? ? </div>
? ? ? ? ? ? ? ? ? ? ? ? </div>
? ? ? ? ? ? ? ? ? ? `
? ? ? ? ? ? ? ? },
? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? id: 'summary',
? ? ? ? ? ? ? ? ? ? title: '6. 總結與最佳實踐',
? ? ? ? ? ? ? ? ? ? content: `
? ? ? ? ? ? ? ? ? ? ? ? <h3 class="text-2xl font-bold text-slate-800 mb-4">總結與關鍵啟示</h3>
? ? ? ? ? ? ? ? ? ? ? ? <p class="mb-6 text-slate-600 leading-relaxed">通過本次交互式探索,我們揭示了Zephyr RTOS中<code>dsp_acts_init</code>函數的完整調用路徑:它始于<code>DEVICE_DEFINE</code>的靜態注冊,經過初始化級別和優先級的分類,由鏈接器進行編譯時排序,最終在系統啟動過程中被內核按預定順序精確調用。這個自動化機制是Zephyr高效和可預測性的關鍵。</p>
? ? ? ? ? ? ? ? ? ? ? ??
? ? ? ? ? ? ? ? ? ? ? ? <div class="bg-sky-50 border-l-4 border-sky-400 p-6 rounded-r-lg">
? ? ? ? ? ? ? ? ? ? ? ? ? ? <h4 class="text-xl font-semibold text-sky-900 mb-3">開發者最佳實踐</h4>
? ? ? ? ? ? ? ? ? ? ? ? ? ? <ul class="list-disc list-inside space-y-2 text-sky-800">
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? <li><strong>深入理解級別與優先級:</strong> 仔細選擇初始化級別和優先級,確保所有依賴項(如時鐘、PINMUX、總線控制器)都已就緒。</li>
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? <li><strong>顯式管理依賴:</strong> 在文檔或代碼注釋中明確記錄驅動的依賴關系。在復雜的系統中,優先考慮使用設備樹來聲明依賴,而不是僅僅依賴優先級數字。</li>
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? <li><strong>擁抱未來機制:</strong> 關注Zephyr社區關于延遲初始化和設備樹序數等新機制的進展,并適時采用它們來構建更健壯、更靈活的系統。</li>
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? <li><strong>利用日志與調試:</strong> 當遇到初始化問題時,善用日志系統在初始化函數中打印關鍵信息,這是定位優先級沖突或資源未就緒問題的最有效方法。</li>
? ? ? ? ? ? ? ? ? ? ? ? ? ? </ul>
? ? ? ? ? ? ? ? ? ? ? ? </div>
? ? ? ? ? ? ? ? ? ? `
? ? ? ? ? ? ? ? },
? ? ? ? ? ? ];
? ? ? ? ? ? let activeLink = null;
? ? ? ? ? ? let priorityChartInstance = null;
? ? ? ? ? ??
? ? ? ? ? ? // Generate Nav and Content
? ? ? ? ? ? contentData.forEach((item, index) => {
? ? ? ? ? ? ? ? // Create Nav Link
? ? ? ? ? ? ? ? const navItemContainer = document.createElement('div');
? ? ? ? ? ? ? ? navItemContainer.className = 'flex items-center w-full';
? ? ? ? ? ? ? ? const navLink = document.createElement('a');
? ? ? ? ? ? ? ? navLink.href = `#${item.id}`;
? ? ? ? ? ? ? ? navLink.id = `nav-${item.id}`;
? ? ? ? ? ? ? ? navLink.className = 'nav-link flex-grow pl-4 pr-2 py-2 border-l-4 border-transparent hover:bg-slate-100 transition-colors rounded-r-md';
? ? ? ? ? ? ? ? navLink.innerHTML = `<span class="text-slate-700">${item.title}</span>`;
? ? ? ? ? ? ? ? navLink.addEventListener('click', (e) => {
? ? ? ? ? ? ? ? ? ? e.preventDefault();
? ? ? ? ? ? ? ? ? ? setActiveSection(item.id);
? ? ? ? ? ? ? ? ? ? // Smooth scroll for better UX on mobile where content is below
? ? ? ? ? ? ? ? ? ? document.getElementById(item.id).scrollIntoView({ behavior: 'smooth', block: 'start' });
? ? ? ? ? ? ? ? });
? ? ? ? ? ? ? ? const dot = document.createElement('div');
? ? ? ? ? ? ? ? dot.className = 'flow-dot -ml-1.5 z-10';
? ? ? ? ? ? ? ??
? ? ? ? ? ? ? ? navItemContainer.appendChild(dot);
? ? ? ? ? ? ? ? navItemContainer.appendChild(navLink);
? ? ? ? ? ? ? ? navContainer.appendChild(navItemContainer);
? ? ? ? ? ? ? ??
? ? ? ? ? ? ? ? if (index < contentData.length - 1) {
? ? ? ? ? ? ? ? ? ? const line = document.createElement('div');
? ? ? ? ? ? ? ? ? ? line.className = 'flow-line';
? ? ? ? ? ? ? ? ? ? navContainer.appendChild(line);
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? // Create Content Section
? ? ? ? ? ? ? ? const section = document.createElement('section');
? ? ? ? ? ? ? ? section.id = item.id;
? ? ? ? ? ? ? ? section.className = 'content-section';
? ? ? ? ? ? ? ? section.innerHTML = item.content;
? ? ? ? ? ? ? ? contentContainer.appendChild(section);
? ? ? ? ? ? });
? ? ? ? ? ? // Accordion Logic
? ? ? ? ? ? document.querySelectorAll('.accordion-header').forEach(button => {
? ? ? ? ? ? ? ? button.addEventListener('click', () => {
? ? ? ? ? ? ? ? ? ? const content = button.nextElementSibling;
? ? ? ? ? ? ? ? ? ? const icon = button.querySelector('svg');
? ? ? ? ? ? ? ? ? ? button.parentElement.classList.toggle('open');
? ? ? ? ? ? ? ? ? ? icon.classList.toggle('rotate-180');
? ? ? ? ? ? ? ? ? ? if (content.style.maxHeight) {
? ? ? ? ? ? ? ? ? ? ? ? content.style.maxHeight = null;
? ? ? ? ? ? ? ? ? ? } else {
? ? ? ? ? ? ? ? ? ? ? ? content.style.maxHeight = content.scrollHeight + "px";
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? });
? ? ? ? ? ? });
? ? ? ? ? ? function setActiveSection(id) {
? ? ? ? ? ? ? ? if (activeLink) {
? ? ? ? ? ? ? ? ? ? activeLink.classList.remove('active');
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? document.querySelectorAll('.content-section').forEach(section => {
? ? ? ? ? ? ? ? ? ? section.classList.remove('active');
? ? ? ? ? ? ? ? });
? ? ? ? ? ? ? ? document.querySelectorAll('.nav-link').forEach(link => {
? ? ? ? ? ? ? ? ? ? link.classList.remove('active');
? ? ? ? ? ? ? ? });
? ? ? ? ? ? ? ? const newActiveSection = document.getElementById(id);
? ? ? ? ? ? ? ? const newActiveLink = document.getElementById(`nav-${id}`);
? ? ? ? ? ? ? ? if (newActiveSection && newActiveLink) {
? ? ? ? ? ? ? ? ? ? newActiveSection.classList.add('active');
? ? ? ? ? ? ? ? ? ? newActiveLink.classList.add('active');
? ? ? ? ? ? ? ? ? ? activeLink = newActiveLink;
? ? ? ? ? ? ? ? ? ? if (id === 'priority') {
? ? ? ? ? ? ? ? ? ? ? ? renderPriorityChart();
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? ? ??
? ? ? ? ? ? function renderPriorityChart() {
? ? ? ? ? ? ? ? const ctx = document.getElementById('priorityChart');
? ? ? ? ? ? ? ? if (!ctx) return;
? ? ? ? ? ? ? ??
? ? ? ? ? ? ? ? if (priorityChartInstance) {
? ? ? ? ? ? ? ? ? ? priorityChartInstance.destroy();
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? const data = {
? ? ? ? ? ? ? ? ? ? labels: ['PINMUX', 'CLOCK_CONTROL', 'DSP (本例)', 'I2C Controller', 'Sensor Driver'],
? ? ? ? ? ? ? ? ? ? datasets: [{
? ? ? ? ? ? ? ? ? ? ? ? label: 'POST_KERNEL 初始化優先級 (值越小越高)',
? ? ? ? ? ? ? ? ? ? ? ? data: [45, 48, 50, 60, 80],
? ? ? ? ? ? ? ? ? ? ? ? backgroundColor: [
? ? ? ? ? ? ? ? ? ? ? ? ? ? 'rgba(56, 189, 248, 0.6)', // sky-400
? ? ? ? ? ? ? ? ? ? ? ? ? ? 'rgba(56, 189, 248, 0.6)',
? ? ? ? ? ? ? ? ? ? ? ? ? ? 'rgba(251, 146, 60, 0.7)', // orange-400
? ? ? ? ? ? ? ? ? ? ? ? ? ? 'rgba(165, 180, 252, 0.6)', // indigo-300
? ? ? ? ? ? ? ? ? ? ? ? ? ? 'rgba(165, 180, 252, 0.6)',
? ? ? ? ? ? ? ? ? ? ? ? ],
? ? ? ? ? ? ? ? ? ? ? ? borderColor: [
? ? ? ? ? ? ? ? ? ? ? ? ? ? 'rgba(14, 165, 233, 1)',
? ? ? ? ? ? ? ? ? ? ? ? ? ? 'rgba(14, 165, 233, 1)',
? ? ? ? ? ? ? ? ? ? ? ? ? ? 'rgba(249, 115, 22, 1)',
? ? ? ? ? ? ? ? ? ? ? ? ? ? 'rgba(99, 102, 241, 1)',
? ? ? ? ? ? ? ? ? ? ? ? ? ? 'rgba(99, 102, 241, 1)',
? ? ? ? ? ? ? ? ? ? ? ? ],
? ? ? ? ? ? ? ? ? ? ? ? borderWidth: 1
? ? ? ? ? ? ? ? ? ? }]
? ? ? ? ? ? ? ? };
? ? ? ? ? ? ? ? priorityChartInstance = new Chart(ctx, {
? ? ? ? ? ? ? ? ? ? type: 'bar',
? ? ? ? ? ? ? ? ? ? data: data,
? ? ? ? ? ? ? ? ? ? options: {
? ? ? ? ? ? ? ? ? ? ? ? indexAxis: 'y',
? ? ? ? ? ? ? ? ? ? ? ? maintainAspectRatio: false,
? ? ? ? ? ? ? ? ? ? ? ? responsive: true,
? ? ? ? ? ? ? ? ? ? ? ? plugins: {
? ? ? ? ? ? ? ? ? ? ? ? ? ? legend: {
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? display: false
? ? ? ? ? ? ? ? ? ? ? ? ? ? },
? ? ? ? ? ? ? ? ? ? ? ? ? ? title: {
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? display: true,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? text: '常見驅動的初始化優先級對比',
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? font: {
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? size: 16
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? },
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? color: '#334155'
? ? ? ? ? ? ? ? ? ? ? ? ? ? },
? ? ? ? ? ? ? ? ? ? ? ? ? ? tooltip: {
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? callbacks: {
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? label: function(context) {
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? return ` 優先級: ${context.raw} (數值越小, 越早執行)`;
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? ? ? },
? ? ? ? ? ? ? ? ? ? ? ? scales: {
? ? ? ? ? ? ? ? ? ? ? ? ? ? x: {
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? beginAtZero: true,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? title: {
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? display: true,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? text: '優先級數值'
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? });
? ? ? ? ? ? }
? ? ? ? ? ? // Set initial state
? ? ? ? ? ? setActiveSection('intro');
? ? ? ? });
? ? </script>
</body>
</html>