Personal commit

This commit is contained in:
vance 2024-08-21 19:27:21 -07:00
parent 5dc481e671
commit 257ee10a85
13 changed files with 915 additions and 0 deletions

3
.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
.zig-cache/
zig-out/
*.fap

37
build.zig Normal file
View File

@ -0,0 +1,37 @@
const std = @import("std");
const Target = std.Target;
const Build = std.Build;
pub fn build(b: *Build) void {
// Module
const flipperzero = b.addModule("flipperzero", .{
.root_source_file = b.path("lib/flipperzero/flipperzero.zig"),
});
// Configuration
const optimize = b.standardOptimizeOption(.{});
const target_query = .{ .cpu_arch = .thumb, .cpu_model = .{ .explicit = &Target.arm.cpu.cortex_m4 }, .os_tag = .freestanding, .abi = .none };
// Relocatable elf
const elf = b.addObject(.{
.name = "zlipper.fap",
.root_source_file = b.path("src/start.zig"),
.target = b.resolveTargetQuery(target_query),
.optimize = optimize,
.strip = true,
.pic = true,
});
elf.root_module.addImport("flipperzero", flipperzero);
elf.setLinkerScript(b.path("linker.ld"));
elf.setVerboseLink(true);
elf.build_id = .none;
elf.bundle_compiler_rt = false;
elf.link_gc_sections = true;
elf.linkage = .static;
b.default_step.dependOn(&elf.step);
const install_artifact = b.addInstallArtifact(elf, .{ .dest_dir = .{ .override = .{ .bin = {} } } });
b.getInstallStep().dependOn(&install_artifact.step);
}

View File

@ -0,0 +1,24 @@
const flipperzero = @import("flipperzero.zig");
const c = flipperzero.c;
pub fn FuriMessageQueue(comptime T: type) type {
return extern struct {
const Self = @This();
pub fn create(msg_count: u32) *Self {
return @ptrCast(c.furi_message_queue_alloc(msg_count, @sizeOf(T)));
}
pub fn destroy(self: *Self) void {
c.furi_message_queue_free(self);
}
pub fn get(self: *Self, msg_ptr: *T, timeout: u32) void {
_ = c.furi_message_queue_get(self, msg_ptr, timeout);
}
pub fn put(self: *Self, msg_ptr: *const T, timeout: u32) void {
_ = c.furi_message_queue_put(self, msg_ptr, timeout);
}
};
}

154
lib/flipperzero/c.zig Normal file
View File

