Add support for SpiNorFlash and FS (#30)
The external SPI flash is implemented as a 4MB on the local filesystem. This allows the FS (littleFS) and settings to work properly. Remove the simulated `FS.h` and `FS.cpp`, because we can now use the files from InfiniTime directly as the heavy lifting is done in the simulated `SpiNorFlash.h` and cpp files. `SpiNorFlash.h` provides read and write functions with `uint8_t` buffer, but `fs::fstream` expects `char` buffer. Use `reinterpret_cast` and check if by any chance the `char` type on a platform is implemented with more than one byte. Then the `reinterpret_cast<char *>(buffer)` would change the meaning of the `size` parameter, which could lead to garbage data. Co-authored-by: Reinhold Gschweicher <pyro4hell@gmail.com>
This commit is contained in:
parent
b1fbae36f9
commit
644431cbc4
|
@ -88,8 +88,6 @@ target_sources(infinisim PUBLIC
|
|||
sim/components/brightness/BrightnessController.cpp
|
||||
sim/components/firmwarevalidator/FirmwareValidator.h
|
||||
sim/components/firmwarevalidator/FirmwareValidator.cpp
|
||||
sim/components/fs/FS.h
|
||||
sim/components/fs/FS.cpp
|
||||
sim/components/heartrate/HeartRateController.h
|
||||
sim/components/heartrate/HeartRateController.cpp
|
||||
sim/components/motion/MotionController.h
|
||||
|
@ -173,13 +171,21 @@ file(GLOB InfiniTime_WIDGETS
|
|||
"${InfiniTime_DIR}/src/displayapp/widgets/*.cpp"
|
||||
"${InfiniTime_DIR}/src/displayapp/widgets/*.h"
|
||||
)
|
||||
set(LITTLEFS_SRC
|
||||
${InfiniTime_DIR}/src/libs/littlefs/lfs_util.h
|
||||
${InfiniTime_DIR}/src/libs/littlefs/lfs.h
|
||||
${InfiniTime_DIR}/src/libs/littlefs/lfs_util.c
|
||||
${InfiniTime_DIR}/src/libs/littlefs/lfs.c
|
||||
)
|
||||
target_sources(infinisim PUBLIC ${InfiniTime_SCREENS})
|
||||
target_sources(infinisim PUBLIC ${InfiniTime_FONTS})
|
||||
target_sources(infinisim PUBLIC ${InfiniTime_ICONS})
|
||||
target_sources(infinisim PUBLIC ${InfiniTime_WIDGETS})
|
||||
target_sources(infinisim PUBLIC ${LITTLEFS_SRC})
|
||||
|
||||
# add files directly from InfiniTime sources
|
||||
target_include_directories(infinisim PRIVATE "${InfiniTime_DIR}/src")
|
||||
target_include_directories(infinisim PRIVATE "${InfiniTime_DIR}/src/libs/littlefs")
|
||||
target_sources(infinisim PUBLIC
|
||||
${InfiniTime_DIR}/src/BootloaderVersion.h
|
||||
${InfiniTime_DIR}/src/BootloaderVersion.cpp
|
||||
|
@ -202,6 +208,8 @@ target_sources(infinisim PUBLIC
|
|||
${InfiniTime_DIR}/src/components/settings/Settings.cpp
|
||||
${InfiniTime_DIR}/src/components/ble/NotificationManager.h
|
||||
${InfiniTime_DIR}/src/components/ble/NotificationManager.cpp
|
||||
${InfiniTime_DIR}/src/components/fs/FS.h
|
||||
${InfiniTime_DIR}/src/components/fs/FS.cpp
|
||||
${InfiniTime_DIR}/src/components/timer/TimerController.h
|
||||
${InfiniTime_DIR}/src/components/timer/TimerController.cpp
|
||||
${InfiniTime_DIR}/src/drivers/PinMap.h
|
||||
|
|
6
main.cpp
6
main.cpp
|
@ -224,7 +224,7 @@ Pinetime::Drivers::Spi lcdSpi {spi, Pinetime::PinMap::SpiLcdCsn};
|
|||
Pinetime::Drivers::St7789 lcd {lcdSpi, Pinetime::PinMap::LcdDataCommand};
|
||||
|
||||
Pinetime::Drivers::Spi flashSpi {spi, Pinetime::PinMap::SpiFlashCsn};
|
||||
Pinetime::Drivers::SpiNorFlash spiNorFlash {flashSpi};
|
||||
Pinetime::Drivers::SpiNorFlash spiNorFlash {"spiNorFlash.raw"};
|
||||
|
||||
// The TWI device should work @ up to 400Khz but there is a HW bug which prevent it from
|
||||
// respecting correct timings. According to erratas heet, this magic value makes it run
|
||||
|
@ -252,7 +252,7 @@ Pinetime::Controllers::Ble bleController;
|
|||
Pinetime::Controllers::HeartRateController heartRateController;
|
||||
Pinetime::Applications::HeartRateTask heartRateApp(heartRateSensor, heartRateController);
|
||||
|
||||
Pinetime::Controllers::FS fs; // {spiNorFlash};
|
||||
Pinetime::Controllers::FS fs {spiNorFlash};
|
||||
Pinetime::Controllers::Settings settingsController {fs};
|
||||
Pinetime::Controllers::MotorController motorController {};
|
||||
|
||||
|
@ -837,6 +837,8 @@ int main(int argc, char **argv)
|
|||
/*Initialize the HAL (display, input devices, tick) for LVGL*/
|
||||
hal_init();
|
||||
|
||||
fs.Init();
|
||||
|
||||
// initialize the core of our Simulator
|
||||
Framework fw(fw_status_window_visible, 240,240);
|
||||
|
||||
|
|
|
@ -1,261 +0,0 @@
|
|||
#include "FS.h"
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
#include <filesystem>
|
||||
//#include <littlefs/lfs.h>
|
||||
#include <lvgl/lvgl.h>
|
||||
|
||||
using namespace Pinetime::Controllers;
|
||||
|
||||
//FS::FS(Pinetime::Drivers::SpiNorFlash& driver)
|
||||
// : flashDriver {driver},
|
||||
// lfsConfig {
|
||||
// .context = this,
|
||||
// .read = SectorRead,
|
||||
// .prog = SectorProg,
|
||||
// .erase = SectorErase,
|
||||
// .sync = SectorSync,
|
||||
//
|
||||
// .read_size = 16,
|
||||
// .prog_size = 8,
|
||||
// .block_size = blockSize,
|
||||
// .block_count = size / blockSize,
|
||||
// .block_cycles = 1000u,
|
||||
//
|
||||
// .cache_size = 16,
|
||||
// .lookahead_size = 16,
|
||||
//
|
||||
// .name_max = 50,
|
||||
// .attr_max = 50,
|
||||
// } {
|
||||
//}
|
||||
|
||||
|
||||
void FS::Init() {
|
||||
|
||||
// // try mount
|
||||
// int err = lfs_mount(&lfs, &lfsConfig);
|
||||
//
|
||||
// // reformat if we can't mount the filesystem
|
||||
// // this should only happen on the first boot
|
||||
// if (err != LFS_ERR_OK) {
|
||||
// lfs_format(&lfs, &lfsConfig);
|
||||
// err = lfs_mount(&lfs, &lfsConfig);
|
||||
// if (err != LFS_ERR_OK) {
|
||||
// return;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
//#ifndef PINETIME_IS_RECOVERY
|
||||
// VerifyResource();
|
||||
// LVGLFileSystemInit();
|
||||
//#endif
|
||||
|
||||
}
|
||||
|
||||
void FS::VerifyResource() {
|
||||
// validate the resource metadata
|
||||
resourcesValid = true;
|
||||
}
|
||||
|
||||
int FS::FileOpen(lfs_file_t* file_p, const char* fileName, const int flags) {
|
||||
// create the file in the current directory
|
||||
const char *local_filename = fileName[0]=='/' ? &fileName[1] : fileName;
|
||||
const char *mode;
|
||||
bool flag_read = flags & LFS_O_RDONLY;
|
||||
bool flag_write = flags & LFS_O_WRONLY;
|
||||
bool flag_create = flags & LFS_O_CREAT;
|
||||
if (flag_create) {
|
||||
if (std::filesystem::exists(local_filename)) {
|
||||
if (flag_read && flag_write) {
|
||||
mode = "rb+";
|
||||
} else if (flag_read) {
|
||||
mode = "rb";
|
||||
} else if (flag_write) {
|
||||
mode = "wb";
|
||||
} else {
|
||||
assert(false); // not implemented
|
||||
}
|
||||
} else {
|
||||
if (flag_read && flag_write) {
|
||||
mode = "wb+";
|
||||
} else if (flag_read) {
|
||||
assert(false); // read only file not existing
|
||||
mode = "rb";
|
||||
} else if (flag_write) {
|
||||
mode = "wb";
|
||||
} else {
|
||||
assert(false); // not implemented
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (std::filesystem::exists(local_filename)) {
|
||||
if (flag_read && flag_write) {
|
||||
mode = "rb+";
|
||||
} else if (flag_read) {
|
||||
mode = "rb";
|
||||
} else if (flag_write) {
|
||||
mode = "wb";
|
||||
} else {
|
||||
assert(false); // not implemented
|
||||
}
|
||||
} else {
|
||||
return LFS_ERR_IO;
|
||||
}
|
||||
}
|
||||
FILE *fptr = fopen(local_filename, mode);
|
||||
if (fptr == nullptr) {
|
||||
return LFS_ERR_BADF;
|
||||
} else {
|
||||
*file_p = fptr;
|
||||
return LFS_ERR_OK;
|
||||
}
|
||||
//return lfs_file_open(&lfs, file_p, fileName, flags);
|
||||
}
|
||||
|
||||
int FS::FileClose(lfs_file_t* file_p) {
|
||||
return fclose(*file_p);
|
||||
//return lfs_file_close(&lfs, file_p);
|
||||
}
|
||||
|
||||
int FS::FileRead(lfs_file_t* file_p, uint8_t* buff, uint32_t size) {
|
||||
return fread(buff, sizeof(uint8_t), size, *file_p);
|
||||
//return lfs_file_read(&lfs, file_p, buff, size);
|
||||
}
|
||||
|
||||
int FS::FileWrite(lfs_file_t* file_p, const uint8_t* buff, uint32_t size) {
|
||||
return fwrite((void*)buff, sizeof(uint8_t), size, *file_p);
|
||||
//return lfs_file_write(&lfs, file_p, buff, size);
|
||||
}
|
||||
|
||||
int FS::FileSeek(lfs_file_t* file_p, uint32_t pos) {
|
||||
return fseek(*file_p, pos, SEEK_SET);
|
||||
//return lfs_file_seek(&lfs, file_p, pos, whence);
|
||||
}
|
||||
|
||||
int FS::FileDelete(const char* fileName) {
|
||||
return std::filesystem::remove(fileName);
|
||||
//return lfs_remove(&lfs, fileName);
|
||||
}
|
||||
|
||||
|
||||
int FS::DirCreate(const char* path) {
|
||||
return std::filesystem::create_directory(path);
|
||||
//return lfs_mkdir(&lfs, path);
|
||||
}
|
||||
|
||||
// Delete directory and all files inside
|
||||
int FS::DirDelete(const char* path) {
|
||||
return std::filesystem::remove_all(path);
|
||||
|
||||
//lfs_dir_t lfs_dir;
|
||||
//lfs_info entryInfo;
|
||||
|
||||
//int err;
|
||||
//err = lfs_dir_open(&lfs, &lfs_dir, path);
|
||||
//if (err) {
|
||||
// return err;
|
||||
//}
|
||||
//while (lfs_dir_read(&lfs, &lfs_dir, &entryInfo)) {
|
||||
// lfs_remove(&lfs, entryInfo.name);
|
||||
//}
|
||||
//lfs_dir_close(&lfs, &lfs_dir);
|
||||
//return LFS_ERR_OK;
|
||||
}
|
||||
|
||||
// check if file exists, if so write file-size into info object
|
||||
int FS::Stat(const char* path, lfs_info* info) {
|
||||
const char *local_filename = path[0]=='/' ? &path[1] : path;
|
||||
if (!std::filesystem::exists(local_filename))
|
||||
{
|
||||
return LFS_ERR_NOENT; // No directory entry
|
||||
}
|
||||
info->size = std::filesystem::file_size(local_filename);
|
||||
return LFS_ERR_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
----------- Interface between littlefs and SpiNorFlash -----------
|
||||
|
||||
*/
|
||||
//int FS::SectorSync(const struct lfs_config* c) {
|
||||
// return 0;
|
||||
//}
|
||||
//
|
||||
//int FS::SectorErase(const struct lfs_config* c, lfs_block_t block) {
|
||||
// Pinetime::Controllers::FS& lfs = *(static_cast<Pinetime::Controllers::FS*>(c->context));
|
||||
// const size_t address = startAddress + (block * blockSize);
|
||||
// lfs.flashDriver.SectorErase(address);
|
||||
// return lfs.flashDriver.EraseFailed() ? -1 : 0;
|
||||
//}
|
||||
//
|
||||
//int FS::SectorProg(const struct lfs_config* c, lfs_block_t block, lfs_off_t off, const void* buffer, lfs_size_t size) {
|
||||
// Pinetime::Controllers::FS& lfs = *(static_cast<Pinetime::Controllers::FS*>(c->context));
|
||||
// const size_t address = startAddress + (block * blockSize) + off;
|
||||
// lfs.flashDriver.Write(address, (uint8_t*) buffer, size);
|
||||
// return lfs.flashDriver.ProgramFailed() ? -1 : 0;
|
||||
//}
|
||||
//
|
||||
//int FS::SectorRead(const struct lfs_config* c, lfs_block_t block, lfs_off_t off, void* buffer, lfs_size_t size) {
|
||||
// Pinetime::Controllers::FS& lfs = *(static_cast<Pinetime::Controllers::FS*>(c->context));
|
||||
// const size_t address = startAddress + (block * blockSize) + off;
|
||||
// lfs.flashDriver.Read(address, static_cast<uint8_t*>(buffer), size);
|
||||
// return 0;
|
||||
//}
|
||||
|
||||
/*
|
||||
|
||||
----------- LVGL filesystem integration -----------
|
||||
|
||||
*/
|
||||
|
||||
namespace {
|
||||
lv_fs_res_t lvglOpen(lv_fs_drv_t* drv, void* file_p, const char* path, lv_fs_mode_t mode) {
|
||||
|
||||
lfs_file_t* file = static_cast<lfs_file_t*>(file_p);
|
||||
FS* filesys = static_cast<FS*>(drv->user_data);
|
||||
int ret = filesys->FileOpen(file, path, LFS_O_RDONLY);
|
||||
if (ret != LFS_ERR_OK) {
|
||||
return LV_FS_RES_FS_ERR;
|
||||
}
|
||||
return LV_FS_RES_OK;
|
||||
}
|
||||
|
||||
lv_fs_res_t lvglClose(lv_fs_drv_t* drv, void* file_p) {
|
||||
FS* filesys = static_cast<FS*>(drv->user_data);
|
||||
lfs_file_t* file = static_cast<lfs_file_t*>(file_p);
|
||||
filesys->FileClose(file);
|
||||
|
||||
return LV_FS_RES_OK;
|
||||
}
|
||||
|
||||
lv_fs_res_t lvglRead(lv_fs_drv_t* drv, void* file_p, void* buf, uint32_t btr, uint32_t* br) {
|
||||
FS* filesys = static_cast<FS*>(drv->user_data);
|
||||
lfs_file_t* file = static_cast<lfs_file_t*>(file_p);
|
||||
filesys->FileRead(file, static_cast<uint8_t*>(buf), btr);
|
||||
*br = btr;
|
||||
return LV_FS_RES_OK;
|
||||
}
|
||||
lv_fs_res_t lvglSeek(lv_fs_drv_t* drv, void* file_p, uint32_t pos) {
|
||||
FS* filesys = static_cast<FS*>(drv->user_data);
|
||||
lfs_file_t* file = static_cast<lfs_file_t*>(file_p);
|
||||
filesys->FileSeek(file, pos);
|
||||
return LV_FS_RES_OK;
|
||||
}
|
||||
}
|
||||
|
||||
void FS::LVGLFileSystemInit() {
|
||||
lv_fs_drv_init(&fs_drv);
|
||||
|
||||
fs_drv.file_size = sizeof(lfs_file_t);
|
||||
fs_drv.letter = 'F';
|
||||
fs_drv.open_cb = lvglOpen;
|
||||
fs_drv.close_cb = lvglClose;
|
||||
fs_drv.read_cb = lvglRead;
|
||||
fs_drv.seek_cb = lvglSeek;
|
||||
|
||||
fs_drv.user_data = this;
|
||||
|
||||
lv_fs_drv_register(&fs_drv);
|
||||
}
|
|
@ -1,157 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstdint>
|
||||
//#include "drivers/SpiNorFlash.h"
|
||||
//#include <littlefs/lfs.h>
|
||||
#include <lvgl/lvgl.h>
|
||||
|
||||
using lfs_file_t = FILE*;
|
||||
|
||||
// copied from src/libs/littlefs/lfs.h
|
||||
// Possible error codes, these are negative to allow
|
||||
// valid positive return values
|
||||
enum lfs_error {
|
||||
LFS_ERR_OK = 0, // No error
|
||||
LFS_ERR_IO = -5, // Error during device operation
|
||||
LFS_ERR_CORRUPT = -84, // Corrupted
|
||||
LFS_ERR_NOENT = -2, // No directory entry
|
||||
LFS_ERR_EXIST = -17, // Entry already exists
|
||||
LFS_ERR_NOTDIR = -20, // Entry is not a dir
|
||||
LFS_ERR_ISDIR = -21, // Entry is a dir
|
||||
LFS_ERR_NOTEMPTY = -39, // Dir is not empty
|
||||
LFS_ERR_BADF = -9, // Bad file number
|
||||
LFS_ERR_FBIG = -27, // File too large
|
||||
LFS_ERR_INVAL = -22, // Invalid parameter
|
||||
LFS_ERR_NOSPC = -28, // No space left on device
|
||||
LFS_ERR_NOMEM = -12, // No more memory available
|
||||
LFS_ERR_NOATTR = -61, // No data/attr available
|
||||
LFS_ERR_NAMETOOLONG = -36, // File name too long
|
||||
};
|
||||
|
||||
enum lfs_open_flags {
|
||||
// open flags
|
||||
LFS_O_RDONLY = 1, // Open a file as read only
|
||||
#ifndef LFS_READONLY
|
||||
LFS_O_WRONLY = 2, // Open a file as write only
|
||||
LFS_O_RDWR = 3, // Open a file as read and write
|
||||
LFS_O_CREAT = 0x0100, // Create a file if it does not exist
|
||||
LFS_O_EXCL = 0x0200, // Fail if a file already exists
|
||||
LFS_O_TRUNC = 0x0400, // Truncate the existing file to zero size
|
||||
LFS_O_APPEND = 0x0800, // Move to end of file on every write
|
||||
#endif
|
||||
};
|
||||
|
||||
// File seek flags
|
||||
enum lfs_whence_flags {
|
||||
LFS_SEEK_SET = 0, // Seek relative to an absolute position
|
||||
LFS_SEEK_CUR = 1, // Seek relative to the current file position
|
||||
LFS_SEEK_END = 2, // Seek relative to the end of the file
|
||||
};
|
||||
|
||||
typedef uint32_t lfs_size_t;
|
||||
typedef int32_t lfs_ssize_t;
|
||||
|
||||
// Maximum name size in bytes, may be redefined to reduce the size of the
|
||||
// info struct. Limited to <= 1022. Stored in superblock and must be
|
||||
// respected by other littlefs drivers.
|
||||
//#ifndef LFS_NAME_MAX
|
||||
//#define LFS_NAME_MAX 255
|
||||
//#endif
|
||||
|
||||
// File info structure
|
||||
struct lfs_info {
|
||||
// // Type of the file, either LFS_TYPE_REG or LFS_TYPE_DIR
|
||||
// uint8_t type;
|
||||
|
||||
// Size of the file, only valid for REG files. Limited to 32-bits.
|
||||
lfs_size_t size;
|
||||
|
||||
// // Name of the file stored as a null-terminated string. Limited to
|
||||
// // LFS_NAME_MAX+1, which can be changed by redefining LFS_NAME_MAX to
|
||||
// // reduce RAM. LFS_NAME_MAX is stored in superblock and must be
|
||||
// // respected by other littlefs drivers.
|
||||
// char name[LFS_NAME_MAX+1];
|
||||
};
|
||||
|
||||
namespace Pinetime {
|
||||
namespace Controllers {
|
||||
class FS {
|
||||
public:
|
||||
//FS(Pinetime::Drivers::SpiNorFlash&);
|
||||
|
||||
void Init();
|
||||
void LVGLFileSystemInit();
|
||||
|
||||
int FileOpen(lfs_file_t* file_p, const char* fileName, const int flags);
|
||||
int FileClose(lfs_file_t* file_p);
|
||||
int FileRead(lfs_file_t* file_p, uint8_t* buff, uint32_t size);
|
||||
int FileWrite(lfs_file_t* file_p, const uint8_t* buff, uint32_t size);
|
||||
int FileSeek(lfs_file_t* file_p, uint32_t pos);
|
||||
|
||||
int FileDelete(const char* fileName);
|
||||
|
||||
//int DirOpen(const char* path, lfs_dir_t* lfs_dir);
|
||||
//int DirClose(lfs_dir_t* lfs_dir);
|
||||
//int DirRead(lfs_dir_t* dir, lfs_info* info);
|
||||
//int DirRewind(lfs_dir_t* dir);
|
||||
int DirCreate(const char* path);
|
||||
int DirDelete(const char* path);
|
||||
|
||||
lfs_ssize_t GetFSSize();
|
||||
int Rename(const char* oldPath, const char* newPath);
|
||||
int Stat(const char* path, lfs_info* info);
|
||||
void VerifyResource();
|
||||
|
||||
static size_t getSize() {
|
||||
return size;
|
||||
}
|
||||
static size_t getBlockSize() {
|
||||
return blockSize;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
//Pinetime::Drivers::SpiNorFlash& flashDriver;
|
||||
|
||||
/*
|
||||
* External Flash MAP (4 MBytes)
|
||||
*
|
||||
* 0x000000 +---------------------------------------+
|
||||
* | Bootloader Assets |
|
||||
* | 256 KBytes |
|
||||
* | |
|
||||
* 0x040000 +---------------------------------------+
|
||||
* | OTA |
|
||||
* | 464 KBytes |
|
||||
* | |
|
||||
* | |
|
||||
* | |
|
||||
* 0x0B4000 +---------------------------------------+
|
||||
* | File System |
|
||||
* | |
|
||||
* | |
|
||||
* | |
|
||||
* | |
|
||||
* 0x400000 +---------------------------------------+
|
||||
*
|
||||
*/
|
||||
static constexpr size_t startAddress = 0x0B4000;
|
||||
static constexpr size_t size = 0x34C000;
|
||||
static constexpr size_t blockSize = 4096;
|
||||
|
||||
lv_fs_drv_t fs_drv;
|
||||
|
||||
bool resourcesValid = false;
|
||||
//const struct lfs_config lfsConfig;
|
||||
|
||||
//lfs_t lfs;
|
||||
|
||||
//static int SectorSync(const struct lfs_config* c);
|
||||
//static int SectorErase(const struct lfs_config* c, lfs_block_t block);
|
||||
//static int SectorProg(const struct lfs_config* c, lfs_block_t block, lfs_off_t off, const void* buffer, lfs_size_t size);
|
||||
//static int SectorRead(const struct lfs_config* c, lfs_block_t block, lfs_off_t off, void* buffer, lfs_size_t size);
|
||||
|
||||
};
|
||||
}
|
||||
}
|
|
@ -1,12 +1,27 @@
|
|||
#include "drivers/SpiNorFlash.h"
|
||||
#include <hal/nrf_gpio.h>
|
||||
#include <libraries/delay/nrf_delay.h>
|
||||
#include <libraries/log/nrf_log.h>
|
||||
#include "drivers/Spi.h"
|
||||
#include <filesystem>
|
||||
#include <iostream>
|
||||
|
||||
using namespace Pinetime::Drivers;
|
||||
|
||||
SpiNorFlash::SpiNorFlash(Spi& spi) : spi {spi} {
|
||||
SpiNorFlash::SpiNorFlash(const std::string& memoryFilePath) : memoryFilePath{memoryFilePath} {
|
||||
namespace fs = std::filesystem;
|
||||
fs::path f{ memoryFilePath };
|
||||
if (fs::exists(f)) {
|
||||
memoryFile = std::fstream(memoryFilePath, std::ios::binary | std::fstream::in | std::fstream::out);
|
||||
} else {
|
||||
memoryFile = std::fstream(memoryFilePath, std::ios::trunc | std::ios::binary | std::fstream::in | std::fstream::out);
|
||||
memoryFile.seekp(memorySize - 1);
|
||||
memoryFile.write("", 1);
|
||||
}
|
||||
}
|
||||
SpiNorFlash::~SpiNorFlash() {
|
||||
if (memoryFile.is_open()) {
|
||||
memoryFile.close();
|
||||
}
|
||||
}
|
||||
|
||||
void SpiNorFlash::Init() {
|
||||
|
@ -19,126 +34,61 @@ void SpiNorFlash::Uninit() {
|
|||
}
|
||||
|
||||
void SpiNorFlash::Sleep() {
|
||||
auto cmd = static_cast<uint8_t>(Commands::DeepPowerDown);
|
||||
spi.Write(&cmd, sizeof(uint8_t));
|
||||
NRF_LOG_INFO("[SpiNorFlash] Sleep")
|
||||
}
|
||||
|
||||
void SpiNorFlash::Wakeup() {
|
||||
// send Commands::ReleaseFromDeepPowerDown then 3 dummy bytes before reading Device ID
|
||||
// static constexpr uint8_t cmdSize = 4;
|
||||
// uint8_t cmd[cmdSize] = {static_cast<uint8_t>(Commands::ReleaseFromDeepPowerDown), 0x01, 0x02, 0x03};
|
||||
// uint8_t id = 0;
|
||||
// spi.Read(reinterpret_cast<uint8_t*>(&cmd), cmdSize, &id, 1);
|
||||
// auto devId = device_id = ReadIdentificaion();
|
||||
// if (devId.type != device_id.type) {
|
||||
// NRF_LOG_INFO("[SpiNorFlash] ID on Wakeup: Failed");
|
||||
// } else {
|
||||
// NRF_LOG_INFO("[SpiNorFlash] ID on Wakeup: %d", id);
|
||||
// }
|
||||
NRF_LOG_INFO("[SpiNorFlash] Wakeup")
|
||||
}
|
||||
|
||||
SpiNorFlash::Identification SpiNorFlash::ReadIdentificaion() {
|
||||
// auto cmd = static_cast<uint8_t>(Commands::ReadIdentification);
|
||||
// Identification identification;
|
||||
// spi.Read(&cmd, 1, reinterpret_cast<uint8_t*>(&identification), sizeof(Identification));
|
||||
// return identification;
|
||||
return {};
|
||||
}
|
||||
|
||||
uint8_t SpiNorFlash::ReadStatusRegister() {
|
||||
auto cmd = static_cast<uint8_t>(Commands::ReadStatusRegister);
|
||||
uint8_t status;
|
||||
spi.Read(&cmd, sizeof(cmd), &status, sizeof(uint8_t));
|
||||
return status;
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool SpiNorFlash::WriteInProgress() {
|
||||
// return (ReadStatusRegister() & 0x01u) == 0x01u;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SpiNorFlash::WriteEnabled() {
|
||||
// return (ReadStatusRegister() & 0x02u) == 0x02u;
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t SpiNorFlash::ReadConfigurationRegister() {
|
||||
auto cmd = static_cast<uint8_t>(Commands::ReadConfigurationRegister);
|
||||
uint8_t status;
|
||||
spi.Read(&cmd, sizeof(cmd), &status, sizeof(uint8_t));
|
||||
return status;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void SpiNorFlash::Read(uint32_t address, uint8_t* buffer, size_t size) {
|
||||
static constexpr uint8_t cmdSize = 4;
|
||||
uint8_t cmd[cmdSize] = {static_cast<uint8_t>(Commands::Read), (uint8_t) (address >> 16U), (uint8_t) (address >> 8U), (uint8_t) address};
|
||||
spi.Read(reinterpret_cast<uint8_t*>(&cmd), cmdSize, buffer, size);
|
||||
static_assert(sizeof(uint8_t) == sizeof(char));
|
||||
memoryFile.seekp(address);
|
||||
memoryFile.read(reinterpret_cast<char *>(buffer), size);
|
||||
}
|
||||
|
||||
void SpiNorFlash::WriteEnable() {
|
||||
auto cmd = static_cast<uint8_t>(Commands::WriteEnable);
|
||||
spi.Read(&cmd, sizeof(cmd), nullptr, 0);
|
||||
|
||||
}
|
||||
|
||||
void SpiNorFlash::SectorErase(uint32_t sectorAddress) {
|
||||
// static constexpr uint8_t cmdSize = 4;
|
||||
// uint8_t cmd[cmdSize] = {static_cast<uint8_t>(Commands::SectorErase),
|
||||
// (uint8_t) (sectorAddress >> 16U),
|
||||
// (uint8_t) (sectorAddress >> 8U),
|
||||
// (uint8_t) sectorAddress};
|
||||
//
|
||||
// WriteEnable();
|
||||
// while (!WriteEnabled())
|
||||
// vTaskDelay(1);
|
||||
//
|
||||
// spi.Read(reinterpret_cast<uint8_t*>(&cmd), cmdSize, nullptr, 0);
|
||||
//
|
||||
// while (WriteInProgress())
|
||||
// vTaskDelay(1);
|
||||
|
||||
}
|
||||
|
||||
uint8_t SpiNorFlash::ReadSecurityRegister() {
|
||||
auto cmd = static_cast<uint8_t>(Commands::ReadSecurityRegister);
|
||||
uint8_t status;
|
||||
spi.Read(&cmd, sizeof(cmd), &status, sizeof(uint8_t));
|
||||
return status;
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool SpiNorFlash::ProgramFailed() {
|
||||
// return (ReadSecurityRegister() & 0x20u) == 0x20u;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SpiNorFlash::EraseFailed() {
|
||||
// return (ReadSecurityRegister() & 0x40u) == 0x40u;
|
||||
return false;
|
||||
}
|
||||
|
||||
void SpiNorFlash::Write(uint32_t address, const uint8_t* buffer, size_t size) {
|
||||
// static constexpr uint8_t cmdSize = 4;
|
||||
//
|
||||
// size_t len = size;
|
||||
// uint32_t addr = address;
|
||||
// const uint8_t* b = buffer;
|
||||
// while (len > 0) {
|
||||
// uint32_t pageLimit = (addr & ~(pageSize - 1u)) + pageSize;
|
||||
// uint32_t toWrite = pageLimit - addr > len ? len : pageLimit - addr;
|
||||
//
|
||||
// uint8_t cmd[cmdSize] = {static_cast<uint8_t>(Commands::PageProgram), (uint8_t) (addr >> 16U), (uint8_t) (addr >> 8U), (uint8_t) addr};
|
||||
//
|
||||
// WriteEnable();
|
||||
// while (!WriteEnabled())
|
||||
// vTaskDelay(1);
|
||||
//
|
||||
// spi.WriteCmdAndBuffer(cmd, cmdSize, b, toWrite);
|
||||
//
|
||||
// while (WriteInProgress())
|
||||
// vTaskDelay(1);
|
||||
//
|
||||
// addr += toWrite;
|
||||
// b += toWrite;
|
||||
// len -= toWrite;
|
||||
// }
|
||||
memoryFile.seekp(address);
|
||||
memoryFile.write(reinterpret_cast<const char *>(buffer), size);
|
||||
memoryFile.flush();
|
||||
}
|
||||
|
|
|
@ -1,13 +1,15 @@
|
|||
#pragma once
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <fstream>
|
||||
|
||||
namespace Pinetime {
|
||||
namespace Drivers {
|
||||
class Spi;
|
||||
class SpiNorFlash {
|
||||
public:
|
||||
explicit SpiNorFlash(Spi& spi);
|
||||
explicit SpiNorFlash(const std::string& memoryFilePath);
|
||||
~SpiNorFlash();
|
||||
SpiNorFlash(const SpiNorFlash&) = delete;
|
||||
SpiNorFlash& operator=(const SpiNorFlash&) = delete;
|
||||
SpiNorFlash(SpiNorFlash&&) = delete;
|
||||
|
@ -53,8 +55,12 @@ namespace Pinetime {
|
|||
};
|
||||
static constexpr uint16_t pageSize = 256;
|
||||
|
||||
Spi& spi;
|
||||
static constexpr size_t memorySize {0x400000};
|
||||
const std::string& memoryFilePath;
|
||||
|
||||
|
||||
Identification device_id;
|
||||
std::fstream memoryFile;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue