linux native fixup #3

This commit is contained in:
liquidraver
2026-06-02 16:08:51 +02:00
parent eb4e6583c7
commit 3c94b83f70
19 changed files with 599 additions and 260 deletions
+13 -2
View File
@@ -194,7 +194,18 @@ list(APPEND BOARD_ROOT ${CMAKE_CURRENT_SOURCE_DIR})
# Usage: zephcore_auto_pair_overlay("path/to/config.conf")
#
function(zephcore_auto_pair_overlay CONF_FILE)
if(NOT CONF_FILE OR NOT EXISTS "${CONF_FILE}")
if(NOT CONF_FILE)
return()
endif()
# User-supplied EXTRA_CONF_FILE entries are relative to the application
# source dir (e.g. "boards/linux_native/femtofox.conf"). CMake's EXISTS does
# not resolve relative paths against it, so resolve to absolute first — else
# the paired .overlay is silently skipped (which dropped the SX1262 node and
# broke ZEPHCORE_LORA when device wiring moved out of linux_common.overlay).
if(NOT IS_ABSOLUTE "${CONF_FILE}")
set(CONF_FILE "${CMAKE_CURRENT_SOURCE_DIR}/${CONF_FILE}")
endif()
if(NOT EXISTS "${CONF_FILE}")
return()
endif()
string(REPLACE ".conf" ".overlay" OVERLAY_FILE "${CONF_FILE}")
@@ -261,7 +272,7 @@ elseif(BOARD MATCHES ".*mg24.*" OR BOARD MATCHES ".*efr32.*")
elseif(DEFINED BOARD_QUALIFIERS AND BOARD_QUALIFIERS MATCHES ".*mg24.*")
set(ZEPHCORE_PLATFORM_CONF "${CMAKE_CURRENT_SOURCE_DIR}/boards/common/mg24_common.conf")
elseif(BOARD MATCHES "native_sim" OR BOARD MATCHES "native_posix")
set(ZEPHCORE_PLATFORM_CONF "${CMAKE_CURRENT_SOURCE_DIR}/boards/common/linux_common.conf")
set(ZEPHCORE_PLATFORM_CONF "${CMAKE_CURRENT_SOURCE_DIR}/boards/linux_native/linux_common.conf")
else()
set(ZEPHCORE_PLATFORM_CONF "")
endif()
+3 -4
View File
@@ -272,11 +272,10 @@ config ZEPHCORE_TRANSPORT_TCP
help
Replaces the ZephyrBLE adapter with LinuxTCPTransport, exposing
the companion NUS protocol over a TCP socket on Linux SBC builds
(BOARD=native_sim). Auto-enabled by boards/common/linux_common.conf.
(BOARD=native_sim). Auto-enabled by boards/linux_native/linux_common.conf.
The wire format is a 2-byte big-endian length prefix followed by
the raw NUS payload, matching upstream MeshCore Linux companion
service convention.
The wire format is MeshCore's SerialWifiInterface framing:
['<'][len_LSB][len_MSB][NUS payload] app->node and ['>']... node->app.
config ZEPHCORE_LINUX_TCP_PORT
int "TCP listen port"
+262 -41
View File
@@ -1,8 +1,10 @@
# ZephCore Native Linux Port
Run ZephCore as a native Linux process on SBCs like the **Femtofox** (Luckfox Pico Mini + E22-900M30S) or **Raspberry Pi 4/5 + RAK6421 HAT**. The full mesh stack runs on top of Zephyr's `native_sim` board, talking to real SPI/GPIO via `/dev/spidev*` and `libgpiod v2`.
Run ZephCore as a native Linux process on SBCs like the **Femtofox** (Luckfox Pico Mini + E22-900M30S) or a **Raspberry Pi + RAK6421 HAT**. The full mesh stack runs on top of Zephyr's `native_sim` board, talking to real SPI/GPIO via `/dev/spidev*` and the kernel's **GPIO V2 character-device uAPI** (direct ioctls — no libgpiod dependency).
The companion app connects via a TCP socket on port **5000**. Wire format is **raw NUS bytes with no length prefix** — each BLE NUS write becomes one TCP write, matching the MeshCore Windows companion "Connect via WiFi" protocol.
The companion app connects via a TCP socket on port **5000**, using MeshCore's `SerialWifiInterface` framing (`['<'][len_LSB][len_MSB][payload]` app→node, `['>']…` node→app) — see [Companion app connection](#companion-app-connection).
> **Real-time clock is automatic.** The binary forces the `native_sim` simulated clock into real-time mode at boot (equivalent to always passing `--rt`), because it drives a *real* radio whose BUSY/DIO1 timing happens in wall-clock time. You do **not** need to pass `--rt`. See [adapters/transport/linux_native_setup.c](adapters/transport/linux_native_setup.c).
---
@@ -13,17 +15,17 @@ On the **build host** (where you run `west build`):
```bash
# Zephyr SDK and west workspace as per the main CLAUDE.md.
# Cross-compile toolchains (for SBC targets):
sudo apt install gcc-arm-linux-gnueabihf # Femtofox (RV1103 ARMv7-A)
sudo apt install gcc-aarch64-linux-gnu # Raspberry Pi 4/5 (aarch64)
# Cross-compile toolchains (for SBC targets) — install BOTH gcc and g++:
# the mesh layer is C++, so the g++ cross-compiler is required (a build with
# only gcc fails at CMake configure with "Tell CMake where to find the compiler").
sudo apt install gcc-arm-linux-gnueabihf g++-arm-linux-gnueabihf # Femtofox (RV1103 ARMv7-A)
sudo apt install gcc-aarch64-linux-gnu g++-aarch64-linux-gnu # Raspberry Pi (aarch64)
```
On the **target SBC** (where the binary runs):
```bash
# Grant your user access to /dev/spidev and /dev/gpiochip (or run as root).
sudo usermod -a -G spi,gpio $USER
```
On the **target SBC** (where the binary runs): grant your user access to
`/dev/spidev*` and `/dev/gpiochip*` so you don't need `sudo`/root — see
[Running without root](#running-without-root) below. (You *can* just run as
root with `sudo`, but it's not required.)
**Femtofox only:** the Femtofox image ships with `meshtasticd` pre-installed and it holds
the SPI bus / GPIO lines. Uninstall it before running ZephCore or the radio will be
@@ -49,12 +51,68 @@ No extra configuration needed; skip straight to adding your user to the `spi`/`g
---
## Running without root
By default `/dev/spidev*` and `/dev/gpiochip*` are owned `root:root`, so the
binary only runs under `sudo`. The binary needs **no** elevated privileges of
its own — it only needs read/write on those two device classes (the TCP port is
5000, non-privileged; the flash file is written in your home dir). Grant access
once with groups + a udev rule:
```bash
# 1. Create the groups (the Femtofox/foxbuntu image ships without them).
sudo groupadd -f spi
sudo groupadd -f gpio
# 2. Add your login user (e.g. "femto") to both.
sudo usermod -aG spi,gpio "$USER"
# 3. udev rule: give those groups access to the SPI + GPIO char devices.
sudo tee /etc/udev/rules.d/90-zephcore.rules >/dev/null <<'EOF'
KERNEL=="spidev*", GROUP="spi", MODE="0660"
SUBSYSTEM=="gpio", KERNEL=="gpiochip*", GROUP="gpio", MODE="0660"
EOF
# 4. Reload udev and re-trigger so the rule applies to the existing nodes.
sudo udevadm control --reload-rules
sudo udevadm trigger --subsystem-match=spidev --subsystem-match=gpio
# 5. Log out and back in (group membership is only picked up at login).
# Verify: id # should list "spi" and "gpio"
# ls -l /dev/spidev0.0 /dev/gpiochip1 # group spi / gpio, mode 0660
```
Then run the binary **without** `sudo`:
```bash
./zephcore_native_linux.exe
```
> **If the udev rule doesn't stick** (some minimal images use `mdev`/busybox
> instead of systemd-udev, which ignores `/etc/udev/rules.d`), set the
> permissions at boot instead — e.g. a tiny systemd unit or an `rc.local` line:
> ```bash
> chgrp gpio /dev/gpiochip* && chmod 660 /dev/gpiochip*
> chgrp spi /dev/spidev* && chmod 660 /dev/spidev*
> ```
> **Femtofox note:** you must still stop/uninstall `meshtasticd` first (it holds
> the SPI bus) — see the Prerequisites section. Running as your user vs root
> doesn't change that.
---
## Quick Start
### 1. Host smoke build (x86-64 Linux, no real radio)
A device preset is required (it provides the SX1262 node); the Femtofox preset
is fine for a host smoke build — the SPI/GPIO opens just fail gracefully with no
hardware:
```bash
west build -b native_sim/native/64 zephcore --pristine
rm -rf build && west build -b native_sim/native/64 zephcore -- \
-DEXTRA_CONF_FILE="boards/linux_native/femtofox.conf"
./build/zephyr/zephcore_native_linux.exe
```
@@ -77,23 +135,53 @@ west build -b native_sim zephcore -- \
-DZEPHYR_TOOLCHAIN_VARIANT=cross-compile \
-DNATIVE_TARGET_HOST=arm \
-DCROSS_COMPILE=/usr/bin/arm-linux-gnueabihf- \
-DEXTRA_CONF_FILE="boards/common/femtofox.conf"
-DEXTRA_CONF_FILE="boards/linux_native/femtofox.conf"
scp build/zephyr/zephcore_native_linux.exe root@femtofox.local:/opt/zephcore/
ssh root@femtofox.local /opt/zephcore/zephcore_native_linux.exe
scp build/zephyr/zephcore_native_linux.exe femto@femtofox.local:~/
ssh femto@femtofox.local ./zephcore_native_linux.exe # no sudo once groups are set up
```
### 3. Raspberry Pi 4 + RAK6421 (aarch64)
(No `--rt` flag needed — real-time mode is forced at boot. See the note at the top.)
### 3. Raspberry Pi + RAK6421 HAT (aarch64)
The `rak6421` preset is named after the **HAT**, not a Pi model — the wiring is
identical on every Pi. The only per-model difference is the Linux gpiochip:
- **Pi 2 / 3 / 4 / Zero 2** → `gpiochip0``rak6421.conf`
- **Pi 5** → `gpiochip4` (RP1) → `rak6421_pi5.conf`
The build command is unchanged by the native-Linux work this cycle — the
GPIO-driver fixes, automatic `--rt`, and per-node persistence apply to every
native build. For a 64-bit Pi OS (the usual case on Pi 3/4/5):
```bash
west build -b native_sim/native/64 zephcore --pristine -- \
rm -rf build && west build -b native_sim/native/64 zephcore -- \
-DZEPHYR_TOOLCHAIN_VARIANT=cross-compile \
-DNATIVE_TARGET_HOST=aarch64 \
-DCROSS_COMPILE=/usr/bin/aarch64-linux-gnu- \
-DEXTRA_CONF_FILE="boards/common/rpi_rak6421.conf"
-DEXTRA_CONF_FILE="boards/linux_native/rak6421.conf" # Pi 5: rak6421_pi5.conf
scp build/zephyr/zephcore_native_linux.exe pi@raspberrypi.local:~/
```
For RPi 5, use `boards/common/rpi5_rak6421.conf` (same wiring, `gpiochip4` instead of `gpiochip0`).
(On a **32-bit** Pi OS — e.g. Pi 2, or Pi 3/4 on 32-bit Raspberry Pi OS — build the
armhf way instead: `-b native_sim -DNATIVE_TARGET_HOST=arm -DCROSS_COMPILE=/usr/bin/arm-linux-gnueabihf-`,
same `-DEXTRA_CONF_FILE`.)
`rak6421_pi5` is just `rak6421` with `gpiochip4` — equivalently you can keep using
`rak6421.conf` and override at runtime with `--lora-gpio-chip=/dev/gpiochip4`.
> **`--pristine` in this WSL workspace:** prefer `rm -rf build &&` over `west build --pristine`.
> `--pristine` can feed Windows-style `D:/…` paths to CMake when `.west/config` was
> initialised on Windows. `rm -rf build &&` is equivalent and works everywhere. (On a
> native-Linux build host, plain `--pristine` is fine.)
>
> **Status:** the RAK6421 presets are **build-verified but not yet hardware-tested** —
> only the Femtofox is confirmed end-to-end (2026-06-02). The same GPIO driver carries the
> fixes, so it *should* work; if the radio is dead, follow the "Radio does nothing"
> troubleshooting below. Note the RAK13300/RAK13302 preset assumes **no DIO3 TCXO** (XTAL +
> discrete RF switch); if your module has a TCXO, add `dio3-tcxo-voltage`/`tcxo-power-startup-delay-ms`
> to `boards/linux_native/rak6421.overlay` (and `rak6421_pi5.overlay`).
### 4. Repeater role (no companion)
@@ -128,9 +216,9 @@ SX1262 extras: DIO2 drives the RF switch (`dio2-tx-enable`), DIO3 powers the TCX
Source: `github.com/femtofox/femtofox``foxbuntu/.../femtofox_SX1262_TCXO.yaml`.
### Raspberry Pi 4/5 + RAK6421 HAT + RAK13300/RAK13302 (IO Slot 1)
### Raspberry Pi + RAK6421 HAT + RAK13300/RAK13302 (IO Slot 1)
BCM GPIO numbers (RPi 4: gpiochip0; RPi 5: gpiochip4):
BCM GPIO numbers (Pi 2/3/4/Zero 2: `gpiochip0``rak6421.conf`; Pi 5: `gpiochip4``rak6421_pi5.conf`):
| Signal | BCM | WisBlock slot 1 pin |
|---|---|---|
@@ -177,6 +265,95 @@ socat /dev/pts/3 TCP-LISTEN:6000,reuseaddr,fork &
nc <sbc-ip> 6000
```
### Run at boot (systemd service)
To start ZephCore automatically at boot and restart it if it ever exits, install
a systemd service. This assumes you've already done the [Running without root](#running-without-root)
setup (the `spi`/`gpio` groups + udev rule), so the service can run as your
normal user — **no root**.
Create `/etc/systemd/system/zephcore.service` (adjust `User=` and the paths to
your setup):
```ini
[Unit]
Description=ZephCore native LoRa mesh
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=femto
SupplementaryGroups=spi gpio
# WorkingDirectory pins where the persistent flash file lands
# (meshcore_settings_<hostname>.bin) and must be writable by User=.
WorkingDirectory=/home/femto
ExecStart=/home/femto/zephcore_native_linux.exe
Restart=always
RestartSec=2
[Install]
WantedBy=multi-user.target
```
Enable + start it (and have it come back on every reboot):
```bash
sudo systemctl daemon-reload
sudo systemctl enable --now zephcore # start now + at boot
sudo systemctl status zephcore # check it's running
journalctl -u zephcore -f # follow logs (replaces stderr)
```
Manage it:
```bash
sudo systemctl restart zephcore
sudo systemctl stop zephcore
sudo systemctl disable zephcore # stop auto-start at boot
```
Notes:
- **No `--rt` flag** is needed — real-time mode is baked into the binary.
- **Stop `meshtasticd` first** (Femtofox): if it's installed it grabs the SPI bus.
Disable it so it doesn't race your service: `sudo systemctl disable --now meshtasticd`.
- **Companion (TCP) role** works perfectly as a service — connect the app to
`<sbc-ip>:5000` as usual.
- **Repeater role:** the CLI is a pseudo-terminal whose path (`/dev/pts/N`) is
printed to the journal at boot (`journalctl -u zephcore | grep pseudotty`). To
reach it remotely, add a bridge as `ExecStartPost`, e.g.
`ExecStartPost=/bin/sh -c 'socat ... TCP-LISTEN:6000,fork &'` — or just run the
repeater in the foreground when you need the CLI.
- If you relocate the binary (e.g. to `/usr/local/bin/zephcore`), keep
`WorkingDirectory=` pointed at a user-writable dir so the settings file persists.
---
## Persistent storage
Identity, prefs, contacts, channels and BLE-equivalent settings all live in
LittleFS on `/lfs`, which is backed by Zephyr's flash simulator. On native Linux
that simulator is **file-backed** (not RAM), so everything survives restarts.
The backing file is named **`meshcore_settings_<hostname>.bin`** and created in
the binary's working directory on first run (`<hostname>` comes from the Linux
`gethostname()`, so multiple nodes on one host each get their own file). For the
Femtofox that's `meshcore_settings_femtofox.bin`.
```bash
ls -l meshcore_settings_*.bin # appears after the first run
```
- To move a node's identity to another machine, copy this file.
- To reset a node to a fresh identity, delete it (a new one is created next run).
- An explicit `--flash=/path/to/file.bin` overrides the default name/location.
- **Migrating from an older build** that used the generic `flash.bin`:
`cp flash.bin meshcore_settings_$(hostname).bin` before first run to keep your
existing identity.
> Implementation: `patches/zephyr/0008-flash-sim-per-node-file.patch` makes the
> flash simulator default to the per-node filename instead of `flash.bin`.
---
## Runtime Pin Override
@@ -189,7 +366,7 @@ For one-off hardware setups or custom wiring, override DT defaults at runtime:
--lora-gpio-chip=/dev/gpiochip1
```
Currently only the **paths** are runtime-overridable; pin offsets come from the DTS overlay you build with. To change pin numbers without rebuilding, create your own `boards/common/<custom>.conf` + `.overlay` and pass it via `-DEXTRA_CONF_FILE`.
Currently only the **paths** are runtime-overridable; pin offsets come from the DTS overlay you build with. To change pin numbers without rebuilding, create your own `boards/linux_native/<device>.conf` + `.overlay` (copy `femtofox.overlay` as a starting point) and pass it via `-DEXTRA_CONF_FILE`.
Run `./zephcore_native_linux.exe --help` to see all available command-line arguments registered by the native_sim infrastructure (Zephyr drivers, our SPI/GPIO drivers, etc.).
@@ -199,10 +376,9 @@ Run `./zephcore_native_linux.exe --help` to see all available command-line argum
### Permission denied opening /dev/spidev0.0 or /dev/gpiochip*
```bash
sudo usermod -a -G spi,gpio $USER
# Log out and back in for group membership to take effect.
```
Set up group access — see [Running without root](#running-without-root). On the
Femtofox image the `spi`/`gpio` groups don't exist yet, so you must `groupadd`
them and add a udev rule (just `usermod` is not enough). Or run with `sudo`.
### `/dev/spidev0.0: No such file or directory`
@@ -224,17 +400,32 @@ west build … -- -DCONFIG_ZEPHCORE_LINUX_TCP_PORT=15000
The transport expects raw NUS bytes with no length prefix. If the connection drops immediately, capture traffic with `tcpdump -i any -X port 5000` and verify the first bytes the app sends look like a MeshCore opcode (e.g. `0x01` = CMD_APP_START), not an HTTP request or other framed protocol.
### LoRa packets fly out but nothing receives them
### Radio does nothing (no RX, CAD always times out, TX never completes)
Check that DIO1 is wired and configured correctly. The interrupt path is the primary RX trigger. If DIO1 is misrouted, the driver will appear to TX fine but never reports RX.
The interrupt path (DIO1) and BUSY readback are the spine of all radio ops. If
they're broken at the GPIO layer, the chip stays wedged in standby and *every*
operation fails (CAD `-ETIMEDOUT`, no RX, no TX-done).
Verify on the host with `gpioget`:
> **Don't** try to verify DIO1/BUSY with `gpioget /dev/gpiochip1 23` while the
> binary is running — the kernel grants GPIO lines **exclusively**, so the
> binary holds them and `gpioget` just returns `-EBUSY`. Reading it with the
> binary stopped tells you nothing (nothing is driving the radio). Instead,
> build with LoRa debug logging and read the chip's own registers:
> ```bash
> west build … -- … -DCONFIG_LORA_LOG_LEVEL_DBG=y
> ```
> A healthy boot shows `sx126x_irq_work_handler: IRQ status: …` lines on RX/CAD/TX.
```bash
gpioget /dev/gpiochip1 23 # should toggle when a peer transmits
```
Things that previously broke this exact path (all fixed; listed so you recognize
the symptoms if a regression appears):
- Native GPIO driver requesting no lines (the `GPIO_DISCONNECTED == 0` trap) →
BUSY stuck-low, commands dropped, chip frozen.
- Double inversion on active-low pins → RESET driven backwards, chip held in reset.
- Missing real-time clock mode → CAD/TX/RX time out before the real radio responds
(now forced automatically; do not remove `linux_native_setup.c`).
If the host can't see DIO1 transitioning, the radio isn't bringing the line up — check SX1262 RESET sequencing and DIO1 wiring.
If a regression appears, check `port_get_raw`/`pin_configure` in
`gpio_native_linux.c` and that `linux_native_setup.c` is still compiled.
### `bind(5000) failed: 98` (EADDRINUSE)
@@ -279,20 +470,27 @@ The mesh C++ layer and the patched SX1262 Zephyr driver are bit-identical to the
- **Not BLE.** The companion app must support TCP/Network mode. No BlueZ integration.
- **Not for production use** per Zephyr's `native_sim` documentation. Works fine for hobby/lab deployments.
- **Single companion client.** One TCP connection at a time, mirroring `BT_MAX_CONN=1`.
- **No persistent flash.** Storage uses the host filesystem under `/lfs` via LittleFS over a flat backing file. Survives reboot if you persist the file; otherwise the node is regenerated each run.
- **Persistent storage** is file-backed and survives restarts — see [Persistent storage](#persistent-storage).
---
## Files
- `boards/common/linux_common.conf` + `.overlay` — auto-applied when `BOARD=native_sim`
- `boards/common/femtofox.conf` / `.overlay` — Femtofox preset
- `boards/common/rpi_rak6421.conf` / `.overlay`Raspberry Pi 4 preset
- `boards/common/rpi5_rak6421.conf` / `.overlay`Raspberry Pi 5 preset
All native-Linux board files live under **`boards/linux_native/`**:
- `boards/linux_native/linux_common.conf` + `.overlay`platform base, auto-applied when `BOARD=native_sim` (no device wiring)
- `boards/linux_native/femtofox.conf` + `.overlay`Femtofox preset (SX1262 TCXO wiring)
- `boards/linux_native/rak6421.conf` + `.overlay` — RAK6421 HAT, Pi 2/3/4/Zero 2 (gpiochip0)
- `boards/linux_native/rak6421_pi5.conf` + `.overlay` — RAK6421 HAT, Pi 5 (gpiochip4)
> These are `EXTRA_CONF_FILE` **presets**, not Zephyr boards — you still build with
> `-b native_sim … -DEXTRA_CONF_FILE="boards/linux_native/<device>.conf"`, not `-b <device>`.
- `adapters/transport/LinuxTCPTransport.c` — TCP companion transport
- `adapters/transport/linux_native_setup.c` — forces real-time clock mode at boot (bakes in `--rt`)
- `patches/zephyr-new/drivers/spi/spi_native_linux*` — spidev SPI driver
- `patches/zephyr-new/drivers/gpio/gpio_native_linux*`libgpiod v2 GPIO driver
- `patches/zephyr-new/drivers/gpio/gpio_native_linux*`GPIO driver (kernel GPIO V2 chardev ioctls, no libgpiod)
- `patches/zephyr/0007-spi-gpio-native-linux.patch` — wires the new drivers into Zephyr's `drivers/spi/` and `drivers/gpio/` CMakeLists + Kconfig
- `patches/zephyr/0008-flash-sim-per-node-file.patch` — flash simulator defaults to `meshcore_settings_<hostname>.bin` for persistent per-node storage
---
@@ -306,12 +504,13 @@ End-to-end verified under WSL Ubuntu 24.04 (gcc 13.3):
- ✅ All 7 `patches/zephyr/*.patch` apply cleanly (including the new `0007-spi-gpio-native-linux.patch`).
- ✅ All files in `patches/zephyr-new/` copy correctly into the Zephyr tree.
- ✅ Platform detection routes `BOARD=native_sim` to `boards/common/linux_common.conf`.
- ✅ Platform detection routes `BOARD=native_sim` to `boards/linux_native/linux_common.conf`.
-`native_sim/native/64` builds clean → `build/zephyr/zephcore_native_linux.exe` (~4.3 MB ELF).
- ✅ Binary runs. Zephyr OS boots, mesh event loop starts.
-`spi_native_linux` driver loads and attempts to open `/dev/spidev0.0` (fails in WSL: no SPI hardware).
-`LinuxTCPTransport` listens on port 5000.
- ✅ TCP client connect/disconnect works; 2-byte BE length framing parses correctly.
- ✅ TCP client connect/disconnect works; `SerialWifiInterface` (`<`/`>` + 2-byte LE length) framing parses correctly.
-**End-to-end on real Femtofox hardware (2026-06-02):** radio RX, CAD (LBT), and TX all working; companion app connects and meshes; settings persist across restarts. (Required fixing two bugs in the native GPIO driver — see "Known caveats" below.)
Build command verified (run from inside WSL with workspace at `/mnt/d/zephcore`):
@@ -327,6 +526,28 @@ cross-compile). The 32-bit variant requires `libc6-dev-i386` on the build host.
### Known caveats found during implementation
- **Native GPIO driver had two bugs that killed the radio** (fixed 2026-06-02,
`patches/zephyr-new/drivers/gpio/`):
1. `rebuild_line()` tested `(flags & GPIO_DISCONNECTED) == GPIO_DISCONNECTED`,
but `GPIO_DISCONNECTED == 0`, so the test was *always true* and **no GPIO
line was ever actually requested** — every input read returned 0 and every
output write was a no-op (SPI still worked only because spidev drove its own
hardware CS). BUSY read stuck-low → driver never waited for the chip →
commands issued while BUSY → silently dropped → chip frozen in STBY_RC. Fix:
test `(flags & (GPIO_INPUT | GPIO_OUTPUT)) == GPIO_DISCONNECTED`.
2. The driver passed `GPIO_V2_LINE_FLAG_ACTIVE_LOW` to the kernel while Zephyr's
generic GPIO layer *already* inverts active-low pins (`data->invert`) →
**double inversion** drove the active-low RESET line backwards, holding the
chip in reset. Fix: driver `port_*_raw` are physical/raw; let Zephyr own
inversion (don't set the kernel `ACTIVE_LOW` flag).
Symptom of both: TCXO/XOSC/CAD all *look* like the culprit (XOSC_START_ERR,
CAD `-ETIMEDOUT`) but are downstream — the chip is simply wedged.
- **`--rt` is mandatory and now automatic.** Without real-time clock mode the
`native_sim` clock free-runs decoupled from wall time, so real-radio timeouts
(200 ms CAD, TX/RX-done) fire before the hardware responds. Forced at boot via
`linux_native_setup.c` (`hwtimer_set_real_time_mode(true)`).
- **Double-overlay listing** in `EXTRA_DTC_OVERLAY_FILE`: `linux_common.overlay` gets auto-paired twice — once when the platform conf is selected, once again when the EXTRA_CONF_FILE list is re-walked. Pre-existing CMakeLists.txt quirk affecting all platform confs; harmless (DTC merges idempotently) but cosmetic.
- **Pin paths are runtime-overridable, pin numbers are not.** Only `--lora-spidev=<path>` and `--lora-gpio-chip=<path>` are wired as command-line args. To change actual pin numbers without rebuilding, create a custom preset overlay and pass it via `-DEXTRA_CONF_FILE`. (A future iteration could expose pin offsets as cmdline args too.)
-9
View File
@@ -1,9 +0,0 @@
# Femtofox (Luckfox Pico Mini + E22-900M30S TCXO) preset.
#
# Pin defaults already match Femtofox in linux_common.overlay; this preset
# exists for clarity ("I am building for Femtofox") and to set the board
# name string. Add to EXTRA_CONF_FILE alongside linux_common implicitly.
#
# Source: github.com/femtofox/femtofox foxbuntu meshtasticd config.
CONFIG_ZEPHCORE_BOARD_NAME="Femtofox"
-9
View File
@@ -1,9 +0,0 @@
/*
* Femtofox (Luckfox Pico Mini + E22-900M30S TCXO).
*
* Femtofox pinout already matches the linux_common.overlay defaults
* (gpiochip1 with offsets CS=16, BUSY=22, DIO1=23, RXEN=24, RESET=25).
* This overlay is intentionally empty — adding boards/common/femtofox.conf
* to EXTRA_CONF_FILE is enough to label the build "Femtofox" without
* changing any pins.
*/
-115
View File
@@ -1,115 +0,0 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* ZephCore native Linux DT overlay (auto-paired with linux_common.conf).
*
* Disables the native_sim emulated GPIO/SPI controllers and adds our
* libgpiod/spidev-backed native_linux versions, with an SX1262 child
* node on the SPI bus.
*
* Generic defaults below match the Femtofox SX1262 wiring. Override per
* device by adding boards/common/<device>.conf + .overlay via
* EXTRA_CONF_FILE, or use --lora-* command-line args at runtime.
*/
#include <zephyr/dt-bindings/gpio/gpio.h>
#include <zephyr/dt-bindings/lora/sx126x.h>
/* Disable native_sim emulated controllers (replaced below). */
&spi0 {
status = "disabled";
};
&gpio0 {
status = "disabled";
};
/* LittleFS on native_sim's simulated flash.
* The native_sim board DTS allocates the first 1MB (0x0..0xfffff) for
* MCUBoot + OTA slots. The second half (0x100000..0x1fffff = 1MB) is unused.
* Use 512KB of it for LittleFS — 128 × 4KB blocks, plenty for identity,
* prefs, contacts, and channels.
* The sim-flash is in-memory (lost on exit); add
* CONFIG_FLASH_SIMULATOR_STATS_FILE for file-backed persistence. */
&flash0 {
partitions {
lfs_partition: partition@100000 {
label = "lfs";
reg = <0x00100000 0x00080000>; /* 512 KB */
};
};
};
#include "filesystem.dtsi"
/* Disable the SDL emulated display + touch (we don't use them and the
* SDL2 dev library isn't a useful dep on a headless SBC). */
&sdl_dc {
status = "disabled";
};
&input_sdl_touch {
status = "disabled";
};
/* Drop the chosen zephyr,display node so HAS_SDL doesn't get selected.
* Also drop the led0 alias — native_sim's base DTS attaches it to the
* emulated gpio0 that we just disabled, which would otherwise cause a
* dangling DEVICE_DT_GET in helpers/ui/ui_common.c. */
/ {
chosen {
/delete-property/ zephyr,display;
/delete-property/ zephyr,touch;
};
aliases {
/delete-property/ led0;
};
};
/ {
/delete-node/ leds;
};
/ {
aliases {
/* The mesh adapter reads lora0 alias to bind the SX126x driver. */
lora0 = &lora_sx1262;
};
/* libgpiod v2 GPIO controller bound to a host /dev/gpiochipX. */
zephcore_gpio0: zephcore_gpio0 {
status = "okay";
compatible = "zephcore,gpio-native-linux";
gpio-controller;
gpio-chip = "/dev/gpiochip1";
ngpios = <64>;
#gpio-cells = <2>;
};
/* spidev-backed SPI bus on /dev/spidev0.0 with one SX1262 child. */
zephcore_spi0: zephcore_spi0 {
status = "okay";
compatible = "zephcore,spi-native-linux";
spi-dev = "/dev/spidev0.0";
clock-frequency = <2000000>;
spi-mode = <0>;
#address-cells = <1>;
#size-cells = <0>;
/* CS line: GPIO 16 on chip 1 = GPIO48 = 1C0 (Femtofox default). */
cs-gpios = <&zephcore_gpio0 16 GPIO_ACTIVE_LOW>;
lora_sx1262: lora@0 {
compatible = "semtech,sx1262";
reg = <0>;
spi-max-frequency = <2000000>;
/* Femtofox defaults; overridden by per-device overlays. */
reset-gpios = <&zephcore_gpio0 25 GPIO_ACTIVE_LOW>;
busy-gpios = <&zephcore_gpio0 22 GPIO_ACTIVE_HIGH>;
dio1-gpios = <&zephcore_gpio0 23 GPIO_ACTIVE_HIGH>;
rx-enable-gpios = <&zephcore_gpio0 24 GPIO_ACTIVE_HIGH>;
dio2-tx-enable;
dio3-tcxo-voltage = <SX126X_DIO3_TCXO_1V8>;
tcxo-power-startup-delay-ms = <5>;
};
};
};
-7
View File
@@ -1,7 +0,0 @@
# Raspberry Pi 5 + RAK6421 WisBlock HAT + RAK13300/RAK13302 (SX1262).
#
# Same WisBlock IO Slot 1 wiring as RPi 4 (rpi_rak6421.conf), but RPi 5
# moves the 40-pin header GPIOs to /dev/gpiochip4. Everything else is
# identical.
CONFIG_ZEPHCORE_BOARD_NAME="RPi5 RAK6421"
@@ -1,25 +0,0 @@
/*
* Raspberry Pi 5 + RAK6421 + RAK13300/RAK13302 SX1262 (IO Slot 1).
* Same as rpi_rak6421.overlay but with gpiochip4 (RPi 5 moved the
* 40-pin header GPIOs).
*/
#include <zephyr/dt-bindings/gpio/gpio.h>
&zephcore_gpio0 {
gpio-chip = "/dev/gpiochip4";
};
&zephcore_spi0 {
cs-gpios = <&zephcore_gpio0 8 GPIO_ACTIVE_LOW>;
};
&lora_sx1262 {
reset-gpios = <&zephcore_gpio0 13 GPIO_ACTIVE_LOW>;
busy-gpios = <&zephcore_gpio0 12 GPIO_ACTIVE_HIGH>;
dio1-gpios = <&zephcore_gpio0 17 GPIO_ACTIVE_HIGH>;
/delete-property/ dio2-tx-enable;
/delete-property/ dio3-tcxo-voltage;
/delete-property/ tcxo-power-startup-delay-ms;
/delete-property/ rx-enable-gpios;
};
-13
View File
@@ -1,13 +0,0 @@
# Raspberry Pi 4 + RAK6421 WisBlock HAT + RAK13300/RAK13302 (SX1262).
#
# IO Slot 1 wiring (BCM GPIO numbers on gpiochip0):
# SPI: /dev/spidev0.0 (CE0 = GPIO 8, hardware CS)
# DIO1/IRQ: GPIO 17 (slot pin 29)
# BUSY: GPIO 12 (slot pin 30)
# RESET: GPIO 13 (slot pin 31)
# No DIO2 RF switch, no DIO3 TCXO (RAK13300 has discrete switch + ext TCXO).
#
# Source: docs.rakwireless.com/.../rak6421/datasheet IO slot table +
# RAKWireless meshtastic-rak6421-guide config.yaml
CONFIG_ZEPHCORE_BOARD_NAME="RPi RAK6421"
@@ -1,28 +0,0 @@
/*
* Raspberry Pi 4 + RAK6421 + RAK13300/RAK13302 SX1262 (IO Slot 1).
* Override Femtofox defaults from linux_common.overlay.
*/
#include <zephyr/dt-bindings/gpio/gpio.h>
&zephcore_gpio0 {
/* RPi 4: header GPIOs live on gpiochip0. */
gpio-chip = "/dev/gpiochip0";
};
&zephcore_spi0 {
/* SPI CE0 is GPIO 8 (driven as a regular GPIO from the kernel). */
cs-gpios = <&zephcore_gpio0 8 GPIO_ACTIVE_LOW>;
};
&lora_sx1262 {
reset-gpios = <&zephcore_gpio0 13 GPIO_ACTIVE_LOW>;
busy-gpios = <&zephcore_gpio0 12 GPIO_ACTIVE_HIGH>;
dio1-gpios = <&zephcore_gpio0 17 GPIO_ACTIVE_HIGH>;
/* RAK13300 uses discrete RF switch, not DIO2. Discard the Femtofox
* dio2-tx-enable and dio3-tcxo-voltage from the base overlay. */
/delete-property/ dio2-tx-enable;
/delete-property/ dio3-tcxo-voltage;
/delete-property/ tcxo-power-startup-delay-ms;
/delete-property/ rx-enable-gpios;
};
@@ -0,0 +1,11 @@
# Femtofox (Luckfox Pico Mini + E22-900M30S TCXO) preset.
#
# Auto-pairs with femtofox.overlay (the SX1262 wiring). Pass this via
# EXTRA_CONF_FILE to build for the Femtofox:
# -DEXTRA_CONF_FILE="boards/linux_native/femtofox.conf"
# linux_common.conf/.overlay (platform base) is applied automatically.
#
# Source: github.com/femtofox/femtofox foxbuntu meshtasticd config
# (femtofox_SX1262_TCXO.yaml).
CONFIG_ZEPHCORE_BOARD_NAME="Femtofox"
@@ -0,0 +1,57 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* Femtofox (Luckfox Pico Mini RV1103 + Ebyte E22-900M30S, SX1262 TCXO) wiring.
* Auto-paired with femtofox.conf. Defines the native_linux SPI/GPIO controllers
* and the SX1262 radio node on top of the platform infra in linux_common.overlay.
*
* Pins match the meshtasticd Femtofox profile (femtofox_SX1262_TCXO.yaml):
* gpiochip1, CS=16/GPIO48, BUSY=22/GPIO54, DIO1=23/GPIO55, RESET=25/GPIO57,
* RXEN=24/GPIO56. DIO2 drives the RF switch, DIO3 powers a 1.8V TCXO.
*/
#include <zephyr/dt-bindings/gpio/gpio.h>
#include <zephyr/dt-bindings/lora/sx126x.h>
/ {
aliases {
/* The mesh adapter reads lora0 to bind the SX126x driver. */
lora0 = &lora_sx1262;
};
/* GPIO V2 chardev controller bound to /dev/gpiochip1. */
zephcore_gpio0: zephcore_gpio0 {
status = "okay";
compatible = "zephcore,gpio-native-linux";
gpio-controller;
gpio-chip = "/dev/gpiochip1";
ngpios = <64>;
#gpio-cells = <2>;
};
/* spidev-backed SPI bus on /dev/spidev0.0 with one SX1262 child. */
zephcore_spi0: zephcore_spi0 {
status = "okay";
compatible = "zephcore,spi-native-linux";
spi-dev = "/dev/spidev0.0";
clock-frequency = <2000000>;
spi-mode = <0>;
#address-cells = <1>;
#size-cells = <0>;
/* CS: gpiochip1 offset 16 = GPIO48. */
cs-gpios = <&zephcore_gpio0 16 GPIO_ACTIVE_LOW>;
lora_sx1262: lora@0 {
compatible = "semtech,sx1262";
reg = <0>;
spi-max-frequency = <2000000>;
reset-gpios = <&zephcore_gpio0 25 GPIO_ACTIVE_LOW>;
busy-gpios = <&zephcore_gpio0 22 GPIO_ACTIVE_HIGH>;
dio1-gpios = <&zephcore_gpio0 23 GPIO_ACTIVE_HIGH>;
rx-enable-gpios = <&zephcore_gpio0 24 GPIO_ACTIVE_HIGH>;
dio2-tx-enable;
dio3-tcxo-voltage = <SX126X_DIO3_TCXO_1V8>;
tcxo-power-startup-delay-ms = <5>;
};
};
};
@@ -2,7 +2,10 @@
#
# Auto-applied by zephcore/CMakeLists.txt when BOARD matches native_sim.
# Runs the full ZephCore stack as a native Linux process via Zephyr's
# native_sim board, talking to real SPI/GPIO via /dev/spidev + libgpiod v2.
# native_sim board, talking to real SPI/GPIO via /dev/spidev* and the kernel
# GPIO V2 chardev uAPI (no libgpiod). Platform base only — pass a device
# preset (femtofox.conf, rak6421.conf, ...) via EXTRA_CONF_FILE for the
# SX1262 wiring.
#
# See LINUX_NATIVE.md for prerequisites and per-device wiring.
@@ -0,0 +1,73 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* ZephCore native Linux PLATFORM overlay (auto-paired with linux_common.conf,
* applied automatically for BOARD=native_sim).
*
* Platform infrastructure ONLY — it disables native_sim's emulated SPI/GPIO
* and SDL display, and sets up the LittleFS partition. The radio wiring and
* the native_linux SPI/GPIO controller nodes live in the per-device preset
* overlay (femtofox.overlay, rak6421.overlay, rak6421_pi5.overlay).
*
* You MUST pass a device preset via EXTRA_CONF_FILE, e.g.
* -DEXTRA_CONF_FILE="boards/linux_native/femtofox.conf"
* A bare `-b native_sim` build with no device preset has no SX1262 node and
* will fail to link the radio adapter (no `lora0` alias).
*/
/* Disable the native_sim emulated controllers — each device preset adds its
* own zephcore_spi0 / zephcore_gpio0 backed by real /dev/spidev* + /dev/gpiochip*. */
&spi0 {
status = "disabled";
};
&gpio0 {
status = "disabled";
};
/* LittleFS on native_sim's simulated flash.
* The native_sim board DTS allocates the first 1MB (0x0..0xfffff) for
* MCUBoot + OTA slots. The second half (0x100000..0x1fffff = 1MB) is unused;
* use 512KB of it for LittleFS — 128 × 4KB blocks, plenty for identity,
* prefs, contacts, and channels.
* The sim-flash is FILE-BACKED on native_sim (ARCH_POSIX): it persists across
* restarts in meshcore_settings_<hostname>.bin in the binary's working dir
* (see patches/zephyr/0008-flash-sim-per-node-file.patch). Pass --flash=<path>
* to override, or --flash_in_ram to make it ephemeral. */
&flash0 {
partitions {
lfs_partition: partition@100000 {
label = "lfs";
reg = <0x00100000 0x00080000>; /* 512 KB */
};
};
};
#include "../common/filesystem.dtsi"
/* Disable the SDL emulated display + touch (headless SBC; the SDL2 dev library
* isn't a useful dep, and HAS_SDL would otherwise get selected). */
&sdl_dc {
status = "disabled";
};
&input_sdl_touch {
status = "disabled";
};
/ {
chosen {
/delete-property/ zephyr,display;
/delete-property/ zephyr,touch;
};
aliases {
/* native_sim's base DTS attaches led0 to the emulated gpio0 we just
* disabled; drop it so helpers/ui/ui_common.c has no dangling
* DEVICE_DT_GET. */
/delete-property/ led0;
};
};
/ {
/delete-node/ leds;
};
+22
View File
@@ -0,0 +1,22 @@
# RAK6421 WisBlock Pi HAT + RAK13300/RAK13302 (SX1262), IO Slot 1.
#
# Named after the HAT, not a Pi model — the wiring is identical on every Pi
# that exposes the 40-pin header on gpiochip0 (Raspberry Pi 2 / 3 / 4 / Zero 2).
# Raspberry Pi 5 moved the header to gpiochip4 — use rak6421_pi5.conf for it
# (or pass --lora-gpio-chip=/dev/gpiochip4 at runtime).
#
# IO Slot 1 wiring (BCM GPIO numbers on gpiochip0), per meshtasticd
# lora-RAK6421-13300-slot1.yaml:
# SPI: /dev/spidev0.0 (CE0 = GPIO 8, hardware CS)
# DIO1/IRQ: GPIO 22 (IO6)
# RESET: GPIO 16 (IO4)
# BUSY: GPIO 24 (IO5)
# DIO2 = RF switch, DIO3 = 1.8V TCXO, Enable_Pins 12+13 held high (GPIO hogs).
#
# Source: github.com/meshtastic/firmware bin/config.d/lora-RAK6421-13300-slot1.yaml
CONFIG_ZEPHCORE_BOARD_NAME="RAK6421"
# Drive the RAK6421 Enable_Pins (GPIO 12/13) high at boot via the GPIO hogs
# declared in rak6421.overlay.
CONFIG_GPIO_HOGS=y
@@ -0,0 +1,76 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* RAK6421 WisBlock Pi HAT + RAK13300/RAK13302 (SX1262), IO Slot 1.
* Auto-paired with rak6421.conf. Defines the native_linux SPI/GPIO controllers
* + SX1262 node on top of linux_common.overlay's platform infra.
*
* Works on any Pi that exposes the 40-pin header on gpiochip0 (Pi 2/3/4/Zero 2).
* Pi 5 moved it to gpiochip4 — use rak6421_pi5.overlay instead.
*
* Pins + clock mirror the authoritative meshtasticd config
* (bin/config.d/lora-RAK6421-13300-slot1.yaml), BCM numbering:
* CS = GPIO 8 (spidev0.0 CE0, hardware CS)
* DIO1 = GPIO 22 (IO6)
* RESET = GPIO 16 (IO4)
* BUSY = GPIO 24 (IO5)
* DIO2 drives the antenna RF switch (DIO2_AS_RF_SWITCH);
* DIO3 powers a 1.8V TCXO (DIO3_TCXO_VOLTAGE);
* Enable_Pins 12 + 13 are held HIGH to enable the module's RF front-end
* (driven via GPIO hogs below — needs CONFIG_GPIO_HOGS=y, set in rak6421.conf).
*
* NOTE: hardware-untested in ZephCore (only the Femtofox is verified). The
* RAK13302 (1W SKY66122) additionally wants a PA gain table that ZephCore's
* SX126x driver does not expose; this overlay drives the 13300 correctly and
* the 13302 at default (non-boosted) PA.
*/
#include <zephyr/dt-bindings/gpio/gpio.h>
#include <zephyr/dt-bindings/lora/sx126x.h>
/ {
aliases {
lora0 = &lora_sx1262;
};
zephcore_gpio0: zephcore_gpio0 {
status = "okay";
compatible = "zephcore,gpio-native-linux";
gpio-controller;
gpio-chip = "/dev/gpiochip0";
ngpios = <64>;
#gpio-cells = <2>;
/* RAK6421 Enable_Pins (meshtasticd): held high at boot to enable
* the module / RF front-end. */
rak6421_enable {
gpio-hog;
gpios = <12 GPIO_ACTIVE_HIGH>, <13 GPIO_ACTIVE_HIGH>;
output-high;
};
};
zephcore_spi0: zephcore_spi0 {
status = "okay";
compatible = "zephcore,spi-native-linux";
spi-dev = "/dev/spidev0.0";
clock-frequency = <2000000>;
spi-mode = <0>;
#address-cells = <1>;
#size-cells = <0>;
/* SPI CE0 = BCM GPIO 8, driven as a regular GPIO. */
cs-gpios = <&zephcore_gpio0 8 GPIO_ACTIVE_LOW>;
lora_sx1262: lora@0 {
compatible = "semtech,sx1262";
reg = <0>;
spi-max-frequency = <2000000>;
reset-gpios = <&zephcore_gpio0 16 GPIO_ACTIVE_LOW>;
busy-gpios = <&zephcore_gpio0 24 GPIO_ACTIVE_HIGH>;
dio1-gpios = <&zephcore_gpio0 22 GPIO_ACTIVE_HIGH>;
dio2-tx-enable;
dio3-tcxo-voltage = <SX126X_DIO3_TCXO_1V8>;
tcxo-power-startup-delay-ms = <5>;
};
};
};
@@ -0,0 +1,11 @@
# RAK6421 WisBlock Pi HAT + RAK13300/RAK13302 (SX1262) on Raspberry Pi 5.
#
# Identical wiring to rak6421.conf, but the Pi 5 moved the 40-pin header GPIOs
# to /dev/gpiochip4 (the RP1 chip) — that's the only difference. Equivalent to
# rak6421.conf + --lora-gpio-chip=/dev/gpiochip4.
CONFIG_ZEPHCORE_BOARD_NAME="RAK6421 (Pi5)"
# Drive the RAK6421 Enable_Pins (GPIO 12/13) high at boot via the GPIO hogs
# declared in rak6421_pi5.overlay.
CONFIG_GPIO_HOGS=y
@@ -0,0 +1,60 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* RAK6421 WisBlock Pi HAT + RAK13300/RAK13302 (SX1262), IO Slot 1, on Pi 5.
* Auto-paired with rak6421_pi5.conf. Identical to rak6421.overlay except the
* Pi 5 moved the 40-pin header GPIOs to /dev/gpiochip4.
*
* Pins + clock mirror meshtasticd (lora-RAK6421-13300-slot1.yaml), BCM numbering:
* CS = GPIO 8 (spidev0.0 CE0), DIO1 = GPIO 22, RESET = GPIO 16, BUSY = GPIO 24,
* DIO2 = RF switch, DIO3 = 1.8V TCXO, Enable_Pins 12+13 held high (GPIO hogs;
* needs CONFIG_GPIO_HOGS=y in rak6421_pi5.conf). Hardware-untested in ZephCore.
*/
#include <zephyr/dt-bindings/gpio/gpio.h>
#include <zephyr/dt-bindings/lora/sx126x.h>
/ {
aliases {
lora0 = &lora_sx1262;
};
zephcore_gpio0: zephcore_gpio0 {
status = "okay";
compatible = "zephcore,gpio-native-linux";
gpio-controller;
gpio-chip = "/dev/gpiochip4";
ngpios = <64>;
#gpio-cells = <2>;
/* RAK6421 Enable_Pins: held high at boot to enable the RF front-end. */
rak6421_enable {
gpio-hog;
gpios = <12 GPIO_ACTIVE_HIGH>, <13 GPIO_ACTIVE_HIGH>;
output-high;
};
};
zephcore_spi0: zephcore_spi0 {
status = "okay";
compatible = "zephcore,spi-native-linux";
spi-dev = "/dev/spidev0.0";
clock-frequency = <2000000>;
spi-mode = <0>;
#address-cells = <1>;
#size-cells = <0>;
cs-gpios = <&zephcore_gpio0 8 GPIO_ACTIVE_LOW>;
lora_sx1262: lora@0 {
compatible = "semtech,sx1262";
reg = <0>;
spi-max-frequency = <2000000>;
reset-gpios = <&zephcore_gpio0 16 GPIO_ACTIVE_LOW>;
busy-gpios = <&zephcore_gpio0 24 GPIO_ACTIVE_HIGH>;
dio1-gpios = <&zephcore_gpio0 22 GPIO_ACTIVE_HIGH>;
dio2-tx-enable;
dio3-tcxo-voltage = <SX126X_DIO3_TCXO_1V8>;
tcxo-power-startup-delay-ms = <5>;
};
};
};
@@ -3,17 +3,18 @@
* SPDX-License-Identifier: Apache-2.0
*
* Zephyr GPIO controller that bridges to a Linux /dev/gpiochipX device
* via libgpiod v2. Runs under native_sim on a real Linux host (not in
* QEMU or simulation).
* via the kernel's GPIO V2 character-device uAPI (direct ioctls, no
* libgpiod). Runs under native_sim on a real Linux host (not in QEMU or
* simulation).
*
* Each pin owns its own gpiod_line_request, lazily (re)created when
* Each pin owns its own kernel line request, lazily (re)created when
* pin_configure or pin_interrupt_configure changes its settings. A
* dedicated k_thread polls() the fds of all edge-detection-enabled pins
* and fires the registered Zephyr gpio_callbacks on each event.
*
* Host-side libgpiod calls live in gpio_native_linux_adapt.c (compiled
* into the native_simulator INTERFACE) to keep libgpiod headers out of
* the Zephyr translation unit.
* Host-side chardev ioctls live in gpio_native_linux_adapt.c (compiled
* into the native_simulator INTERFACE) to keep host headers out of the
* Zephyr translation unit.
*/
#define DT_DRV_COMPAT zephcore_gpio_native_linux