@ -0,0 +1,154 @@
// C
pub extern fn aligned_malloc(len: usize, alignment: usize) ?*anyopaque;
pub extern fn aligned_free(ptr: *anyopaque) void;
pub extern fn malloc(size: usize) ?*anyopaque;
pub extern fn memset(dest: *anyopaque, c: i32, count: usize) *anyopaque;
pub extern fn free(memblock: *anyopaque) void;
pub extern fn snprintf(buffer: [*:0]u8, count: usize, format: [*:0]const u8, ...) i32;
// Canvas
pub extern fn canvas_clear(canvas: *anyopaque) void;
pub extern fn canvas_draw_str(canvas: *anyopaque, x: u8, y: u8, str: [*:0]const u8) void;
pub extern fn canvas_set_font(canvas: *anyopaque, font: Font) void;
// Furi
pub const FuriMutexType = enum(u8) {
FuriMutexTypeNormal,
FuriMutexTypeRecursive,
};
pub const FuriWait = enum(u32) {
FuriWaitForever = 0xFFFFFFFF,
};
pub const FuriStatus = enum(i32) { FuriStatusOk = 0, FuriStatusError = -1, FuriStatusErrorTimeout = -2, FuriStatusErrorResource = -3, FuriStatusErrorParameter = -4, FuriStatusErrorNoMemory = -5, FuriStatusErrorISR = -6, FuriStatusReserved = 0x7FFFFFFF };
pub extern fn furi_delay_us(microseconds: u32) void;
pub extern fn furi_message_queue_alloc(msg_count: u32, msg_size: u32) *anyopaque;
pub extern fn furi_message_queue_free(instance: *anyopaque) void;
pub extern fn furi_message_queue_get(instance: *anyopaque, msg_ptr: *anyopaque, timeout: u32) FuriStatus;
pub extern fn furi_message_queue_put(instance: *anyopaque, msg_ptr: *const anyopaque, timeout: u32) FuriStatus;
pub extern fn furi_mutex_alloc(type: FuriMutexType) *anyopaque;
pub extern fn furi_mutex_free(instance: *anyopaque) void;
pub extern fn furi_record_close(name: [*:0]const u8) void;
pub extern fn furi_record_open(name: [*:0]const u8) *anyopaque;
// GUI
pub const RECORD_GUI = "gui";
pub const Font = enum(u8) {
FontPrimary,
FontSecondary,
FontKeyboard,
FontBigNumbers,
FontTotalNumber,
};
pub const GuiLayer = enum(u8) {
GuiLayerDesktop,
GuiLayerWindow,
GuiLayerStatusBarTop, // Custom on RogueMaster
GuiLayerStatusBarLeft,
GuiLayerStatusBarLeftSlim, // Custom on RogueMaster
GuiLayerStatusBarRight,
GuiLayerStatusBarRightSlim, // Custom on RogueMaster
GuiLayerFullscreen,
GuiLayerMAX,
};
pub extern fn gui_add_view_port(gui: *anyopaque, view_port: *anyopaque, layer: GuiLayer) void;
pub extern fn gui_remove_view_port(gui: *anyopaque, view_port: *anyopaque) void;
// Input
pub const InputEvent = extern struct {
sequence: u32 align(4),
key: InputKey align(1),
type: InputType align(1),
};
pub const InputKey = enum(u8) {
InputKeyUp,
InputKeyDown,
InputKeyRight,
InputKeyLeft,
InputKeyOk,
InputKeyBack,
InputKeyMAX,
};
pub const InputType = enum(u8) {
InputTypePress,
InputTypeRelease,
InputTypeShort,
InputTypeLong,
InputTypeRepeat,
InputTypeMAX,
};
pub extern fn input_get_key_name(key: InputKey) [*:0]const u8;
pub extern fn input_get_type_name(type: InputType) [*:0]const u8;
// SceneManager
pub extern fn scene_manager_alloc() *anyopaque;
pub extern fn scene_manager_free(scene_manager: *anyopaque) void;
pub extern fn scene_manager_get_scene_state(scene_manager: *anyopaque, scene_id: u32) u32;
pub extern fn scene_manager_handle_back_event(scene_manager: *anyopaque) bool;
pub extern fn scene_manager_handle_custom_event(scene_manager: *anyopaque, custom_event: u32) bool;
pub extern fn scene_manager_handle_tick_event(scene_manager: *anyopaque) void;
pub extern fn scene_manager_has_previous_scene(scene_manager: *const anyopaque, scene_id: u32) bool;
pub extern fn scene_manager_next_scene(scene_manager: *anyopaque, next_scene_id: u32) bool;
pub extern fn scene_manager_previous_scene(scene_manager: *anyopaque) bool;
pub extern fn scene_manager_search_and_switch_to_another_scene(scene_manager: *anyopaque, scene_id: u32) bool;
pub extern fn scene_manager_search_and_switch_to_previous_scene(scene_manager: *anyopaque, scene_id: u32) bool;
pub extern fn scene_manager_search_and_switch_to_previous_scene_one_of(scene_manager: *anyopaque, scene_ids: *const u32, scene_ids_size: usize) bool;
pub extern fn scene_manager_set_scene_state(scene_manager: *anyopaque, scene_id: u32, state: u32) void;
pub extern fn scene_manager_stop(scene_manager: *anyopaque) void;
// Storage
pub const RECORD_STORAGE = "storage";
// View
pub const ViewModelType = enum(u8) {
ViewModelTypeNone,
ViewModelTypeLockFree,
ViewModelTypeLocking,
};
pub extern fn view_alloc() *anyopaque;
pub extern fn view_allocate_model(view: *anyopaque, type: ViewModelType, size: usize) void;
pub extern fn view_commit_model(view: *anyopaque, update: bool) void;
pub extern fn view_free(view: *anyopaque) void;
pub extern fn view_free_model(view: *anyopaque) void;
pub extern fn view_get_model(view: *anyopaque) *anyopaque;
// Viewdispatcher
pub const ViewDispatcherType = enum(u8) {
ViewDispatcherTypeDesktop,
ViewDispatcherTypeWindow,
ViewDispatcherTypeFullscreen,
};
pub extern fn view_dispatcher_add_view(view_dispatcher: *anyopaque, view_id: u32, view: *anyopaque) void;
pub extern fn view_dispatcher_alloc() *anyopaque;
pub extern fn view_dispatcher_attach_to_gui(view_dispatcher: *anyopaque, gui: *anyopaque, type: ViewDispatcherType) void;
pub extern fn view_dispatcher_enable_queue(view_dispatcher: *anyopaque) void;
pub extern fn view_dispatcher_free(view_dispatcher: *anyopaque) void;
pub extern fn view_dispatcher_get_event_loop(view_dispatcher: *anyopaque) *anyopaque;
pub extern fn view_dispatcher_remove_view(view_dispatcher: *anyopaque, view_id: u32) void;
pub extern fn view_dispatcher_run(view_dispatcher: *anyopaque) void;
pub extern fn view_dispatcher_send_custom_event(view_dispatcher: *anyopaque, event: u32) void;
pub extern fn view_dispatcher_send_to_back(view_dispatcher: *anyopaque) void;
pub extern fn view_dispatcher_send_to_front(view_dispatcher: *anyopaque) void;
pub const ViewDispatcherCustomEventCallback = *const fn (?*anyopaque, event: u32) callconv(.C) void;
pub extern fn view_dispatcher_set_custom_event_callback(view_dispatcher: *anyopaque, callback: ViewDispatcherCustomEventCallback) void;
pub extern fn view_dispatcher_set_event_callback_context(view_dispatcher: *anyopaque, context: ?*anyopaque) void;
pub const ViewDispatcherNavigationEventCallback = *const fn (?*anyopaque) callconv(.C) void;
pub extern fn view_dispatcher_set_navigation_event_callback(view_dispatcher: *anyopaque, callback: ViewDispatcherNavigationEventCallback) void;
pub const ViewDispatcherTickEventCallback = *const fn (*anyopaque) callconv(.C) void;
pub extern fn view_dispatcher_set_tick_event_callback(view_dispatcher: *anyopaque, callback: ViewDispatcherTickEventCallback, tick_period: u32) void;
pub extern fn view_dispatcher_stop(view_dispatcher: *anyopaque) void;
pub extern fn view_dispatcher_switch_to_view(view_dispatcher: *anyopaque, view_id: u32) void;
// Viewport
pub extern fn view_port_alloc() *anyopaque;
pub const ViewPortDrawCallback = *const fn (*anyopaque, ?*anyopaque) callconv(.C) void;
pub extern fn view_port_draw_callback_set(view_port: *anyopaque, draw_callback: ViewPortDrawCallback, context: ?*anyopaque) void;
pub extern fn view_port_enabled_set(view_port: *anyopaque, enabled: bool) void;
pub extern fn view_port_free(view_port: *anyopaque) void;
pub const ViewPortInputCallback = *const fn (*InputEvent, ?*anyopaque) callconv(.C) void;
pub extern fn view_port_input_callback_set(view_port: *anyopaque, input_callback: ViewPortInputCallback, context: ?*anyopaque) void;
pub extern fn view_port_update(view_port: *anyopaque) void;

