mirror of
https://github.com/MeshEnvy/lobbs.git
synced 2026-10-31 02:11:59 +01:00
refactor(core): split pal from kernel
Move the BBS kernel under core/ and host I/O under platforms/.
This commit is contained in:
1 parent
6fdcc71953
commit
1243b2bc1b
131 files changed
+3500
-1428
No files matched your search
+17
-7
@@ -95,19 +95,25 @@ Machine: records encoded as LoScalar lines, sliced into pages with `<id>ok [n:ma
|
||||
|
||||
## LoFS and install
|
||||
|
||||
LoFS exposes `/` as a virtual root listing mounts. Writable paths start with `/<mount>/…` (optional `sd`, optional `extra` when built with `LOBBS_EXTRA_QSPI=1`, `flash2` on nRF52840, `flash`). Mount roots cannot be removed, renamed, or used as copy sources. Cross-mount `mv` copies files then deletes the source. Directories require same-mount rename.
|
||||
LoFS exposes `/` as a virtual root listing mounts. Writable paths start with `/<mount>/…`. Slot names in install preference order: `sd`, `qspi`, `reserve`, `spare`, `internal`. Each slot maps to a `LoFSVolume` provider (adopted host LittleFS or LoBBS-mounted block device). Host composition lives in `lofs/platforms/meshtastic/LoFSMountsMeshtastic.cpp` and `lofs/platforms/meshcore/LoFSMountsMeshcore.cpp`. Mount roots cannot be removed, renamed, or used as copy sources. Cross-mount `mv` copies files then deletes the source. Directories require same-mount rename.
|
||||
|
||||
`/flash2` is a second nRF52840 internal-flash partition, 100 KiB at `0xD4000`–`0xED000` between the app and InternalFS. The linker scripts `src/platform/nrf52/nrf52840_s140_v6.ld` (set on `nrf52840_base`) and `nrf52840_s140_v7.ld` end `FLASH` at `0xD4000` and provide `__flash2_start` / `__flash2_end`. LoFS reads them as weak symbols, so nRF builds on other linker scripts have no `/flash2`. The partition is a second `Adafruit_LittleFS` with 128 B blocks over `flash_nrf5x`. It is formatted when mount fails or by SysOp `/format flash2` (`LoFS::format`, which erases the pages first). Its block IO takes InternalFS's lock because the `flash_nrf5x` page cache is shared and the BLE task writes bonds to InternalFS.
|
||||
`/spare` is the middle nRF52840 internal window (100 KiB at `0xD4000`–`0xED000`, weak symbols `__flash2_start` / `__flash2_end`). Meshtastic mounts it with `LoFSNrfFlashBlockDevice` when the linker provides the symbols. MeshCore adopts host `ExtraFS` on the same range when `EXTRAFS` is enabled.
|
||||
|
||||
`/extra` is optional onboard QSPI flash (2 MiB, 4096 B sectors, 256 B read/prog, 512-block lookahead). LoFS uses `LoFSQspi` (`nrfx_qspi`, FASTREAD/PP at SCK/8, no quad-enable). Boot sends release-from-deep-power-down (`0xAB`) and software reset (`0x66`/`0x99`), then reads the JEDEC ID and expects Puya `0x85`. A wrong or missing ID skips the mount and never formats. A mount failure on a good ID formats, as does `/format extra`. `/format flash` runs `FSCom.format()` then `nodeDB->saveToDisk()`, the same recovery Meshtastic uses after a failed save. Formatting the install mount reruns `lobbsInstallInit`, so the node goes Blank unless another mount holds an install. Every custom instruction holds IO2/IO3 high: they are WP#/HOLD# while the quad-enable bit is clear, so LoFSQspi polls the status register (`0x05`) itself instead of `nrfx_qspi_mem_busy_check`, which sends it with HOLD# low.
|
||||
`/reserve` is the low window (`0xCC000`–`0xD4000`, `__flash3_*`) when the opt-in MeshCore linker script or Meshtastic layout leaves it empty. LoBBS mounts it with the same block device helper.
|
||||
|
||||
`/qspi` is onboard NOR (2 MiB). Meshtastic always mounts via `LoFSQspiNorBlockDevice` when `LOFS_ENABLE_EXTRA_QSPI`. MeshCore adopts `QSPIFlash` when `QSPIFLASH`, otherwise LoBBS mounts the chip when present.
|
||||
|
||||
`/internal` is the host primary filesystem (`InternalFS` / `FSCom` on Meshtastic, the filesystem pointer passed to `lobbsMeshCoreInit` on MeshCore). It is shared: LoBBS keeps a reserve on writes. `/format internal` on Meshtastic runs `FSCom.format()` then `nodeDB->saveToDisk()`. Formatting the install mount reruns `lobbsInstallInit`.
|
||||
|
||||
`LoFS::list` callbacks get `(ctx, basename, isDirectory, size)`. `size` is the file length, 0 for directories and mounts.
|
||||
|
||||
Each mount has a `dbSafe` flag (`LoFS::mountDbSafe`). `sd`, `extra`, and `flash2` are db-safe. `flash` is db-safe only when there is no `flash2` mount, because a failed Meshtastic save on nRF52 formats InternalFS. Install points come from the `install_mounts` list filter. Core registers a provider that lists present db-safe mounts in mount-table order, which is preference order (`sd`, `extra`, `flash2`, `flash`). `/install` accepts only listed mounts, the install hint and usage show them, and demo seeding uses the first one.
|
||||
Each mount has `dbSafe` (computed at boot: non-shared volumes are always db-safe; shared volumes are db-safe only when no higher-preference mount is present) and `formattable`. LittleFS mounts are formattable; `sd` is not. Install points come from the `install_mounts` list filter in preference order above.
|
||||
|
||||
Shared mounts (`/flash`) keep `LOFS_SHARED_RESERVE_BYTES` free (16 KiB nRF52, 128 KiB other hardware, 0 Portduino; override with `-D`). `LoFS::hasRoom(path, bytes)` rounds `bytes` up to the block size, adds slack for metadata, adds the mount reserve, and compares with free space. It returns true when the mount reports no size. LoDB checks it before every record write and returns `LODB_ERR_FULL`. FsCommands checks it for `/mkdir`, `/cp`, `/upload`, and cross-mount `/mv`. Apps map `LODB_ERR_FULL` to `Disk full.` via `lobbsDbErrorText`. Deletes are never blocked.
|
||||
MeshCore nRF52840 can opt into `/reserve` with `boards/nrf52840_s140_v7_lobbs_flash3.ld`. Example env: `RAK_4631_terminal_chat` in `lobbs-meshcore-firmware`. `lobbsMeshCoreInit` calls `lofsMeshcoreSetHostFilesystem` before `LoFS::begin`.
|
||||
|
||||
LoBBS home: everything lives under `/<mount>/lobbs` (`LOBBS_HOME_DIR`). `install.ls` (field `LOBBS_INSTALL_FIELD_VERSION` = `LOBBS_VERSION` at install) marks the install and is written last. `db/` is the LoDB (`LoDb("db")` opened at the home). `apps/<app>/` and `home/<user>/` are reserved conventions. At boot `lobbsInstallInit` walks `install_mounts` in order and takes the first mount holding `lobbs/install.ls`. Later hits are logged and ignored. No marker lives on `/flash`.
|
||||
Shared mounts keep reserve bytes free (16 KiB nRF52, 128 KiB other hardware, 0 Portduino). `LoFS::hasRoom(path, bytes)` rounds `bytes` up to the block size, adds slack for metadata, adds the mount reserve, and compares with free space. It returns true when the mount reports no size. LoDB checks it before every record write and returns `LODB_ERR_FULL`. FsCommands checks it for `/mkdir`, `/cp`, `/upload`, and cross-mount `/mv`. Apps map `LODB_ERR_FULL` to `Disk full.` via `lobbsDbErrorText`. Deletes are never blocked.
|
||||
|
||||
LoBBS home: everything lives under `/<mount>/lobbs` (`LOBBS_HOME_DIR`). `install.ls` marks the install and is written last. At boot `lobbsInstallInit` walks `install_mounts` in order and takes the first mount holding `lobbs/install.ls`. No marker lives on `/internal`.
|
||||
|
||||
| State | Behavior |
|
||||
| ------- | ----------------------------------------------------------------------- |
|
||||
@@ -172,7 +178,11 @@ Strip 95 and 96 before `update` to get default stamps. Times are Unix seconds, n
|
||||
|
||||
## Verifying
|
||||
|
||||
Build `pio run -e rak4631` and run `trunk fmt` before commit. Native tests are not green on this branch. See `.cursor/rules/lobbs-verification.mdc`.
|
||||
Product platforms are Meshtastic and MeshCore only. Build `pio run -e rak4631` (Meshtastic fork) or a MeshCore terminal-chat env, and run `trunk fmt` before commit.
|
||||
|
||||
Protocol paging tests (no fork): `cd ci/host && pio test -e host -f test_protocol_host` (`LOBBS_PLATFORM_NATIVE`).
|
||||
|
||||
Command integration tests use the Meshtastic fork’s `native-macos` env (`pio test -e native-macos -f test_lobbs_commands`). That runs on upstream’s Portduino desktop target. It is not a separate LoBBS platform.
|
||||
|
||||
## Plugin checklist
|
||||
|
||||
|
||||
+11
-10
@@ -14,10 +14,11 @@ A new LoBBS node has no database until you install it. Only `/help` and `/instal
|
||||
|
||||
| Hardware | Install mounts |
|
||||
| ------------------------ | ---------------------------------------------------- |
|
||||
| nRF52840 | `sd`, `extra`, `flash2` (100 KB set aside for LoBBS) |
|
||||
| ESP32 and other hardware | `sd`, `extra`, `flash` |
|
||||
| nRF52840 Meshtastic | `sd`, `qspi`, `reserve` (if linked), `spare` (100 KB LoBBS) |
|
||||
| nRF52840 MeshCore | `qspi`, `reserve` (opt-in linker), `spare` (host ExtraFS), `internal` |
|
||||
| ESP32 and other hardware | `sd`, `qspi`, `internal` |
|
||||
|
||||
Mounts are listed in preference order. `sd` appears when a card is present. `extra` (about 2 MB) appears on Seeed XIAO nRF52840 kit and SenseCAP Solar Node builds (`LOBBS_EXTRA_QSPI=1`). On nRF52840 `/flash` is Meshtastic's own 28 KB and is not offered.
|
||||
Mounts are listed in preference order. `sd` appears when a card is present. `qspi` (about 2 MB) appears on Seeed XIAO nRF52840 kit and SenseCAP Solar Node builds (`LOBBS_EXTRA_QSPI=1`). On nRF52840 Meshtastic, `/internal` is the radio's own filesystem and is only offered when no better mount exists.
|
||||
|
||||
`/install <mount> <user> <pass>` creates the database on that mount and makes `<user>` the SysOp. Use it from the local client (phone app connected over serial/BLE) or from a remote DM encrypted with a configured admin key. If the target already holds a LoBBS database, the same command adopts it and you must supply an existing SysOp username and password. Once installed, `/install` replies `Already installed at /<mount>.`
|
||||
|
||||
@@ -30,7 +31,7 @@ Everything LoBBS stores lives under `/<mount>/lobbs`:
|
||||
| `/<mount>/lobbs/apps/<app>/` | Reserved for per-app files |
|
||||
| `/<mount>/lobbs/home/<user>/` | Reserved for user files |
|
||||
|
||||
On boot LoBBS checks the install mounts in preference order and uses the first one holding `lobbs/install.ls`. Nothing is stored on `/flash`, so a Meshtastic wipe of `/flash` does not lose the install. Pulling the SD card that holds it makes the node look new until the card is back.
|
||||
On boot LoBBS checks the install mounts in preference order and uses the first one holding `lobbs/install.ls`. Nothing is stored on `/internal`, so a Meshtastic wipe of `/internal` does not lose the install when it lives on `spare`, `qspi`, or `sd`. Pulling the SD card that holds it makes the node look new until the card is back.
|
||||
|
||||
## Demo builds
|
||||
|
||||
@@ -62,22 +63,22 @@ Config keys (uint32, defaults in parentheses): `session.max` (16), `session.idle
|
||||
| `/rm /path` | Delete a file (absolute path only) |
|
||||
| `/rmdir /path` | Remove an empty directory (absolute path only) |
|
||||
| `/rmtree /path /path` | Recursive delete (absolute path, typed twice) |
|
||||
| `/mkdir path` | Create a directory under a mount (`/flash/...`, etc.) |
|
||||
| `/mkdir path` | Create a directory under a mount (`/internal/...`, etc.) |
|
||||
| `/cp src dst` | Copy a file (no overwrite; directories refused) |
|
||||
| `/mv src dst` | Rename on one mount, or copy then delete across mounts (files only) |
|
||||
| `/upload path [offset:b62]` | Chunked file write at byte offset, or show current size |
|
||||
| `/commit src dst` | Move when file CRC32 matches the 8-hex segment in the source name |
|
||||
| `/stat path` | `file N` or `dir` |
|
||||
| `/df` | One line per mount, e.g. `extra: 1.8M free of 2.0M (12% used) [lobbs]`. Free space excludes the `/flash` reserve. `[lobbs]` marks the install mount |
|
||||
| `/format mount [code]` | Erase a mount. The first call replies with a code; repeat with the code within 2 minutes from the same node. On `/flash` the radio settings are saved again from memory (BLE pairings are lost). On the install mount LoBBS goes blank until `/install`. `sd` is refused (format cards on a PC) |
|
||||
| `/df` | One line per mount, e.g. `qspi: 1.8M free of 2.0M (12% used) [lobbs]`. Free space excludes the `/internal` reserve. `[lobbs]` marks the install mount |
|
||||
| `/format mount [code]` | Erase a mount. The first call replies with a code; repeat with the code within 2 minutes from the same node. On `/internal` the radio settings are saved again from memory (BLE pairings are lost). On the install mount LoBBS goes blank until `/install`. `sd` is refused (format cards on a PC) |
|
||||
|
||||
SysOps painting the wall or adding yarn do not use quota.
|
||||
|
||||
## Files
|
||||
|
||||
Paths use mount prefixes: `/flash/...`, `/flash2/...` on nRF52840, `/sd/...`, `/extra/...` on builds with `LOBBS_EXTRA_QSPI=1` and a QSPI flash chip. `/` lists mounts. Do not `/rmtree` `<mount>/lobbs` on your install mount unless you intend to wipe the BBS.
|
||||
Paths use mount prefixes: `/internal/...`, `/spare/...` on nRF52840, `/sd/...`, `/qspi/...` on builds with `LOBBS_EXTRA_QSPI=1` and a QSPI flash chip. `/` lists mounts. Do not `/rmtree` `<mount>/lobbs` on your install mount unless you intend to wipe the BBS.
|
||||
|
||||
`/flash` is shared with Meshtastic's own settings and node database. LoBBS leaves a reserve free there (16 KB on nRF52, 128 KB elsewhere). Posts, mail, uploads, and copies that would cut into it reply `Disk full.`. Deleting files always works. `/flash2`, `/sd` and `/extra` have no reserve.
|
||||
`/internal` is shared with Meshtastic's own settings and node database. LoBBS leaves a reserve free there (16 KB on nRF52, 128 KB elsewhere). Posts, mail, uploads, and copies that would cut into it reply `Disk full.`. Deleting files always works. `/spare`, `/sd`, and `/qspi` have no reserve.
|
||||
|
||||
Relative paths work under your session working directory for `ls`, `cat`, `hex`, `stat`, `mkdir`, `cp`, `mv`, `upload`, and `commit`. `rm`, `rmdir`, and `rmtree` require absolute paths.
|
||||
|
||||
@@ -88,7 +89,7 @@ Relative paths work under your session working directory for `ls`, `cat`, `hex`,
|
||||
From the firmware repo root:
|
||||
|
||||
```bash
|
||||
python src/modules/LoBBS/bin/lobbs_chunkify.py local.txt /flash/path/dest.txt
|
||||
python src/modules/LoBBS/bin/lobbs_chunkify.py local.txt /internal/path/dest.txt
|
||||
```
|
||||
|
||||
The script prints `/mkdir`, `/upload`, and `/commit` lines. Temp files use `<name>.<crc8>.tmp`.
|
||||
Reference in new issue
Block a user