171 lines
6.1 KiB
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
|