summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/CMakeLists.txt3
-rw-r--r--src/components/ble/FSService.cpp330
-rw-r--r--src/components/ble/FSService.h191
-rw-r--r--src/components/ble/NimbleController.cpp4
-rw-r--r--src/components/ble/NimbleController.h2
-rw-r--r--src/components/fs/FS.cpp103
-rw-r--r--src/components/fs/FS.h61
-rw-r--r--src/systemtask/Messages.h2
-rw-r--r--src/systemtask/SystemTask.cpp13
9 files changed, 632 insertions, 77 deletions
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 <nrf_log.h>
+#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<FSService*>(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<commands>(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 <host/ble_gap.h>
+#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({&currentTimeClient, &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,
-
- .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,
- }
-{ }
-
+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() {
@@ -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<lfs_file_t*>(file_p);
FS* filesys = static_cast<FS*>(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();