Kaynağa Gözat

add wacky canvas support

Oliver Fabel 1 yıl önce
ebeveyn
işleme
b446c30bec

+ 3 - 1
CHANGELOG.md

@@ -10,7 +10,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 ### Added
 
 * Floating point support
-* Basic speaker support for `flipperzero` module
+* Extend `flipperzero` module with support for:
+  * Speaker, set volume and frequency
+  * Canvas, very wacky implementation
 
 ## [0.2.0-alpha.1] - 2024-04-03
 

+ 16 - 0
examples/flipperzero_canvas_test.py

@@ -0,0 +1,16 @@
+import time
+import flipperzero
+
+color = False
+
+for x in range(0, 128):
+  color = not color
+
+  for y in range(0, 64):
+    flipperzero.canvas_draw_dot(x, y, color)
+
+    color = not color
+
+flipperzero.canvas_update()
+
+time.sleep(2)

+ 20 - 0
lib/micropython-port/modflipperzero.c

@@ -79,6 +79,24 @@ static mp_obj_t flipperzero_speaker_stop() {
 }
 static MP_DEFINE_CONST_FUN_OBJ_0(flipperzero_speaker_stop_obj, flipperzero_speaker_stop);
 
+static mp_obj_t flipperzero_canvas_draw_dot(mp_obj_t x_obj, mp_obj_t y_obj, mp_obj_t color_obj) {
+    mp_int_t x = mp_obj_get_int(x_obj);
+    mp_int_t y = mp_obj_get_int(y_obj);
+    bool color = mp_obj_is_true(color_obj);
+
+    mp_flipper_canvas_draw_dot(x, y, color);
+
+    return mp_const_none;
+}
+static MP_DEFINE_CONST_FUN_OBJ_3(flipperzero_canvas_draw_dot_obj, flipperzero_canvas_draw_dot);
+
+static mp_obj_t flipperzero_canvas_update() {
+    mp_flipper_canvas_update();
+
+    return mp_const_none;
+}
+static MP_DEFINE_CONST_FUN_OBJ_0(flipperzero_canvas_update_obj, flipperzero_canvas_update);
+
 static const mp_rom_map_elem_t flipperzero_module_globals_table[] = {
     {MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_flipperzero)},
     {MP_ROM_QSTR(MP_QSTR_LIGHT_RED), MP_ROM_INT(MP_FLIPPER_LED_RED)},
@@ -93,6 +111,8 @@ static const mp_rom_map_elem_t flipperzero_module_globals_table[] = {
     {MP_ROM_QSTR(MP_QSTR_speaker_start), MP_ROM_PTR(&flipperzero_speaker_start_obj)},
     {MP_ROM_QSTR(MP_QSTR_speaker_set_volume), MP_ROM_PTR(&flipperzero_speaker_set_volume_obj)},
     {MP_ROM_QSTR(MP_QSTR_speaker_stop), MP_ROM_PTR(&flipperzero_speaker_stop_obj)},
+    {MP_ROM_QSTR(MP_QSTR_canvas_draw_dot), MP_ROM_PTR(&flipperzero_canvas_draw_dot_obj)},
+    {MP_ROM_QSTR(MP_QSTR_canvas_update), MP_ROM_PTR(&flipperzero_canvas_update_obj)},
 };
 static MP_DEFINE_CONST_DICT(flipperzero_module_globals, flipperzero_module_globals_table);
 

+ 3 - 0
lib/micropython-port/modflipperzero.h

@@ -18,3 +18,6 @@ void mp_flipper_vibro(bool state);
 bool mp_flipper_speaker_start(float frequency, float volume);
 bool mp_flipper_speaker_set_volume(float volume);
 bool mp_flipper_speaker_stop();
+
+void mp_flipper_canvas_draw_dot(uint8_t x, uint8_t y, bool color);
+void mp_flipper_canvas_update();

+ 15 - 0
lib/micropython-port/modflipperzero_impl.c

@@ -1,5 +1,9 @@
+#include <stdint.h>
+
 #include <furi_hal.h>
 
