bad-apple/ch32_decoder/bad_apple.c

263 lines
4.5 KiB
C
Raw Normal View History

2024-04-12 22:26:24 +02:00
#define SSD1306_128X32
#include "ch32v003fun.h"
#include <stdio.h>
#include "ssd1306_i2c.h"
#include "ssd1306.h"
#include "data.h"
#define PIN_LED PC4
#define PIN_BTN PC7
#define WIDTH 40
#define HEIGHT 32
#define X_OFFSET ((128 - WIDTH) / 2)
void decode_next_frame();
void refresh_screen();
2024-04-12 22:36:16 +02:00
void clear_screen();
2024-04-12 22:26:24 +02:00
u32 reader = 0;
u32 frame[WIDTH];
int main()
{
SystemInit();
// funGpioInitAll();
// funPinMode(PIN_LED, GPIO_CFGLR_OUT_10Mhz_PP);
// funPinMode(PIN_BTN, GPIO_CFGLR_IN_PUPD);
// initialize OLED
ssd1306_i2c_init();
// not using ssd1306_init because it does more than i want
uint8_t *cmd_list = (uint8_t *)ssd1306_init_array;
while (*cmd_list != SSD1306_TERMINATE_CMDS)
ssd1306_cmd(*cmd_list++);
2024-04-12 22:36:16 +02:00
clear_screen();
2024-04-12 22:26:24 +02:00
while (1)
{
decode_next_frame();
refresh_screen();
Delay_Ms(300);
if (reader >= sizeof(video))
reader = 0;
}
}
void refresh_screen()
{
ssd1306_cmd(SSD1306_COLUMNADDR);
ssd1306_cmd(X_OFFSET); // Column start address (0 = reset)
ssd1306_cmd(X_OFFSET + WIDTH - 1); // Column end address (127 = reset)
ssd1306_cmd(SSD1306_PAGEADDR);
ssd1306_cmd(0); // Page start address (0 = reset)
ssd1306_cmd(7); // Page end address
u8 packet[SSD1306_PSZ];
u8 x;
u8 packet_index;
u8 page = 0;
while (page < 8)
{
/* odd rows are unused so each nybble is expanded */
packet[packet_index] = expand[(frame[x] >> (page * 4)) & 0xf];
x++;
packet_index++;
if (x == WIDTH)
{
x = 0;
page++;
}
if (packet_index == SSD1306_PSZ)
{
ssd1306_data(packet, SSD1306_PSZ);
packet_index = 0;
}
}
}
2024-04-12 22:36:16 +02:00
void clear_screen()
{
ssd1306_cmd(SSD1306_COLUMNADDR);
ssd1306_cmd(0); // Column start address (0 = reset)
ssd1306_cmd(127); // Column end address (127 = reset)
ssd1306_cmd(SSD1306_PAGEADDR);
ssd1306_cmd(0); // Page start address (0 = reset)
ssd1306_cmd(7); // Page end address
for (u32 i = 0; i < 32 * 8; i++)
ssd1306_data(frame, SSD1306_PSZ);
}
2024-04-12 22:26:24 +02:00
u8 next_byte()
{
u8 byte = video[reader];
reader += 1;
return byte;
}
void fill_frame(u8 color)
{
memset(frame, color ? 0xFFFFFFFF : 0x00, sizeof(frame));
}
void set_pixel(u8 x, u8 y, u8 color)
{
if (color)
frame[x] |= (1 << (y & 31));
else
frame[x] &= ~(1 << (y & 31));
}
void rle_horizontal();
void rle_vertical();
void bg_strips_h();
void cell_diff_8v();
void decode_next_frame()
{
Encoding_t encoding = next_byte();
switch (encoding)
{
#ifdef USE_FillBlack
case Encoding_FillBlack:
fill_frame(0);
break;
#endif
#ifdef USE_FillWhite
case Encoding_FillWhite:
fill_frame(1);
break;
#endif
#ifdef USE_RLEHorizontal
case Encoding_RLEHorizontal:
rle_horizontal();
break;
#endif
#ifdef USE_RLEVertical
case Encoding_RLEVertical:
rle_vertical();
break;
#endif
#ifdef USE_BGStripsH
case Encoding_BGStripsH:
bg_strips_h();
break;
#endif
#ifdef USE_CellDiff8V
case Encoding_CellDiff8V:
cell_diff_8v();
break;
#endif
default:
memset(frame, 0b10101010, sizeof(frame));
break;
}
}
#ifdef USE_RLEHorizontal
void rle_horizontal()
{
u8 x = 0;
u8 y = 0;
u8 color = 0;
while (y < HEIGHT)
{
u8 run = next_byte();
for (int i = 0; i < run; i++)
{
set_pixel(x, y, color);
x += 1;
if (x == WIDTH)
{
x = 0;
y += 1;
}
}
color = 1 - color;
}
}
#endif
#ifdef USE_RLEVertical
void rle_vertical()
{
u8 x = 0;
u8 y = 0;
u8 color = 0;
while (x < WIDTH)
{
u8 run = next_byte();
for (int i = 0; i < run; i++)
{
set_pixel(x, y, color);
y += 1;
if (y == HEIGHT)
{
y = 0;
x += 1;
}
}
color = 1 - color;
}
}
#endif
#ifdef USE_BGStripsH
void bg_strips_h()
{
u8 head = next_byte();
u8 bg = head >> 7;
u8 fg = 1 - bg;
fill_frame(bg);
u8 strip_count = head & 127;
for (u8 i = 0; i < strip_count; i++)
{
u16 packed = (next_byte() << 8) | next_byte();
u8 y = packed >> 11;
u8 x_start = (packed >> 5) & 0x3f;
u8 width = packed & 0x1f;
for (int x = x_start; x < (x_start + width); x++)
{
set_pixel(x, y, fg);
}
}
}
#endif
#ifdef USE_CellDiff8V
void cell_diff_8v()
{
u32 bitmap = (next_byte() << 16) | (next_byte() << 8) | next_byte();
u8 run_remaining = next_byte();
u8 color = 0;
for (u8 x = 0; x < WIDTH; x++)
{
u8 cellx = x >> 3;
for (u8 y = 0; y < HEIGHT; y++)
{
u8 celly = y >> 3;
if (bitmap >> (cellx + (WIDTH / 8) * celly) & 1)
{
// advance rle once
if (run_remaining == 0)
{
run_remaining = next_byte();
color = 1 - color;
if (run_remaining == 0)
{
run_remaining = next_byte();
color = 1 - color;
}
}
set_pixel(x, y, color);
run_remaining--;
}
}
}
}
#endif