View File

@ -0,0 +1,7 @@
pub const atomic = @import("atomic.zig");
pub const c = @import("c.zig");
pub const gui = @import("gui.zig");
pub const heap = @import("heap.zig");
pub const manifest = @import("manifest.zig");
pub const storage = @import("storage.zig");
pub const thread = @import("thread.zig");

227
lib/flipperzero/gui.zig Normal file
View File

@ -0,0 +1,227 @@
const flipperzero = @import("flipperzero.zig");
const c = flipperzero.c;
pub const Canvas = extern struct {
const Self = @This();
pub fn clear(self: *Self) void {
c.canvas_clear(@ptrCast(self));
}
pub fn drawStr(self: *Self, x: u8, y: u8, str: [*:0]const u8) void {
c.canvas_draw_str(@ptrCast(self), x, y, str);
}
pub fn setFont(self: *Self, font: c.Font) void {
c.canvas_set_font(@ptrCast(self), font);
}
};
pub const Gui = extern struct {
const Self = @This();
pub fn open() *Self {
return @ptrCast(c.furi_record_open(c.RECORD_GUI));
}
pub fn close(self: *Self) void {
_ = self;
c.furi_record_close(c.RECORD_GUI);
}
pub fn addViewPort(self: *Self, view_port: *ViewPort, layer: c.GuiLayer) void {
c.gui_add_view_port(self, view_port, layer);
}
pub fn removeViewPort(self: *Self, view_port: *ViewPort) void {
c.gui_remove_view_port(self, view_port);
}
};
pub const SceneManager = extern struct {
const Self = @This();
pub fn create() *Self {
return @ptrCast(c.scene_manager_alloc());
}
pub fn destroy(self: *Self) void {
c.scene_manager_free(self);
}
pub fn getSceneState(self: *Self, scene_id: u32) u32 {
return c.scene_manager_get_scene_state(self, scene_id);
}
pub fn handleBackEvent(self: *Self) bool {
return c.scene_manager_handle_back_event(self);
}
pub fn handleCustomEvent(self: *Self, custom_event: u32) bool {
return c.scene_manager_handle_custom_event(self, custom_event);
}
pub fn handleTickEvent(self: *Self) void {
c.scene_manager_handle_tick_event(self);
}
pub fn hasPreviousScene(self: *Self, scene_id: u32) bool {
return c.scene_manager_has_previous_scene(self, scene_id);
}
pub fn nextScene(self: *Self, next_scene_id: u32) void {
c.scene_manager_next_scene(self, next_scene_id);
}
pub fn previousScene(self: *Self) bool {
return c.scene_manager_previous_scene(self);
}
pub fn searchAndSwitchToAnotherScene(self: *Self, scene_id: u32) bool {
return c.scene_manager_search_and_switch_to_another_scene(self, scene_id);
}
pub fn searchAndSwitchToPreviousScene(self: *Self, scene_id: u32) bool {
return c.scene_manager_search_and_switch_to_previous_scene(self, scene_id);
}
pub fn searchAndSwitchToPreviousSceneOneOf(self: *Self, scene_ids: *const u32, scene_ids_size: usize) bool {
return c.scene_manager_search_and_switch_to_previous_scene_one_of(self, scene_ids, scene_ids_size);
}
pub fn setSceneState(self: *Self, scene_id: u32, state: u32) void {
c.scene_manager_set_scene_state(self, scene_id, state);
}
pub fn stop(self: *Self) void {
c.scene_manager_stop(self);
}
};
pub const View = extern struct {
const Self = @This();
pub fn create() *Self {
return @ptrCast(c.view_alloc());
}
pub fn allocateModel(self: *Self, type_: c.ViewModelType, size: usize) void {
c.view_allocate_model(self, type_, size);
}
pub fn commitModel(self: *Self, update: bool) void {
c.view_commit_model(self, update);
}
pub fn destroy(self: *Self) void {
c.view_free(self);
}
pub fn freeModel(self: *Self) void {
c.view_free_model(self);
}
pub fn getModel(self: *Self) *anyopaque {
return c.view_get_model(self);
}
};
pub const ViewDispatcher = extern struct {
const Self = @This();
pub fn create() *Self {
return @ptrCast(c.view_dispatcher_alloc());
}
pub fn addView(self: *Self, view_id: u32, view: *View) void {
c.view_dispatcher_add_view(self, view_id, view);
}
pub fn attachToGui(self: *Self, gui: *Gui, type_: c.ViewDispatcherType) void {
c.view_dispatcher_attach_to_gui(self, gui, type_);
}
pub fn enableQueue(self: *Self) void {
c.view_dispatcher_enable_queue(self);
}
pub fn destroy(self: *Self) void {
c.view_dispatcher_free(self);
}
pub fn getEventLoop(self: *Self) *anyopaque {
return c.view_dispatcher_get_event_loop(self);
}
pub fn removeView(self: *Self, view_id: u32) void {
c.view_dispatcher_remove_view(self, view_id);
}
pub fn run(self: *Self) void {
c.view_dispatcher_run(self);
}
pub fn sendCustomEvent(self: *Self, event: u32) void {
c.view_dispatcher_send_custom_event(self, event);
}
pub fn sendToBack(self: *Self) void {
c.view_dispatcher_send_to_back(self);
}
pub fn sendToFront(self: *Self) void {
c.view_dispatcher_send_to_front(self);
}
pub fn setCustomEventCallback(self: *Self, callback: c.ViewDispatcherCustomEventCallback) void {
c.view_dispatcher_set_custom_event_callback(self, callback);
}
pub fn setEventCallbackContext(self: *Self, context: ?*anyopaque) void {
c.view_dispatcher_set_event_callback_context(self, context orelse null);
}
pub fn setNavigationEventCallback(self: *Self, callback: c.ViewDispatcherNavigationEventCallback) void {
c.view_dispatcher_set_navigation_event_callback(self, callback);
}
pub fn setTickEventCallback(self: *Self, callback: c.ViewDispatcherTickEventCallback, tick_period: u32) void {
c.view_dispatcher_set_tick_event_callback(self, callback, tick_period);
}
pub fn stop(self: *Self) void {
c.view_dispatcher_stop(self);
}
pub fn switchToView(self: *Self, view_id: u32) void {
c.view_dispatcher_switch_to_view(self, view_id);
}
};
pub const ViewPort = extern struct {
const Self = @This();
pub fn create() *Self {
return @ptrCast(c.view_port_alloc());
}
pub fn destroy(self: *Self) void {
c.view_port_free(self);
}
pub fn update(self: *Self) void {
c.view_port_update(self);
}
pub fn setDrawCallback(self: *Self, callback: c.ViewPortDrawCallback, context: ?*anyopaque) void {
c.view_port_draw_callback_set(self, callback, context orelse null);
}
pub fn setInputCallback(self: *Self, callback: c.ViewPortInputCallback, context: ?*anyopaque) void {
c.view_port_input_callback_set(self, callback, context orelse null);
}
pub fn setEnabled(self: *Self, enabled: bool) void {
c.view_port_enabled_set(self, enabled);
}
};

