Reference·03

Troubleshooting

Common issues with generated code, simulation, and porting — and how to fix them.

Studio on desktop

The IDE feels slow, or I see "Software rendering active"

  • Studio warns you when the GPU is unavailable and the UI falls back to software rendering (SwiftShader/llvmpipe). This is a driver/environment issue, not Studio itself.
  • Linux + NVIDIA/Wayland: the most common cause. Update the driver, or try an X11 session. You can also launch with --use-gl=egl or --use-angle=gl.
  • Virtual machines / remote desktop: GPU passthrough is often missing — enable 3D acceleration in the VM settings if available.
  • Check what renderer is in use: open DevTools console and inspect chrome://gpu in a Chromium-based browser for comparison, or look at the WebGL renderer string the warning shows.
  • Last resort: launch with --disable-gpu — rendering stays on CPU but GPU init errors disappear.

Sign-in or any server request fails with "Failed to fetch"

  • Check the system clock first. TLS certificate validation is strict: if the PC clock is behind the certificate's notBefore (or past notAfter), every request to protok.space fails before it leaves the machine. Certificates are renewed regularly, so a clock that is even tens of minutes off can break the app while other software still works. Sync the clock (Windows: Settings → Time & Language → Sync now; Linux: timedatectl / NTP) and restart Studio.
  • Corporate proxies, firewalls, and VPNs that intercept TLS can produce the same error — the app must reach protok.space:443 directly.
  • To see the exact network error, press F12 inside the app and check the DevTools console for a net::ERR_* code (e.g. ERR_CERT_DATE_INVALID, ERR_PROXY_CONNECTION_FAILED).

Generated code

Generated C does not compile on my target

  • LVGL version mismatch. Protok targets LVGL 9.6.0. Older LVGL releases lack APIs the generated UI calls. Upgrade your LVGL.
  • Missing runtime files. The generated code calls into the Protok runtime and LVGL. Make sure both are in your build and their include paths are set.
  • Compiler not in C99 mode. The output is C99. Enable C99 (or later) in your toolchain.
  • Stale generation. If you changed the project after generating, regenerate. The output is not patched in place.

Widget shows the wrong value or no value

  • Check the signal binding in Studio — the signal must be bound to that widget's property.
  • Check the DBC scaling (factor/offset) — the runtime applies it automatically; a wrong factor in the DBC means a wrong value on screen.
  • Check the CAN ID and DLC match your DBC definition.

Simulation

The simulator shows a blank screen

  • Make sure a screen is set as the active/load screen. The runtime loads the screen you marked for load on start.
  • Check that assets (fonts/images) finished importing — a missing font can leave text invisible.
  • Switch the canvas to Simulate mode; in Edit mode the preview is static.

Injected CAN frames do nothing

  • Verify the frame ID matches a message in your imported DBC.
  • Verify the DLC and byte layout match the signal definition.
  • Confirm the signal is bound to a widget or logic input — unbound signals have no visible effect.

Logic nodes do not react to inputs

  • Check that the node inputs are actually connected to a signal or widget — a floating input does nothing.
  • Verify the node's condition/constants are set correctly in the inspector.
  • Confirm the driving signal is arriving (check the CAN trace / injection).

Porting to my hardware

The UI renders but never updates

  • Your LVGL display driver flush callback must call lv_display_flush_ready() (or set flush_cb to signal completion) — otherwise LVGL stops refreshing.
  • Make sure lv_tick_inc() is called every millisecond from a timer, and lv_timer_handler() runs in your main loop.

Touch input does not work

  • Register an lv_indev_t of type LV_INDEV_TYPE_POINTER and feed touch coordinates in its read callback.
  • Call the read callback on each lv_timer_handler() — LVGL polls it.

CAN frames are not received by the firmware

  • Your CAN RX path must call pli_can_sae1939_process_frame(bus, id, data, dlc) for every incoming frame — the generated code does not poll the bus.
  • Check CAN bitrate, filters, and transceiver wiring on the hardware side.
  • Verify the frame ID matches a message in your DBC — unmatched IDs are ignored.

CAN TX does not reach the bus

  • You must override the pli_can_send_message weak stub in pli_hal.c — the default stub does nothing.
  • Check that your CAN peripheral is initialized and the bus is in normal mode (not listen-only).

Hard fault / crash on startup

  • Stack size: the generated code is static but LVGL and your drivers need stack headroom. Increase your task stack.
  • Display framebuffer: make sure the LVGL draw buffer(s) are placed in accessible RAM (often non-cacheable or DMA-friendly).
  • Initialization order: call lv_init() and your display/input setup before ui_init() and pli_can_init().
  • pli_get_tick returning 0 forever (the weak stub) breaks all timing — override it with a real 1 ms tick source.

Simulator = ground truth

If a problem appears on hardware but not in the simulator, it is almost certainly in your HAL port (drivers, tick, stack, framebuffer) — not in the generated logic. The simulator runs the same runtime, so logic bugs show up there first.

Still stuck?

Reach out at contact@protok.tech with your project (or a minimal repro), the generated C, and your target details. We will help you get it running.

Where to go