Oliver Fabel 1 год назад
Родитель
Сommit
1690115d12

+ 1 - 0
.gitignore

@@ -2,6 +2,7 @@
 /venv/
 /node_modules/
 /flipperzero/__init__.py
+/fssdk
 .vscode
 .clang-format
 .clangd

+ 7 - 0
CHANGELOG.md

@@ -7,6 +7,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 
 ## [Unreleased]
 
+### Added
+
+* Support for basic file system operations using the `io` module:
+  * Read a file.
+  * Write a file.
+  * Append to a file.
+
 ## [1.4.0] - 2024-09-29
 
 ### Added

+ 2 - 2
docs/pages/conf.py

@@ -13,8 +13,8 @@ sys.path.append(flipperzero)
 project = 'uPython'
 copyright = str(now.year) + ', Oliver Fabel'
 author = 'Oliver Fabel'
-release = '1.1.0'
-version = '1.1'
+release = '1.4.0'
+version = '1.4'
 language = 'en'
 
 extensions = [

+ 5 - 0
examples/open.py

@@ -0,0 +1,5 @@
+fp = open('/ext/spam.txt', 'w')
+
+fp.write('Some spam')
+
+fp.close()

+ 14 - 0
flipper.json

@@ -0,0 +1,14 @@
+{
+    "source": "examples",
+    "target": "/ext/examples",
+    "orphans": "ignore",
+    "include": [
+        "*.py"
+    ],
+    "exclude": [
+        "**.git**"
+    ],
+    "run": [
+        "loader open /ext/apps/Tools/upython.fap"
+    ]
+}

+ 1 - 1
lib/micropython

@@ -1 +1 @@
-Subproject commit 55fca52c45c820244147bfb3a54bd9801635974e
+Subproject commit 5ec95678f441f564e5bc1897f6b106d955e0a05d

+ 2 - 0
lib/micropython-port/mp_flipper_context.h

@@ -3,6 +3,7 @@
 #include <furi.h>
 #include <gui/gui.h>
 #include <dialogs/dialogs.h>
+#include <storage/storage.h>
 
 #include <mp_flipper_modflipperzero.h>
 
@@ -40,6 +41,7 @@ typedef struct {
     const char* dialog_message_button_left;
     const char* dialog_message_button_center;
     const char* dialog_message_button_right;
+    Storage* storage;
     FuriHalAdcHandle* adc_handle;
     mp_flipper_gpio_pin_t* gpio_pins;
     mp_flipper_infrared_rx_t* infrared_rx;

+ 7 - 6
lib/micropython-port/mp_flipper_file_helper.c

@@ -4,10 +4,13 @@
 #include <furi.h>
 #include <storage/storage.h>
 
+#include "mp_flipper_context.h"
+
 mp_flipper_import_stat_t mp_flipper_try_resolve_filesystem_path(FuriString* path) {
+    mp_flipper_context_t* ctx = mp_flipper_context;
+
     const char* path_str = furi_string_get_cstr(path);
     FuriString* _path = furi_string_alloc_printf("%s", path_str);
-    Storage* storage = furi_record_open(RECORD_STORAGE);
 
     mp_flipper_import_stat_t stat = MP_FLIPPER_IMPORT_STAT_FILE;
 
@@ -21,7 +24,7 @@ mp_flipper_import_stat_t mp_flipper_try_resolve_filesystem_path(FuriString* path
         }
 
         // check if file or folder exists
-        error = storage_common_stat(storage, furi_string_get_cstr(_path), &info);
+        error = storage_common_stat(ctx->storage, furi_string_get_cstr(_path), &info);
         if(error == FSE_OK) {
             break;
         }
@@ -29,7 +32,7 @@ mp_flipper_import_stat_t mp_flipper_try_resolve_filesystem_path(FuriString* path
         // check for existing python file
         furi_string_cat_str(_path, ".py");
 
-        error = storage_common_stat(storage, furi_string_get_cstr(_path), &info);
+        error = storage_common_stat(ctx->storage, furi_string_get_cstr(_path), &info);
         if(error == FSE_OK) {
             break;
         }
@@ -48,9 +51,7 @@ mp_flipper_import_stat_t mp_flipper_try_resolve_filesystem_path(FuriString* path
         stat = MP_FLIPPER_IMPORT_STAT_DIR;
     }
 
-    furi_record_close(RECORD_STORAGE);
-
     furi_string_move(path, _path);
 
     return stat;
-}
+}

+ 18 - 17
lib/micropython-port/mp_flipper_file_reader.c

@@ -6,19 +6,21 @@
 #include <mp_flipper_runtime.h>
 #include <mp_flipper_file_reader.h>
 
+#include "mp_flipper_context.h"
 #include "mp_flipper_file_helper.h"
 
 typedef struct {
     size_t pointer;
     FuriString* content;
     size_t size;
-} FileReaderContext;
+} FileDescriptor;
 
 inline void* mp_flipper_file_reader_context_alloc(const char* filename) {
+    mp_flipper_context_t* ctx = mp_flipper_context;
+
     FuriString* path = furi_string_alloc_printf("%s", filename);
-    Storage* storage = furi_record_open(RECORD_STORAGE);
-    File* file = storage_file_alloc(storage);
-    FileReaderContext* ctx = NULL;
+    File* file = storage_file_alloc(ctx->storage);
+    FileDescriptor* fd = NULL;
 
     do {
         if(mp_flipper_try_resolve_filesystem_path(path) == MP_FLIPPER_IMPORT_STAT_NO_EXIST) {
@@ -33,42 +35,41 @@ inline void* mp_flipper_file_reader_context_alloc(const char* filename) {
             break;
         }
 
-        ctx = malloc(sizeof(FileReaderContext));
+        fd = malloc(sizeof(FileDescriptor));
 
-        ctx->pointer = 0;
-        ctx->content = furi_string_alloc();
-        ctx->size = storage_file_size(file);
+        fd->pointer = 0;
+        fd->content = furi_string_alloc();
+        fd->size = storage_file_size(file);
 
         char character = '\0';
 
-        for(size_t i = 0; i < ctx->size; i++) {
+        for(size_t i = 0; i < fd->size; i++) {
             storage_file_read(file, &character, 1);
 
-            furi_string_push_back(ctx->content, character);
+            furi_string_push_back(fd->content, character);
         }
     } while(false);
 
     storage_file_free(file);
-    furi_record_close(RECORD_STORAGE);
     furi_string_free(path);
 
-    return ctx;
+    return fd;
 }
 
 inline uint32_t mp_flipper_file_reader_read(void* data) {
-    FileReaderContext* ctx = data;
+    FileDescriptor* fd = data;
 
-    if(ctx->pointer >= ctx->size) {
+    if(fd->pointer >= fd->size) {
         return MP_FLIPPER_FILE_READER_EOF;
     }
 
-    return furi_string_get_char(ctx->content, ctx->pointer++);
+    return furi_string_get_char(fd->content, fd->pointer++);
 }
 
 void mp_flipper_file_reader_close(void* data) {
-    FileReaderContext* ctx = data;
+    FileDescriptor* fd = data;
 
-    furi_string_free(ctx->content);
+    furi_string_free(fd->content);
 
     free(data);
 }

+ 77 - 0
lib/micropython-port/mp_flipper_fileio.c

@@ -0,0 +1,77 @@
+#include <furi.h>
+#include <storage/storage.h>
+
+#include <mp_flipper_fileio.h>
+#include <mp_flipper_runtime.h>
+
+#include "mp_flipper_context.h"
+#include "mp_flipper_file_helper.h"
+
+inline void* mp_flipper_file_open(
+    const char* name,
+    mp_flipper_file_access_mode_t access_mode,
+    mp_flipper_file_open_mode_t open_mode,
+    size_t* offset) {
+    mp_flipper_context_t* ctx = mp_flipper_context;
+
+    File* file = storage_file_alloc(ctx->storage);
+    FuriString* path = furi_string_alloc_set_str(name);
+
+    do {
+        if(mp_flipper_try_resolve_filesystem_path(path) == MP_FLIPPER_IMPORT_STAT_NO_EXIST) {
+            mp_flipper_raise_os_error_with_filename(MP_ENOENT, name);
+
+            break;
+        }
+
+        if(!storage_file_open(file, furi_string_get_cstr(path), access_mode, open_mode)) {
+            mp_flipper_raise_os_error_with_filename(MP_ENOENT, name);
+
+            break;
+        }
+    } while(false);
+
+    // TODO close open files upon application exit
+
+    return file;
+}
+
+inline int mp_flipper_file_close(void* handle) {
+    mp_flipper_context_t* ctx = mp_flipper_context;
+
+    File* file = handle;
+
+    if(storage_file_is_open(file) && storage_file_close(file)) {
+        // NOP
+    } else {
+        // TODO handle error
+    }
+
+    storage_file_free(file);
+
+    return 0;
+}
+
+inline bool mp_flipper_file_writable(void* handle) {
+    File* file = handle;
+
+    // TODO
+
+    return true;
+}
+
+inline size_t mp_flipper_file_read(void* handle, void* buffer, size_t size, int* errcode) {
+    File* file = handle;
+
+    *errcode = 0; // TODO handle error
+
+    return storage_file_read(file, buffer, size);
+}
+
+inline size_t mp_flipper_file_write(void* handle, const void* buffer, size_t size, int* errcode) {
+    File* file = handle;
+
+    *errcode = 0; // TODO handle error
+
+    return storage_file_write(file, buffer, size);
+}

+ 7 - 3
lib/micropython-port/mp_flipper_runtime.c

@@ -14,8 +14,9 @@ static void on_input_callback(const InputEvent* event, void* ctx) {
 }
 
 void mp_flipper_save_file(const char* file_path, const char* data, size_t size) {
-    Storage* storage = furi_record_open(RECORD_STORAGE);
-    File* file = storage_file_alloc(storage);
+    mp_flipper_context_t* ctx = mp_flipper_context;
+
+    File* file = storage_file_alloc(ctx->storage);
 
     do {
         if(!storage_file_open(file, file_path, FSAM_WRITE, FSOM_CREATE_ALWAYS)) {
@@ -30,7 +31,6 @@ void mp_flipper_save_file(const char* file_path, const char* data, size_t size)
     } while(false);
 
     storage_file_free(file);
-    furi_record_close(RECORD_STORAGE);
 }
 
 inline void mp_flipper_nlr_jump_fail(void* val) {
@@ -84,6 +84,8 @@ void* mp_flipper_context_alloc() {
     ctx->dialog_message_button_center = NULL;
     ctx->dialog_message_button_right = NULL;
 
+    ctx->storage = furi_record_open(RECORD_STORAGE);
+
     ctx->adc_handle = NULL;
 
     // GPIO
@@ -129,6 +131,8 @@ void mp_flipper_context_free(void* context) {
     furi_record_close(RECORD_GUI);
     furi_record_close(RECORD_INPUT_EVENTS);
 
+    furi_record_close(RECORD_STORAGE);
+
     // disable ADC handle
     if(ctx->adc_handle) {
         furi_hal_adc_release(ctx->adc_handle);