Compare commits

..

3 commits

Author SHA1 Message Date
0e95a0a1bb implement ch32v003 decoder 2024-04-12 22:26:24 +02:00
dc26664372 add build instructions 2024-04-12 19:42:15 +02:00
1c2cd2ff40 add README.md 2024-04-12 19:19:49 +02:00
10 changed files with 2101 additions and 5 deletions

20
.vscode/c_cpp_properties.json vendored Normal file
View file

@ -0,0 +1,20 @@
{
"configurations": [
{
"name": "Linux",
"includePath": [
"${workspaceFolder}/**",
"${workspaceFolder}/../ch32v003fun/ch32v003fun"
],
"defines": [],
"compilerPath": "/usr/bin/clang",
"cppStandard": "c++14",
"intelliSenseMode": "linux-clang-x64",
"compilerArgs": [
"-DCH32V003FUN_BASE"
],
"configurationProvider": "ms-vscode.makefile-tools"
}
],
"version": 4
}

18
README.md Normal file
View file

@ -0,0 +1,18 @@
# video compressor and player for the ch32v003 with an SSD1306 32x128 OLED display
Put a webm file in `video/` and run `./convert <framerate>` to convert the video to a sequence of 32x40 images.
Run `cd encoder && cargo run` to convert to bytes, this will be exported to `data.h`.
Tweak framerate or MAX_ERROR in `main.rs` until the total size fits the 16k flash alongside the decoder.
By default it's tuned for bad apple.
## building ch32_decoder
If you are not on Linux, good luck.
You will need [ch32v003fun](https://github.com/cnlohr/ch32v003fun/) in next to the folder for this repository.
The `gdbinit` file contains the device path for uploading via a Pi Pico with [PicoRVD](https://github.com/aappleby/PicoRVD). This is triggered with `make flash`.
If you have an official WCH programmer you can probably run `make cv_flash` to use minchlink from ch32v003fun, but I can't test this.

11
ch32_decoder/Makefile Normal file
View file

@ -0,0 +1,11 @@
all : flash
TARGET:=bad_apple
CH32V003FUN:=../../ch32v003fun/ch32v003fun
include ../../ch32v003fun/ch32v003fun/ch32v003fun.mk
flash : build
gdb-multiarch -x gdbinit -ex 'load' -ex 'detach' -ex 'quit' $(TARGET).elf
clean : cv_clean

248
ch32_decoder/bad_apple.c Normal file
View file

@ -0,0 +1,248 @@
#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();
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

836
ch32_decoder/data.h Normal file
View file

@ -0,0 +1,836 @@
// Generated by the `encoder` rust app
#define USE_FillBlack
#define USE_FillWhite
#define USE_RLEHorizontal
#define USE_RLEVertical
#define USE_BGStripsH
#define USE_CellDiff8V
typedef enum Encoding {
Encoding_FillBlack = 0,
Encoding_FillWhite = 1,
Encoding_RLEHorizontal = 2,
Encoding_RLEVertical = 3,
Encoding_BGStripsH = 6,
Encoding_CellDiff8V = 7,
} Encoding_t;
const unsigned char video[] = {
0,0,7,8,99,152,57,1,13,3,19,5,18,6,16,8,
3,1,10,15,9,15,9,16,8,17,7,18,14,19,13,28,
4,29,3,29,3,30,2,64,3,0,255,0,30,3,27,5,
19,2,3,8,19,13,15,17,1,3,9,23,8,28,2,255,
0,49,4,25,9,68,4,25,15,16,18,14,22,10,30,2,
224,7,13,41,78,0,146,9,6,2,13,5,3,8,1,4,
9,5,4,9,1,7,3,29,1,7,1,7,1,7,1,39,
5,23,2,1,7,18,17,15,20,12,23,9,25,7,128,7,
5,41,206,0,119,8,22,11,18,14,16,16,1,5,1,1,
5,19,1,15,2,14,2,14,2,14,3,13,3,13,2,14,
3,4,7,2,3,3,10,16,19,12,193,7,5,41,206,0,
213,4,10,1,15,9,6,4,9,1,2,5,7,2,2,14,
2,14,2,14,2,14,1,15,1,15,1,31,1,4,8,19,
16,16,20,12,22,9,97,3,0,255,0,158,2,28,5,1,
1,18,1,3,14,10,25,6,81,1,31,1,31,1,31,2,
30,2,30,1,31,1,22,4,5,1,6,1,2,6,8,9,
6,11,14,1,4,14,13,22,10,24,8,26,6,28,4,224,
7,15,123,142,0,85,4,19,6,18,6,3,3,12,12,14,
10,23,9,24,8,24,8,24,8,8,4,13,7,7,6,11,
8,6,10,6,9,6,13,3,11,2,30,2,30,2,30,3,
29,4,28,4,28,4,28,5,39,7,5,4,8,7,1,3,
1,144,3,0,255,0,180,5,26,7,5,2,18,14,18,14,
19,13,22,10,8,4,11,9,6,7,12,7,5,10,8,9,
4,12,7,11,2,16,2,106,1,31,2,30,2,30,2,30,
3,29,4,28,7,14,8,3,10,11,8,1,31,1,130,3,
0,255,0,242,5,26,7,4,5,16,16,16,16,7,4,5,
16,5,7,4,16,4,11,6,10,4,14,5,10,3,17,3,
9,2,222,1,31,2,30,2,30,4,21,4,3,7,15,9,
1,10,12,9,1,21,1,8,1,65,3,0,255,0,119,3,
28,6,25,8,24,8,24,12,20,12,7,6,10,10,4,9,
10,11,1,10,11,23,10,29,2,59,3,27,3,11,1,18,
1,12,1,127,1,31,2,30,5,20,1,6,7,14,3,2,
17,10,171,3,0,177,5,26,7,24,9,23,9,24,8,24,
7,27,5,28,3,29,5,1,7,18,14,17,15,18,14,18,
14,18,14,18,14,19,13,19,13,19,13,19,13,19,13,19,
13,19,13,19,5,3,5,18,5,7,2,17,7,1,7,18,
14,19,13,18,14,17,15,11,3,3,15,5,10,2,15,4,
28,3,29,2,30,2,30,6,139,122,131,130,102,138,72,146,
72,154,42,162,42,170,42,178,42,186,72,194,103,202,132,6,
142,58,130,66,70,74,40,75,65,82,41,90,10,98,11,106,
11,114,11,122,11,130,11,138,41,146,71,154,99,6,33,1,
94,10,86,18,55,26,24,34,24,42,55,50,101,51,140,58,
100,59,202,66,100,67,233,74,100,76,8,82,100,84,7,90,
101,92,37,98,102,100,67,106,72,108,98,114,41,122,10,130,
11,137,236,146,11,154,11,162,11,170,42,178,73,186,134,194,
194,6,159,2,117,10,179,18,148,26,179,34,210,42,241,50,
210,58,179,65,225,66,179,74,179,82,179,89,162,90,179,97,
193,98,179,106,179,114,179,122,179,130,241,136,161,139,233,144,
130,148,8,152,99,154,164,155,199,160,68,163,3,168,67,176,
35,3,255,0,97,1,31,3,29,3,29,5,27,6,26,7,
25,8,10,2,12,9,8,5,10,10,6,7,10,11,4,7,
10,12,2,9,9,23,9,27,5,31,1,18,5,27,3,1,
1,255,0,143,2,24,2,255,0,6,3,33,2,1,6,30,
8,1,2,30,7,34,8,34,7,32,9,30,2,1,8,30,
10,31,5,2,1,32,9,31,9,31,2,1,7,30,1,2,
10,11,3,12,1,2,18,4,12,2,2,1,19,7,33,12,
3,5,20,20,20,25,3,4,8,25,1,1,1,10,2,200,
6,14,58,66,58,161,66,99,74,131,82,101,90,132,98,132,
106,164,113,165,114,107,122,1,122,139,130,194,131,99,6,14,
58,33,58,99,66,36,74,100,82,69,90,100,98,100,106,133,
107,67,113,146,122,100,123,6,130,162,131,98,6,14,58,65,
58,161,66,68,74,100,82,100,90,132,98,132,106,164,113,132,
114,107,121,226,122,108,130,194,131,69,6,19,51,99,59,36,
67,38,75,100,83,70,91,101,99,99,99,226,107,133,115,133,
116,101,123,109,130,179,138,226,139,78,147,163,148,39,155,194,
156,163,3,25,7,25,7,22,10,20,12,20,12,22,10,23,
9,23,9,25,7,25,7,25,7,25,7,25,7,25,7,26,
6,22,10,23,9,208,1,23,2,5,2,22,11,21,10,24,
2,1,7,25,6,27,5,27,5,28,4,255,0,15,3,25,
7,25,7,21,11,21,11,19,13,20,12,21,11,25,7,22,
10,23,9,25,7,25,7,25,7,25,7,25,7,25,7,23,
1,2,6,22,10,170,1,6,2,22,6,1,3,21,11,23,
9,27,6,27,5,27,5,28,3,255,0,46,3,26,6,26,
6,22,10,21,11,19,13,19,13,21,11,26,6,25,7,23,
9,24,8,26,6,26,6,26,6,26,6,26,6,26,6,27,
5,23,2,2,5,22,10,104,1,6,2,22,6,1,4,20,
13,21,10,22,2,2,7,26,6,26,6,26,5,28,4,255,
0,15,6,29,3,233,12,8,68,163,76,132,84,132,90,69,
92,70,98,40,100,39,105,237,107,233,113,227,114,98,114,210,
121,196,122,97,122,241,129,194,130,34,131,16,137,228,139,41,
140,132,146,3,147,100,154,34,162,34,170,34,178,34,6,6,
114,2,121,228,129,197,137,135,145,132,153,162,6,132,3,39,
11,70,19,101,27,131,7,1,136,200,0,57,3,10,2,5,
7,10,2,2,8,12,15,8,15,8,11,2,2,6,8,16,
6,18,5,20,2,124,7,1,140,194,0,113,4,7,4,5,
3,4,9,3,8,4,28,3,29,3,29,3,29,4,28,9,
23,10,6,7,9,3,1,60,7,7,189,206,0,255,0,209,
1,1,14,5,27,4,28,4,28,4,28,4,28,4,15,3,
10,7,1,2,8,8,6,11,2,1,4,12,2,15,2,30,
1,112,3,0,205,1,31,1,31,5,27,4,28,4,28,4,
28,4,28,4,28,4,28,4,28,3,28,4,22,1,5,6,
2,2,9,1,5,4,3,10,4,6,3,29,2,30,2,30,
2,30,1,31,2,30,3,29,4,2,5,21,12,8,24,3,
30,1,255,0,51,7,15,57,236,0,226,4,19,3,28,6,
24,9,11,1,10,9,11,1,10,8,9,7,7,13,4,11,
2,15,4,28,4,28,4,28,4,28,4,28,5,27,6,26,
10,22,18,14,20,15,61,3,0,255,0,233,1,29,6,2,
3,21,11,23,2,1,7,26,6,8,2,17,6,1,11,16,
17,15,17,6,1,8,17,6,3,2,1,2,18,6,26,5,
27,4,28,4,28,3,29,2,30,4,28,4,28,5,27,6,
8,8,10,26,6,30,2,96,3,0,255,0,178,5,27,7,
24,10,22,12,20,13,1,2,13,7,3,9,12,2,11,7,
9,2,15,6,8,3,15,6,8,4,14,6,7,6,10,9,
4,28,1,31,1,49,4,29,2,255,0,76,1,31,3,0,
255,0,86,1,27,6,26,7,23,11,20,14,18,16,16,18,
5,7,2,18,6,26,7,25,11,21,15,17,16,16,19,13,
26,6,27,5,28,4,29,3,29,3,30,2,31,1,255,0,
33,2,0,101,6,3,2,28,12,27,14,26,15,25,13,27,
13,26,14,25,13,27,13,28,11,30,10,30,11,30,9,33,
4,24,2,8,7,22,4,6,11,18,6,4,12,17,9,1,
13,16,25,7,2,5,35,4,5,3,28,16,14,2,8,17,
12,5,6,17,12,6,2,20,12,28,12,30,9,31,8,31,
10,30,10,12,2,0,177,5,34,8,32,10,29,12,28,12,
28,12,27,12,29,10,30,9,31,9,32,8,34,5,20,2,
12,5,20,5,8,9,9,1,7,7,6,11,6,4,5,9,
5,11,4,7,4,36,4,2,1,34,3,2,4,6,2,24,
11,2,4,10,2,1,2,1,4,4,16,10,11,4,14,11,
14,1,15,10,31,7,32,8,32,9,31,9,31,9,16,2,
0,177,7,3,2,28,12,27,14,26,14,26,13,26,14,25,
12,29,11,30,10,30,10,30,10,21,2,8,8,22,2,10,
4,23,4,6,7,21,7,4,11,12,2,3,9,2,13,9,
4,2,25,7,6,4,2,2,32,9,1,1,29,12,14,2,
12,14,12,4,10,14,11,10,1,17,12,29,11,31,9,31,
8,31,9,31,9,16,6,171,4,39,11,202,19,171,27,140,
35,109,43,109,51,78,59,47,66,210,74,241,82,241,91,47,
99,78,107,109,115,109,123,140,131,140,137,39,140,7,145,41,
147,230,153,73,155,229,161,74,163,105,169,106,171,105,178,5,
179,44,180,225,186,6,187,13,188,225,194,52,196,194,202,55,
210,86,218,86,226,117,234,143,236,194,243,72,251,72,6,149,
2,170,4,70,10,111,12,132,18,20,20,163,25,246,28,225,
34,8,35,78,42,68,43,140,51,202,59,233,68,39,76,101,
217,198,225,106,233,75,241,106,249,106,6,142,33,195,41,199,
49,201,57,204,65,206,73,238,81,236,83,129,89,234,91,129,
97,237,105,232,113,231,122,67,6,49,24,97,32,100,40,132,
48,133,56,164,64,227,73,33,138,225,147,2,152,193,155,35,
160,194,168,194,169,65,170,193,176,229,178,194,179,195,180,65,
185,6,186,163,187,165,193,39,194,164,195,193,201,133,202,164,
203,163,209,134,210,133,211,101,217,165,218,165,219,102,225,167,
226,196,227,98,227,197,233,199,234,197,235,193,236,3,241,199,
243,4,243,225,244,34,249,228,251,35,252,2,6,9,90,194,
98,132,106,101,114,101,122,70,130,70,138,36,146,34,154,2,
6,15,67,65,75,34,83,3,90,226,98,98,98,194,106,69,
114,69,122,39,130,39,137,233,145,170,153,99,154,37,162,98,
7,7,57,128,127,1,2,5,11,5,2,14,1,80,1,6,
2,15,11,13,15,2,22,3,22,3,1,1,21,2,124,7,
7,56,196,57,1,22,2,22,2,21,3,22,3,11,1,9,
4,6,6,14,6,3,9,15,17,8,5,1,18,6,26,6,
26,6,14,2,10,7,10,6,9,8,6,10,3,3,2,8,
1,119,7,7,57,196,154,5,8,3,6,7,5,4,5,6,
5,16,4,28,5,27,5,27,5,27,5,27,6,26,7,7,
1,9,1,7,4,1,3,5,4,6,11,2,6,5,19,3,
123,3,255,0,255,0,125,1,30,3,8,1,1,3,16,6,
3,8,15,6,2,10,15,5,2,20,5,5,2,30,2,30,
2,30,3,29,3,29,3,29,4,9,2,17,6,7,2,17,
10,1,6,13,20,5,2,5,18,6,3,5,3,4,2,1,
6,7,16,14,21,10,23,8,15,6,10,107,193,115,162,123,
162,124,129,130,21,138,103,139,132,140,98,147,162,155,193,3,
17,10,21,2,2,3,25,2,29,2,30,2,1,3,26,10,
21,2,1,6,22,2,30,2,31,2,2,5,24,11,22,6,
27,2,31,2,1,5,25,10,23,5,27,1,32,1,1,4,
26,9,7,4,1,7,4,1,1,4,9,13,4,1,14,11,
6,1,7,3,4,9,6,13,3,10,4,15,3,12,2,15,
2,13,1,16,2,30,2,30,2,30,2,30,2,13,1,16,
3,10,3,16,4,9,4,15,9,2,7,14,20,9,1,2,
20,2,30,2,30,2,1,3,26,10,22,8,4,3,15,1,
31,1,31,1,1,7,23,7,24,2,1,2,27,2,30,1,
2,1,27,9,23,7,24,2,30,2,31,2,1,7,23,7,
26,2,32,1,2,7,23,8,25,1,1,1,29,1,21,2,
9,8,10,4,10,6,5,1,5,6,9,1,6,5,3,9,
6,14,2,11,4,15,2,13,1,16,2,30,1,31,2,30,
2,30,2,12,1,17,3,11,2,16,4,9,4,15,9,2,
8,12,11,1,8,8,24,1,2,2,27,1,31,1,1,2,
28,8,24,1,1,3,58,6,8,3,240,1,29,3,27,4,
28,3,30,2,32,2,23,1,6,2,19,2,1,3,5,2,
14,1,3,8,4,3,9,5,2,10,2,18,2,10,2,18,
2,30,2,30,2,30,2,30,3,29,3,29,3,9,4,1,
12,3,4,4,8,4,11,1,5,2,9,3,30,1,31,1,
30,3,29,2,29,1,31,2,29,3,29,2,30,2,31,3,
29,3,30,4,28,1,1,3,11,3,18,3,28,4,27,2,
29,5,26,1,2,2,27,1,32,5,7,1,19,3,9,1,
30,2,20,1,1,2,5,3,21,4,5,1,30,2,22,1,
6,2,23,4,2,3,23,1,1,6,15,2,7,7,5,3,
4,7,4,8,3,6,3,10,1,18,3,10,1,18,3,29,
3,29,3,10,1,18,3,10,1,18,4,7,4,17,5,8,
3,2,2,12,5,10,2,1,1,3,3,7,6,8,3,4,
9,2,17,1,63,4,27,1,1,4,25,1,31,3,28,6,
26,1,31,4,29,5,28,2,1,1,29,3,30,3,11,3,
17,6,25,1,3,4,23,3,28,7,25,1,3,3,25,2,
12,1,18,5,8,1,18,2,1,3,7,1,19,1,9,3,
20,4,5,3,20,1,1,4,3,2,21,1,7,3,21,5,
3,2,22,9,15,1,7,1,4,4,11,5,7,8,4,3,
3,8,4,9,1,7,2,11,1,18,2,11,1,18,2,30,
2,30,2,11,1,18,2,11,1,18,3,9,3,9,2,6,
4,5,1,1,6,8,4,3,4,10,3,1,5,3,11,10,
2,6,1,2,12,2,2,4,3,4,4,2,22,1,7,2,
22,1,1,4,3,2,21,5,4,2,20,1,9,3,19,1,
1,1,9,1,18,6,7,1,18,1,30,2,3,3,25,1,
1,4,27,3,30,1,2,4,26,5,9,3,17,1,30,5,
26,1,1,6,24,1,31,1,1,3,9,1,18,6,7,2,
17,1,12,2,18,1,9,3,19,7,3,3,20,4,5,2,
30,2,21,5,3,2,21,6,2,3,21,1,6,3,12,2,
8,9,9,8,5,9,4,3,2,10,3,17,1,12,2,17,
1,12,1,18,1,31,1,31,1,12,1,18,1,12,2,17,
2,10,3,17,3,8,6,8,4,3,4,9,4,3,2,4,
9,12,2,1,6,3,9,10,3,6,2,3,22,4,4,2,
31,2,20,6,4,2,20,6,4,3,18,1,10,3,18,1,
1,1,10,1,17,7,7,1,17,1,2,1,10,1,16,1,
31,2,1,5,25,5,28,2,14,3,0,10,5,14,3,9,
2,1,4,13,3,9,1,5,2,10,5,9,2,1,2,13,
5,10,6,12,4,10,8,11,3,11,1,17,3,11,7,10,
4,12,8,7,4,13,1,14,4,13,1,13,4,14,6,6,
5,15,17,5,3,7,2,1,12,7,4,8,11,6,10,5,
28,3,30,2,158,2,31,1,30,3,28,3,13,5,8,5,
2,1,13,5,19,2,7,4,16,9,4,2,15,11,4,2,
8,1,4,14,4,13,7,9,3,12,6,11,4,11,1,17,
3,10,1,1,5,12,3,9,7,12,4,9,5,13,5,8,
2,16,1,1,4,9,1,2,5,11,4,9,6,13,4,2,
7,1,23,2,7,1,38,2,3,1,30,1,255,0,69,1,
38,1,80,1,38,2,37,3,9,126,23,1,255,0,70,1,
39,1,38,2,28,1,9,2,28,1,5,2,79,1,38,2,
38,2,32,1,5,2,32,1,5,2,33,1,4,2,34,6,
36,2,111,2,36,4,30,1,4,6,13,26,32,9,34,6,
35,5,34,6,35,5,35,5,35,5,35,5,35,5,27,2,
6,5,29,2,4,5,4,3,24,2,1,12,26,11,30,8,
31,8,27,15,23,19,4,2,11,5,5,4,26,6,4,5,
27,4,4,6,34,4,1,2,39,2,39,1,60,2,39,3,
39,2,41,1,3,4,35,6,21,1,13,5,20,2,14,4,
20,2,14,5,19,3,12,5,1,2,17,3,13,3,21,3,
13,3,21,3,12,4,1,2,18,3,12,6,19,3,7,4,
1,4,21,3,10,6,19,4,12,10,28,8,30,3,1,7,
28,2,3,8,32,9,31,9,30,9,30,2,1,6,31,1,
7,1,30,2,7,1,15,3,86,1,31,1,25,1,5,1,
21,11,21,10,26,1,99,1,30,1,31,1,31,1,29,3,
27,5,2,10,8,2,2,4,2,10,11,20,12,20,11,21,
11,4,2,4,1,12,9,3,3,3,2,1,2,12,14,2,
1,1,2,1,1,4,21,3,5,2,23,2,3,1,27,2,
15,1,31,1,31,3,28,5,27,5,27,5,28,3,30,2,
219,2,37,3,103,1,35,5,34,6,34,6,34,6,15,1,
17,7,14,2,18,5,13,2,21,3,13,1,22,8,3,6,
9,1,11,18,9,3,10,7,1,2,1,1,1,4,10,2,
11,7,5,3,12,3,9,8,3,3,14,3,4,2,3,1,
2,4,3,2,16,4,5,1,1,2,1,5,1,3,17,3,
7,3,1,7,20,2,8,2,1,6,20,3,8,8,21,3,
8,8,21,3,8,8,21,3,6,11,18,5,4,3,2,9,
16,1,2,1,3,4,4,11,18,5,5,10,1,2,15,4,
8,10,3,2,13,1,10,12,4,1,23,12,28,12,21,1,
6,12,15,2,10,16,23,18,4,2,16,18,3,1,18,18,
8,3,11,18,2,1,5,2,12,21,5,3,10,22,4,1,
2,1,10,21,4,2,2,1,10,19,2,1,1,1,4,3,
9,18,3,2,6,3,7,19,2,1,8,3,7,21,6,6,
8,19,5,8,7,21,1,3,3,4,7,27,2,2,8,31,
9,30,9,30,10,30,11,28,12,28,13,19,2,7,12,28,
13,16,3,8,17,11,4,8,32,7,33,8,32,8,31,9,
31,9,31,9,31,9,6,2,167,8,31,10,30,11,28,13,
27,13,27,13,25,15,25,15,25,15,27,14,25,14,26,13,
26,14,25,16,23,16,26,14,28,12,27,13,27,13,27,14,
25,15,25,15,25,16,24,15,24,17,18,2,3,17,17,3,
3,17,15,5,3,17,15,4,2,7,10,148,167,107,1,30,
3,29,3,5,2,17,15,4,8,4,28,4,4,3,5,3,
5,2,6,2,6,3,5,3,5,4,4,4,28,5,27,7,
25,16,4,1,11,25,7,28,4,128,2,51,1,34,6,32,
9,31,11,28,12,28,13,27,13,26,14,24,16,24,16,25,
15,27,14,26,13,27,13,26,14,26,15,25,15,25,15,27,
9,2,2,26,12,26,14,3,7,16,15,1,10,14,15,1,
12,12,28,12,16,1,10,13,27,13,26,13,18,1,7,14,
26,14,25,15,25,15,2,15,1,38,2,35,7,32,9,30,
11,29,12,27,13,27,14,26,14,26,13,25,16,24,16,25,
15,26,14,26,14,26,14,25,15,25,15,25,15,25,15,27,
12,28,13,27,13,26,14,26,15,24,16,24,16,24,16,24,
22,18,25,14,27,12,30,5,2,90,1,38,3,32,8,30,
11,28,12,28,13,26,14,26,15,25,17,24,15,25,14,27,
13,12,1,13,13,13,1,13,12,28,12,28,12,27,12,28,
11,29,14,28,13,27,13,26,14,3,7,17,25,14,28,12,
29,11,30,10,31,8,32,8,33,8,32,7,2,52,1,39,
2,34,7,32,9,29,11,28,13,27,16,24,16,24,15,25,
15,25,15,26,13,27,12,28,12,28,12,29,11,29,11,29,
8,32,10,30,13,26,14,26,23,17,25,15,27,13,28,12,
29,11,30,9,32,9,31,9,31,8,13,1,16,6,3,0,
32,1,31,2,30,3,29,4,28,5,27,6,18,1,7,7,
16,2,7,8,15,2,7,8,8,1,3,5,7,8,7,11,
6,8,2,16,6,29,3,202,1,255,0,255,0,151,6,7,
106,71,114,9,121,233,129,201,137,200,145,230,153,229,6,15,
89,193,90,33,97,193,98,33,98,229,105,162,106,33,106,107,
113,208,121,177,129,51,137,50,145,47,153,106,161,132,6,20,
66,195,74,226,82,226,90,227,99,1,106,227,114,227,122,196,
123,225,130,165,131,194,137,10,138,202,145,23,153,54,161,84,
169,207,177,238,186,34,186,226,2,8,3,7,7,24,2,6,
9,23,1,5,11,22,2,4,11,24,1,4,11,24,1,3,
12,24,1,3,12,28,11,28,12,14,2,15,9,10,6,19,
5,6,10,20,3,3,14,19,21,9,255,0,15,1,38,2,
37,3,36,4,35,5,33,7,31,9,30,12,26,16,21,23,
10,102,2,3,6,7,8,19,4,2,3,4,8,19,4,5,
3,1,8,18,4,9,8,19,4,10,6,20,4,10,9,17,
3,13,6,1,6,11,3,13,6,4,6,8,3,13,6,5,
10,3,3,13,13,5,4,2,3,12,12,10,1,2,3,12,
9,16,3,12,6,19,3,13,5,19,3,14,5,18,4,13,
5,19,3,12,6,19,3,11,8,18,3,9,11,18,2,7,
13,18,2,6,14,18,1,6,15,18,1,5,16,18,1,4,
17,18,1,4,18,17,2,3,18,12,1,5,2,2,18,8,
5,8,18,6,8,7,19,2,12,7,33,9,31,5,35,3,
43,14,14,21,11,25,8,9,6,9,8,4,15,5,8,2,
31,1,32,1,31,1,31,1,32,1,31,1,31,1,32,1,
29,3,18,1,9,5,15,3,7,8,4,2,7,4,6,9,
2,5,5,5,6,14,1,2,2,7,6,26,6,26,6,26,
6,5,3,18,8,1,5,18,15,1,2,4,3,7,15,1,
4,2,5,5,15,1,3,3,6,2,18,1,2,2,27,1,
2,2,27,5,27,4,28,3,30,1,31,1,31,1,31,2,
31,1,31,1,31,2,12,2,182,5,34,7,16,3,13,8,
17,4,10,8,18,7,6,10,16,5,3,3,2,11,16,5,
6,12,17,5,9,10,16,4,12,10,14,4,12,12,11,5,
13,9,2,8,3,5,15,8,5,4,3,5,14,9,5,4,
3,5,14,9,3,5,4,5,13,17,6,4,13,2,1,12,
8,4,14,11,11,4,15,7,14,4,16,6,14,4,16,7,
14,3,16,7,14,4,14,8,14,4,12,11,14,4,10,13,
13,4,8,15,14,3,7,16,14,3,4,19,14,3,3,21,
6,3,255,0,164,22,7,255,0,234,21,6,255,0,61,3,
255,0,187,1,30,2,30,6,25,8,23,9,23,9,23,32,
9,23,9,23,9,24,8,25,6,27,1,31,1,255,0,166,
7,7,48,128,62,2,1,5,4,8,1,5,1,23,1,47,
24,1,23,1,23,1,6,3,14,4,3,7,2,112,7,7,
49,128,76,1,7,4,5,2,3,14,2,5,1,16,2,24,
22,1,23,1,23,2,7,1,14,2,7,2,13,5,2,10,
3,20,3,20,3,102,7,7,57,132,103,3,1,2,8,11,
6,2,9,15,5,27,13,40,11,21,11,22,10,24,1,231,
7,7,25,198,107,1,28,5,16,10,7,8,10,7,11,3,
11,7,25,6,26,8,24,9,23,12,1,2,17,13,9,4,
6,12,4,5,3,5,3,14,2,6,2,22,2,7,2,13,
2,1,2,11,2,14,2,14,2,72,6,3,116,5,124,8,
132,194,7,2,115,132,5,3,26,7,3,3,7,10,3,29,
4,28,4,28,6,26,9,23,11,8,18,4,247,7,7,57,
198,57,1,29,3,28,4,27,4,28,3,29,2,15,4,11,
2,13,7,5,7,12,9,1,19,2,30,3,29,5,27,6,
26,7,25,12,18,1,1,7,10,175,7,3,60,198,49,1,
7,2,22,2,31,1,31,2,30,2,30,3,30,2,30,2,
18,2,8,4,15,6,5,5,16,8,1,19,3,29,2,30,
2,30,4,28,7,25,10,30,2,1,53,3,210,1,27,2,
2,1,26,6,26,6,27,2,2,2,30,3,29,3,30,2,
29,3,14,1,11,6,8,3,3,6,4,7,2,1,2,7,
3,29,3,29,3,29,2,30,2,30,1,31,2,3,2,17,
1,7,12,12,1,7,14,14,27,4,255,0,166,7,5,125,
238,118,1,3,1,18,6,25,7,25,5,1,2,27,1,2,
3,29,3,30,2,28,6,24,7,6,4,9,14,4,21,2,
22,2,22,3,21,4,20,4,20,3,7,3,9,5,6,6,
7,6,4,16,6,9,1,20,2,30,3,29,3,30,2,30,
1,30,2,14,1,59,7,2,125,238,167,1,16,2,1,2,
2,2,14,11,13,7,1,5,13,5,2,5,20,4,6,3,
7,7,2,1,3,4,3,23,3,29,3,29,4,28,4,28,
4,28,3,29,3,3,1,2,1,14,1,7,3,3,8,8,
20,4,19,5,12,5,2,4,12,10,15,8,17,3,2,2,
94,7,7,111,255,30,6,17,8,3,2,11,14,8,17,6,
19,3,23,1,51,5,30,2,64,1,31,1,22,4,37,2,
1,1,28,6,18,3,2,1,48,3,3,2,13,6,1,4,
10,14,10,4,6,3,11,3,21,3,188,1,28,4,24,8,
46,2,19,1,1,3,10,2,5,7,11,2,1,10,11,61,
1,7,3,156,227,58,1,8,2,19,4,7,5,11,1,3,
5,6,14,1,2,2,8,6,26,6,29,4,27,10,21,12,
22,11,18,20,12,24,8,5,5,20,1,4,11,21,12,20,
5,9,6,4,6,7,9,2,7,4,133,7,3,156,227,46,
6,16,3,5,8,7,2,7,18,3,4,8,15,3,7,7,
12,3,10,7,27,7,1,1,23,10,21,12,21,11,19,13,
19,11,21,2,2,5,22,3,28,4,29,3,22,2,23,1,
144,3,48,3,27,5,8,2,15,6,8,3,8,1,5,6,
4,1,2,5,7,13,1,3,2,7,6,15,3,9,6,27,
5,27,5,26,11,22,11,20,13,2,3,14,22,9,255,0,
157,3,23,9,14,19,12,20,11,23,4,26,6,28,4,12,
1,13,6,25,6,1,5,7,3,10,5,1,7,7,4,7,
15,6,6,5,16,3,30,3,16,3,222,2,28,4,18,4,
4,6,11,21,8,24,7,25,6,26,6,26,4,11,1,11,
3,2,5,9,3,10,9,9,7,2,1,3,9,5,1,4,
7,2,1,2,26,2,1,2,25,6,26,6,28,2,1,2,
12,2,3,4,7,2,1,2,12,8,7,2,1,3,12,8,
3,9,12,9,1,11,11,26,6,26,7,25,8,24,11,21,
26,6,27,5,27,5,27,5,28,4,29,3,30,2,64,3,
255,0,30,3,27,5,2,1,23,9,2,1,3,23,1,3,
1,27,2,62,2,1,1,28,4,1,2,21,3,1,8,19,
15,1,3,9,25,6,26,6,24,9,12,24,12,21,10,26,
6,26,7,25,7,25,4,1,2,25,4,4,18,6,3,2,
21,6,4,1,22,5,27,5,28,4,29,3,30,2,128,3,
10,5,26,7,24,9,22,11,20,14,17,18,13,21,10,24,
8,26,5,29,2,31,1,10,2,192,1,30,7,25,9,23,
10,24,8,26,7,27,5,28,4,28,4,28,4,28,4,27,
5,25,6,9,2,3,3,7,7,10,4,1,16,10,21,10,
20,2,2,8,19,1,4,7,18,1,6,6,27,5,30,2,
31,1,31,1,5,2,0,22,18,22,18,22,18,22,18,22,
18,22,18,22,18,22,17,23,16,24,17,23,17,22,19,21,
19,21,19,20,20,19,21,18,22,18,22,16,24,15,27,11,
32,5,229,1,39,1,39,1,38,2,38,2,38,2,3,0,
13,19,13,19,13,19,13,19,13,19,13,19,13,19,12,20,
12,20,11,21,10,22,8,24,7,255,0,193,3,19,3,7,
4,14,7,7,5,1,5,2,12,7,25,7,25,8,24,10,
22,15,8,1,8,26,6,29,3,128,7,14,115,8,85,1,
14,2,9,1,3,1,7,5,6,5,4,5,2,10,7,5,
1,19,7,25,7,25,8,24,11,21,20,4,2,6,28,4,
22,2,168,7,14,49,204,0,4,4,3,5,2,25,1,8,
1,7,1,15,2,31,1,31,1,31,1,31,2,29,3,30,
2,13,4,6,5,2,4,8,7,7,25,7,25,8,24,9,
23,14,18,15,17,21,4,2,5,29,3,64,7,6,33,200,
0,4,4,3,5,2,35,1,7,1,7,1,15,2,14,2,
14,2,14,2,14,2,14,2,6,5,3,3,1,7,7,5,
1,6,1,12,7,25,7,25,8,24,11,21,15,17,27,5,
29,3,7,14,115,220,0,4,4,3,5,2,255,0,76,3,
27,5,25,7,14,5,4,9,10,22,8,24,7,25,7,25,
7,5,2,18,7,4,5,3,3,10,27,5,160,6,13,1,
22,9,22,17,22,25,22,33,53,41,52,49,52,57,83,65,
82,73,112,81,142,89,172,97,232,7,2,19,222,139,2,29,
4,3,3,3,9,9,23,9,23,10,22,13,19,19,13,31,
1,128,6,10,8,8,9,7,11,5,11,5,12,4,13,3,
13,3,7,2,18,144,26,3,20,4,4,15,1,23,1,23,
2,22,3,21,9,15,16,6,10,8,8,9,7,10,6,11,
5,12,4,12,4,7,6,51,156,40,2,11,4,14,4,6,
15,6,8,2,16,5,27,5,27,5,27,5,27,6,26,7,
25,9,23,255,0,33,6,31,58,133,66,73,74,43,82,12,
90,13,98,13,106,13,114,13,122,44,130,75,138,43,146,43,
154,33,154,105,162,12,170,12,177,237,185,238,193,208,201,209,
209,179,217,149,225,99,225,243,233,68,233,244,241,67,241,246,
249,36,249,204,251,138,6,18,4,194,12,194,20,225,138,132,
146,103,154,74,162,44,170,44,178,13,185,238,193,238,201,206,
209,175,217,175,225,144,233,144,241,113,249,81,1,7,15,128,
0,0,42,1,3,2,2,6,1,7,2,2,2,2,73,1,
2,20,4,4,74,3,1,2,1,7,1,7,2,2,2,2,
40,7,15,220,0,0,11,4,13,3,13,4,12,4,11,5,
11,1,1,3,5,11,4,12,5,11,14,2,148,12,3,13,
4,6,2,4,8,3,2,3,9,2,4,1,68,3,1,1,
5,2,3,13,4,12,5,1,1,9,7,2,6,1,8,2,
14,2,14,2,6,7,15,255,192,2,11,1,2,2,11,2,
1,3,10,6,10,3,1,3,9,3,1,3,10,2,1,4,
10,6,10,1,1,3,1,10,4,1,3,49,8,7,4,4,
12,3,7,1,15,1,141,1,4,2,16,5,2,2,5,6,
2,5,5,2,4,14,3,3,5,14,2,4,5,3,14,2,
5,3,15,1,32,1,23,2,23,1,5,2,6,1,9,2,
3,4,4,3,7,13,1,3,1,1,2,14,3,5,1,23,
2,3,1,1,6,2,5,4,120,3,0,12,2,30,2,10,
2,17,4,9,2,18,3,8,4,17,4,8,4,16,5,8,
4,14,6,8,5,7,2,3,2,1,5,8,5,5,16,2,
4,1,4,6,21,2,3,8,1,5,5,2,6,3,1,17,
2,5,2,141,1,31,3,6,2,21,3,4,5,3,1,16,
17,13,14,3,3,12,6,3,5,3,3,26,4,252,1,29,
4,1,4,19,10,2,2,1,2,10,14,2,5,10,22,10,
7,3,3,7,2,11,2,1,2,15,2,14,2,14,2,14,
2,15,1,15,1,20,3,0,8,2,3,4,9,4,15,4,
10,2,15,2,1,3,26,1,2,3,25,2,1,4,13,1,
11,1,1,4,13,2,11,5,13,3,10,6,11,5,2,5,
2,7,10,6,2,15,6,9,2,18,2,10,1,63,2,30,
3,29,3,6,2,21,6,1,5,1,5,3,2,9,5,1,
24,2,5,1,255,0,255,0,188,3,0,5,27,6,26,7,
25,8,1,2,6,4,1,1,9,13,1,13,5,30,2,170,
2,30,3,29,5,27,7,25,1,2,4,25,1,3,3,18,
3,3,1,2,4,19,4,1,2,1,4,14,3,4,11,8,
9,5,27,1,177,4,10,1,14,9,8,2,6,3,2,14,
5,29,3,6,1,23,2,6,1,62,2,217,3,0,23,9,
6,2,15,9,6,6,6,14,6,9,2,15,5,10,1,16,
5,27,2,30,3,29,3,2,1,26,7,25,8,1,2,4,
2,15,28,4,29,3,255,0,255,0,63,3,17,1,5,1,
1,7,13,19,9,23,8,24,7,25,6,26,8,14,4,6,
9,4,3,6,8,2,9,2,5,6,10,6,164,26,226,34,
227,42,228,50,196,58,104,66,105,74,105,82,135,90,104,98,
105,106,105,114,105,122,104,130,135,138,165,145,68,146,104,153,
38,154,74,161,38,162,12,169,143,177,174,185,163,186,73,194,
73,202,72,208,4,210,72,216,6,218,72,224,9,226,41,232,
25,240,25,248,25,6,147,114,8,121,203,128,243,131,102,136,
250,144,250,153,24,161,24,169,55,177,56,185,84,193,114,201,
114,209,115,217,115,225,114,233,145,241,114,249,114,3,189,2,
29,2,30,1,30,2,29,3,19,14,16,18,12,20,12,20,
13,19,14,18,15,17,16,16,17,15,19,13,19,13,17,15,
16,16,15,17,14,18,13,19,12,20,12,20,14,18,16,16,
26,3,30,2,31,1,31,2,31,2,161,6,147,146,69,154,
9,161,115,169,54,177,24,184,250,192,220,200,190,208,190,216,
159,220,97,224,159,228,97,232,102,233,121,240,102,241,122,248,
101,249,122,3,255,0,97,3,29,6,17,18,13,23,8,75,
1,31,9,23,18,14,18,14,18,14,18,14,18,14,12,20,
10,22,8,11,1,12,7,7,8,10,7,5,11,9,6,5,
14,7,6,5,26,6,26,5,27,5,26,6,26,6,26,5,
27,4,29,3,56,3,255,0,247,5,25,7,24,4,27,13,
12,21,10,22,7,25,6,2,1,21,8,1,1,24,7,2,
2,7,7,7,6,2,6,4,9,1,1,3,6,1,8,2,
21,1,255,0,154,6,28,60,193,68,132,76,194,84,194,92,
194,100,194,107,193,108,194,112,212,115,195,116,194,123,233,132,
39,140,194,148,194,156,194,164,194,172,194,180,194,188,163,196,
163,204,163,212,163,220,162,228,162,236,130,244,130,252,129,2,
14,1,39,1,39,1,40,1,39,1,39,1,39,2,39,1,
39,1,39,1,39,2,7,3,29,1,1,10,28,13,27,12,
11,40,7,4,7,7,33,6,34,6,32,8,31,9,30,10,
30,10,30,11,30,11,29,11,29,11,30,9,32,9,33,3,
2,1,35,2,3,1,34,3,2,1,36,1,3,1,13,2,
10,18,5,7,12,15,7,6,12,14,9,5,11,13,13,3,
11,10,31,8,33,7,33,8,32,8,30,11,29,12,28,12,
16,3,9,14,4,1,8,4,4,2,3,15,3,2,6,6,
2,4,2,21,1,91,1,38,3,23,3,3,1,7,3,22,
9,6,4,9,2,10,10,5,4,4,7,4,18,3,5,1,
8,5,19,2,14,5,34,7,32,9,30,11,28,11,16,2,
9,12,17,1,11,10,31,9,18,3,11,10,12,3,1,3,
0,13,15,19,12,20,7,1,3,26,2,30,2,255,0,89,
1,34,3,29,4,26,13,19,15,17,17,22,1,2,7,31,
1,255,0,125,2,30,2,30,2,29,2,30,2,13,4,12,
2,4,7,14,182,224,0,255,0,2,1,24,2,25,4,20,
5,16,2,1,16,4,20,4,21,4,20,2,5,5,6,12,
4,13,3,15,1,192,7,15,115,140,0,62,1,28,5,23,
9,16,1,1,7,3,4,12,8,8,4,5,13,3,5,2,
4,5,3,7,4,1,12,18,14,9,2,8,13,8,8,2,
14,7,25,6,26,6,26,6,26,6,26,7,25,7,49,2,
10,7,5,144,7,11,120,204,0,49,1,23,2,29,3,20,
5,3,3,14,4,1,9,11,15,19,13,20,12,20,12,16,
15,9,21,11,1,12,7,25,11,8,7,4,13,7,9,6,
10,6,10,6,10,6,10,6,10,6,10,7,41,96,3,0,
248,2,28,6,25,8,22,10,10,1,10,11,6,2,1,1,
2,1,6,13,6,7,4,15,4,29,2,61,1,30,5,11,
2,17,8,25,6,26,6,26,6,26,6,26,6,26,6,26,
6,26,7,25,8,24,11,21,255,0,65,3,0,255,0,255,
0,108,2,1,10,19,13,23,1,4,2,25,1,31,1,70,
2,24,1,4,3,10,3,3,10,3,2,4,15,4,8,2,
18,5,6,1,60,1,14,2,30,3,29,6,26,8,24,9,
4,4,15,10,2,9,1,21,2,31,2,18,7,15,123,216,
0,114,2,16,9,1,1,2,1,3,2,1,13,1,26,1,
23,2,1,3,4,1,10,1,2,19,1,255,0,255,0,126,
7,3,24,194,0,55,9,7,1,5,2,3,14,6,4,1,
21,6,26,6,26,7,4,4,3,2,12,9,1,14,8,23,
1,168,7,5,41,66,0,31,1,22,10,13,2,2,15,6,
4,2,20,6,26,6,26,7,4,2,1,2,1,3,12,8,
2,14,8,8,2,19,1,1,2,4,3,4,2,6,6,1,
2,1,3,2,3,6,9,2,9,5,19,6,18,6,2,4,
11,7,1,6,3,8,7,15,121,64,0,20,4,12,12,1,
1,3,3,1,90,11,10,1,2,16,5,119,2,15,2,4,
3,14,3,3,3,14,8,4,5,6,19,5,19,6,18,7,
3,3,3,2,5,9,1,5,2,6,1,7,3,14,2,103,
7,15,249,66,0,61,3,22,10,14,2,2,14,7,4,2,
19,6,26,6,26,7,25,8,4,4,3,6,7,197,2,15,
1,5,12,6,18,6,18,5,19,4,6,3,3,5,2,6,
3,1,1,142,7,7,249,198,0,115,3,6,4,4,9,5,
14,3,10,4,15,3,29,3,29,3,29,3,29,3,22,2,
5,4,20,1,7,4,27,7,23,11,4,1,19,13,19,10,
20,1,1,8,108,6,6,1,10,15,1,4,4,21,3,21,
3,14,2,61,6,129,128,107,6,146,97,227,98,195,105,164,
106,229,113,101,115,7,121,8,123,10,128,140,131,12,136,233,
139,9,145,71,147,6,153,164,154,229,162,2,162,195,3,0,
6,26,5,27,4,28,4,28,3,29,2,30,1,31,1,50,
2,28,5,26,7,25,8,22,1,1,8,20,12,18,12,20,
11,20,12,20,14,17,15,17,15,18,14,18,14,18,14,19,
12,9,1,11,10,10,1,11,10,9,2,13,6,10,3,28,
4,28,4,27,5,26,6,25,7,24,8,22,10,21,11,19,
13,18,14,15,17,11,53,3,255,0,243,2,14,4,11,3,
12,7,9,4,6,5,1,9,5,8,1,8,1,10,3,29,
4,26,6,17,2,6,8,4,4,3,2,3,16,4,29,2,
30,2,255,0,207,7,2,57,132,77,3,16,3,9,4,16,
5,7,5,6,4,5,6,4,19,3,6,3,18,5,4,5,
20,3,2,8,5,3,1,2,6,16,4,8,3,9,4,12,
3,14,1,91,7,3,17,196,117,3,1,2,17,4,7,5,
15,5,3,9,13,19,12,22,11,19,1,1,11,11,4,4,
1,1,12,5,27,4,21,3,5,3,50,3,255,0,113,2,
30,3,13,1,14,5,12,2,13,6,11,3,12,7,5,3,
2,3,6,1,5,14,3,3,6,4,2,13,4,5,3,5,
2,255,0,62,3,30,9,24,13,20,16,17,16,16,16,17,
15,17,15,19,13,20,12,21,11,7,1,13,11,2,132,1,
38,3,37,4,35,6,34,7,32,8,32,9,30,11,29,12,
28,12,28,13,27,14,2,16,8,32,7,33,7,33,7,21,
9,1,10,18,22,14,1,2,23,13,27,12,28,12,29,10,
30,9,31,9,32,7,33,6,23,1,11,5,22,2,11,4,
22,3,12,2,23,3,7,11,127,198,255,0,84,3,1,1,
16,1,3,10,18,14,18,15,1,1,18,4,1,6,28,3,
255,0,140,7,6,49,132,27,1,29,5,15,5,3,1,1,
9,11,21,9,22,8,24,7,24,9,4,1,22,2,6,1,
13,6,2,6,8,20,3,123,2,216,1,38,5,35,6,34,
5,36,5,35,6,32,6,2,2,29,8,31,10,30,7,2,
2,32,4,3,6,27,6,33,7,33,7,33,8,31,9,30,
10,29,13,25,17,21,21,19,21,18,22,20,19,23,16,28,
10,30,2,3,1,34,2,3,2,19,3,255,0,202,1,12,
1,15,1,1,2,9,13,4,6,9,13,5,27,5,27,5,
27,5,27,5,27,5,27,5,27,5,27,5,27,4,5,10,
13,7,2,12,11,7,2,18,5,7,1,255,0,89,2,183,
1,30,1,2,7,30,10,31,12,26,13,27,12,28,11,30,
10,16,2,13,9,16,1,15,9,15,3,13,9,15,4,13,
8,15,4,13,8,16,3,13,8,17,3,8,13,16,3,6,
15,16,4,4,16,17,4,2,18,16,4,1,19,17,9,3,
12,17,5,6,12,17,3,8,12,28,12,28,11,29,11,29,
11,29,12,24,16,12,3,255,0,89,2,27,7,25,10,20,
6,3,4,9,1,1,2,6,5,6,2,7,6,5,14,5,
27,4,28,4,28,4,28,4,28,4,28,4,28,5,27,6,
26,7,2,2,1,6,14,21,7,2,2,255,0,161,3,250,
4,26,8,22,10,7,1,2,2,9,6,3,2,4,8,9,
5,11,7,8,12,6,10,3,13,6,26,6,26,6,26,6,
26,6,26,6,26,6,26,6,26,5,27,4,7,10,11,7,
4,11,10,8,1,16,1,14,1,255,0,184,3,0,183,2,
30,3,6,1,21,5,5,2,18,8,4,3,11,2,3,11,
2,5,7,19,1,5,5,28,2,255,0,158,4,26,7,23,
10,21,12,20,13,18,16,3,3,9,24,5,29,1,231,3,
0,7,1,2,25,5,29,3,31,1,76,1,28,3,2,1,
25,2,3,3,3,5,16,2,1,6,1,6,16,16,8,1,
7,24,9,22,11,21,16,17,17,15,20,13,18,14,20,13,
21,11,22,10,22,10,22,10,22,10,22,11,21,11,21,12,
20,14,9,7,2,15,8,25,8,25,7,27,5,28,4,29,
4,29,2,168,3,0,255,0,112,1,31,3,29,7,27,6,
25,7,25,8,24,9,25,8,12,5,10,6,3,1,6,6,
11,10,2,11,5,14,1,13,3,15,2,13,1,16,2,30,
3,29,4,28,4,28,6,9,1,7,1,1,2,5,9,5,
2,7,7,2,11,1,3,8,23,8,22,10,1,1,20,16,
17,16,17,18,15,17,16,16,17,15,17,15,3,0,255,0,
113,1,31,3,30,6,28,5,27,5,26,7,25,8,24,9,
27,6,10,4,13,9,5,6,9,12,2,11,4,15,1,13,
2,16,1,13,1,17,1,31,3,29,3,29,4,22,1,5,
5,10,1,7,7,2,8,6,2,7,8,1,15,8,22,9,
22,12,20,16,18,15,18,17,15,17,16,16,17,15,3,0,
255,0,22,1,31,2,30,3,30,4,29,5,28,4,29,3,
18,2,9,4,17,3,9,3,17,12,1,2,18,11,1,3,
23,4,2,3,22,5,2,5,19,13,5,4,1,1,6,15,
4,9,3,16,3,10,2,17,3,29,2,30,1,31,1,31,
1,23,5,3,2,22,7,1,5,18,22,10,21,15,17,17,
16,18,16,17,15,17,16,16,17,15,6,138,194,162,202,163,
210,195,219,2,227,3,227,162,235,4,235,162,242,201,250,201,
6,148,97,162,105,196,114,4,122,36,130,68,138,101,146,133,
154,165,162,198,171,6,179,38,187,70,195,103,203,136,211,200,
219,233,228,8,236,39,244,70,252,132,3,0,219,4,27,6,
25,7,22,10,21,11,21,11,21,11,20,11,21,9,14,2,
10,6,2,1,5,3,1,5,8,6,2,2,6,10,3,13,
7,25,6,26,1,63,6,26,6,26,7,15,2,8,9,2,
16,4,255,0,194,3,0,201,3,27,7,24,8,23,10,22,
10,1,1,20,14,19,17,15,17,4,1,1,2,9,8,4,
3,18,7,4,2,19,7,4,7,3,2,9,6,4,13,10,
5,4,13,10,22,8,24,8,24,8,24,7,18,6,1,8,
17,6,1,8,19,3,2,7,25,6,3,1,6,4,12,5,
3,1,6,9,8,4,3,2,5,14,4,3,4,27,2,1,
1,28,1,253,3,0,233,1,28,6,25,8,23,9,23,9,
2,2,19,19,14,18,6,1,7,10,5,3,16,8,5,3,
17,8,4,12,9,6,5,12,9,6,5,12,11,5,1,15,
10,22,9,23,9,18,4,1,9,17,15,23,9,23,9,23,
8,11,6,7,8,9,9,5,8,3,1,6,10,3,8,3,
2,4,23,3,3,1,24,3,28,2,1,1,27,1,188,3,
0,255,0,39,6,25,7,24,9,2,2,19,9,1,7,15,
20,1,4,1,2,4,12,1,7,13,11,5,2,16,9,5,
11,9,7,5,11,9,7,5,11,10,5,5,12,13,4,1,
14,12,20,10,17,15,17,15,19,13,22,10,22,10,22,10,
10,8,4,10,2,1,6,10,3,9,3,1,5,23,2,2,
4,23,2,3,3,23,4,27,4,28,1,30,1,122,3,0,
255,0,96,1,30,5,4,2,20,8,1,16,4,4,2,5,
1,11,8,5,2,9,3,6,6,17,6,3,5,6,3,10,
6,3,2,8,3,10,7,25,5,1,2,14,4,7,2,19,
5,4,3,20,11,21,10,22,10,22,10,22,11,21,11,12,
4,5,10,12,19,3,1,8,19,3,2,6,21,1,4,2,
24,2,4,2,30,2,209,3,0,255,0,69,1,25,1,4,
7,7,1,1,3,1,3,1,4,4,15,1,1,15,14,15,
2,1,4,1,10,13,9,7,4,10,13,6,5,6,15,7,
5,3,18,7,5,1,20,4,28,3,27,4,28,4,20,3,
3,3,21,11,21,10,22,10,22,11,21,11,21,12,15,17,
15,17,14,18,14,18,13,18,2,1,3,1,7,18,1,2,
3,1,6,22,2,4,2,23,3,29,3,29,4,15,3,0,
27,5,28,4,29,3,29,3,30,2,255,0,127,2,29,7,
25,8,7,1,16,9,5,2,16,9,23,9,22,9,22,10,
21,11,20,7,21,11,19,13,18,14,18,14,18,14,18,14,
17,15,17,15,16,16,13,19,9,23,7,25,6,26,6,26,
6,135,154,129,162,99,170,68,178,38,186,38,194,68,202,129,
7,2,16,128,0,39,3,16,1,2,6,12,14,10,14,14,
9,23,1,28,7,6,49,140,0,14,5,1,4,20,12,21,
1,1,9,24,8,7,1,5,3,9,2,8,5,4,5,5,
6,2,10,4,6,2,20,3,29,3,29,4,28,6,5,1,
3,6,11,23,9,26,6,28,4,30,2,32,7,7,57,204,
0,107,6,4,2,8,17,7,17,7,17,20,12,20,4,1,
7,21,3,5,2,22,4,25,8,3,3,4,2,9,17,3,
8,3,18,2,9,2,19,1,31,1,31,1,20,3,8,2,
16,9,5,2,12,14,4,3,10,17,2,6,2,56,3,0,
255,0,123,6,21,11,20,9,23,12,20,12,26,6,27,5,
27,5,26,5,26,5,27,5,26,5,18,3,5,6,1,2,
11,21,2,1,7,28,3,30,1,138,5,24,11,21,13,15,
19,13,21,3,125,7,15,123,156,0,165,5,26,7,25,8,
25,8,27,6,26,8,24,9,23,10,22,11,25,8,24,9,
23,10,22,10,22,9,23,9,23,7,25,5,15,1,12,1,
2,1,2,2,11,1,13,8,10,1,11,10,10,1,10,11,
18,14,16,16,10,6,149,105,226,113,196,121,196,129,200,137,
229,146,4,154,6,162,8,170,43,178,75,186,105,194,136,202,
138,210,134,211,100,218,132,219,130,226,161,227,66,235,34,243,
33,7,6,56,196,0,113,2,10,3,9,2,8,5,13,1,
3,2,7,6,11,10,3,8,1,2,8,23,2,1,6,19,
1,2,2,1,8,18,5,1,13,4,1,10,2,1,2,1,
15,3,1,10,2,1,4,5,4,1,1,1,5,3,106,6,
160,42,101,50,102,58,41,66,42,74,43,82,76,90,75,98,
73,106,105,113,163,114,137,121,164,122,169,129,226,130,139,137,
227,138,108,146,16,154,17,162,3,162,142,170,142,178,143,186,
174,194,174,202,173,210,203,218,202,226,203,234,172,242,172,250,
172,6,156,4,194,9,194,12,225,17,195,20,225,25,196,33,
197,41,230,49,231,58,71,66,104,74,138,82,171,84,162,90,
210,99,16,107,109,115,171,123,233,131,230,132,225,139,201,147,
202,155,202,163,202,172,8,180,101,188,132,6,152,3,228,11,
168,19,138,20,225,27,109,35,109,43,109,51,109,59,140,67,
109,75,109,83,171,91,202,100,8,107,231,115,230,123,167,131,
135,139,72,147,8,154,200,162,105,170,67,178,97,7,0,115,
222,0,104,2,6,4,4,5,3,18,6,17,1,2,4,12,
2,2,8,8,16,5,19,3,255,0,198,6,7,0,9,3,
101,4,101,8,1,8,164,11,162,12,225,6,5,50,130,99,
97,121,129,137,193,232,97,7,3,205,103,13,4,8,5,13,
8,6,5,11,11,4,6,10,12,4,6,10,12,3,7,9,
23,9,25,7,23,9,25,7,13,1,5,3,2,8,12,21,
8,11,2,12,6,202,1,158,1,7,7,3,220,231,107,3,
15,2,9,8,10,5,7,10,10,4,7,11,10,5,5,10,
11,6,4,11,10,7,4,11,10,8,2,10,10,10,2,10,
5,2,2,11,1,31,1,31,1,31,1,9,3,19,1,6,
1,1,6,17,1,4,11,3,15,2,13,1,31,1,206,3,
219,2,13,7,9,4,10,9,8,5,8,11,8,6,6,11,
8,7,5,11,9,8,3,10,10,9,3,10,10,9,2,11,
9,10,2,18,1,11,2,30,2,30,2,4,1,4,2,19,
2,2,4,1,5,18,17,2,11,2,16,3,30,1,136,1,
100,1,255,0,65,6,30,50,129,58,100,66,69,74,38,82,
37,90,36,98,68,106,68,114,69,122,69,130,69,138,70,146,
68,146,226,147,65,154,106,162,78,170,80,178,38,179,41,186,
7,187,34,193,201,201,170,209,139,217,109,225,78,233,109,241,
109,249,140,7,7,113,140,52,2,5,4,27,5,26,7,24,
8,16,3,4,9,7,5,3,6,1,10,6,12,2,12,4,
63,4,3,3,19,14,2,3,13,25,7,29,3,192,6,33,
52,34,59,229,67,199,75,199,83,200,91,200,99,231,108,6,
116,37,122,46,124,5,128,72,129,216,136,20,139,46,144,82,
147,232,154,97,156,8,162,97,164,8,170,34,172,39,180,39,
188,39,196,39,204,38,212,70,220,70,228,39,236,8,244,8,
252,8,3,22,4,28,4,28,4,28,4,28,4,28,4,28,
4,28,5,27,5,3,1,23,9,18,2,1,8,20,15,15,
16,15,17,13,17,13,19,4,1,5,20,6,2,2,22,6,
20,1,5,6,15,6,5,6,13,8,5,6,10,11,5,6,
8,14,4,6,6,16,4,6,2,20,5,23,2,2,5,21,
3,3,5,20,2,5,5,18,4,5,5,15,17,13,19,12,
21,9,23,8,24,6,20,1,5,4,16,8,4,4,16,8,
4,4,15,9,5,3,12,13,4,3,9,16,4,3,3,18,
14,18,14,18,14,18,2,5,7,18,2,11,1,17,2,30,
2,29,2,30,2,30,2,30,1,31,1,31,1,31,2,30,
2,30,2,30,2,30,2,31,1,31,2,30,2,30,2,31,
2,30,2,30,4,8,2,1,1,6,1,1,3,2,8,3,
6,1,1,4,255,0,9,4,29,3,15,2,2,2,14,2,
10,9,10,5,8,14,4,8,6,28,3,3,42,3,30,13,
19,17,15,19,13,21,11,21,11,2,16,3,11,2,30,1,
30,2,30,1,31,1,31,1,31,1,31,1,31,1,20,1,
7,2,1,2,15,5,4,9,12,7,4,9,1,1,8,9,
3,29,3,29,3,29,3,29,4,6,2,10,2,8,4,1,
8,8,24,8,25,7,25,2,2,3,26,6,27,5,27,3,
30,3,31,2,31,2,31,3,31,3,31,2,31,3,29,3,
3,2,138,3,35,8,31,8,32,8,32,9,31,9,30,9,
32,8,31,9,25,3,3,8,22,18,18,6,6,9,19,4,
12,6,18,2,15,8,32,9,31,10,30,12,28,9,1,4,
26,9,3,3,25,9,1,5,26,15,25,12,2,2,24,5,
4,3,3,2,23,5,11,2,21,6,12,1,21,6,12,2,
19,7,13,2,17,8,13,2,17,8,14,2,1,2,54,3,
35,10,29,10,29,11,29,11,29,12,28,12,28,11,28,12,
27,13,29,11,19,20,20,20,27,13,29,10,31,10,31,11,
31,12,28,14,26,14,27,15,25,16,24,12,1,5,22,13,
2,4,22,11,3,5,21,19,21,20,20,17,1,3,19,16,
3,3,18,7,6,3,4,2,18,7,14,2,2,2,22,3,
34,7,32,9,30,14,26,13,27,12,26,13,26,14,28,13,
27,12,14,9,4,12,13,27,13,4,3,19,14,1,11,14,
29,11,31,8,33,7,33,8,32,11,28,13,28,14,26,8,
1,5,26,15,25,16,24,13,1,3,23,13,2,4,21,13,
2,5,20,13,1,6,20,21,19,21,19,17,2,3,18,8,
5,4,3,2,3,0,177,15,12,20,7,25,3,255,0,255,
0,255,0,32,2,29,5,25,7,24,9,1,4,16,28,2,
72,3,255,0,65,1,31,4,28,6,26,8,24,9,23,11,
22,11,27,6,30,3,31,2,255,0,255,0,147,6,1,98,
98,6,10,122,38,130,8,138,8,146,8,154,8,161,234,169,
204,177,204,185,234,194,68,6,17,194,98,201,234,209,138,210,
229,217,99,218,68,219,36,225,67,226,68,227,68,233,67,234,
67,235,99,241,36,243,99,249,68,251,68,7,7,16,128,85,
3,8,1,6,9,8,16,7,17,7,17,8,16,14,10,21,
3,64,7,7,16,128,62,2,14,3,2,5,3,2,6,13,
3,21,3,21,3,21,3,21,3,2,6,13,14,3,2,5,
6,2,56,7,7,56,192,89,2,21,3,20,5,18,5,5,
4,4,2,1,7,2,28,1,100,3,16,10,14,13,11,6,
3,6,1,7,2,15,1,87,6,26,57,129,58,6,65,138,
73,139,81,170,89,169,97,200,105,200,113,199,121,200,129,232,
137,233,145,234,153,234,161,235,169,235,177,203,185,204,193,205,
201,174,209,173,217,142,225,111,233,112,241,80,249,81,7,5,
57,206,128,75,1,31,1,31,1,13,4,6,1,1,1,10,
7,4,3,10,16,8,16,8,7,3,5,10,4,6,1,1,
1,11,3,7,1,23,1,31,1,84,128,3,0,255,0,55,
1,31,2,27,4,26,5,24,7,24,5,26,4,27,4,17,
3,7,4,18,13,5,4,10,12,5,4,11,12,2,1,1,
4,12,20,12,20,12,20,12,21,11,21,11,8,2,11,11,
6,3,4,2,6,11,4,5,3,4,5,26,5,27,1,255,
0,49,3,0,104,3,29,6,18,2,6,2,1,4,17,9,
2,4,17,15,17,16,16,16,16,17,17,15,20,1,3,3,
2,2,26,2,255,0,245,254,2,23,9,23,9,23,9,3,
0,72,1,3,1,19,10,1,2,19,14,18,14,18,4,2,
6,20,3,30,1,255,0,127,255,0,152,3,28,5,25,7,
1,4,19,13,19,2,1,10,24,3,2,3,24,2,38,7,
12,64,99,0,32,4,2,1,4,2,3,10,1,2,3,15,
1,14,2,5,4,1,1,2,4,3,5,1,2,1,4,2,
7,1,117,56,1,13,3,13,5,8,8,8,13,2,14,6,
10,6,2,24,7,14,80,231,0,3,4,13,4,12,4,13,
4,12,4,13,4,12,4,13,3,13,3,14,2,14,2,15,
1,186,12,12,167,1,6,3,9,1,2,4,9,1,2,5,
8,9,7,9,7,9,8,8,9,7,9,6,2,3,0,52,
12,18,14,16,16,14,18,13,3,6,10,12,1,13,6,11,
1,17,3,10,1,19,2,31,9,24,8,24,7,8,4,13,
7,8,4,13,7,9,3,13,7,9,2,14,8,24,8,24,
9,23,11,21,13,3,6,10,24,8,25,7,15,2,9,6,
15,3,8,6,14,5,8,5,15,4,8,6,26,6,26,7,
24,9,23,10,26,7,16,1,10,7,12,3,10,13,1,6,
12,19,13,17,15,15,17,12,52,3,0,11,10,19,17,12,
22,9,24,6,28,3,30,1,120,5,25,10,20,12,19,13,
18,14,17,15,17,15,16,16,16,8,4,4,16,8,5,3,
4,4,8,8,5,3,3,5,8,8,5,3,3,5,8,9,
3,4,4,4,8,16,16,16,15,17,15,17,14,18,14,18,
13,19,11,23,7,119,1,30,3,28,6,24,9,22,12,18,
17,12,10,2,0,2,38,2,38,1,187,2,37,4,35,5,
35,5,35,5,18,4,14,3,16,10,29,12,26,16,20,1,
2,17,20,1,2,18,18,2,1,20,16,3,1,21,14,15,
1,12,11,14,4,13,7,16,5,34,6,34,6,35,5,36,
3,186,1,38,2,38,2,2,187,3,36,5,35,6,34,6,
34,6,14,6,15,4,13,10,28,14,25,16,23,18,22,19,
21,20,20,20,20,21,19,21,19,22,18,23,16,10,4,12,
12,11,6,13,8,13,6,34,7,33,6,34,6,35,4,187,
3,0,13,6,26,5,255,0,47,81,2,30,2,31,1,31,
1,31,1,31,1,25,1,5,1,24,4,3,1,24,5,2,
1,24,5,1,2,23,10,22,11,22,10,22,10,22,11,23,
9,27,4,28,4,28,3,29,3,28,5,27,5,27,5,27,
5,28,3,76,3,0,14,4,255,0,47,241,1,31,2,31,
1,31,2,31,1,31,1,31,1,63,2,22,3,4,4,22,
10,22,12,21,1,1,9,22,1,3,5,29,3,29,4,29,
3,29,4,28,4,28,4,29,3,71,3,105,2,31,2,58,
11,19,15,16,17,12,21,11,21,11,21,11,21,11,21,11,
21,11,21,11,21,11,21,11,21,11,21,11,22,10,22,3,
2,5,20,5,25,8,24,8,24,8,24,7,26,5,29,1,
255,0,107,3,0,255,0,170,2,2,2,23,10,21,12,7,
8,4,28,5,27,5,27,5,27,5,9,2,16,5,27,5,
7,7,13,5,3,10,14,17,5,1,9,17,4,4,7,29,
2,255,0,162,0,0,
};

7
ch32_decoder/funconfig.h Normal file
View file

@ -0,0 +1,7 @@
#ifndef _FUNCONFIG_H
#define _FUNCONFIG_H
#define CH32V003 1
#endif

2
ch32_decoder/gdbinit Normal file
View file

@ -0,0 +1,2 @@
#set debug remote 1
target extended-remote /dev/ttyACM1

586
ch32_decoder/ssd1306.h Normal file
View file

@ -0,0 +1,586 @@
/*
* Single-File-Header for using SPI OLED
* 05-05-2023 E. Brombaugh
*/
#ifndef _SSD1306_H
#define _SSD1306_H
#include <stdint.h>
#include <string.h>
// comfortable packet size for this OLED
#define SSD1306_PSZ 32
// characteristics of each type
#if !defined(SSD1306_64X32) && !defined(SSD1306_128X32) && !defined(SSD1306_128X64)
#error "Please define the SSD1306_WXH resolution used in your application"
#endif
#ifdef SSD1306_64X32
#define SSD1306_W 64
#define SSD1306_H 32
#define SSD1306_FULLUSE
#define SSD1306_OFFSET 32
#endif
#ifdef SSD1306_128X32
#define SSD1306_W 128
#define SSD1306_H 32
#define SSD1306_OFFSET 0
#endif
#ifdef SSD1306_128X64
#define SSD1306_W 128
#define SSD1306_H 64
#define SSD1306_FULLUSE
#define SSD1306_OFFSET 0
#endif
/*
* send OLED command byte
*/
uint8_t ssd1306_cmd(uint8_t cmd)
{
ssd1306_pkt_send(&cmd, 1, 1);
return 0;
}
/*
* send OLED data packet (up to 32 bytes)
*/
uint8_t ssd1306_data(uint8_t *data, uint8_t sz)
{
ssd1306_pkt_send(data, sz, 0);
return 0;
}
#define SSD1306_SETCONTRAST 0x81
#define SSD1306_SEGREMAP 0xA0
#define SSD1306_DISPLAYALLON_RESUME 0xA4
#define SSD1306_DISPLAYALLON 0xA5
#define SSD1306_NORMALDISPLAY 0xA6
#define SSD1306_INVERTDISPLAY 0xA7
#define SSD1306_DISPLAYOFF 0xAE
#define SSD1306_DISPLAYON 0xAF
#define SSD1306_SETDISPLAYOFFSET 0xD3
#define SSD1306_SETCOMPINS 0xDA
#define SSD1306_SETVCOMDETECT 0xDB
#define SSD1306_SETDISPLAYCLOCKDIV 0xD5
#define SSD1306_SETPRECHARGE 0xD9
#define SSD1306_SETMULTIPLEX 0xA8
#define SSD1306_SETLOWCOLUMN 0x00
#define SSD1306_SETHIGHCOLUMN 0x10
#define SSD1306_SETSTARTLINE 0x40
#define SSD1306_MEMORYMODE 0x20
#define SSD1306_COLUMNADDR 0x21
#define SSD1306_PAGEADDR 0x22
#define SSD1306_COMSCANINC 0xC0
#define SSD1306_COMSCANDEC 0xC8
#define SSD1306_CHARGEPUMP 0x8D
#define SSD1306_EXTERNALVCC 0x1
#define SSD1306_SWITCHCAPVCC 0x2
#define SSD1306_TERMINATE_CMDS 0xFF
/* choose VCC mode */
#define SSD1306_EXTERNALVCC 0x1
#define SSD1306_SWITCHCAPVCC 0x2
// #define vccstate SSD1306_EXTERNALVCC
#define vccstate SSD1306_SWITCHCAPVCC
// OLED initialization commands for 128x32
const uint8_t ssd1306_init_array[] =
{
SSD1306_DISPLAYOFF, // 0xAE
SSD1306_SETDISPLAYCLOCKDIV, // 0xD5
0x80, // the suggested ratio 0x80
SSD1306_SETMULTIPLEX, // 0xA8
#ifdef SSD1306_64X32
0x1F, // for 64-wide displays
#else
0x3F, // for 128-wide displays
#endif
SSD1306_SETDISPLAYOFFSET, // 0xD3
0x00, // no offset
SSD1306_SETSTARTLINE | 0x0, // 0x40 | line
SSD1306_CHARGEPUMP, // 0x8D
0x14, // enable?
SSD1306_MEMORYMODE, // 0x20
0x00, // 0x0 act like ks0108
SSD1306_SEGREMAP | 0x1, // 0xA0 | bit
SSD1306_COMSCANDEC,
SSD1306_SETCOMPINS, // 0xDA
0x12, //
SSD1306_SETCONTRAST, // 0x81
0x8F,
SSD1306_SETPRECHARGE, // 0xd9
0xF1,
SSD1306_SETVCOMDETECT, // 0xDB
0x40,
SSD1306_DISPLAYALLON_RESUME, // 0xA4
SSD1306_NORMALDISPLAY, // 0xA6
SSD1306_DISPLAYON, // 0xAF --turn on oled panel
SSD1306_TERMINATE_CMDS // 0xFF --fake command to mark end
};
// the display buffer
uint8_t ssd1306_buffer[SSD1306_W * SSD1306_H / 8];
/*
* set the buffer to a color
*/
void ssd1306_setbuf(uint8_t color)
{
memset(ssd1306_buffer, color ? 0xFF : 0x00, sizeof(ssd1306_buffer));
}
#ifndef SSD1306_FULLUSE
/*
* expansion array for OLED with every other row unused
*/
const uint8_t expand[16] =
{
0x00, // 0000 0000
0x02, // 0000 0010
0x08, // 0000 1000
0x0a, // 0000 1010
0x20, // 0010 0000
0x22, // 0010 0010
0x28, // 0010 1000
0x2a, // 0010 1010
0x80, // 1000 0000
0x82, // 1000 0010
0x88, // 1000 1000
0x8a, // 1000 1010
0xa0, // 1010 0000
0xa2, // 1010 0010
0xa8, // 1010 1000
0xaa, // 1010 1010
};
#endif
/*
* Send the frame buffer
*/
void ssd1306_refresh(void)
{
uint16_t i;
ssd1306_cmd(SSD1306_COLUMNADDR);
ssd1306_cmd(SSD1306_OFFSET); // Column start address (0 = reset)
ssd1306_cmd(SSD1306_OFFSET + SSD1306_W - 1); // Column end address (127 = reset)
ssd1306_cmd(SSD1306_PAGEADDR);
ssd1306_cmd(0); // Page start address (0 = reset)
ssd1306_cmd(7); // Page end address
#ifdef SSD1306_FULLUSE
/* for fully used rows just plow thru everything */
for (i = 0; i < sizeof(ssd1306_buffer); i += SSD1306_PSZ)
{
/* send PSZ block of data */
ssd1306_data(&ssd1306_buffer[i], SSD1306_PSZ);
}
#else
/* for displays with odd rows unused expand bytes */
uint8_t tbuf[SSD1306_PSZ], j, k;
for (i = 0; i < sizeof(ssd1306_buffer); i += 128) // for each page
{
/* low nybble */
for (j = 0; j < 128; j += SSD1306_PSZ)
{
for (k = 0; k < SSD1306_PSZ; k++)
tbuf[k] = expand[ssd1306_buffer[i + j + k] & 0xf];
/* send PSZ block of data */
ssd1306_data(tbuf, SSD1306_PSZ);
}
/* high nybble */
for (j = 0; j < 128; j += SSD1306_PSZ)
{
for (k = 0; k < SSD1306_PSZ; k++)
tbuf[k] = expand[(ssd1306_buffer[i + j + k] >> 4) & 0xf];
/* send PSZ block of data */
ssd1306_data(tbuf, SSD1306_PSZ);
}
}
#endif
}
/*
* plot a pixel in the buffer
*/
void ssd1306_drawPixel(uint8_t x, uint8_t y, uint8_t color)
{
uint16_t addr;
/* clip */
if (x >= SSD1306_W)
return;
if (y >= SSD1306_H)
return;
/* compute buffer address */
addr = x + SSD1306_W * (y / 8);
/* set/clear bit in buffer */
if (color)
ssd1306_buffer[addr] |= (1 << (y & 7));
else
ssd1306_buffer[addr] &= ~(1 << (y & 7));
}
/*
* plot a pixel in the buffer
*/
void ssd1306_xorPixel(uint8_t x, uint8_t y)
{
uint16_t addr;
/* clip */
if (x >= SSD1306_W)
return;
if (y >= SSD1306_H)
return;
/* compute buffer address */
addr = x + SSD1306_W * (y / 8);
ssd1306_buffer[addr] ^= (1 << (y & 7));
}
/*
* draw a an image from an array, directly into to the display buffer
* the color modes allow for overwriting and even layering (sprites!)
*/
void ssd1306_drawImage(uint8_t x, uint8_t y, const unsigned char *input, uint8_t width, uint8_t height, uint8_t color_mode)
{
uint8_t x_absolute;
uint8_t y_absolute;
uint8_t pixel;
uint8_t bytes_to_draw = width / 8;
uint16_t buffer_addr;
for (uint8_t line = 0; line < height; line++)
{
y_absolute = y + line;
if (y_absolute >= SSD1306_H)
{
break;
}
// SSD1306 is in vertical mode, yet we want to draw horizontally, which necessitates assembling the output bytes from the input data
// bitmask for current pixel in vertical (output) byte
uint8_t v_mask = 1 << (y_absolute & 7);
for (uint8_t byte = 0; byte < bytes_to_draw; byte++)
{
uint8_t input_byte = input[byte + line * bytes_to_draw];
for (pixel = 0; pixel < 8; pixel++)
{
x_absolute = x + 8 * (bytes_to_draw - byte) + pixel;
if (x_absolute >= SSD1306_W)
{
break;
}
// looking at the horizontal display, we're drawing bytes bottom to top, not left to right, hence y / 8
buffer_addr = x_absolute + SSD1306_W * (y_absolute / 8);
// state of current pixel
uint8_t input_pixel = input_byte & (1 << pixel);
switch (color_mode)
{
case 0:
// write pixels as they are
ssd1306_buffer[buffer_addr] = (ssd1306_buffer[buffer_addr] & ~v_mask) | (input_pixel ? v_mask : 0);
break;
case 1:
// write pixels after inversion
ssd1306_buffer[buffer_addr] = (ssd1306_buffer[buffer_addr] & ~v_mask) | (!input_pixel ? v_mask : 0);
break;
case 2:
// 0 clears pixel
ssd1306_buffer[buffer_addr] &= input_pixel ? 0xFF : ~v_mask;
break;
case 3:
// 1 sets pixel
ssd1306_buffer[buffer_addr] |= input_pixel ? v_mask : 0;
break;
case 4:
// 0 sets pixel
ssd1306_buffer[buffer_addr] |= !input_pixel ? v_mask : 0;
break;
case 5:
// 1 clears pixel
ssd1306_buffer[buffer_addr] &= input_pixel ? ~v_mask : 0xFF;
break;
}
}
#if SSD1306_LOG_IMAGE == 1
printf("%02x ", input_byte);
#endif
}
#if SSD1306_LOG_IMAGE == 1
printf("\n\r");
#endif
}
}
/*
* fast vert line
*/
void ssd1306_drawFastVLine(uint8_t x, uint8_t y, uint8_t h, uint8_t color)
{
// clipping
if ((x >= SSD1306_W) || (y >= SSD1306_H))
return;
if ((y + h - 1) >= SSD1306_H)
h = SSD1306_H - y;
while (h--)
{
ssd1306_drawPixel(x, y++, color);
}
}
/*
* fast horiz line
*/
void ssd1306_drawFastHLine(uint8_t x, uint8_t y, uint8_t w, uint8_t color)
{
// clipping
if ((x >= SSD1306_W) || (y >= SSD1306_H))
return;
if ((x + w - 1) >= SSD1306_W)
w = SSD1306_W - x;
while (w--)
{
ssd1306_drawPixel(x++, y, color);
}
}
/*
* abs() helper function for line drawing
*/
int16_t gfx_abs(int16_t x)
{
return (x < 0) ? -x : x;
}
/*
* swap() helper function for line drawing
*/
void gfx_swap(uint16_t *z0, uint16_t *z1)
{
uint16_t temp = *z0;
*z0 = *z1;
*z1 = temp;
}
/*
* Bresenham line draw routine swiped from Wikipedia
*/
void ssd1306_drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint8_t color)
{
int16_t steep;
int16_t deltax, deltay, error, ystep, x, y;
/* flip sense 45deg to keep error calc in range */
steep = (gfx_abs(y1 - y0) > gfx_abs(x1 - x0));
if (steep)
{
gfx_swap(&x0, &y0);
gfx_swap(&x1, &y1);
}
/* run low->high */
if (x0 > x1)
{
gfx_swap(&x0, &x1);
gfx_swap(&y0, &y1);
}
/* set up loop initial conditions */
deltax = x1 - x0;
deltay = gfx_abs(y1 - y0);
error = deltax / 2;
y = y0;
if (y0 < y1)
ystep = 1;
else
ystep = -1;
/* loop x */
for (x = x0; x <= x1; x++)
{
/* plot point */
if (steep)
/* flip point & plot */
ssd1306_drawPixel(y, x, color);
else
/* just plot */
ssd1306_drawPixel(x, y, color);
/* update error */
error = error - deltay;
/* update y */
if (error < 0)
{
y = y + ystep;
error = error + deltax;
}
}
}
/*
* draws a circle
*/
void ssd1306_drawCircle(int16_t x, int16_t y, int16_t radius, int8_t color)
{
/* Bresenham algorithm */
int16_t x_pos = -radius;
int16_t y_pos = 0;
int16_t err = 2 - 2 * radius;
int16_t e2;
do
{
ssd1306_drawPixel(x - x_pos, y + y_pos, color);
ssd1306_drawPixel(x + x_pos, y + y_pos, color);
ssd1306_drawPixel(x + x_pos, y - y_pos, color);
ssd1306_drawPixel(x - x_pos, y - y_pos, color);
e2 = err;
if (e2 <= y_pos)
{
err += ++y_pos * 2 + 1;
if (-x_pos == y_pos && e2 <= x_pos)
{
e2 = 0;
}
}
if (e2 > x_pos)
{
err += ++x_pos * 2 + 1;
}
} while (x_pos <= 0);
}
/*
* draws a filled circle
*/
void ssd1306_fillCircle(int16_t x, int16_t y, int16_t radius, int8_t color)
{
/* Bresenham algorithm */
int16_t x_pos = -radius;
int16_t y_pos = 0;
int16_t err = 2 - 2 * radius;
int16_t e2;
do
{
ssd1306_drawPixel(x - x_pos, y + y_pos, color);
ssd1306_drawPixel(x + x_pos, y + y_pos, color);
ssd1306_drawPixel(x + x_pos, y - y_pos, color);
ssd1306_drawPixel(x - x_pos, y - y_pos, color);
ssd1306_drawFastHLine(x + x_pos, y + y_pos, 2 * (-x_pos) + 1, color);
ssd1306_drawFastHLine(x + x_pos, y - y_pos, 2 * (-x_pos) + 1, color);
e2 = err;
if (e2 <= y_pos)
{
err += ++y_pos * 2 + 1;
if (-x_pos == y_pos && e2 <= x_pos)
{
e2 = 0;
}
}
if (e2 > x_pos)
{
err += ++x_pos * 2 + 1;
}
} while (x_pos <= 0);
}
/*
* draw a rectangle
*/
void ssd1306_drawRect(uint8_t x, uint8_t y, uint8_t w, uint8_t h, uint8_t color)
{
ssd1306_drawFastVLine(x, y, h, color);
ssd1306_drawFastVLine(x + w - 1, y, h, color);
ssd1306_drawFastHLine(x, y, w, color);
ssd1306_drawFastHLine(x, y + h - 1, w, color);
}
/*
* fill a rectangle
*/
void ssd1306_fillRect(uint8_t x, uint8_t y, uint8_t w, uint8_t h, uint8_t color)
{
uint8_t m, n = y, iw = w;
/* scan vertical */
while (h--)
{
m = x;
w = iw;
/* scan horizontal */
while (w--)
{
/* invert pixels */
ssd1306_drawPixel(m++, n, color);
}
n++;
}
}
/*
* invert a rectangle in the buffer
*/
void ssd1306_xorrect(uint8_t x, uint8_t y, uint8_t w, uint8_t h)
{
uint8_t m, n = y, iw = w;
/* scan vertical */
while (h--)
{
m = x;
w = iw;
/* scan horizontal */
while (w--)
{
/* invert pixels */
ssd1306_xorPixel(m++, n);
}
n++;
}
}
/*
* initialize I2C and OLED
*/
uint8_t ssd1306_init(void)
{
// pulse reset
ssd1306_rst();
// initialize OLED
uint8_t *cmd_list = (uint8_t *)ssd1306_init_array;
while (*cmd_list != SSD1306_TERMINATE_CMDS)
{
if (ssd1306_cmd(*cmd_list++))
return 1;
}
// clear display
ssd1306_setbuf(0);
ssd1306_refresh();
return 0;
}
#endif

363
ch32_decoder/ssd1306_i2c.h Normal file
View file

@ -0,0 +1,363 @@
/*
* Single-File-Header for SSD1306 I2C interface
* 05-07-2023 E. Brombaugh
*/
#ifndef _SSD1306_I2C_H
#define _SSD1306_I2C_H
#include <string.h>
// SSD1306 I2C address
#define SSD1306_I2C_ADDR 0x3c
// I2C Bus clock rate - must be lower the Logic clock rate
#define SSD1306_I2C_CLKRATE 1000000
// I2C Logic clock rate - must be higher than Bus clock rate
#define SSD1306_I2C_PRERATE 2000000
// uncomment this for high-speed 36% duty cycle, otherwise 33%
#define SSD1306_I2C_DUTY
// I2C Timeout count
#define TIMEOUT_MAX 100000
// uncomment this to enable IRQ-driven operation
//#define SSD1306_I2C_IRQ
#ifdef SSD1306_I2C_IRQ
// some stuff that IRQ mode needs
volatile uint8_t ssd1306_i2c_send_buffer[64], *ssd1306_i2c_send_ptr, ssd1306_i2c_send_sz, ssd1306_i2c_irq_state;
// uncomment this to enable time diags in IRQ
//#define IRQ_DIAG
#endif
/*
* init just I2C
*/
void ssd1306_i2c_setup(void)
{
uint16_t tempreg;
// Reset I2C1 to init all regs
RCC->APB1PRSTR |= RCC_APB1Periph_I2C1;
RCC->APB1PRSTR &= ~RCC_APB1Periph_I2C1;
// set freq
tempreg = I2C1->CTLR2;
tempreg &= ~I2C_CTLR2_FREQ;
tempreg |= (FUNCONF_SYSTEM_CORE_CLOCK/SSD1306_I2C_PRERATE)&I2C_CTLR2_FREQ;
I2C1->CTLR2 = tempreg;
// Set clock config
tempreg = 0;
#if (SSD1306_I2C_CLKRATE <= 100000)
// standard mode good to 100kHz
tempreg = (FUNCONF_SYSTEM_CORE_CLOCK/(2*SSD1306_I2C_CLKRATE))&SSD1306_I2C_CKCFGR_CCR;
#else
// fast mode over 100kHz
#ifndef SSD1306_I2C_DUTY
// 33% duty cycle
tempreg = (FUNCONF_SYSTEM_CORE_CLOCK/(3*SSD1306_I2C_CLKRATE))&SSD1306_I2C_CKCFGR_CCR;
#else
// 36% duty cycle
tempreg = (FUNCONF_SYSTEM_CORE_CLOCK/(25*SSD1306_I2C_CLKRATE))&I2C_CKCFGR_CCR;
tempreg |= I2C_CKCFGR_DUTY;
#endif
tempreg |= I2C_CKCFGR_FS;
#endif
I2C1->CKCFGR = tempreg;
#ifdef SSD1306_I2C_IRQ
// enable IRQ driven operation
NVIC_EnableIRQ(I2C1_EV_IRQn);
// initialize the state
ssd1306_i2c_irq_state = 0;
#endif
// Enable I2C
I2C1->CTLR1 |= I2C_CTLR1_PE;
// set ACK mode
I2C1->CTLR1 |= I2C_CTLR1_ACK;
}
/*
* error descriptions
*/
char *errstr[] =
{
"not busy",
"master mode",
"transmit mode",
"tx empty",
"transmit complete",
};
/*
* error handler
*/
uint8_t ssd1306_i2c_error(uint8_t err)
{
// report error
printf("ssd1306_i2c_error - timeout waiting for %s\n\r", errstr[err]);
// reset & initialize I2C
ssd1306_i2c_setup();
return 1;
}
// event codes we use
#define SSD1306_I2C_EVENT_MASTER_MODE_SELECT ((uint32_t)0x00030001) /* BUSY, MSL and SB flag */
#define SSD1306_I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED ((uint32_t)0x00070082) /* BUSY, MSL, ADDR, TXE and TRA flags */
#define SSD1306_I2C_EVENT_MASTER_BYTE_TRANSMITTED ((uint32_t)0x00070084) /* TRA, BUSY, MSL, TXE and BTF flags */
/*
* check for 32-bit event codes
*/
uint8_t ssd1306_i2c_chk_evt(uint32_t event_mask)
{
/* read order matters here! STAR1 before STAR2!! */
uint32_t status = I2C1->STAR1 | (I2C1->STAR2<<16);
return (status & event_mask) == event_mask;
}
#ifdef SSD1306_I2C_IRQ
/*
* packet send for IRQ-driven operation
*/
uint8_t ssd1306_i2c_send(uint8_t addr, uint8_t *data, uint8_t sz)
{
int32_t timeout;
#ifdef IRQ_DIAG
GPIOC->BSHR = (1<<(3));
#endif
// error out if buffer under/overflow
if((sz > sizeof(ssd1306_i2c_send_buffer)) || !sz)
return 2;
// wait for previous packet to finish
while(ssd1306_i2c_irq_state);
#ifdef IRQ_DIAG
GPIOC->BSHR = (1<<(16+3));
GPIOC->BSHR = (1<<(4));
#endif
// init buffer for sending
ssd1306_i2c_send_sz = sz;
ssd1306_i2c_send_ptr = ssd1306_i2c_send_buffer;
memcpy((uint8_t *)ssd1306_i2c_send_buffer, data, sz);
// wait for not busy
timeout = TIMEOUT_MAX;
while((I2C1->STAR2 & I2C_STAR2_BUSY) && (timeout--));
if(timeout==-1)
return ssd1306_i2c_error(0);
// Set START condition
I2C1->CTLR1 |= I2C_CTLR1_START;
// wait for master mode select
timeout = TIMEOUT_MAX;
while((!ssd1306_i2c_chk_evt(SSD1306_I2C_EVENT_MASTER_MODE_SELECT)) && (timeout--));
if(timeout==-1)
return ssd1306_i2c_error(1);
// send 7-bit address + write flag
I2C1->DATAR = addr<<1;
// wait for transmit condition
timeout = TIMEOUT_MAX;
while((!ssd1306_i2c_chk_evt(SSD1306_I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)) && (timeout--));
if(timeout==-1)
return ssd1306_i2c_error(2);
// Enable TXE interrupt
I2C1->CTLR2 |= I2C_CTLR2_ITBUFEN | I2C_CTLR2_ITEVTEN;
ssd1306_i2c_irq_state = 1;
#ifdef IRQ_DIAG
GPIOC->BSHR = (1<<(16+4));
#endif
// exit
return 0;
}
/*
* IRQ handler for I2C events
*/
void I2C1_EV_IRQHandler(void) __attribute__((interrupt));
void I2C1_EV_IRQHandler(void)
{
uint16_t STAR1, STAR2 __attribute__((unused));
#ifdef IRQ_DIAG
GPIOC->BSHR = (1<<(4));
#endif
// read status, clear any events
STAR1 = I2C1->STAR1;
STAR2 = I2C1->STAR2;
/* check for TXE */
if(STAR1 & I2C_STAR1_TXE)
{
/* check for remaining data */
if(ssd1306_i2c_send_sz--)
I2C1->DATAR = *ssd1306_i2c_send_ptr++;
/* was that the last byte? */
if(!ssd1306_i2c_send_sz)
{
// disable TXE interrupt
I2C1->CTLR2 &= ~(I2C_CTLR2_ITBUFEN | I2C_CTLR2_ITEVTEN);
// reset IRQ state
ssd1306_i2c_irq_state = 0;
// wait for tx complete
while(!ssd1306_i2c_chk_evt(SSD1306_I2C_EVENT_MASTER_BYTE_TRANSMITTED));
// set STOP condition
I2C1->CTLR1 |= I2C_CTLR1_STOP;
}
}
#ifdef IRQ_DIAG
GPIOC->BSHR = (1<<(16+4));
#endif
}
#else
/*
* low-level packet send for blocking polled operation via i2c
*/
uint8_t ssd1306_i2c_send(uint8_t addr, uint8_t *data, uint8_t sz)
{
int32_t timeout;
// wait for not busy
timeout = TIMEOUT_MAX;
while((I2C1->STAR2 & I2C_STAR2_BUSY) && (timeout--));
if(timeout==-1)
return ssd1306_i2c_error(0);
// Set START condition
I2C1->CTLR1 |= I2C_CTLR1_START;
// wait for master mode select
timeout = TIMEOUT_MAX;
while((!ssd1306_i2c_chk_evt(SSD1306_I2C_EVENT_MASTER_MODE_SELECT)) && (timeout--));
if(timeout==-1)
return ssd1306_i2c_error(1);
// send 7-bit address + write flag
I2C1->DATAR = addr<<1;
// wait for transmit condition
timeout = TIMEOUT_MAX;
while((!ssd1306_i2c_chk_evt(SSD1306_I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)) && (timeout--));
if(timeout==-1)
return ssd1306_i2c_error(2);
// send data one byte at a time
while(sz--)
{
// wait for TX Empty
timeout = TIMEOUT_MAX;
while(!(I2C1->STAR1 & I2C_STAR1_TXE) && (timeout--));
if(timeout==-1)
return ssd1306_i2c_error(3);
// send command
I2C1->DATAR = *data++;
}
// wait for tx complete
timeout = TIMEOUT_MAX;
while((!ssd1306_i2c_chk_evt(SSD1306_I2C_EVENT_MASTER_BYTE_TRANSMITTED)) && (timeout--));
if(timeout==-1)
return ssd1306_i2c_error(4);
// set STOP condition
I2C1->CTLR1 |= I2C_CTLR1_STOP;
// we're happy
return 0;
}
#endif
/*
* high-level packet send for I2C
*/
uint8_t ssd1306_pkt_send(uint8_t *data, uint8_t sz, uint8_t cmd)
{
uint8_t pkt[33];
/* build command or data packets */
if(cmd)
{
pkt[0] = 0;
pkt[1] = *data;
}
else
{
pkt[0] = 0x40;
memcpy(&pkt[1], data, sz);
}
return ssd1306_i2c_send(SSD1306_I2C_ADDR, pkt, sz+1);
}
/*
* init I2C and GPIO
*/
uint8_t ssd1306_i2c_init(void)
{
// Enable GPIOC and I2C
RCC->APB2PCENR |= RCC_APB2Periph_GPIOC;
RCC->APB1PCENR |= RCC_APB1Periph_I2C1;
// PC1 is SDA, 10MHz Output, alt func, open-drain
GPIOC->CFGLR &= ~(0xf<<(4*1));
GPIOC->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_OD_AF)<<(4*1);
// PC2 is SCL, 10MHz Output, alt func, open-drain
GPIOC->CFGLR &= ~(0xf<<(4*2));
GPIOC->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_OD_AF)<<(4*2);
#ifdef IRQ_DIAG
// GPIO diags on PC3/PC4
GPIOC->CFGLR &= ~(0xf<<(4*3));
GPIOC->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP)<<(4*3);
GPIOC->BSHR = (1<<(16+3));
GPIOC->CFGLR &= ~(0xf<<(4*4));
GPIOC->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP)<<(4*4);
GPIOC->BSHR = (1<<(16+4));
#endif
// load I2C regs
ssd1306_i2c_setup();
#if 0
// test if SSD1306 is on the bus by sending display off command
uint8_t command = 0xAF;
return ssd1306_pkt_send(&command, 1, 1);
#else
return 0;
#endif
}
/*
* reset is not used for SSD1306 I2C interface
*/
void ssd1306_rst(void)
{
}
#endif

