Skip to Content
Plugin 開發Dongle 專屬功能(ABI 4.1)

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 地圖。