使用範例
九個情境,由簡單到完整。每個範例都有:你對 AI 說的話、AI 會用到哪些工具、你該注意看什麼,
以及兩張圖——左邊是 AI 工具的對話,右邊是同一時刻的 nexus 畫面(狀態列有 MCP:<n>,Log 有
[mcp] 開頭的行)。
範例用的 AI 工具是 Claude Code,換成別的 AI 工具,工具呼叫的內容一樣。 註冊方式見安裝與註冊。
標「示意」的範例(5 與 8)使用的是示範用的暫存器定義檔與一段示意性的韌體程式碼, 不是任何廠商的真實檔案;網站上不會出現廠商的定義檔內容。
範例 1:讀晶片 ID
你說:
用 nexus 讀一下目前這顆晶片 0x00 開始的 16 個暫存器,告訴我晶片 ID 是什麼。AI 用到的工具: get_status(確認目前分頁與位址)→ get_commands(確認 rd 的用法)→
nexus_exec(rd 0x00 16)。
看什麼: AI 先查指令表才下指令,不是亂猜語法;nexus 的 Log 面板會依序出現
[mcp] rd 0x00 16 與 [mcp] -> ... 的結果行,內容和你自己下 rd 一模一樣。

![nexus 畫面:Log 面板出現 [mcp] rd 0x00 16 與結果,狀態列顯示 MCP:1](/img/mcp/ex1-host.png)
範例 2:人機協作——你改值,AI 看見
你說:
我等一下會在 nexus 裡手動改 0x10 的值。你用 wait_event 等到 Log 出現寫入的紀錄,
然後讀快取確認改成了什麼。AI 用到的工具: get_log(取得目前的序號)→ wait_event(source: log,等含 0x10 的新紀錄)→
get_reg_snapshot(讀快取確認)。
看什麼: 你在畫面上用 wr 0x10 0x85 改值的那一刻,AI 那邊的 wait_event 就回來了;
接著它讀到的快取值與你寫的一致。AI 全程沒有碰匯流排——它只是看 Log 與快取。你切到別的分頁
操作也不影響它。


範例 3:dump diff——找出改動前後的差異
你說:
先 dump 一份目前的暫存器存成檔案當 baseline,我去按一下設備上的按鈕,之後你再跟
baseline 比對,告訴我哪些位元變了。AI 用到的工具: nexus_exec(dump all 存 baseline,結果的 files[] 會列出檔案的絕對路徑)→
(等你操作)→ nexus_exec(dump diff <baseline 路徑>,它會讀回目前的值再逐位元組比對)→ read_file(把差異報告讀進對話)。
需要自己寫檔時用 write_file。
看什麼: 指令產生的檔案路徑會直接出現在工具回傳的 files 裡,AI 不用猜檔名;
read_file 只讀得到 logs\ 底下的檔案。


範例 4:AI 寫 Lua,跑起來,看結果,修正
你說:
寫一支 Lua:把 0x20 寫成 0x5A 再讀回來比對,不一致就判定失敗。存起來跑跑看,
失敗的話自己改到通過。AI 用到的工具: write_file(存到 logs\mcp\verify.lua,回傳絕對路徑)→ nexus_exec
(run <絕對路徑>)→ 讀回傳的 PASS/FAIL 摘要 → 有問題就改寫再 write_file → 重跑。
腳本卡住時它會用 nexus_abort 中止。
看什麼: 腳本是寫在 logs\mcp\ 裡的,你可以隨時打開來看它寫了什麼;Lua 腳本的結束摘要
(check() 的通過/失敗)就是它判斷成敗的依據。Lua 的寫法見Lua 自動化。


範例 5:用暫存器定義檔輔助 debug(示意)
這個範例用的是示範用的暫存器定義檔,不是真實晶片的資料。
前提: 該分頁已載入暫存器定義檔(見面板裡的 REGDEF)。
你說:
解讀目前 bank 的暫存器,哪個欄位的值看起來不合理?不確定的地方直接說不確定。AI 用到的工具: get_status(確認有載入定義檔)→ nexus_exec(dump 先把值讀進快取)→
get_regdef_decoded(用定義檔解碼:欄位名稱、列舉名稱、目前的檢視)。
看什麼: 沒有讀過的暫存器,AI 看到的是「沒有值」,不是 0;有「條件檢視」的暫存器,
如果決定檢視的那個暫存器沒讀過,檢視會標成 unknown,並套用預設檢視。AI 不會為了回答而去碰
匯流排——這就是為什麼它要先 dump。