View file

@ -10,7 +10,7 @@ pub use util::*;
const INSPECT_ENC: bool = false;
const INSPECT_DEC: bool = false;
const MAX_ERROR: usize = 4; // max wrong pixels
const MAX_ERROR: usize = 0; // max wrong pixels
const MAX_LOSS: usize = 16; // highest "loss" value tried for all lossy encodings
const LOSSLESS_ENCODINGS: &[FrameEncoder] = &[
@ -43,7 +43,7 @@ fn main() {
last_frame = decoder(&last_frame, &encoded[reader..], &mut reader);
if INSPECT_DEC {
println!(
"\n{frame_type:?}, error: {}",
"\n{frame_type:?}, error: {}, index: {frame_index}",
frame_error(&frames[frame_index], &last_frame)
);
render_images(&frames[frame_index], &last_frame);
@ -63,7 +63,12 @@ fn main() {
);
let mut export_string = String::from("// Generated by the `encoder` rust app\n");
export_string += "typedef enum {\n";
for (encoding, count) in stats {
if count > 0 {
export_string += &format!("#define USE_{encoding:?}\n");
}
}
export_string += "\n\ntypedef enum Encoding {\n";
for (encoding, count) in stats {
if count > 0 {
export_string += &format!("\tEncoding_{encoding:?} = {},\n", encoding as u8);
@ -81,7 +86,7 @@ fn main() {
export_string += &format!("{byte},");
}
export_string += "\n};\n";
let mut file = File::create("../data.h").unwrap();
let mut file = File::create("../ch32_decoder/data.h").unwrap();
file.write_all(export_string.as_bytes()).unwrap();
}
@ -117,7 +122,7 @@ fn encode(frames: &[Frame]) -> Vec<u8> {
// render_images(&frame, &decoded);
// panic!("error in 'loss 0' compression");
// }
if error < MAX_ERROR {
if error <= MAX_ERROR {
options.push(encoded);
} else {
// higher loss value will mean more error so can be skipped