+#include <mp_flipper_app.h>
+
 #include "modflipperzero.h"
 
 static Light decode_light(uint8_t value) {
@@ -69,3 +73,14 @@ inline bool mp_flipper_speaker_stop() {
 
     return false;
 }
+
+inline void mp_flipper_canvas_draw_dot(uint8_t x, uint8_t y, bool color) {
+    size_t index = (x + 1) / SCREEN_PIXEL_PER_ITEM + y * (SCREEN_WIDTH / SCREEN_PIXEL_PER_ITEM);
+    const uint32_t mask = 1 << (x % SCREEN_PIXEL_PER_ITEM);
+
+    mp_flipper_canvas[index] |= color ? (UINT32_MAX & mask) : 0;
+}
+
+inline void mp_flipper_canvas_update() {
+    view_port_update(mp_flipper_view_port);
+}

+ 50 - 3
mp_flipper_app.c

@@ -1,3 +1,5 @@
+#include <malloc.h>
+
 #include <furi.h>
 #include <dialogs/dialogs.h>
 #include <storage/storage.h>
@@ -8,6 +10,33 @@
 
 const char* root_module_path;
 
+uint32_t* mp_flipper_canvas;
+ViewPort* mp_flipper_view_port;
+FuriMessageQueue* mp_flipper_event_queue;
+
+static void draw_callback(Canvas* canvas, void* ctx) {
+    UNUSED(ctx);
+
+    uint8_t x = 0, y = 0;
+    size_t i = 0;
+    uint32_t mask = 1;
+    Color color = ColorBlack;
+
+    for(size_t index = 0; index < (SCREEN_WIDTH * SCREEN_HEIGHT) / SCREEN_PIXEL_PER_ITEM; index++) {
+        for(i = 0, mask = 1; i < SCREEN_PIXEL_PER_ITEM; i++, mask <<= 1) {
+            color = (mp_flipper_canvas[index] & mask) > 0 ? ColorBlack : ColorWhite;
+
+            canvas_set_color(canvas, color);
+            canvas_draw_dot(canvas, x, y);
+
+            if(++x % SCREEN_WIDTH == 0) {
+                x = 0;
+                y++;
+            }
+        }
+    }
+}
+
 static void load_python_file(FuriString* file_path, FuriString* code) {
     Storage* storage = furi_record_open(RECORD_STORAGE);
     DialogsApp* dialogs = furi_record_open(RECORD_DIALOGS);
@@ -52,18 +81,21 @@ static void load_python_file(FuriString* file_path, FuriString* code) {
 int32_t mp_flipper_app(void* p) {
     UNUSED(p);
 
+    mp_flipper_canvas = malloc(((SCREEN_WIDTH * SCREEN_HEIGHT) / SCREEN_PIXEL_PER_ITEM) * sizeof(uint32_t));
+
     const size_t memory_size = memmgr_get_free_heap() * 0.5;
     const size_t stack_size = 2 * 1024;
     uint8_t* memory = malloc(memory_size * sizeof(uint8_t));
 
-    FURI_LOG_I(TAG, "allocated memory is %zu bytes", memory_size);
-    FURI_LOG_I(TAG, "stack size is %zu bytes", stack_size);
-
     FuriString* file_path = furi_string_alloc();
     FuriString* code = furi_string_alloc();
 
     load_python_file(file_path, code);
 
+    FURI_LOG_I(TAG, "allocated memory is %zu bytes", memory_size);
+    FURI_LOG_I(TAG, "stack size is %zu bytes", stack_size);
+    FURI_LOG_I(TAG, "executing python script %s", furi_string_get_cstr(file_path));
+
     size_t index = furi_string_search_rchar(file_path, '/');
 
     furi_check(index != FURI_STRING_FAILURE);
@@ -72,13 +104,28 @@ int32_t mp_flipper_app(void* p) {
 
     root_module_path = furi_string_get_cstr(file_path);
 
+    // initialize view port
+    mp_flipper_view_port = view_port_alloc();
+    view_port_draw_callback_set(mp_flipper_view_port, draw_callback, NULL);
+
+    // initialize GUI
+    Gui* gui = furi_record_open(RECORD_GUI);
+    gui_add_view_port(gui, mp_flipper_view_port, GuiLayerFullscreen);
+
     mp_embed_init(memory + stack_size, memory_size - stack_size, memory);
     mp_embed_exec_str(furi_string_get_cstr(code));
     mp_embed_deinit();
 
+    // destroy GUI and view port
+    gui_remove_view_port(gui, mp_flipper_view_port);
+    view_port_free(mp_flipper_view_port);
+    furi_record_close(RECORD_GUI);
+
     furi_string_free(file_path);
     furi_string_free(code);
     free(memory);
 
+    free(mp_flipper_canvas);
+
     return 0;
 }

+ 12 - 0
mp_flipper_app.h

@@ -1,5 +1,17 @@
 #pragma once
 
+#include <stdbool.h>
+
+#include <gui/gui.h>
+
 #define TAG "uPython"
 
+#define SCREEN_WIDTH 128
+#define SCREEN_HEIGHT 64
+#define SCREEN_PIXEL_PER_ITEM 32
+
+extern uint32_t* mp_flipper_canvas;
+extern ViewPort* mp_flipper_view_port;
+extern FuriMessageQueue* mp_flipper_event_queue;
+
 extern const char* root_module_path;