diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index bb9f76fe..809544c9 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -487,6 +487,7 @@ list(APPEND SOURCE_FILES components/ble/NavigationService.cpp displayapp/fonts/lv_font_navi_80.c components/ble/BatteryInformationService.cpp + components/ble/FSService.cpp components/ble/ImmediateAlertService.cpp components/ble/ServiceDiscovery.cpp components/ble/HeartRateService.cpp @@ -557,6 +558,7 @@ list(APPEND RECOVERY_SOURCE_FILES components/ble/MusicService.cpp components/ble/weather/WeatherService.cpp components/ble/BatteryInformationService.cpp + components/ble/FSService.cpp components/ble/ImmediateAlertService.cpp components/ble/ServiceDiscovery.cpp components/ble/NavigationService.cpp @@ -669,6 +671,7 @@ set(INCLUDE_FILES components/ble/DfuService.h components/firmwarevalidator/FirmwareValidator.h components/ble/BatteryInformationService.h + components/ble/FSService.h components/ble/ImmediateAlertService.h components/ble/ServiceDiscovery.h components/ble/BleClient.h diff --git a/src/components/ble/FSService.cpp b/src/components/ble/FSService.cpp new file mode 100644 index 00000000..8dc9ed67 --- /dev/null +++ b/src/components/ble/FSService.cpp @@ -0,0 +1,330 @@ +#include +#include "FSService.h" +#include "components/ble/BleController.h" +#include "systemtask/SystemTask.h" + +using namespace Pinetime::Controllers; + +constexpr ble_uuid16_t FSService::fsServiceUuid; +constexpr ble_uuid128_t FSService::fsVersionUuid; +constexpr ble_uuid128_t FSService::fsTransferUuid; + +int FSServiceCallback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt, void* arg) { + auto* fsService = static_cast(arg); + return fsService->OnFSServiceRequested(conn_handle, attr_handle, ctxt); +} + +FSService::FSService(Pinetime::System::SystemTask& systemTask, Pinetime::Controllers::FS& fs) + : systemTask {systemTask}, + fs {fs}, + characteristicDefinition {{.uuid = &fsVersionUuid.u, + .access_cb = FSServiceCallback, + .arg = this, + .flags = BLE_GATT_CHR_F_READ, + .val_handle = &versionCharacteristicHandle}, + { + .uuid = &fsTransferUuid.u, + .access_cb = FSServiceCallback, + .arg = this, + .flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY, + .val_handle = &transferCharacteristicHandle, + }, + {0}}, + serviceDefinition { + {/* Device Information Service */ + .type = BLE_GATT_SVC_TYPE_PRIMARY, + .uuid = &fsServiceUuid.u, + .characteristics = characteristicDefinition}, + {0}, + } { +} + +void FSService::Init() { + int res = 0; + res = ble_gatts_count_cfg(serviceDefinition); + ASSERT(res == 0); + + res = ble_gatts_add_svcs(serviceDefinition); + ASSERT(res == 0); +} + +int FSService::OnFSServiceRequested(uint16_t connectionHandle, uint16_t attributeHandle, ble_gatt_access_ctxt* context) { + if (attributeHandle == versionCharacteristicHandle) { + NRF_LOG_INFO("FS_S : handle = %d", versionCharacteristicHandle); + int res = os_mbuf_append(context->om, &fsVersion, sizeof(fsVersion)); + return (res == 0) ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES; + } + if (attributeHandle == transferCharacteristicHandle) { + return FSCommandHandler(connectionHandle, context->om); + } + return 0; +} + +int FSService::FSCommandHandler(uint16_t connectionHandle, os_mbuf* om) { + auto command = static_cast(om->om_data[0]); + NRF_LOG_INFO("[FS_S] -> FSCommandHandler Command %d", command); + // Just always make sure we are awake... + systemTask.PushMessage(Pinetime::System::Messages::StartFileTransfer); + vTaskDelay(10); + while (systemTask.IsSleeping()) { + vTaskDelay(100); // 50ms + } + lfs_dir_t dir = {0}; + lfs_info info = {0}; + lfs_file f = {0}; + switch (command) { + case commands::READ: { + NRF_LOG_INFO("[FS_S] -> Read"); + auto* header = (ReadHeader*) om->om_data; + uint16_t plen = header->pathlen; + if (plen > maxpathlen) { //> counts for null term + return -1; + } + memcpy(filepath, header->pathstr, plen); + filepath[plen] = 0; // Copy and null teminate string + ReadResponse resp; + os_mbuf* om; + resp.command = commands::READ_DATA; + resp.status = 0x01; + resp.chunkoff = header->chunkoff; + int res = fs.Stat(filepath, &info); + if (res == LFS_ERR_NOENT && info.type != LFS_TYPE_DIR) { + resp.status = (int8_t) res; + resp.chunklen = 0; + resp.totallen = 0; + om = ble_hs_mbuf_from_flat(&resp, sizeof(ReadResponse)); + } else { + resp.chunklen = std::min(header->chunksize, info.size); // TODO add mtu somehow + resp.totallen = info.size; + fs.FileOpen(&f, filepath, LFS_O_RDONLY); + fs.FileSeek(&f, header->chunkoff); + uint8_t fileData[resp.chunklen] = {0}; + resp.chunklen = fs.FileRead(&f, fileData, resp.chunklen); + om = ble_hs_mbuf_from_flat(&resp, sizeof(ReadResponse)); + os_mbuf_append(om, fileData, resp.chunklen); + fs.FileClose(&f); + } + + ble_gattc_notify_custom(connectionHandle, transferCharacteristicHandle, om); + break; + } + case commands::READ_PACING: { + NRF_LOG_INFO("[FS_S] -> Readpacing"); + auto* header = (ReadHeader*) om->om_data; + ReadResponse resp; + resp.command = commands::READ_DATA; + resp.status = 0x01; + resp.chunkoff = header->chunkoff; + int res = fs.Stat(filepath, &info); + if (res == LFS_ERR_NOENT && info.type != LFS_TYPE_DIR) { + resp.status = (int8_t) res; + resp.chunklen = 0; + resp.totallen = 0; + } else { + resp.chunklen = std::min(header->chunksize, info.size); // TODO add mtu somehow + resp.totallen = info.size; + fs.FileOpen(&f, filepath, LFS_O_RDONLY); + fs.FileSeek(&f, header->chunkoff); + } + os_mbuf* om; + if (resp.chunklen > 0) { + uint8_t fileData[resp.chunklen] = {0}; + resp.chunklen = fs.FileRead(&f, fileData, resp.chunklen); + om = ble_hs_mbuf_from_flat(&resp, sizeof(ReadResponse)); + os_mbuf_append(om, fileData, resp.chunklen); + } else { + resp.chunklen = 0; + om = ble_hs_mbuf_from_flat(&resp, sizeof(ReadResponse)); + } + fs.FileClose(&f); + ble_gattc_notify_custom(connectionHandle, transferCharacteristicHandle, om); + break; + } + case commands::WRITE: { + NRF_LOG_INFO("[FS_S] -> Write"); + auto* header = (WriteHeader*) om->om_data; + uint16_t plen = header->pathlen; + if (plen > maxpathlen) { //> counts for null term + return -1; // TODO make this actually return a BLE notif + } + memcpy(filepath, header->pathstr, plen); + filepath[plen] = 0; // Copy and null teminate string + fileSize = header->totalSize; + WriteResponse resp; + resp.command = commands::WRITE_PACING; + resp.offset = header->offset; + resp.modTime = 0; + + int res = fs.FileOpen(&f, filepath, LFS_O_RDWR | LFS_O_CREAT); + if (res == 0) { + fs.FileClose(&f); + resp.status = (res == 0) ? 0x01 : (int8_t) res; + } + resp.freespace = std::min(fs.getSize() - (fs.GetFSSize() * fs.getBlockSize()), fileSize - header->offset); + auto* om = ble_hs_mbuf_from_flat(&resp, sizeof(WriteResponse)); + ble_gattc_notify_custom(connectionHandle, transferCharacteristicHandle, om); + break; + } + case commands::WRITE_DATA: { + NRF_LOG_INFO("[FS_S] -> WriteData"); + auto* header = (WritePacing*) om->om_data; + WriteResponse resp; + resp.command = commands::WRITE_PACING; + resp.offset = header->offset; + int res = 0; + + if (!(res = fs.FileOpen(&f, filepath, LFS_O_RDWR | LFS_O_CREAT))) { + if ((res = fs.FileSeek(&f, header->offset)) >= 0) { + res = fs.FileWrite(&f, header->data, header->dataSize); + } + fs.FileClose(&f); + } + if (res < 0) { + resp.status = (int8_t) res; + } + resp.freespace = std::min(fs.getSize() - (fs.GetFSSize() * fs.getBlockSize()), fileSize - header->offset); + auto* om = ble_hs_mbuf_from_flat(&resp, sizeof(WriteResponse)); + ble_gattc_notify_custom(connectionHandle, transferCharacteristicHandle, om); + break; + } + case commands::DELETE: { + NRF_LOG_INFO("[FS_S] -> Delete"); + auto* header = (DelHeader*) om->om_data; + uint16_t plen = header->pathlen; + char path[plen + 1] = {0}; + memcpy(path, header->pathstr, plen); + path[plen] = 0; // Copy and null teminate string + DelResponse resp {}; + resp.command = commands::DELETE_STATUS; + int res = fs.FileDelete(path); + resp.status = (res == 0) ? 0x01 : (int8_t) res; + auto* om = ble_hs_mbuf_from_flat(&resp, sizeof(DelResponse)); + ble_gattc_notify_custom(connectionHandle, transferCharacteristicHandle, om); + break; + } + case commands::MKDIR: { + NRF_LOG_INFO("[FS_S] -> MKDir"); + auto* header = (MKDirHeader*) om->om_data; + uint16_t plen = header->pathlen; + char path[plen + 1] = {0}; + memcpy(path, header->pathstr, plen); + path[plen] = 0; // Copy and null teminate string + MKDirResponse resp {}; + resp.command = commands::MKDIR_STATUS; + resp.modification_time = 0; + int res = fs.DirCreate(path); + resp.status = (res == 0) ? 0x01 : (int8_t) res; + auto* om = ble_hs_mbuf_from_flat(&resp, sizeof(MKDirResponse)); + ble_gattc_notify_custom(connectionHandle, transferCharacteristicHandle, om); + break; + } + case commands::LISTDIR: { + NRF_LOG_INFO("[FS_S] -> ListDir"); + ListDirHeader* header = (ListDirHeader*) om->om_data; + uint16_t plen = header->pathlen; + char path[plen + 1] = {0}; + path[plen] = 0; // Copy and null teminate string + memcpy(path, header->pathstr, plen); + + ListDirResponse resp {}; + + resp.command = commands::LISTDIR_ENTRY; + resp.status = 0x01; + resp.totalentries = 0; + resp.entry = 0; + resp.modification_time = 0; + int res = fs.DirOpen(path, &dir); + if (res != 0) { + resp.status = (int8_t) res; + auto* om = ble_hs_mbuf_from_flat(&resp, sizeof(ListDirResponse)); + ble_gattc_notify_custom(connectionHandle, transferCharacteristicHandle, om); + break; + }; + while (fs.DirRead(&dir, &info)) { + resp.totalentries++; + } + fs.DirRewind(&dir); + while (true) { + res = fs.DirRead(&dir, &info); + if (res <= 0) { + break; + } + switch (info.type) { + case LFS_TYPE_REG: { + resp.flags = 0; + resp.file_size = info.size; + break; + } + case LFS_TYPE_DIR: { + resp.flags = 1; + resp.file_size = 0; + break; + } + } + + // strcpy(resp.path, info.name); + resp.path_length = strlen(info.name); + auto* om = ble_hs_mbuf_from_flat(&resp, sizeof(ListDirResponse)); + os_mbuf_append(om, info.name, resp.path_length); + ble_gattc_notify_custom(connectionHandle, transferCharacteristicHandle, om); + /* + * Todo Figure out how to know when the previous Notify was TX'd + * For now just delay 100ms to make sure that the data went out... + */ + vTaskDelay(100); // Allow stuff to actually go out over the BLE conn + resp.entry++; + } + assert(fs.DirClose(&dir) == 0); + resp.file_size = 0; + resp.path_length = 0; + resp.flags = 0; + auto* om = ble_hs_mbuf_from_flat(&resp, sizeof(ListDirResponse)); + ble_gattc_notify_custom(connectionHandle, transferCharacteristicHandle, om); + break; + } + case commands::MOVE: { + NRF_LOG_INFO("[FS_S] -> Move"); + MoveHeader* header = (MoveHeader*) om->om_data; + uint16_t plen = header->OldPathLength; + // Null Terminate string + header->pathstr[plen] = 0; + char path[header->NewPathLength + 1] = {0}; + memcpy(path, &header->pathstr[plen + 1], header->NewPathLength); + path[header->NewPathLength] = 0; // Copy and null teminate string + MoveResponse resp {}; + resp.command = commands::MOVE_STATUS; + int8_t res = (int8_t) fs.Rename(header->pathstr, path); + resp.status = (res == 0) ? 1 : res; + auto* om = ble_hs_mbuf_from_flat(&resp, sizeof(MoveResponse)); + ble_gattc_notify_custom(connectionHandle, transferCharacteristicHandle, om); + } + default: + break; + } + NRF_LOG_INFO("[FS_S] -> done "); + systemTask.PushMessage(Pinetime::System::Messages::StopFileTransfer); + return 0; +} + +// Loads resp with file data given a valid filepath header and resp +void FSService::prepareReadDataResp(ReadHeader* header, ReadResponse* resp) { + // uint16_t plen = header->pathlen; + resp->command = commands::READ_DATA; + resp->chunkoff = header->chunkoff; + resp->status = 0x01; + struct lfs_info info = {}; + int res = fs.Stat(filepath, &info); + if (res == LFS_ERR_NOENT && info.type != LFS_TYPE_DIR) { + resp->status = 0x03; + resp->chunklen = 0; + resp->totallen = 0; + } else { + lfs_file f; + resp->chunklen = std::min(header->chunksize, info.size); + resp->totallen = info.size; + fs.FileOpen(&f, filepath, LFS_O_RDONLY); + fs.FileSeek(&f, header->chunkoff); + resp->chunklen = fs.FileRead(&f, resp->chunk, resp->chunklen); + fs.FileClose(&f); + } +} diff --git a/src/components/ble/FSService.h b/src/components/ble/FSService.h new file mode 100644 index 00000000..828925a8 --- /dev/null +++ b/src/components/ble/FSService.h @@ -0,0 +1,191 @@ +#pragma once +#define min // workaround: nimble's min/max macros conflict with libstdc++ +#define max +#include +#undef max +#undef min + +#include "components/fs/FS.h" + +namespace Pinetime { + namespace System { + class SystemTask; + } + namespace Controllers { + class Ble; + class FSService { + public: + FSService(Pinetime::System::SystemTask& systemTask, Pinetime::Controllers::FS& fs); + void Init(); + + int OnFSServiceRequested(uint16_t connectionHandle, uint16_t attributeHandle, ble_gatt_access_ctxt* context); + void NotifyFSRaw(uint16_t connectionHandle); + + private: + Pinetime::System::SystemTask& systemTask; + Pinetime::Controllers::FS& fs; + static constexpr uint16_t FSServiceId {0xFEBB}; + static constexpr uint16_t fsVersionId {0x0100}; + static constexpr uint16_t fsTransferId {0x0200}; + uint16_t fsVersion = {0x0004}; + static constexpr uint16_t maxpathlen = 256; + static constexpr ble_uuid16_t fsServiceUuid { + .u {.type = BLE_UUID_TYPE_16}, + .value = {0xFEBB}}; // {0x72, 0x65, 0x66, 0x73, 0x6e, 0x61, 0x72, 0x54, 0x65, 0x6c, 0x69, 0x46, 0xBB, 0xFE, 0xAF, 0xAD}}; + + static constexpr ble_uuid128_t fsVersionUuid { + .u {.type = BLE_UUID_TYPE_128}, + .value = {0x72, 0x65, 0x66, 0x73, 0x6e, 0x61, 0x72, 0x54, 0x65, 0x6c, 0x69, 0x46, 0x00, 0x01, 0xAF, 0xAD}}; + + static constexpr ble_uuid128_t fsTransferUuid { + .u {.type = BLE_UUID_TYPE_128}, + .value = {0x72, 0x65, 0x66, 0x73, 0x6e, 0x61, 0x72, 0x54, 0x65, 0x6c, 0x69, 0x46, 0x00, 0x02, 0xAF, 0xAD}}; + + struct ble_gatt_chr_def characteristicDefinition[3]; + struct ble_gatt_svc_def serviceDefinition[2]; + uint16_t versionCharacteristicHandle; + uint16_t transferCharacteristicHandle; + + enum class commands : uint8_t { + INVALID = 0x00, + READ = 0x10, + READ_DATA = 0x11, + READ_PACING = 0x12, + WRITE = 0x20, + WRITE_PACING = 0x21, + WRITE_DATA = 0x22, + DELETE = 0x30, + DELETE_STATUS = 0x31, + MKDIR = 0x40, + MKDIR_STATUS = 0x41, + LISTDIR = 0x50, + LISTDIR_ENTRY = 0x51, + MOVE = 0x60, + MOVE_STATUS = 0x61 + }; + enum class FSState : uint8_t { + IDLE = 0x00, + READ = 0x01, + WRITE = 0x02, + }; + FSState state; + char filepath[maxpathlen]; // TODO ..ugh fixed filepath len + int fileSize; + using ReadHeader = struct __attribute__((packed)) { + commands command; + uint8_t padding; + uint16_t pathlen; + uint32_t chunkoff; + uint32_t chunksize; + char pathstr[]; + }; + + using ReadResponse = struct __attribute__((packed)) { + commands command; + uint8_t status; + uint16_t padding; + uint32_t chunkoff; + uint32_t totallen; + uint32_t chunklen; + uint8_t chunk[]; + }; + using ReadPacing = struct __attribute__((packed)) { + commands command; + uint8_t status; + uint16_t padding; + uint32_t chunkoff; + uint32_t chunksize; + }; + + using WriteHeader = struct __attribute__((packed)) { + commands command; + uint8_t padding; + uint16_t pathlen; + uint32_t offset; + uint64_t modTime; + uint32_t totalSize; + char pathstr[]; + }; + + using WriteResponse = struct __attribute__((packed)) { + commands command; + uint8_t status; + uint16_t padding; + uint32_t offset; + uint64_t modTime; + uint32_t freespace; + }; + + using WritePacing = struct __attribute__((packed)) { + commands command; + uint8_t status; + uint16_t padding; + uint32_t offset; + uint32_t dataSize; + uint8_t data[]; + }; + using ListDirHeader = struct __attribute__((packed)) { + commands command; + uint8_t padding; + uint16_t pathlen; + char pathstr[]; + }; + + using ListDirResponse = struct __attribute__((packed)) { + commands command; + uint8_t status; + uint16_t path_length; + uint32_t entry; + uint32_t totalentries; + uint32_t flags; + uint64_t modification_time; + uint32_t file_size; + char path[]; + }; + + using MKDirHeader = struct __attribute__((packed)) { + commands command; + uint8_t padding; + uint16_t pathlen; + uint32_t padding2; + uint64_t time; + char pathstr[]; + }; + + using MKDirResponse = struct __attribute__((packed)) { + commands command; + uint8_t status; + uint32_t padding1; + uint16_t padding2; + uint64_t modification_time; + }; + + using DelHeader = struct __attribute__((packed)) { + commands command; + uint8_t padding; + uint16_t pathlen; + char pathstr[]; + }; + + using DelResponse = struct __attribute__((packed)) { + commands command; + uint8_t status; + }; + using MoveHeader = struct __attribute__((packed)) { + commands command; + uint8_t padding; + uint16_t OldPathLength; + uint16_t NewPathLength; + char pathstr[]; + }; + + using MoveResponse = struct __attribute__((packed)) { + commands command; + uint8_t status; + }; + + int FSCommandHandler(uint16_t connectionHandle, os_mbuf* om); + void prepareReadDataResp(ReadHeader* header, ReadResponse* resp); + }; + } +} diff --git a/src/components/ble/NimbleController.cpp b/src/components/ble/NimbleController.cpp index acf4f94b..3bf1ec80 100644 --- a/src/components/ble/NimbleController.cpp +++ b/src/components/ble/NimbleController.cpp @@ -30,7 +30,7 @@ NimbleController::NimbleController(Pinetime::System::SystemTask& systemTask, Pinetime::Drivers::SpiNorFlash& spiNorFlash, Controllers::HeartRateController& heartRateController, Controllers::MotionController& motionController, - Pinetime::Controllers::FS& fs) + Controllers::FS& fs) : systemTask {systemTask}, bleController {bleController}, dateTimeController {dateTimeController}, @@ -50,6 +50,7 @@ NimbleController::NimbleController(Pinetime::System::SystemTask& systemTask, immediateAlertService {systemTask, notificationManager}, heartRateService {systemTask, heartRateController}, motionService {systemTask, motionController}, + fsService {systemTask, fs}, serviceDiscovery({¤tTimeClient, &alertNotificationClient}) { } @@ -97,6 +98,7 @@ void NimbleController::Init() { immediateAlertService.Init(); heartRateService.Init(); motionService.Init(); + fsService.Init(); int rc; rc = ble_hs_util_ensure_addr(0); diff --git a/src/components/ble/NimbleController.h b/src/components/ble/NimbleController.h index 12bd6924..7a387037 100644 --- a/src/components/ble/NimbleController.h +++ b/src/components/ble/NimbleController.h @@ -22,6 +22,7 @@ #include "components/ble/MotionService.h" #include "components/ble/weather/WeatherService.h" #include "components/fs/FS.h" +#include "components/ble/FSService.h" namespace Pinetime { namespace Drivers { @@ -110,6 +111,7 @@ namespace Pinetime { HeartRateService heartRateService; MotionService motionService; ServiceDiscovery serviceDiscovery; + FSService fsService; uint8_t addrType; uint16_t connectionHandle = BLE_HS_CONN_HANDLE_NONE; diff --git a/src/components/fs/FS.cpp b/src/components/fs/FS.cpp index 1cad4f02..8c98ae34 100644 --- a/src/components/fs/FS.cpp +++ b/src/components/fs/FS.cpp @@ -5,29 +5,28 @@ using namespace Pinetime::Controllers; -FS::FS(Pinetime::Drivers::SpiNorFlash& driver) : - flashDriver{ driver }, - lfsConfig{ - .context = this, - .read = SectorRead, - .prog = SectorProg, - .erase = SectorErase, - .sync = SectorSync, +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, + .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, - } -{ } + .cache_size = 16, + .lookahead_size = 16, + .name_max = 50, + .attr_max = 50, + } { +} void FS::Init() { @@ -48,7 +47,6 @@ void FS::Init() { VerifyResource(); LVGLFileSystemInit(); #endif - } void FS::VerifyResource() { @@ -56,7 +54,7 @@ void FS::VerifyResource() { resourcesValid = true; } -int FS::FileOpen(lfs_file_t* file_p, const char* fileName, const int flags) { +int FS::FileOpen(lfs_file_t* file_p, const char* fileName, const int flags) { return lfs_file_open(&lfs, file_p, fileName, flags); } @@ -80,27 +78,31 @@ int FS::FileDelete(const char* fileName) { return lfs_remove(&lfs, fileName); } +int FS::DirOpen(const char* path, lfs_dir_t* lfs_dir) { + return lfs_dir_open(&lfs, lfs_dir, path); +} +int FS::DirClose(lfs_dir_t* lfs_dir) { + return lfs_dir_close(&lfs, lfs_dir); +} + +int FS::DirRead(lfs_dir_t* dir, lfs_info* info) { + return lfs_dir_read(&lfs, dir, info); +} +int FS::DirRewind(lfs_dir_t* dir) { + return lfs_dir_rewind(&lfs, dir); +} int FS::DirCreate(const char* path) { return lfs_mkdir(&lfs, path); } - -// Delete directory and all files inside -int FS::DirDelete(const char* 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; +int FS::Rename(const char* oldPath, const char* newPath){ + return lfs_rename(&lfs,oldPath,newPath); +} +int FS::Stat(const char* path, lfs_info* info) { + return lfs_stat(&lfs, path, info); +} +lfs_ssize_t FS::GetFSSize() { + return lfs_fs_size(&lfs); } /* @@ -141,17 +143,17 @@ int FS::SectorRead(const struct lfs_config* c, lfs_block_t block, lfs_off_t off, 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(file_p); FS* filesys = static_cast(drv->user_data); - filesys->FileOpen(file, path, LFS_O_RDONLY); - - if (file->type == 0) { - return LV_FS_RES_FS_ERR; - } - else { - return LV_FS_RES_OK; + int res = filesys->FileOpen(file, path, LFS_O_RDONLY); + if (res == 0) { + if (file->type == 0) { + return LV_FS_RES_FS_ERR; + } else { + return LV_FS_RES_OK; + } } + return LV_FS_RES_NOT_EX; } lv_fs_res_t lvglClose(lv_fs_drv_t* drv, void* file_p) { @@ -193,5 +195,4 @@ void FS::LVGLFileSystemInit() { fs_drv.user_data = this; lv_fs_drv_register(&fs_drv); - } \ No newline at end of file diff --git a/src/components/fs/FS.h b/src/components/fs/FS.h index 75ba16c8..2b27ae5d 100644 --- a/src/components/fs/FS.h +++ b/src/components/fs/FS.h @@ -21,37 +21,49 @@ namespace Pinetime { 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(); - private: + 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 +---------------------------------------+ - * - */ + * 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; @@ -65,7 +77,6 @@ namespace Pinetime { 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); - }; } } diff --git a/src/systemtask/Messages.h b/src/systemtask/Messages.h index 516f6462..cc30fdc6 100644 --- a/src/systemtask/Messages.h +++ b/src/systemtask/Messages.h @@ -27,6 +27,8 @@ namespace Pinetime { StopRinging, MeasureBatteryTimerExpired, BatteryPercentageUpdated, + StartFileTransfer, + StopFileTransfer, }; } } diff --git a/src/systemtask/SystemTask.cpp b/src/systemtask/SystemTask.cpp index 28f81243..a95d479d 100644 --- a/src/systemtask/SystemTask.cpp +++ b/src/systemtask/SystemTask.cpp @@ -342,6 +342,19 @@ void SystemTask::Work() { doNotGoToSleep = false; xTimerStart(dimTimer, 0); break; + case Messages::StartFileTransfer: + NRF_LOG_INFO("[systemtask] FS Started"); + doNotGoToSleep = true; + if (isSleeping && !isWakingUp) + GoToRunning(); + //TODO add intent of fs access icon or something + break; + case Messages::StopFileTransfer: + NRF_LOG_INFO("[systemtask] FS Stopped"); + doNotGoToSleep = false; + xTimerStart(dimTimer, 0); + //TODO add intent of fs access icon or something + break; case Messages::OnTouchEvent: if (touchHandler.GetNewTouchInfo()) { touchHandler.UpdateLvglTouchPoint();