feat: expose dongle debug info through the C API

Add an opaque xone_dongle session handle to the C ABI bridge:
xone_open() probes, resets, and loads the firmware (path optional),
and xone_pid/xone_chip_id/xone_mac_address/xone_firmware_build return
debug info for the open session. chip captures the firmware build
string from the image header during load.

The Swift app opens a session when the dongle appears and shows PID,
chip ID, MAC address, and firmware build string in a debug section.

Co-Authored-By: qwen3.8-27b@q2_k_xl: added C API session handle and debug UI
This commit is contained in:
portersky
2026-08-17 16:44:02 +02:00
parent 21dc0e09b3
commit 4f5f16e43f
6 changed files with 153 additions and 5 deletions
+39 -1
View File
@@ -26,6 +26,7 @@ final class AppDelegate: NSObject, NSApplicationDelegate {
struct ContentView: View {
@State private var donglePresent = false
@State private var session: OpaquePointer? = nil
private let timer = Timer.publish(every: 1.0, on: .main, in: .common)
.autoconnect()
@@ -42,6 +43,10 @@ struct ContentView: View {
statusView
if let session {
debugView(session)
}
Divider()
controllersView
@@ -62,10 +67,43 @@ struct ContentView: View {
.frame(width: 420)
.frame(minHeight: 320)
.onReceive(timer) { _ in
donglePresent = xone_dongle_present()
let present = xone_dongle_present()
if present && session == nil {
session = xone_open("firmware/xow_dongle.bin")
} else if !present, let s = session {
xone_close(s)
session = nil
}
donglePresent = present
}
}
private func debugView(_ session: OpaquePointer) -> some View {
VStack(alignment: .leading, spacing: 4) {
Text("Debug")
.font(.headline)
debugRow("PID", String(format: "0x%04X", xone_pid(session)))
debugRow("Chip ID", String(format: "0x%04X", xone_chip_id(session)))
debugRow("MAC", String(cString: xone_mac_address(session)))
debugRow("Firmware", firmwareBuildText(session))
}
}
private func debugRow(_ label: String, _ value: String) -> some View {
HStack {
Text(label)
.foregroundStyle(.secondary)
Spacer()
Text(value)
.font(.system(.body, design: .monospaced))
}
}
private func firmwareBuildText(_ session: OpaquePointer) -> String {
let build = String(cString: xone_firmware_build(session))
return build.isEmpty ? "not loaded" : build
}
private var statusView: some View {
HStack(spacing: 8) {
Circle()