debug
Run your driver's Lua on your own machine while a real controller drives it. Set breakpoints in your IDE, inspect variables, step through handlers, and save a file to have the next event run the new code. No rebuild, no redeploy.
Live debugging is new. If something doesn't behave the way this page describes, tell us.
Usage
driverforge debug [options]
debug swaps your driver on the controller for a small stub and runs your
real source in a Lua process on your machine. Every callback the controller
makes is handed to your local code, and every C4:* call your code makes is
carried out on the controller, with the real result handed back. From your
driver's point of view it is running on the controller; from your debugger's
point of view it is an ordinary local Lua process.
When you're done, Ctrl+C ends the session and
driverforge deploy puts your real driver back.
Prerequisites
- The project is initialised (
driverforge init) - You're signed in (
driverforge login) - A target controller is selected (
driverforge device select) - The Anvil Agent is installed and running on the controller
- A Lua 5.1 interpreter is on your machine. LuaJIT is the easiest to get
(
brew install luajit); the CLI looks forlua5.1,luajitorluaon yourPATH, or uses whatever--luaorDRIVERFORGE_LUApoints at.
When to reach for it
sync is the fast loop when you know what to change. debug is
for when you don't: a handler that misbehaves only with a real device on the
other end, a property change that sets off something you can't see, state that
goes wrong three callbacks in. Instead of adding print statements and
redeploying, you stop at a breakpoint while the controller is talking to your
driver, and look.
How it works
The stub that replaces your driver has no business logic of its own. It
forwards each callback (OnDriverInit, ReceivedFromProxy,
OnPropertyChanged, OnTimerExpired, …) to your machine, and executes the
C4:* calls your code makes in reply.
Both ends connect outbound to Anvil's broker, the same service the Anvil Agent reports to. Your machine never needs a route to the controller once the stub is deployed, so a session works across VLANs and through a customer's firewall just as well as on your own bench.
A session, step by step
- Your driver loads locally first. A driver that fails to load stops the session here, before the controller is touched.
- The stub is built. The CLI builds your project exactly as
deploydoes, then replaces the Lua inside the.c4zwith the stub.driver.xmlis left byte-for-byte as it was, so your bindings, proxies and properties stay put. - The stub is deployed through the agent, like any
deploy. - The controller now drives your local code.
printoutput appears in your terminal; with--verbose, so does everyC4call and its result. - Saving a file reloads your driver in place. Handlers are redefined,
OnDriverInit/OnDriverLateInitdon't re-run, and in-memory state survives: the same rules assync. A file that fails to compile is reported, and the previous code keeps running. - Ctrl+C ends the session. The stub stays on the controller, inert, until
you run
driverforge deploy.
Attaching a debugger
Your driver runs in an ordinary Lua process, so any Lua 5.1 debugger that can attach to one will work.
ZeroBrane Studio, or anything that speaks mobdebug. Start the debugger server in your IDE, then:
luarocks install mobdebug
driverforge debug --mobdebug localhost:8172
VS Code. Point --lua at the debugger-aware interpreter or launcher your
extension provides. The local process talks to the CLI over stdin and stdout,
so your debugger has to use a socket of its own rather than stdio.
Options
| Option | Description |
|---|---|
--device | Controller to debug on (name, hostname, or id); overrides the selected one |
--select | Re-select the target controller first |
--configuration, -c | Build configuration to debug; also selects config.<name>.lua in the local process |
--lua | Lua 5.1 interpreter to run your driver with (default: lua5.1, luajit or lua on PATH) |
--mobdebug | Start mobdebug in the local process and connect it to your IDE at host:port |
--no-reload | Don't reload your driver when source files change |
Examples
Debug on the selected controller:
driverforge debug
Debug the release configuration on a specific controller, showing every C4
call as it happens:
driverforge debug -c release --device "Plant Room" --verbose
Debug under ZeroBrane Studio:
driverforge debug --mobdebug localhost:8172
What's different from running on the controller
Your code is real and so is the controller, but there's a network between them. A few things behave differently because of that:
- Callbacks don't wait for your answer. The controller hands a callback over
and carries on. A handler whose return value the controller uses
(
UIRequest,GetPrivateKeyPassword, theList*family) still runs, but the controller seesnil. - Every
C4:*call is a round trip. Each one travels to the controller and back through the broker, so timing-sensitive code won't behave the way it does in production. - State starts fresh. Swapping the stub in reloads the driver, so anything it
held in memory is gone.
PropertiesandPersistDataare copied to your local process on every callback, but writes toPersistDataaren't saved during a session. - Timers, URL requests and other controller objects work. Callbacks you pass
to
C4:SetTimerorC4:url():OnDonefire in your local code, and objects the controller returns can be used and cancelled as usual. - Anvil reports from the stub, not your SDK. The stub is instrumented, so the console shows one event per callback and every error your handlers raise. Your driver's own Anvil SDK stays quiet for the session.
- One session per driver. If a colleague is already debugging the same driver on the same controller, starting a second session replaces their stub.
Troubleshooting
- "Your sign-in has expired, so the debug session can't start": run
driverforge login, thendriverforge debugagain. A session needs a current sign-in to connect, and yours has expired or been revoked. - "Couldn't reach Driverforge to start the debug session": your machine couldn't reach Driverforge to set the session up. Check your connection and try again; there's no need to sign in again.
- "no Lua 5.1 interpreter found": install one (
brew install luajit) or point--luaat one you already have. - Nothing arrives after "Debug session active": the stub reaches the broker
from the controller, so the controller needs outbound access to
ingest.driverforge.com:8883, the same route the Anvil Agent uses. Check the agent's connectivity in the console. - You quit without deploying: the stub is still installed, and does nothing.
Run
driverforge deploywhenever you're ready; the nextdebugreplaces it too.
Global flags
Every driverforge command also accepts these global flags: --verbose/-v, --project-dir, --no-tui, --no-update-check, and --help/-h. See the overview for details.