Reorg, added more sources

This commit is contained in:
UberGuidoZ
2022-12-28 22:34:27 -08:00
parent 034d4cd172
commit 24f88bf731
1646 changed files with 39096 additions and 0 deletions
@@ -0,0 +1,10 @@
App(
appid="BadApple",
name="Bad Apple",
apptype=FlipperAppType.EXTERNAL,
entry_point="bad_apple_main",
requires=["gui"],
stack_size=1 * 1024,
fap_icon="bad_apple_10px.png",
fap_category="Misc"
)
@@ -0,0 +1,183 @@
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <furi.h>
#include <furi_hal.h>
#include <stm32wbxx_ll_tim.h>
#include <gui/gui.h>
#include <input/input.h>
#include <storage/storage.h>
#include <notification/notification.h>
#include <notification/notification_messages.h>
#include "bad_apple.h"
#include "video_player.h"
#define TAG "badapple"
typedef enum {
BadAppleEventTypeInput,
BadAppleEventTypeTick,
} BadAppleEventType;
typedef struct {
BadAppleEventType type;
InputEvent* input;
} BadAppleEvent;
// Screen is 128x64 px
static void app_draw_callback(Canvas* canvas, void* ctx) {
BadAppleCtx* inst = ctx;
canvas_clear(canvas);
canvas_draw_xbm(canvas, VIDEO_X, VIDEO_Y, VIDEO_WIDTH, SCREEN_HEIGHT, inst->framebuffer);
canvas_draw_box(canvas, 0, 0, VIDEO_X, SCREEN_HEIGHT);
canvas_draw_box(
canvas, VIDEO_X + VIDEO_WIDTH, 0, SCREEN_WIDTH - VIDEO_WIDTH - VIDEO_X, SCREEN_HEIGHT);
}
static void app_input_callback(InputEvent* input_event, void* ctx) {
furi_assert(ctx);
FuriMessageQueue* event_queue = ctx;
BadAppleEvent event = {.type = BadAppleEventTypeInput, .input = input_event};
furi_message_queue_put(event_queue, &event, FuriWaitForever);
}
BadAppleCtx* bad_apple_ctx_alloc(void) {
BadAppleCtx* inst = malloc(sizeof(BadAppleCtx));
memset(inst, 0, sizeof(BadAppleCtx));
if(inst) {
inst->storage = furi_record_open(RECORD_STORAGE);
inst->video_file = storage_file_alloc(inst->storage);
inst->file_buffer_offset = sizeof(inst->file_buffer);
}
return inst;
}
void bad_apple_ctx_free(BadAppleCtx* inst) {
if(inst) {
storage_file_free(inst->video_file);
furi_record_close(RECORD_STORAGE);
free(inst);
}
}
void bad_apple_load_next_video_chunk(BadAppleCtx* inst) {
size_t bytes_to_read = sizeof(inst->file_buffer);
uint8_t* buf_ptr = inst->file_buffer;
while(bytes_to_read > 0) {
uint16_t curr_bytes_to_read = bytes_to_read > (UINT16_MAX / 2 + 1) ? (UINT16_MAX / 2 + 1) :
bytes_to_read;
uint16_t read = storage_file_read(inst->video_file, buf_ptr, curr_bytes_to_read);
bytes_to_read -= read;
buf_ptr += read;
if(read == 0) break;
}
inst->file_buffer_offset = 0;
}
uint8_t bad_apple_read_byte(BadAppleCtx* inst) {
if(inst->file_buffer_offset >= sizeof(inst->file_buffer)) {
bad_apple_load_next_video_chunk(inst);
}
return inst->file_buffer[inst->file_buffer_offset++];
}
void bad_apple_timer_isr(void* ctx) {
FuriMessageQueue* event_queue = ctx;
BadAppleEvent event = {.type = BadAppleEventTypeTick};
furi_message_queue_put(event_queue, &event, 0);
LL_TIM_ClearFlag_UPDATE(TIM2);
}
void bad_apple_timer_setup(BadAppleCtx* inst, void* ctx) {
UNUSED(inst);
LL_TIM_InitTypeDef tim_init = {
.Prescaler = 63999,
.CounterMode = LL_TIM_COUNTERMODE_UP,
.Autoreload = 30,
};
LL_TIM_Init(TIM2, &tim_init);
LL_TIM_SetClockSource(TIM2, LL_TIM_CLOCKSOURCE_INTERNAL);
LL_TIM_DisableCounter(TIM2);
LL_TIM_SetCounter(TIM2, 0);
furi_hal_interrupt_set_isr(FuriHalInterruptIdTIM2, bad_apple_timer_isr, ctx);
LL_TIM_EnableIT_UPDATE(TIM2);
}
void bad_apple_timer_deinit(void) {
LL_TIM_DisableCounter(TIM2);
LL_TIM_DisableIT_UPDATE(TIM2);
furi_hal_interrupt_set_isr(FuriHalInterruptIdTIM2, NULL, NULL);
LL_TIM_DeInit(TIM2);
}
int32_t bad_apple_main(void* p) {
UNUSED(p);
BadAppleCtx* ctx = bad_apple_ctx_alloc();
FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(BadAppleEvent));
// Configure view port
ViewPort* view_port = view_port_alloc();
view_port_draw_callback_set(view_port, app_draw_callback, ctx);
view_port_input_callback_set(view_port, app_input_callback, event_queue);
// Register view port in GUI
Gui* gui = furi_record_open(RECORD_GUI);
gui_add_view_port(gui, view_port, GuiLayerFullscreen);
NotificationApp* notification = furi_record_open(RECORD_NOTIFICATION);
// Frame rate: 32 FPS
bad_apple_timer_setup(ctx, event_queue);
bool is_opened = storage_file_open(ctx->video_file, VIDEO_PATH, FSAM_READ, FSOM_OPEN_EXISTING);
if(is_opened) {
BadAppleEvent event;
notification_message(notification, &sequence_display_backlight_enforce_on);
bool running = true;
LL_TIM_EnableCounter(TIM2);
while(running) {
if(furi_message_queue_get(event_queue, &event, 100) == FuriStatusOk) {
if(event.type == BadAppleEventTypeInput) {
InputEvent* input_event = event.input;
if(input_event->type == InputTypeLong) {
if(input_event->key == InputKeyBack) {
running = false;
}
}
} else if(event.type == BadAppleEventTypeTick) {
// FURI_LOG_D(TAG, "Update frame");
if(!vp_play_frame(ctx)) {
running = false;
}
}
}
view_port_update(view_port);
}
LL_TIM_DisableCounter(TIM2);
notification_message(notification, &sequence_display_backlight_enforce_auto);
storage_file_close(ctx->video_file);
}
furi_record_close(RECORD_NOTIFICATION);
view_port_enabled_set(view_port, false);
gui_remove_view_port(gui, view_port);
view_port_free(view_port);
furi_message_queue_free(event_queue);
furi_record_close(RECORD_GUI);
bad_apple_timer_deinit();
bad_apple_ctx_free(ctx);
return 0;
}
@@ -0,0 +1,25 @@
#pragma once
#include <stdint.h>
#include <storage/storage.h>
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define VIDEO_WIDTH 104
#define VIDEO_HEIGHT 80
#define FILE_BUFFER_SIZE (1024 * 64)
#define VIDEO_PATH EXT_PATH("apps_data/bad_apple/video.bin")
#define VIDEO_X ((SCREEN_WIDTH - VIDEO_WIDTH) / 2)
#define VIDEO_Y 0
typedef struct {
uint8_t framebuffer[VIDEO_HEIGHT * VIDEO_WIDTH / 8];
uint8_t file_buffer[FILE_BUFFER_SIZE];
uint32_t file_buffer_offset;
uint32_t frame_write_offset; // bit index
Storage* storage;
File* video_file;
} BadAppleCtx;
uint8_t bad_apple_read_byte(BadAppleCtx* inst);
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

