#define SSD1306_128X32 #include "ch32v003fun.h" #include #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(); 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++); 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; } } } 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