48
lib/flipperzero/heap.zig Normal file
View File

@ -0,0 +1,48 @@
const std = @import("std");
const Allocator = std.mem.Allocator;
const flipperzero = @import("flipperzero.zig");
const c = flipperzero.c;
pub const FuriAllocator = struct {
fn alloc(
_: *anyopaque,
len: usize,
log2_align: u8,
return_address: usize,
) ?[*]u8 {
_ = return_address;
const alignment = @as(usize, 1) << @intCast(log2_align);
return @ptrCast(c.aligned_malloc(len, alignment));
}
fn resize(
_: *anyopaque,
buf: []u8,
log2_buf_align: u8,
new_len: usize,
return_address: usize,
) bool {
_ = return_address;
_ = log2_buf_align;
return new_len <= buf.len;
}
fn free(
_: *anyopaque,
buf: []u8,
log2_buf_align: u8,
return_address: usize,
) void {
_ = return_address;
_ = log2_buf_align;
c.aligned_free(buf.ptr);
}
};
const furi_allocator_vtable = Allocator.VTable{
.alloc = FuriAllocator.alloc,
.resize = FuriAllocator.resize,
.free = FuriAllocator.free,
};
pub const furi_allocator = Allocator{ .ptr = undefined, .vtable = &furi_allocator_vtable };

