Skip to content

Commit

Permalink
add basic IO support
Browse files Browse the repository at this point in the history
  • Loading branch information
ofabel committed Sep 30, 2024
1 parent 7b89577 commit 1690115
Show file tree
Hide file tree
Showing 11 changed files with 141 additions and 29 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
/venv/
/node_modules/
/flipperzero/__init__.py
/fssdk
.vscode
.clang-format
.clangd
Expand Down
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions docs/pages/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@
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 = [
Expand Down
5 changes: 5 additions & 0 deletions examples/open.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
fp = open('/ext/spam.txt', 'w')

fp.write('Some spam')

fp.close()
14 changes: 14 additions & 0 deletions flipper.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"source": "examples",
"target": "/ext/examples",
"orphans": "ignore",
"include": [
"*.py"
],
"exclude": [
"**.git**"
],
"run": [
"loader open /ext/apps/Tools/upython.fap"
]
}
2 changes: 2 additions & 0 deletions lib/micropython-port/mp_flipper_context.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include <furi.h>
#include <gui/gui.h>
#include <dialogs/dialogs.h>
#include <storage/storage.h>

#include <mp_flipper_modflipperzero.h>

Expand Down Expand Up @@ -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;
Expand Down
13 changes: 7 additions & 6 deletions lib/micropython-port/mp_flipper_file_helper.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -21,15 +24,15 @@ 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;
}

// 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;
}
Expand All @@ -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;
}
}
35 changes: 18 additions & 17 deletions lib/micropython-port/mp_flipper_file_reader.c
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -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 changes: 77 additions & 0 deletions lib/micropython-port/mp_flipper_fileio.c
Original file line number Diff line number Diff line change
@@ -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);
}
10 changes: 7 additions & 3 deletions lib/micropython-port/mp_flipper_runtime.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)) {
Expand All @@ -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) {
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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);
Expand Down

0 comments on commit 1690115

Please sign in to comment.