Dongle 專屬功能(ABI 4.1)
有些 dongle(例如 STM32 dongle)除了一般 I2C 讀寫,還提供
外部中斷(INT)邊緣事件、匯流排恢復、微秒級 GPIO 脈衝和自述的廠商操作(vendor op)。
ABI 4.1 把它們開放給 Plugin;全部在 IcPlugin/NxHostApi 結尾追加,
4.0 的 Plugin 不用重編就能在 4.1 主程式上跑。
用之前先確認主程式有這個欄位,不要比較 abi_minor:
if (NX_ABI_HAS_FIELD(s_host->size_of_struct, NxHostApi, IntConfigure)) { /* 4.1 以上 */ }這些服務都要 dongle 支援,不支援的回 ERR_NOT_SUPPORTED。只能在 I2C Worker 的 callback 內呼叫
(probe、poll_fn、自訂指令、on_widget_event、on_tick、on_int_event);
在 UI Thread(例如 init)呼叫回 ERR_WRONG_THREAD,不會碰硬體。
INT 邊緣事件
IC 的中斷輸出接到 dongle 的 INT 腳時,不用輪詢暫存器,dongle 會替每個邊緣記一筆帶時間戳的事件:
/* probe() 裡 */
if (NX_ABI_HAS_FIELD(s_host->size_of_struct, NxHostApi, IntConfigure))
(void)s_host->IntConfigure(ctx, NX_INT_EDGE_FALLING, NX_INT_PULL_UP);
/* 在 NexusPluginGetInterface() 把 on_int_event 指到這個函式 */
static void NX_CALL my_on_int_event(NxPluginCtx ctx, const NxIntEvent *ev,
NxDword count, NxDword dropped)
{
if (dropped) s_resync = 1; /* 有邊緣缺漏:重讀一次 IC 的狀態暫存器 */
/* ev[i].level 是邊緣之後的電位;ev[i].t_us 是 dongle 本地微秒 */
}要記住的幾件事:
- 時間戳不是時鐘。
t_us是 dongle 本地的 32 位元微秒計數,約 71.6 分鐘繞回一次; 算兩個邊緣的間隔一律(NxDword)(b.t_us - a.t_us)。絕對時間只能用rx_tick(主程式讀回該批時的毫秒計時)估計,誤差可以很大。 - INT 線只有一條,設定是合併的。 同一個後端上所有請求者(Plugin、
dongle int config指令、Lua 腳本)的請求合併後才套用:邊緣取聯集, 上下拉取第一個非NONE的。所以你可能收到自己沒要求的邊緣,請依level過濾。NX_INT_EDGE_NONE只釋放你自己的請求,Plugin 卸載或下線時也會自動釋放,不必在cleanup手動關。 - 事件廣播。 同一個後端上所有實作
on_int_event的 Plugin 各收一份;events只在 callback 期間有效。 dropped是增量。 非零代表這一批和上一批之間有邊緣缺漏。- 有 INT 時
poll_fn不會自動停。 請在poll_fn內自行節流,或保留慢速保險輪詢——INT 涵蓋不全的 IC、 多顆 IC 共線(wired-OR)的 INT 線漏掉的邊緣都需要它。SetPollingInterval目前回ERR_NOT_IMPLEMENTED,不能用它停輪詢。 poll off時不取事件。 事件取回本身是主程式在背景輪詢 dongle,受poll off管制;poll on後一次交出累積的事件,超出容量的計入dropped。
IntGetStatus 讀目前設定、電位與 dongle 端累計計數(呼叫前先填 SizeOfStruct),IntClear 清計數與未取走的事件
(不檢查擁有權,會影響同後端其他 Plugin 還沒處理的事件)。
匯流排恢復與 GPIO 脈衝
NxDword pins = 0;
if (s_host->BusRecover(ctx, &pins) == ERR_OK && (pins & 3) == 3) { /* SCL、SDA 都已釋放 */ }
/* 腳 1 已用 GpioConfigure(..., NX_PIN_FUNC_GPIO_OUT, ...) 持有 */
s_host->GpioPulse(ctx, 1, 1, 2000); /* 高電位 2000 微秒 */BusRecover的ERR_OK只代表「動作做完」,不代表線已釋放,要檢查out_pins。GpioPulse呼叫期間這條匯流排的 Worker 被佔住(其他 Job 與 callback 都得等)。API 的寬度範圍是1~1000000微秒, 實際範圍看 dongle:STM32 dongle 是 1 微秒~699 毫秒,超出回ERR_INVALID_PARAM,不會被縮短。 脈衝結束後的靜止電位由 dongle 決定,主程式的腳位表不更新,需要特定電位請自己再GpioWrite一次。
Vendor op:用名稱呼叫
dongle 自己宣告它支援哪些廠商操作(見硬體頁的目錄表與 dongle op 指令)。
Plugin 用 ExecSync 搭配 NX_JOB_VENDOR,以名稱定址,不必知道 op 代碼:
NxJobRequest req;
NxByte out[64];
memset(&req, 0, sizeof(req));
req.size_of_struct = (NxDword)sizeof(req);
req.op = NX_JOB_VENDOR;
req.vendor_op = "uart_stats";
/* 有參數的 op:req.data/req.length 放依目錄編碼好的 payload(全部小端) */
rc = s_host->ExecSync(ctx, &req, out, (NxWord)sizeof(out));- 只有
ExecSync支援;SubmitJob對NX_JOB_VENDOR回ERR_NOT_SUPPORTED。 - 結果寫進
out整段(結果在前、其餘補0),out_cap必須不小於目錄宣告的最長結果,否則執行前就回ERR_BUFFER_TOO_SMALL。 - 名稱不在目錄裡回
ERR_NOT_SUPPORTED;payload 長度不符回ERR_INVALID_PARAM。 - payload 與結果怎麼編碼,由 dongle 的目錄決定(
dongle op help <名稱>會列出參數與結果欄位)。要免手動編碼,改用 Lua 的dongle.op。
ERR_HW_BUS_PARKED
dongle 的 I2C 腳位可以被切成 GPIO 或方波模式(bus_set、wave 這類 vendor op)。腳位不在 I2C 模式時,
I2C 讀寫回 ERR_HW_BUS_PARKED——這代表裝置健康、只是腳位被借走了,不會被算成離線。
dongle recover 或 BusRecover 會強制切回 I2C 模式。
完整簽章與每個函式的錯誤碼見參考文件; 全部成員的一頁式索引見 Plugin API 地圖。