View File

@ -0,0 +1,39 @@
const std = @import("std");
const mem = std.mem;
const MANIFEST_MAGIC: u32 = 0x52474448;
const API_VERSION: u32 = 0x00480001; // API_VERSION 72.1
const FlipperManifestBase = extern struct {
manifest_magic: u32 align(1),
manifest_version: u32 align(1),
api_version: u32 align(1),
hardware_target_id: u16 align(1),
};
const FlipperApplicationManifestV1 = extern struct {
base: FlipperManifestBase,
stack_size: u16 align(1),
app_version: u32 align(1),
name: [32]u8 align(1),
has_icon: u8 align(1),
icon: [32]u8 align(1),
};
const FlipperApplicationManifest = FlipperApplicationManifestV1;
pub fn createApplicationManifest(stack_size: u16, app_version: u32, comptime name: [*:0]const u8, has_icon: u8, icon: ?[32]u8) FlipperApplicationManifest {
return FlipperApplicationManifest{
.base = FlipperManifestBase{
.manifest_magic = MANIFEST_MAGIC,
.manifest_version = 1,
.api_version = API_VERSION,
.hardware_target_id = 7,
},
.stack_size = stack_size,
.app_version = app_version,
.name = (mem.span(name) ++ mem.zeroes([32 - mem.len(name)]u8)).*,
.has_icon = has_icon,
.icon = icon orelse mem.zeroes([32]u8),
};
}

