Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docker-build
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
docker run --rm -v $PWD:/sources infinitime-build
11 changes: 10 additions & 1 deletion docker/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ RUN apt-get update -qq \
# x86_64 / generic packages
bash \
build-essential \
cmake \
git \
make \
python3 \
Expand All @@ -22,6 +21,16 @@ RUN apt-get update -qq \

RUN pip3 install adafruit-nrfutil

# install latest CMake (and utils)
RUN apt install -y \
make
ARG CMAKE_VERSION=3.17.2
ADD https://github.com/Kitware/CMake/releases/download/v${CMAKE_VERSION}/cmake-${CMAKE_VERSION}-Linux-x86_64.sh /tmp/cmake-install.sh
RUN apt install -y \
tar gzip
RUN yes | sh /tmp/cmake-install.sh --skip-license --prefix=/
RUN rm /tmp/cmake-install.sh

# build.sh knows how to compile
COPY build.sh /opt/

Expand Down
6 changes: 5 additions & 1 deletion src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -476,6 +476,9 @@ include_directories(
.
../
libs/
# FIXME workaround hack
${CMAKE_BINARY_DIR}/_deps/project_littlefs-src/
components/littlefs/
FreeRTOS/
libs/date/includes
libs/mynewt-nimble/porting/npl/freertos/include
Expand Down Expand Up @@ -624,7 +627,8 @@ set(EXECUTABLE_FILE_NAME ${EXECUTABLE_NAME}-${pinetime_VERSION_MAJOR}.${pinetime
set(NRF5_LINKER_SCRIPT "${CMAKE_SOURCE_DIR}/gcc_nrf52.ld")
add_executable(${EXECUTABLE_NAME} ${SOURCE_FILES})
set_target_properties(${EXECUTABLE_NAME} PROPERTIES OUTPUT_NAME ${EXECUTABLE_FILE_NAME})
target_link_libraries(${EXECUTABLE_NAME} nimble nrf-sdk lvgl)
add_subdirectory("components/littlefs")
target_link_libraries(${EXECUTABLE_NAME} nimble nrf-sdk lvgl littlefs)
target_compile_options(${EXECUTABLE_NAME} PUBLIC
$<$<AND:$<COMPILE_LANGUAGE:C>,$<CONFIG:DEBUG>>: ${COMMON_FLAGS} -O0 -g3>
$<$<AND:$<COMPILE_LANGUAGE:C>,$<CONFIG:RELEASE>>: ${COMMON_FLAGS} -O3>
Expand Down
52 changes: 52 additions & 0 deletions src/components/littlefs/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@

include(FetchContent)
set(FETCHCONTENT_QUIET OFF) # enable GIT_PROGRESS output

FetchContent_Declare(project_littlefs
GIT_REPOSITORY https://github.com/littlefs-project/littlefs.git
GIT_SHALLOW ON
GIT_PROGRESS ON
)

# littlefs Pull
#-------------------------------------------------------------------------------
if(NOT project_littlefs_POPULATED)
FetchContent_Populate(project_littlefs)
endif()

add_library(littlefs
${project_littlefs_SOURCE_DIR}/lfs_util.c
${project_littlefs_SOURCE_DIR}/lfs.c
)
target_include_directories(littlefs
PUBLIC
${project_littlefs_SOURCE_DIR}/
)
target_link_libraries(littlefs littlefs-target)
target_compile_options(littlefs
PUBLIC
$<$<AND:$<COMPILE_LANGUAGE:C>,$<CONFIG:DEBUG>>: ${COMMON_FLAGS} -O0 -g3>
$<$<AND:$<COMPILE_LANGUAGE:C>,$<CONFIG:RELEASE>>: ${COMMON_FLAGS} -O3>
$<$<AND:$<COMPILE_LANGUAGE:CXX>,$<CONFIG:DEBUG>>: ${COMMON_FLAGS} -O0 -g3>
$<$<AND:$<COMPILE_LANGUAGE:CXX>,$<CONFIG:RELEASE>>: ${COMMON_FLAGS} -O3>
$<$<COMPILE_LANGUAGE:ASM>: -MP -MD -std=c99 -x assembler-with-cpp>
)

add_library(littlefs-target
LittleFs.cpp
)
target_include_directories(littlefs-target
PUBLIC
./
#FIXME refactor source into actual components
../../
)
target_link_libraries(littlefs-target littlefs)
target_compile_options(littlefs-target
PUBLIC
$<$<AND:$<COMPILE_LANGUAGE:C>,$<CONFIG:DEBUG>>: ${COMMON_FLAGS} -O0 -g3>
$<$<AND:$<COMPILE_LANGUAGE:C>,$<CONFIG:RELEASE>>: ${COMMON_FLAGS} -O3>
$<$<AND:$<COMPILE_LANGUAGE:CXX>,$<CONFIG:DEBUG>>: ${COMMON_FLAGS} -O0 -g3>
$<$<AND:$<COMPILE_LANGUAGE:CXX>,$<CONFIG:RELEASE>>: ${COMMON_FLAGS} -O3>
$<$<COMPILE_LANGUAGE:ASM>: -MP -MD -std=c99 -x assembler-with-cpp>
)
116 changes: 116 additions & 0 deletions src/components/littlefs/LittleFs.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
#include "LittleFs.h"

using namespace Pinetime::System;

static int read(const struct lfs_config *c, lfs_block_t block,
lfs_off_t off, void *buffer, lfs_size_t size);

static int prog(const struct lfs_config *c, lfs_block_t block,
lfs_off_t off, const void *buffer, lfs_size_t size);

static int erase(const struct lfs_config *c, lfs_block_t block);

static int sync(const struct lfs_config *c);

constexpr size_t BLOCK_SIZE_BYTES = 256u;
constexpr size_t PAGE_SIZE_BYTES = BLOCK_SIZE_BYTES;
constexpr size_t CACHE_PAGE_COUNT = 1u;
constexpr size_t CACHE_SIZE_BYTES = (CACHE_PAGE_COUNT * PAGE_SIZE_BYTES);
constexpr size_t LOOKAHEAD_SIZE_BYTES = (CACHE_PAGE_COUNT * 8u);
static uint8_t readBuffer[CACHE_SIZE_BYTES];
static uint8_t progBuffer[CACHE_SIZE_BYTES];
static uint8_t __attribute__((aligned(32)))
lookaheadBuffer[LOOKAHEAD_SIZE_BYTES];
const static struct lfs_config baseLfsConfig = {
.read = read,
.prog = prog,
.erase = erase,
.sync = sync,

.read_size = PAGE_SIZE_BYTES,
.prog_size = PAGE_SIZE_BYTES,
.block_size = BLOCK_SIZE_BYTES,
.block_cycles = 500u,

.cache_size = CACHE_SIZE_BYTES,
.lookahead_size = LOOKAHEAD_SIZE_BYTES,

.read_buffer = readBuffer,
.prog_buffer = progBuffer,
.lookahead_buffer = lookaheadBuffer,

.name_max = 0u, /** use LFS default */
.file_max = 0u, /** use LFS default */
.attr_max = 0u, /** use LFS default */
};

constexpr struct lfs_config createLfsConfig(Pinetime::System::LittleFs& lfs, const size_t totalSize_bytes) {
struct lfs_config config = baseLfsConfig;
config.context = &lfs;
config.block_count = totalSize_bytes / BLOCK_SIZE_BYTES;
return config;
}

LittleFs::LittleFs(Pinetime::Drivers::SpiNorFlash& driver,
const size_t startAddress,
const size_t size_bytes,
const bool allowFormat)
:mDriver{driver}, mStartAddress{startAddress}, mSize_bytes{size_bytes},
mLfsConfig{createLfsConfig(*this, size_bytes)}
{
// try mount
if(0u != lfs_mount(&mLfs, &mLfsConfig)) {
if(allowFormat) {
// format and mount
if(0u == lfs_format(&mLfs, &mLfsConfig)) {
lfs_mount(&mLfs, &mLfsConfig);
}
}
}
}

static int read(const struct lfs_config *c, lfs_block_t block,
lfs_off_t off, void *buffer, lfs_size_t size) {
Pinetime::System::LittleFs& lfs = *(reinterpret_cast<Pinetime::System::LittleFs*>(c->context));
const size_t address = lfs.mStartAddress + (block * BLOCK_SIZE_BYTES) + off;
lfs.mDriver.Read(address, (uint8_t*)buffer, size);
// TODO assumes READ was successful
return 0u;
}

static int prog(const struct lfs_config *c, lfs_block_t block,
lfs_off_t off, const void *buffer, lfs_size_t size) {
Pinetime::System::LittleFs& lfs = *(reinterpret_cast<Pinetime::System::LittleFs*>(c->context));
const size_t address = lfs.mStartAddress + (block * BLOCK_SIZE_BYTES) + off;
lfs.mDriver.Write(address, (uint8_t*)buffer, size);
return lfs.mDriver.ProgramFailed() ? -1u : 0u;
}

static int erase(const struct lfs_config *c, lfs_block_t block) {
Pinetime::System::LittleFs& lfs = *(reinterpret_cast<Pinetime::System::LittleFs*>(c->context));
const size_t address = lfs.mStartAddress + (block * BLOCK_SIZE_BYTES);
lfs.mDriver.SectorErase(address);
return lfs.mDriver.EraseFailed() ? -1u : 0u;
}

static int sync(const struct lfs_config *c) {
// no hardware caching used
return 0u;
}

const LittleFs::LittleFsDir::LittleFsEntry LittleFs::LittleFsDir::next() {
lfs_info entryInfo;
const int rtn = lfs_dir_read(&mLfs, &mLfs_dir, &entryInfo);
if(rtn == 0) {
LittleFsEntry entry{
.type = (entryInfo.type == LFS_TYPE_DIR) ?
LittleFs::LittleFsDir::LittleFsEntry::Type::DIR :
LittleFs::LittleFsDir::LittleFsEntry::Type::FILE,
.size = entryInfo.size
};
strncpy(entry.name, entryInfo.name, sizeof(entry.name));
return entry;
}
else
return LittleFsEntry{ .type = LittleFs::LittleFsDir::LittleFsEntry::Type::NULLENTRY };
}
101 changes: 101 additions & 0 deletions src/components/littlefs/LittleFs.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
#pragma once

#include <drivers/SpiNorFlash.h>
#include <lfs.h>

namespace Pinetime {
namespace System {
class LittleFs {
public:
class LittleFsFile;
class LittleFsDir;
explicit LittleFs(Pinetime::Drivers::SpiNorFlash&,
const size_t startAddress, ///< address of first block to use
const size_t size_bytes, ///< must be a multiple of block size
const bool allowFormat = true ///< if filesystem not detected, format the space
);
LittleFs(const LittleFs&) = delete;
LittleFs& operator=(const LittleFs&) = delete;
LittleFs(LittleFs&&) = delete;
LittleFs& operator=(LittleFs&&) = delete;

bool remove(const char* path) { return 0u == lfs_remove(&mLfs, path); }
bool rename(const char* oldpath, const char* newpath) { return 0u == lfs_rename(&mLfs, oldpath, newpath); }
ssize_t filesize(const char* path) {
struct lfs_info info;
if(0u == lfs_stat(&mLfs, path, &info))
return info.size;
return -1;
}
/// file resource is closed upon leave of scope
LittleFsFile& open(const char* const path,
const int flags ///< @see lfs_open_flags
) { return *(new LittleFsFile(mLfs, path, flags)); }
bool mkdir(const char* path) { return 0u == lfs_mkdir(&mLfs, path); }
/// dir resource is closed upon leave of scope
LittleFsDir& opendir(const char* path) { return *(new LittleFsDir(mLfs, path)); }

// the following require owner to delete the instance
LittleFsFile* open_danger(const char* const path,
const int flags ///< @see lfs_open_flags
) { return new LittleFsFile(mLfs, path, flags); }
LittleFsDir* opendir_danger(const char* const path) { return new LittleFsDir(mLfs, path); }

Pinetime::Drivers::SpiNorFlash& mDriver;
const size_t mStartAddress;
const size_t mSize_bytes;

private:
lfs_t mLfs;
const struct lfs_config mLfsConfig;

public:
class LittleFsFile {
public:
explicit LittleFsFile(lfs_t& lfs, const char* const path, const int flags)
: mLfs{lfs} { mLfs_file.type = ~LFS_TYPE_REG; lfs_file_open(&mLfs, &mLfs_file, path, flags); }
LittleFsFile(const LittleFsFile&) = delete;
LittleFsFile& operator=(const LittleFsFile&) = delete;
LittleFsFile(LittleFsFile&&) = delete;
LittleFsFile& operator=(LittleFsFile&&) = delete;
~LittleFsFile() {
lfs_file_close(&mLfs, &mLfs_file);
}
bool isNULL() { return mLfs_file.type != LFS_TYPE_REG; }
ssize_t read(void* buffer, size_t size) { return lfs_file_read(&mLfs, &mLfs_file, buffer, size); }
ssize_t write(const void* buffer, size_t size) { return lfs_file_write(&mLfs, &mLfs_file, buffer, size); }
ssize_t seek(size_t offset, size_t whence) { return 0u == lfs_file_seek(&mLfs, &mLfs_file, offset, whence); }
bool truncate(size_t sz) { return 0u == lfs_file_truncate(&mLfs, &mLfs_file, sz); }
/// return the current position within the file
ssize_t tell() { return lfs_file_tell(&mLfs, &mLfs_file); }
ssize_t size() { return lfs_file_size(&mLfs, &mLfs_file); }
private:
lfs_t& mLfs;
lfs_file_t mLfs_file;
};

class LittleFsDir {
public:
explicit LittleFsDir(lfs_t& lfs, const char* path)
: mLfs{lfs} { mLfs_dir.type = ~LFS_TYPE_DIR; lfs_dir_open(&mLfs, &mLfs_dir, path); }
LittleFsDir(const LittleFsDir&) = delete;
LittleFsDir& operator=(const LittleFsDir&) = delete;
LittleFsDir(LittleFsDir&&) = delete;
LittleFsDir& operator=(LittleFsDir&&) = delete;
~LittleFsDir() {
lfs_dir_close(&mLfs, &mLfs_dir);
}
bool isNULL() { return mLfs_dir.type != LFS_TYPE_DIR; }
struct LittleFsEntry {
enum class Type : uint8_t { NULLENTRY, FILE, DIR } type;
char name[LFS_NAME_MAX+1];
size_t size = 0;
};
const LittleFsEntry next();
private:
lfs_t& mLfs;
lfs_dir_t mLfs_dir;
};
};
}
}