rumpk/libs/membrane/fs/lfs_nim.nim

171 lines
6.1 KiB
Nim

# SPDX-License-Identifier: LSL-1.0
# Copyright (c) 2026 Markus Maiwald
# Stewardship: Self Sovereign Society Foundation
## Nexus Membrane: LittleFS Bindings (L0 Physics)
## Provides Nim bindings to the LittleFS C library.
import ../blk
type
LfsConfig* {.importc: "struct lfs_config", header: "lfs.h", nodecl, final.} = object
context*: pointer
read*: proc(cfg: ptr LfsConfig, blk: uint32, off: uint32, buf: pointer, size: uint32): cint {.cdecl.}
prog*: proc(cfg: ptr LfsConfig, blk: uint32, off: uint32, buf: pointer, size: uint32): cint {.cdecl.}
erase*: proc(cfg: ptr LfsConfig, blk: uint32): cint {.cdecl.}
sync*: proc(cfg: ptr LfsConfig): cint {.cdecl.}
read_size*: uint32
prog_size*: uint32
block_size*: uint32
block_count*: uint32
block_cycles*: int32
cache_size*: uint32
lookahead_size*: uint32
read_buffer*: pointer
prog_buffer*: pointer
lookahead_buffer*: pointer
name_max*: uint32
file_max*: uint32
attr_max*: uint32
metadata_max*: uint32
Lfs* {.importc: "lfs_t", header: "lfs.h".} = object
LfsFile* {.importc: "lfs_file_t", header: "lfs.h".} = object
LfsInfo* {.importc: "struct lfs_info", header: "lfs.h".} = object
lfsType*: uint8
size*: uint32
name*: array[256, char]
const
LFS_TYPE_REG* = 1'u8
LFS_TYPE_DIR* = 2'u8
LFS_O_RDONLY* = 1
LFS_O_WRONLY* = 2
LFS_O_RDWR* = 3
LFS_O_CREAT* = 0x0100
LFS_O_EXCL* = 0x0200
LFS_O_TRUNC* = 0x0400
LFS_O_APPEND* = 0x0800
# LittleFS C API
proc lfs_mount(lfs: ptr Lfs, cfg: ptr LfsConfig): cint {.importc, header: "lfs.h", cdecl.}
proc lfs_format(lfs: ptr Lfs, cfg: ptr LfsConfig): cint {.importc, header: "lfs.h", cdecl.}
proc lfs_file_open(lfs: ptr Lfs, file: ptr LfsFile, path: cstring, flags: cint): cint {.importc, header: "lfs.h", cdecl.}
proc lfs_file_close(lfs: ptr Lfs, file: ptr LfsFile): cint {.importc, header: "lfs.h", cdecl.}
proc lfs_file_read(lfs: ptr Lfs, file: ptr LfsFile, buf: pointer, size: uint32): cint {.importc, header: "lfs.h", cdecl.}
proc lfs_file_write(lfs: ptr Lfs, file: ptr LfsFile, buf: pointer, size: uint32): cint {.importc, header: "lfs.h", cdecl.}
proc lfs_file_seek(lfs: ptr Lfs, file: ptr LfsFile, off: int32, whence: cint): int32 {.importc, header: "lfs.h", cdecl.}
proc lfs_file_rewind(lfs: ptr Lfs, file: ptr LfsFile): int32 {.importc, header: "lfs.h", cdecl.}
proc lfs_stat(lfs: ptr Lfs, path: cstring, info: ptr LfsInfo): cint {.importc, header: "lfs.h", cdecl.}
proc lfs_remove(lfs: ptr Lfs, path: cstring): cint {.importc, header: "lfs.h", cdecl.}
proc lfs_mkdir(lfs: ptr Lfs, path: cstring): cint {.importc, header: "lfs.h", cdecl.}
# =========================================================
# LFS Wrapper Procs (Callbacks)
# =========================================================
var lfs_start_sector: uint64 = 8192
proc lfs_block_read(cfg: ptr LfsConfig, blk: uint32, off: uint32, buf: pointer, size: uint32): cint {.cdecl.} =
# Calculate absolute sector
let sector = lfs_start_sector + uint64(blk) * (cfg.block_size div 512) + uint64(off div 512)
var temp: array[512, byte]
if size == 512 and off mod 512 == 0:
if blk_read(sector, addr temp[0]) < 0: return -1
copyMem(buf, addr temp[0], 512)
return 0
var remaining = int(size)
var dst = cast[int](buf)
var cur_off = off
while remaining > 0:
let sec = lfs_start_sector + uint64(blk) * (cfg.block_size div 512) + uint64(cur_off div 512)
if blk_read(sec, addr temp[0]) < 0: return -1
let in_sec_off = int(cur_off mod 512)
let copy_len = min(remaining, 512 - in_sec_off)
copyMem(cast[pointer](dst), addr temp[in_sec_off], copy_len)
dst += copy_len
cur_off += uint32(copy_len)
remaining -= copy_len
return 0
proc lfs_block_prog(cfg: ptr LfsConfig, blk: uint32, off: uint32, buf: pointer, size: uint32): cint {.cdecl.} =
let sector = lfs_start_sector + uint64(blk) * (cfg.block_size div 512) + uint64(off div 512)
var temp: array[512, byte]
if size == 512 and off mod 512 == 0:
copyMem(addr temp[0], buf, 512)
if blk_write(sector, addr temp[0]) < 0: return -1
return 0
var remaining = int(size)
var src = cast[int](buf)
var cur_off = off
while remaining > 0:
let sec = lfs_start_sector + uint64(blk) * (cfg.block_size div 512) + uint64(cur_off div 512)
if blk_read(sec, addr temp[0]) < 0: return -1
let in_sec_off = int(cur_off mod 512)
let copy_len = min(remaining, 512 - in_sec_off)
copyMem(addr temp[in_sec_off], cast[pointer](src), copy_len)
if blk_write(sec, addr temp[0]) < 0: return -1
src += copy_len
cur_off += uint32(copy_len)
remaining -= copy_len
return 0
proc lfs_block_erase(cfg: ptr LfsConfig, blk: uint32): cint {.cdecl.} =
var zeros: array[512, byte]
let sectors_per_block = cfg.block_size div 512
for i in 0'u32 ..< sectors_per_block:
let sec = lfs_start_sector + uint64(blk) * uint64(sectors_per_block) + uint64(i)
if blk_write(sec, addr zeros[0]) < 0: return -1
return 0
proc lfs_block_sync(cfg: ptr LfsConfig): cint {.cdecl.} =
discard blk_sync()
return 0
# =========================================================
# High-Level API
# =========================================================
var g_lfs: Lfs
var g_cfg: LfsConfig
var g_mounted: bool = false
# Static buffers
var lfs_read_buf: array[512, byte]
var lfs_prog_buf: array[512, byte]
var lfs_lookahead_buf: array[16, byte]
proc lfs_nim_init*(start_sector: uint64 = 8192, block_count: uint32 = 1024) =
lfs_start_sector = start_sector
g_cfg.context = nil
g_cfg.read = lfs_block_read
g_cfg.prog = lfs_block_prog
g_cfg.erase = lfs_block_erase
g_cfg.sync = lfs_block_sync
g_cfg.read_size = 512
g_cfg.prog_size = 512
g_cfg.block_size = 4096
g_cfg.block_count = block_count
g_cfg.block_cycles = 500
g_cfg.cache_size = 512
g_cfg.lookahead_size = 16
g_cfg.read_buffer = addr lfs_read_buf
g_cfg.prog_buffer = addr lfs_prog_buf
g_cfg.lookahead_buffer = addr lfs_lookahead_buf
proc lfs_nim_format*(): bool =
lfs_nim_init()
return lfs_format(addr g_lfs, addr g_cfg) == 0
proc lfs_nim_mount*(): bool =
if g_mounted: return true
lfs_nim_init()
if lfs_mount(addr g_lfs, addr g_cfg) == 0:
g_mounted = true
return true
return false