@@ -0,0 +1,137 @@
#include <stdbool.h>
#include <furi.h>
#include "bad_apple.h"
#include "video_player.h"
#define TAG "video_player"
static void vp_decode_rle(BadAppleCtx* ctx);
static void vp_decode_delta(BadAppleCtx* ctx);
int vp_play_frame(BadAppleCtx* ctx) {
// Check frame type
// FURI_LOG_D(TAG, "Buffer offset: %04lx", ctx->file_buffer_offset);
uint8_t b = bad_apple_read_byte(ctx);
// FURI_LOG_D(TAG, "Frame byte: %02x", b);
switch(b) {
case 1: // PFrame (delta)
vp_decode_delta(ctx);
break;
case 2: // IFrame (rle)
vp_decode_rle(ctx);
break;
case 3: // DFrame (duplicate)
break;
case 4: // next page (not supported)
case 5: // end
default:
return 0;
}
return 1;
}
static inline void vp_write_pixel(BadAppleCtx* ctx, bool color) {
if(color) {
// White
ctx->framebuffer[ctx->frame_write_offset / 8] &= ~(1 << (ctx->frame_write_offset % 8));
} else {
// Black
ctx->framebuffer[ctx->frame_write_offset / 8] |= (1 << (ctx->frame_write_offset % 8));
}
++ctx->frame_write_offset;
}
static inline void vp_set_rect_fast(BadAppleCtx* ctx, int x, int y) {
ctx->frame_write_offset = y * VIDEO_WIDTH + x;
}
static void vp_decode_rle(BadAppleCtx* ctx) {
int i = 0;
int repeat_byte = bad_apple_read_byte(ctx);
// Set rect to video area
vp_set_rect_fast(ctx, 0, 0);
while(i < VIDEO_WIDTH * VIDEO_HEIGHT) {
int count;
unsigned pixels;
int j;
int b = bad_apple_read_byte(ctx);
if(b == repeat_byte) {
count = bad_apple_read_byte(ctx);
if(count == 0) count = 256;
pixels = bad_apple_read_byte(ctx);
} else {
count = 1;
pixels = (unsigned)b;
}
for(j = 0; j < count; ++j) {
bool out_color;
int k;
unsigned loop_pixels = pixels;
for(k = 0; k < 8; ++k) {
if(loop_pixels & 0x80)
out_color = COLOR_WHITE;
else
out_color = COLOR_BLACK;
vp_write_pixel(ctx, out_color);
loop_pixels <<= 1;
++i;
}
}
}
}
static void vp_decode_delta(BadAppleCtx* ctx) {
int frame_header[(VIDEO_HEIGHT + 7) / 8];
uint i;
int fh_byte = 0;
int fh_index = 0;
for(i = 0; i < sizeof(frame_header) / sizeof(frame_header[0]); ++i) {
frame_header[i] = bad_apple_read_byte(ctx);
}
for(i = 0; i < VIDEO_HEIGHT; ++i) {
if(i % 8 == 0) fh_byte = frame_header[fh_index++];
if(fh_byte & 0x80) {
int j;
int sl_byte = 0;
for(j = 0; j < VIDEO_WIDTH;) {
if(j % (8 * 8) == 0) sl_byte = bad_apple_read_byte(ctx);
if(sl_byte & 0x80) {
unsigned out_color;
int k;
unsigned pixel_group = bad_apple_read_byte(ctx);
// Note: this needs to be revised for screen width not multiple of 8
vp_set_rect_fast(ctx, j, i);
for(k = 0; k < 8 && j < VIDEO_WIDTH; ++k, ++j) {
if(pixel_group & 0x80)
out_color = COLOR_WHITE;
else
out_color = COLOR_BLACK;
vp_write_pixel(ctx, out_color);
pixel_group <<= 1;
}
} else {
j += 8;
}
sl_byte <<= 1;
}
}
fh_byte <<= 1;
}
}
@@ -0,0 +1,6 @@
#pragma once
#define COLOR_WHITE true
#define COLOR_BLACK false
int vp_play_frame(BadAppleCtx* ctx);