View File

@ -0,0 +1,15 @@
const flipperzero = @import("flipperzero.zig");
const c = flipperzero.c;
pub const Storage = extern struct {
const Self = @This();
pub fn open() *Self {
return @ptrCast(c.furi_record_open(c.RECORD_STORAGE));
}
pub fn close(self: *Self) void {
_ = self;
c.furi_record_close(c.RECORD_STORAGE);
}
};

View File

@ -0,0 +1,35 @@
const flipperzero = @import("flipperzero.zig");
const c = flipperzero.c;
pub const FuriMutex = struct {
const Self = @This();
pub fn create(type_: c.FuriMutexType) *Self {
return @ptrCast(c.furi_mutex_alloc(type_));
}
pub fn destroy(self: *Self) void {
c.furi_mutex_free(self);
}
};
// pub const FuriThread = struct {
// data: *anyopaque,
// const Self = @This();
// pub fn create() Self {
// return Self{
// .data = c.furi_thread_alloc()
// };
// }
// pub fn join(self: Self) void {
// c.furi_thread_join(self.data);
// }
// pub fn destroy(self: Self) void {
// self.join();
// c.furi_thread_free(self.data);
// }
// };

51
linker.ld Normal file
View File

@ -0,0 +1,51 @@
ENTRY(_start);
SECTIONS
{
.text 0x00000000 : ALIGN(4)
{
KEEP(*(.init));
*(.text .text.*);
KEEP(*(.fini));
}
.rodata :
{
*(.rodata .rodata.*);
}
.bss :
{
*(.bss .bss.*);
}
.data :
{
*(.data .data.*);
}
.ARM.attributes :
{
*(.ARM.attributes .ARM.attributes.*);
}
.fapmeta (INFO) :
{
KEEP(*(.fapmeta));
}
/DISCARD/ :
{
*(.text.strlen);
/* LLVM bitcode should never be in the binary */
*(.llvmbc .llvmcmd);
/* Unwinding is not supported */
*(.ARM.exidx .ARM.exidx.*);
*(.comment .comment.*);
*(.note .note.*);
*(.debug*);
}
}

263
src/app.zig Normal file
View File

