Mob.VendorUsb: Android USB host peripheral#5
Conversation
Flat-ns module. Wraps UsbManager for bulk-transfer from Elixir. iOS = unsupported envelope (no host API). Files: - lib/mob/vendor_usb.ex — 7-fn API + normalize_message - test/mob/vendor_usb_test.exs — 10 tests, all pass - src/mob_nif.erl — 7 NIF stubs - android/jni/mob_nif.c — 7 NIFs + 6 delivery fns + jmethodID cache - android/jni/mob_beam.h — 6 extern decls - ios/mob_nif.m — 7 unsupported stubs - lib/mob/screen.ex — handle_info routes through normalize_message Tested e2e: macOS iex → Android BEAM → JNI → UsbManager → AtomVM ESP32 → TX-AH HaLow at 908 MHz. Full lifecycle works.
|
Thanks for this — the design is solid (lifecycle, error envelopes, try/catch convention, normalize_message routing through screen.ex all match the existing peripheral patterns). However, this can't merge as-is because of a structural change that landed after this PR was opened: The Android NIF surface migrated from C to Zig. In commit Concretely:
The cleanest path is probably to rebase your branch on current master and port Happy to pair on the port if you'd like — open to suggestions. Marking as needing rebase rather than closing. |
|
Filed #6 with the full porting plan — what changed, what to port, what's already clean, and the test hardware caveat. Someone (an agent or yourself) will pick that up against current master; this PR will be the natural home for the rebased branch when ready. |
|
FYI — the Zig port landed as |
|
Closing — both sides of the vendor_usb contribution have now landed:
End-to-end USB lifecycle still gated on your hardware rig (HaLow modem + ESP32). The cacheOptional design from the Zig port means existing apps on the unmodified template degrade to `:unsupported` events rather than crashing, so the templates merge is a strict improvement. Thanks again for the work. The peripheral patterns you established (lifecycle envelope shape, try/catch fallback convention, normalize_message routing) are now standard for any future device-host transports we add. |
Four small lost-in-the-shuffle items closed in this batch. All four were held up by Phase 2 work touching the same files (#1/#2/#4 in live_view_patcher.ex; #5 in native_build.ex). #1 — Phoenix LiveReload mac_listener warnings: code_reloader/watchers/ live_reload disabled in on-device endpoint config. #2 — esbuild/tailwind version-not-configured warnings: versions set via Application.put_env in mob_app.ex before ensure_all_started. #4 — port 4200 collisions across multiple Mob LV apps: per-app hash into 4200..4999 via :erlang.phash2(:<app>, 800). #5 — deploy auto-pick of iPhone over sim was silent: prints the --device <short-id> alternative when both are connected. #3 (WS→longpoll fallback in WKWebView) is investigation, not a fix — deferred. #6-#11 are larger work (OTP rebuild, AX modifiers, Compose semantics walker, Android 17 SELinux patch). #12, #13 already fixed earlier. #14 is moderate — sim node naming reconciliation between mob_dev's connect.ex and mob_beam.m, deferred.
Flat-ns
Mob.VendorUsb. Wrap AndroidUsbManagerbulk-transfer for Elixir. iOS ={:peripheral, :vendor_usb, :error, nil, :unsupported}(no host API; useMob.Blefor iOS-equivalent hardware).Companion templates PR in
mob_new.API
Async socket-in/out + handle_info, matches camera/clipboard/audio convention.
Events:
{:peripheral, :vendor_usb, tag, session, payload}.Files
lib/mob/vendor_usb.ex— API +normalize_message/1test/mob/vendor_usb_test.exs— 10 tests passsrc/mob_nif.erl— 7 NIF stubsandroid/jni/mob_nif.c— 7 NIFs + 6 delivery fns + jmethodID cacheandroid/jni/mob_beam.h— 6 extern decls (after webview block)ios/mob_nif.m— 7 unsupported stubslib/mob/screen.ex— handle_info routes throughnormalize_message/1Robustness
Two layers, both load-bearing:
@JvmStatic vendor_usb_*wrapped in try/catch → error envelope. Matches existing camera/audio convention. Unhandled JVM exception in JNI = BEAM dies, no crash dump. Defense caught 2 nil-bugs during testing.:json.encode.:json.encodeturns Elixirnilinto JSON string\"nil\"not JSONnull. KotlingetIntchoke on string. Same bug class twice (list_devices + open) before we patched both layers.Tested
Full lifecycle. AT commands round-trip. Broadcast frames transmit. OTP 28.5 / Elixir 1.19.5-otp-28.