Personal commit
This commit is contained in:
parent
5dc481e671
commit
257ee10a85
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
.zig-cache/
|
||||
zig-out/
|
||||
*.fap
|
37
build.zig
Normal file
37
build.zig
Normal 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);
|
||||
}
|
24
lib/flipperzero/atomic.zig
Normal file
24
lib/flipperzero/atomic.zig
Normal 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
154
lib/flipperzero/c.zig
Normal 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;
|
7
lib/flipperzero/flipperzero.zig
Normal file
7
lib/flipperzero/flipperzero.zig
Normal 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
227
lib/flipperzero/gui.zig
Normal 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
48
lib/flipperzero/heap.zig
Normal 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 };
|
39
lib/flipperzero/manifest.zig
Normal file
39
lib/flipperzero/manifest.zig
Normal 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),
|
||||
};
|
||||
}
|
15
lib/flipperzero/storage.zig
Normal file
15
lib/flipperzero/storage.zig
Normal 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);
|
||||
}
|
||||
};
|
35
lib/flipperzero/thread.zig
Normal file
35
lib/flipperzero/thread.zig
Normal 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
51
linker.ld
Normal 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
263
src/app.zig
Normal 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
12
src/start.zig
Normal 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);
|
||||
}
|
Loading…
Reference in New Issue
Block a user