@ -0,0 +1,263 @@
// Imports
const std = @import("std");
const fz = @import("flipperzero");
// const Zlipper = struct {
// allocator: std.mem.Allocator,
// mutex: *anyopaque,
// gui: *anyopaque,
// view_port: *anyopaque,
// input_queue: *anyopaque,
// input_event: ?*c.InputEvent,
// running: bool,
// acc: u32,
// const Self = @This();
// pub fn init(allocator: std.mem.Allocator) *Self {
// const self = allocator.create(Self) catch unreachable;
// self.* = Self{
// .allocator = allocator,
// .mutex = c.furi_mutex_alloc(c.FuriMutexType.FuriMutexTypeNormal),
// .gui = c.furi_record_open(c.RECORD_GUI),
// .view_port = c.view_port_alloc(),
// .input_queue = c.furi_message_queue_alloc(8, @sizeOf(c.InputEvent)),
// .input_event = null,
// .running = true,
// .acc = 0,
// };
// c.view_port_draw_callback_set(self.view_port, Self.draw_callback, @ptrCast(self));
// c.view_port_input_callback_set(self.view_port, Self.input_callback, @ptrCast(self));
// c.gui_add_view_port(self.gui, self.view_port, c.GuiLayer.GuiLayerFullscreen);
// return self;
// }
// pub fn deinit(self: *Self) void {
// c.view_port_enabled_set(self.view_port, false);
// c.gui_remove_view_port(self.gui, self.view_port);
// c.view_port_free(self.view_port);
// c.furi_message_queue_free(self.input_queue);
// c.furi_mutex_free(self.mutex);
// c.furi_record_close(c.RECORD_GUI);
// self.allocator.destroy(self);
// }
// pub fn update(self: *Self) void {
// var event: c.InputEvent = undefined;
// _ = c.furi_message_queue_get(self.input_queue, @ptrCast(&event), @intFromEnum(c.FuriWait.FuriWaitForever));
// self.input_event = &event;
// if (event.type == c.InputType.InputTypeShort and event.key == c.InputKey.InputKeyBack) {
// self.running = !self.running;
// }
// c.view_port_update(self.view_port);
// self.acc += 1;
// }
// fn draw_callback(canvas: *anyopaque, context: ?*anyopaque) callconv(.C) void {
// const self: *Self = @alignCast(@ptrCast(context.?));
// var c_buf = std.mem.zeroes([32:0]u8);
// _ = c.snprintf(&c_buf, 32, "snprintf: %d", self.acc);
// var zig_buf = std.mem.zeroes([32:0]u8);
// _ = std.fmt.bufPrint(&zig_buf, "bufPrint: {}", .{self.acc}) catch return;
// const alloc_buf = std.fmt.allocPrintZ(self.allocator, "allocPrint: {}", .{self.acc}) catch return;
// defer self.allocator.free(alloc_buf);
// c.canvas_clear(canvas);
// c.canvas_set_font(canvas, c.Font.FontPrimary);
// c.canvas_draw_str(canvas, 0, 10, &c_buf);
// c.canvas_draw_str(canvas, 0, 20, &zig_buf);
// c.canvas_draw_str(canvas, 0, 30, alloc_buf);
// if (self.input_event) |input_event| {
// const type_buf = std.fmt.allocPrintZ(self.allocator, "InputType: {s}", .{c.input_get_type_name(input_event.type)}) catch return;
// defer self.allocator.free(type_buf);
// c.canvas_draw_str(canvas, 0, 40, type_buf);
// const key_buf = std.fmt.allocPrintZ(self.allocator, "InputKey: {s}", .{c.input_get_key_name(input_event.key)}) catch return;
// defer self.allocator.free(key_buf);
// c.canvas_draw_str(canvas, 0, 50, key_buf);
// }
// }
// fn input_callback(input_event: *c.InputEvent, context: ?*anyopaque) callconv(.C) void {
// const self: *Self = @alignCast(@ptrCast(context.?));
// _ = c.furi_message_queue_put(self.input_queue, input_event, @intFromEnum(c.FuriWait.FuriWaitForever));
// }
// };
const Zlipper = struct {
allocator: std.mem.Allocator,
mutex: *fz.thread.FuriMutex,
gui: *fz.gui.Gui,
view_port: *fz.gui.ViewPort,
input_queue: *fz.atomic.FuriMessageQueue(fz.c.InputEvent),
input_event: ?*const fz.c.InputEvent,
running: bool,
acc: u32,
const Self = @This();
pub fn init(allocator: std.mem.Allocator) *Self {
const self = allocator.create(Self) catch unreachable;
self.* = Self{
.allocator = allocator,
.mutex = fz.thread.FuriMutex.create(fz.c.FuriMutexType.FuriMutexTypeNormal),
.gui = fz.gui.Gui.open(),
.view_port = fz.gui.ViewPort.create(),
.input_queue = fz.atomic.FuriMessageQueue(fz.c.InputEvent).create(8),
.input_event = null,
.running = true,
.acc = 0,
};
self.view_port.setDrawCallback(Self.draw_callback, @ptrCast(self));
self.view_port.setInputCallback(Self.input_callback, @ptrCast(self));
self.gui.addViewPort(self.view_port, fz.c.GuiLayer.GuiLayerFullscreen);
return self;
}
pub fn deinit(self: *Self) void {
self.view_port.setEnabled(false);
self.gui.removeViewPort(self.view_port);
self.view_port.destroy();
self.input_queue.destroy();
self.mutex.destroy();
self.gui.close();
self.allocator.destroy(self);
}
pub fn update(self: *Self) void {
var event: fz.c.InputEvent = undefined;
self.input_queue.get(&event, @intFromEnum(fz.c.FuriWait.FuriWaitForever));
self.input_event = &event;
if (event.type == fz.c.InputType.InputTypeShort and event.key == fz.c.InputKey.InputKeyBack) {
self.running = !self.running;
}
self.view_port.update();
self.acc += 1;
}
fn draw_callback(canvas_: *anyopaque, context: ?*anyopaque) callconv(.C) void {
const self: *Self = @alignCast(@ptrCast(context.?));
const canvas: *fz.gui.Canvas = @ptrCast(canvas_);
var c_buf = std.mem.zeroes([32:0]u8);
_ = fz.c.snprintf(&c_buf, 32, "snprintf: %d", self.acc);
var zig_buf = std.mem.zeroes([32:0]u8);
_ = std.fmt.bufPrint(&zig_buf, "bufPrint: {}", .{self.acc}) catch return;
const alloc_buf = std.fmt.allocPrintZ(self.allocator, "allocPrint: {}", .{self.acc}) catch return;
defer self.allocator.free(alloc_buf);
canvas.clear();
canvas.setFont(fz.c.Font.FontPrimary);
canvas.drawStr(0, 10, &c_buf);
canvas.drawStr(0, 20, &zig_buf);
canvas.drawStr(0, 30, alloc_buf);
if (self.input_event) |input_event| {
const type_buf = std.fmt.allocPrintZ(self.allocator, "InputType: {s}", .{fz.c.input_get_type_name(input_event.type)}) catch return;
defer self.allocator.free(type_buf);
canvas.drawStr(0, 40, type_buf);
const key_buf = std.fmt.allocPrintZ(self.allocator, "InputKey: {s}", .{fz.c.input_get_key_name(input_event.key)}) catch return;
defer self.allocator.free(key_buf);
canvas.drawStr(0, 50, key_buf);
}
}
fn input_callback(input_event: *fz.c.InputEvent, context: ?*anyopaque) callconv(.C) void {
const self: *Self = @alignCast(@ptrCast(context.?));
self.input_queue.put(input_event, @intFromEnum(fz.c.FuriWait.FuriWaitForever));
}
};
// const ZlipperView = enum(u8) {
// MainMenu,
// FileBrowser,
// };
// const Zlipper = struct {
// allocator: std.mem.Allocator,
// gui: *fz.gui.Gui,
// storage: *fz.storage.Storage,
// scene_manager: *fz.gui.SceneManager,
// view_dispatcher: *fz.gui.ViewDispatcher,
// // file_browser_output: *fz.string.
// running: bool,
// const Self = @This();
// pub fn init(allocator: std.mem.Allocator) *Self {
// const self = allocator.create(Self) catch unreachable;
// self.* = Self {
// .allocator = allocator,
// .gui = fz.gui.Gui.open(),
// .storage = fz.storage.Storage.open(),
// .scene_manager = fz.gui.SceneManager.create(),
// .view_dispatcher = fz.gui.ViewDispatcher.create(),
// .running = true,
// };
// self.view_dispatcher.enableQueue();
// self.view_dispatcher.setEventCallbackContext(@ptrCast(self));
// self.view_dispatcher.setCustomEventCallback(Self.customEventCallback);
// self.view_dispatcher.setNavigationEventCallback(Self.navigationEventCallback);
// self.view_dispatcher.attachToGui(self.gui, fz.c.ViewDispatcherType.ViewDispatcherTypeFullscreen);
// return self;
// }
// pub fn customEventCallback(context: ?*anyopaque, event: u32) callconv(.C) void {
// const self: *Self = @alignCast(@ptrCast(context));
// _ = self;
// _ = event;
// }
// pub fn navigationEventCallback(context: ?*anyopaque) callconv(.C) void {
// const self: *Self = @alignCast(@ptrCast(context));
// _ = self;
// }
// pub fn update(self: *Self) void {
// self.running = false;
// }
// pub fn deinit(self: *Self) void {
// self.view_dispatcher.removeView(ZlipperView.MainMenu);
// self.view_dispatcher.destroy();
// self.scene_manager.destroy();
// self.storage.close();
// self.gui.close();
// self.allocator.destroy(self);
// }
// };
// Application
pub fn main(args: *u8) i32 {
_ = args;
var zlipper = Zlipper.init(fz.heap.furi_allocator);
defer zlipper.deinit();
while (zlipper.running) {
zlipper.update();
}
return 0;
}

12
src/start.zig Normal file
View File

@ -0,0 +1,12 @@
// Imports
const flipperzero = @import("flipperzero");
const app = @import("app.zig");
const manifest = flipperzero.manifest;
// Manifest
export const FAP_MANIFEST linksection(".fapmeta") = manifest.createApplicationManifest(2048, 1, "Zlipper", 0, null);
// Entry function
export fn _start(args: *u8) i32 {
return app.main(args);
}