範例 6:UART——送出文字,等韌體回應
你說:
開著的 UART 面板上,送一個 "PING" 給裝置,等它回含 "PONG" 的一行,告訴我回了什麼。AI 用到的工具: get_status(確認 UART 面板與埠已開)→ get_log(取得目前序號)→
nexus_exec(uart send "PING\n")→ wait_event(source: uart,contains: PONG)。
看什麼: uart send 與你按 UART 面板的巨集是同一條路徑;wait_event 在回應到達的當下就回來,
不需要 AI 一直輪詢。UART 紀錄的時間戳與 Log 是同一個時間基準,可以對照。


範例 7:Plugin 面板——讀狀態、按按鈕
你說:
看一下目前 Plugin 面板上有哪些控件,把「Enable」勾起來,然後按「Apply」,
告訴我 Plugin 回報了什麼。AI 用到的工具: get_plugin_widgets(列出控件與目前的值)→ set_plugin_widget
(value: true 勾選;activate: true 按按鈕)→ get_log(用回傳的 cmd_id 讀 Plugin 因此寫的 Log)。
看什麼: AI 的操作和你用滑鼠點是同一條路徑,Plugin 無法分辨;控件的 id 不是座標, 所以不受視窗大小影響。使用 Canvas 自繪的 Plugin 面板沒有控件可讀,AI 會得到「不支援」的回覆。

![nexus 畫面:Plugin 面板的控件狀態已改變,Log 有 [mcp] widget 的行](/img/mcp/ex7-host.png)
範例 8:韌體 debug(示意)
最完整的情境:把 Claude Code 開在 MCU 韌體的原始碼資料夾,讓 AI 同時看得到韌體原始碼與 裝置實際的 UART log 與暫存器。這個範例的韌體片段與 UART 輸出是示意用的, UART 由模擬後端產生資料。
你說:
這個韌體資料夾是我們的 MCU 程式。用 nexus 掃一下 UART 埠、開起來收 log,
等它出現 "LINK LOST" 時,把當下的暫存器狀態抓下來。然後對照原始碼,
說明這個 log 是哪一行 printf 印的、當下裝置處於什麼狀態。AI 的做法:
nexus_exec:uart scan,再uart <埠> <鮑率>開埠收 log。- 事件發生的當下,AI 一來一回是「秒」級,狀態早就變了。所以它寫一支 Lua
(
write_file):用uart.expect("LINK LOST", 30000)等到那一行,立刻dump()抓暫存器; 腳本以毫秒級反應。用nexus_exec跑run。 nexus_exec:uart export——大量 UART log 不逐筆傳進對話,而是匯出成logs\下的檔案, AI 直接對檔案 grep,再到原始碼資料夾找對應的printf。- 需要寫入受保護的暫存器時,先
password <晶片>解鎖,再用rd/wr驗證它的推論。
示意的 Lua(logs\mcp\capture.lua):
i2c.addr(0x58)
local line = uart.expect("LINK LOST", 30000) -- 逾時回傳 nil
if line then
dump() -- 事件當下的 256 位元組
else
log("warn", "no LINK LOST within 30 s")
end看什麼: 暫存器快照是「事件發生當下」的,不是 AI 回頭去讀的;uart export 回傳的檔案路徑
出現在 files 裡;AI 把 log 內容與原始碼對起來說明。

![nexus 畫面:UART 面板的 LINK LOST,Log 面板有 [mcp] uart export 與 run](/img/mcp/ex8-host.png)
範例 9:操作 TERM(UART/SSH 終端)
AI 可以看你的 TERM 面板畫面,也可以在裡面打字——但只限於你已經開好、連好的那一個。
先決條件(要你自己做): AI 不能替你連線,term open/term close 對 AI 一律被拒絕。
請先在要用的分頁放好 TERM 面板,並自己連上:
term open ssh demo-board或序列埠:
term open uart COM11 115200連上、看到 shell 提示字元之後,再交給 AI。沒連線時 term_read 會回 connected:false,term_send 會回
「the TERM is not connected」;分頁根本沒有 TERM 面板則兩者都回「no TERM panel」。
9.1 看畫面,幫我整理
你說:
看一下 nexus 的 TERM 現在畫面上有什麼,用兩三句話整理給我。AI 用到的工具: term_read
{"tool": "term_read", "args": {}}回覆(示意,合成資料;節錄,實際 lines 有 rows 筆,空列為 ""):
{
"tab": 0, "connected": true, "source": "ssh", "target": "demo-board",
"cols": 100, "rows": 24, "cursor": {"row": 3, "col": 19},
"lines": [
"demo@demo-board:~$ ls",
"firmware logs notes.txt",
"demo@demo-board:~$ cat notes.txt",
"demo@demo-board:~$ "
]
}lines 是畫面上每一列的純文字(沒有顏色,列尾空白已去掉,全形字只出現一次),cursor 是游標的列/欄(從 0 起算)。
只有「現在看得到的畫面」,沒有回捲的內容。
9.2 跑一個指令,讀結果
你說:
在 TERM 裡執行 uname -a,把結果告訴我。AI 用到的工具: term_send → (稍等)→ term_read
{"tool": "term_send", "args": {"text": "uname -a\r"}}回覆:{"sent": 9}。Enter 要寫成 JSON 的 \r。指令送出後輸出是非同步到達的,AI 會等一下再讀畫面:
{"tool": "term_read", "args": {}}{"lines": ["demo@demo-board:~$ uname -a",
"Linux demo-board 6.1.0-demo #1 SMP aarch64 GNU/Linux",
"demo@demo-board:~$ "], "cursor": {"row": 2, "col": 19}}(節錄。)AI 看到提示字元回來、游標停在新的一列,就知道指令跑完了。
9.3 查核心訊息有沒有錯誤
你說:
在 TERM 裡看 dmesg 最後 30 行有沒有 error 或 fail,有的話告訴我是哪幾行。AI 送出 {"text": "dmesg | tail -n 30\r"},再 term_read 讀畫面並挑出可疑的列。輸出超過一個畫面時,AI 應該改用
dmesg | grep -i -E 'error|fail' | tail -n 20,讓結果留在畫面內。
9.4 卡住的指令:Ctrl+C
你說:
剛剛那個 ping 一直不停,幫我停掉。Ctrl+C 是控制字元 0x03,在 JSON 裡寫成 \u0003:
{"tool": "term_send", "args": {"text": "\u0003"}}再 term_read 確認提示字元回來了。其他常用的:Tab 補全 \t、離開 exit\r、Ctrl+D \u0004、方向鍵上 \u001b[A。
9.5 序列埠:在 getty 登入提示登入
你說:
TERM 連著板子的序列埠,停在 login 提示。用帳號 demo 登入,密碼我來輸入,你先送帳號就好。AI 送 {"text": "demo\r"},用 term_read 確認出現 Password:,然後停下來等你自己在 TERM 面板打密碼。
不要把密碼交給 AI 去 term_send:雖然 Log 只記位元組數,但 AI 的對話紀錄裡會有密碼。
注意事項
- 打字之後要再讀:
term_send回sent只表示位元組已排進傳輸佇列,輸出之後才會出現。讀到的畫面還沒變就稍等再term_read, 不要連續重送同一個指令。 - 序列埠的終端大小:Linux 序列埠 console 不會自動知道面板有多大。畫面折行怪怪的,請在 TERM 裡執行
stty rows <列> cols <欄>(數字看面板標題的欄×列)或eval $(resize)。SSH 連線會自動同步,不用管。 - 很長的輸出:
term_read只回目前看得到的畫面。要完整的內容,請 AI 在 shell 裡先導向檔案、或使用 TERM 的 session 記錄 (回捲與 session 記錄功能上線後,檔案在logs\底下),再用read_file讀。 - 風險:
term_send等於 AI 直接在你登入的 shell 打字,包括sudo、rm、reboot。nexus 不攔、不確認; Log 面板只看得到[mcp] term_send 9 bytes(只記位元組數,不記內容,避免密碼進 Log),所以你要看實際做了什麼,請看 TERM 面板本身。 不想讓 AI 碰就不要核准term_send的呼叫,或用mcp off。
之後
- 想讓 AI 做更多事,先讓它呼叫
get_commands——它會看到你這個版本實際有哪些指令。 - GPIO 沒有對應的指令,只能從 Lua 的
gpio.*操作,請 AI 寫腳本。 - Lua 的函式不在
get_commands的指令表裡,完整參考見API 參考。AI 常踩的幾個坑:uart.expect()用的是 Lua pattern,[ ] ( ) . % - + * ? ^ $要用%跳脫,例如"En%[0%]"。run回rc 0只代表腳本已入列;結果看 Log 最後一行:Script PASSED、Script FAILED、Script error加Script INCOMPLETE(執行期錯誤)或Script ABORTED。rd <位移> <數量>的數量是十六進位:rd 0x00 16讀的是 22 個位元組。uart send原樣送出文字,再附加該 UART 面板目前的 TX 換行模式(預設 CRLF,可在面板改;get_status的uart.tx_newline會回報)。沒有指令能設定這個模式,要精確的位元組就用 Lua 的uart.write("...")。HEX 模式下文字必須是成對十六進位;模式為 none 時uart send ""會被拒絕。- 已掛載的 widget Plugin 可能攔截部分指令(例如
tab 2);指令沒作用時先看 Log。
- 回頭看概念與安全須知,確認你知道 AI 能做什麼。