├── Arduino
└── oled_animate.ino
├── LICENSE
├── Linux
└── tcomp
├── MacOS
└── tcomp
├── Makefile
├── README.md
├── grid.bin
├── main.c
├── make_player
├── play.c
├── pokemon.bin
├── swirl.bin
└── wolf.bin
/Arduino/oled_animate.ino:
--------------------------------------------------------------------------------
1 | //
2 | // oled_animate
3 | //
4 | // Copyright (c) 2018 BitBank Software, Inc.
5 | // Written by Larry Bank
6 | // project started 5/19/2018
7 | // bitbank@pobox.com
8 | //
9 | // This project is to demonstrate practical animation on I2C OLED displays driven by resource-constrained
10 | // MCUs like the ATtiny85. By using efficient I2C bit-banging along with a simple compressed image format
11 | // complex animations can be stored in a small amount of flash memory and played back at impressive frame
12 | // rates.
13 | //
14 | // This program is free software: you can redistribute it and/or modify
15 | // it under the terms of the GNU General Public License as published by
16 | // the Free Software Foundation, either version 3 of the License, or
17 | // (at your option) any later version.
18 | //
19 | // This program is distributed in the hope that it will be useful,
20 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
21 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 | // GNU General Public License for more details.
23 | //
24 | // You should have received a copy of the GNU General Public License
25 | // along with this program. If not, see .
26 | //
27 | //
28 | // Packed animation data
29 | //
30 | const byte bAnimation[] PROGMEM = {
31 | 0xe5,0x00,0x48,0x80,0xff,0x00,0xf9,0x00,0x40,0x0f,0xc0,0xe0,0xf0,0xfe,0xfe,0xff,
32 | 0xfe,0xfc,0xf8,0xf0,0xf0,0xe0,0xe0,0xc0,0x80,0x80,0xff,0x00,0xea,0x00,0x58,0x04,
33 | 0x0e,0x1e,0xc4,0x1f,0x50,0x3f,0x7f,0xcb,0xff,0x70,0xfe,0xf8,0xf0,0xc0,0x80,0x80,
34 | 0xff,0x00,0xed,0x00,0x48,0x01,0xdf,0xff,0xc4,0xfe,0xc2,0xff,0xc3,0x7f,0xce,0xff,
35 | 0x40,0x07,0x7f,0x7f,0x3f,0x3f,0x1f,0x0f,0x07,0x03,0xfd,0x00,0x50,0x03,0x07,0xcd,
36 | 0xff,0xc6,0x7f,0xcf,0xff,0x50,0xfc,0xe0,0xc5,0x00,0xc7,0x01,0xff,0x00,0xc8,0x00,
37 | 0x48,0xe0,0xc2,0xff,0x40,0x08,0x7f,0x1f,0x0f,0x03,0x00,0x00,0x01,0x0f,0x7f,0xc2,
38 | 0xff,0xc6,0x00,0x50,0x07,0x3f,0xc3,0xff,0x40,0x10,0x1f,0x07,0x03,0x03,0x07,0x0f,
39 | 0x0f,0x1f,0x1f,0x3f,0x3f,0x7f,0x7f,0xfc,0xf8,0xf0,0xe0,0xff,0x00,0xcc,0x00,0x40,
40 | 0x08,0x80,0x80,0xc0,0xf8,0xfe,0x7f,0x1f,0x07,0x01,0xc6,0x00,0xc1,0x80,0xc2,0xff,
41 | 0xc4,0x00,0x40,0x07,0x80,0x80,0xc0,0xf0,0xff,0xff,0x3f,0x0f,0xcc,0x00,0x68,0x01,
42 | 0x8f,0xff,0xff,0xf0,0xff,0x00,0xca,0x00,0x68,0x01,0x01,0x03,0x03,0x01,0xcb,0x00,
43 | 0xc3,0x01,0xc5,0x00,0xc4,0x01,0xcf,0x00,0xc3,0x03,0x48,0x01,0xe8,0x00,0x00,0x25,
44 | 0x48,0x00,0x00,0x79,0x4a,0x80,0x51,0xf8,0xff,0x4f,0xff,0x48,0xc0,0x00,0x6b,0x48,
45 | 0x00,0x00,0x14,0x49,0xfc,0x48,0xe0,0x00,0x70,0x48,0x00,0x00,0x1e,0x4d,0xfe,0x5a,
46 | 0xfe,0xfe,0xbe,0x95,0xff,0xc1,0xfe,0x00,0x07,0x40,0x08,0xff,0xff,0x7f,0x7f,0x3f,
47 | 0x1f,0x0f,0x06,0x02,0x00,0x3c,0x49,0x01,0x48,0xcf,0x00,0x0b,0x48,0x7f,0x00,0x1c,
48 | 0xc1,0x01,0x00,0x07,0x48,0x01,0x00,0x47,0x52,0x00,0xf0,0x54,0xff,0x3f,0x59,0x7f,
49 | 0xff,0xff,0x57,0x03,0x00,0x5b,0x00,0x0f,0x7f,0x5b,0xff,0x0f,0x07,0x49,0x1f,0x4b,
50 | 0x3f,0x68,0xfe,0xf8,0xe0,0xe0,0x00,0x00,0x4c,0x49,0x00,0x61,0x80,0xe0,0xf8,0xff,
51 | 0x57,0x0f,0x03,0x51,0x1f,0xff,0x55,0xf8,0x00,0x40,0x09,0x00,0x00,0x80,0x80,0xe0,
52 | 0xfd,0x7f,0x3f,0x0f,0x02,0x00,0x0a,0x52,0x03,0xff,0x48,0x00,0x00,0x4a,0x51,0x00,
53 | 0x03,0x49,0x01,0x48,0x01,0x00,0x0d,0x4e,0x00,0x4c,0x00,0x48,0x01,0x00,0x0e,0x68,
54 | 0x00,0x01,0x01,0x00,0x00,0x00,0x28,0x00,0xa1,0x4d,0xf0,0x49,0xfe,0x49,0xf8,0x49,
55 | 0xf0,0x48,0xe0,0x00,0x6d,0x5c,0x06,0x0e,0x0f,0x58,0x1f,0x1f,0x3f,0x00,0x09,0x4a,
56 | 0xfe,0x4a,0xf0,0x48,0x00,0x00,0x6e,0x48,0x1f,0x00,0x1c,0x4c,0xfe,0x4b,0xfc,0xc2,
57 | 0x7e,0xc6,0xfe,0x10,0xc2,0xfe,0x20,0xc2,0xfe,0x70,0x7e,0x7e,0x3e,0x3e,0x1e,0x0e,
58 | 0x00,0x3e,0x50,0x03,0x87,0x00,0x12,0x50,0x3f,0x7f,0x00,0x0e,0x53,0xf8,0x00,0x48,
59 | 0x01,0x00,0x0a,0xc1,0x01,0x00,0x46,0x4b,0xe0,0x49,0x7f,0x49,0x01,0x91,0xff,0x58,
60 | 0x3f,0x07,0x00,0x00,0x08,0x5b,0x03,0x1f,0x7f,0x79,0xff,0x0f,0x0f,0x1f,0x1f,0x3f,
61 | 0x3f,0x78,0x7f,0x7f,0xfc,0xf0,0xe0,0x00,0x00,0x00,0x4e,0x49,0x00,0x7c,0x80,0xe0,
62 | 0xfc,0xff,0x3f,0x0f,0x01,0x70,0x0f,0x3f,0xff,0xf0,0xe0,0x00,0x00,0x07,0x40,0x07,
63 | 0x00,0x00,0x80,0xe0,0xff,0x7f,0x1f,0x07,0x00,0x09,0x68,0xff,0xff,0x7f,0x00,0x00,
64 | 0x00,0x4c,0x53,0x00,0x01,0x48,0x01,0x00,0x09,0x48,0x00,0x00,0x09,0x70,0x00,0x03,
65 | 0x03,0x03,0x03,0x01,0x00,0x0d,0x58,0x01,0x00,0x00,0x00,0x2a,0x00,0x26,0x48,0x80,
66 | 0x00,0x79,0x4a,0xe0,0x4b,0xfc,0x49,0xfc,0x49,0xf8,0x49,0xf0,0x50,0xe0,0xc0,0x00,
67 | 0x6b,0x4a,0x02,0x78,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x1f,0x00,0x09,0x70,0xff,0xfe,
68 | 0xfc,0xf8,0xe0,0xc0,0x00,0x6f,0x48,0x0f,0x00,0x13,0xac,0xfe,0x4c,0xff,0x4b,0xfe,
69 | 0x48,0x3e,0x00,0x0d,0xa3,0xfe,0x49,0xfe,0x4a,0x7e,0x50,0x1e,0x0c,0x00,0x3c,0x49,
70 | 0x00,0x48,0x07,0x00,0x0a,0x4f,0x7f,0x48,0x7f,0x00,0x0e,0x93,0x00,0x4a,0x01,0xca,
71 | 0x03,0x09,0x01,0x00,0x45,0x52,0x00,0xf8,0x62,0xff,0x1f,0x03,0xe1,0x58,0x7f,0x1f,
72 | 0x03,0x00,0x0b,0x48,0x3f,0x00,0x07,0x4a,0x1f,0x68,0x7e,0xf8,0xf0,0xe0,0x00,0x00,
73 | 0x53,0x73,0x80,0xe0,0xfe,0x7f,0x1f,0x07,0x70,0x1f,0xff,0xff,0xf0,0x00,0x00,0x00,
74 | 0x0a,0x7f,0x00,0x80,0xc0,0xff,0xff,0x3f,0x06,0x51,0x7f,0xff,0xc1,0x00,0x00,0x4f,
75 | 0x4c,0x00,0x48,0x01,0x00,0x07,0x60,0x01,0x01,0x00,0x00,0x00,0x08,0x52,0x00,0x01,
76 | 0x58,0x03,0x03,0x01,0x00,0x0b,0x48,0x00,0x00,0x2c,0x00,0x25,0x50,0x80,0xc0,0x00,
77 | 0x79,0x4d,0xf0,0x55,0xff,0xfe,0x49,0xc0,0x48,0x80,0x00,0x6b,0x4f,0x06,0x48,0x3f,
78 | 0x00,0x0e,0x48,0x80,0x00,0x6f,0x48,0x01,0x00,0x12,0x4a,0xfe,0xc2,0xff,0x00,0x08,
79 | 0x4b,0xfc,0x49,0x7e,0x4a,0xfe,0xd3,0xfc,0x58,0x7c,0x3c,0x1c,0x00,0x53,0x50,0x3f,
80 | 0xff,0x00,0x11,0x49,0x01,0x91,0x03,0xc8,0x07,0x0c,0x03,0x03,0x01,0x01,0x00,0x44,
81 | 0x4b,0xf0,0xc2,0xff,0x68,0x7f,0x1f,0x07,0x01,0x00,0x00,0x09,0x4e,0x07,0x40,0x0a,
82 | 0xff,0x3f,0x3f,0x7f,0x7f,0xff,0xff,0xf0,0x60,0x00,0x00,0x00,0x52,0x4a,0x00,0x70,
83 | 0xc0,0xf8,0xff,0xff,0x1f,0x1f,0xc2,0xff,0x58,0xc0,0x00,0x00,0x00,0x0d,0x59,0x00,
84 | 0x80,0xc3,0x5b,0xff,0x7f,0x06,0x70,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0x52,0x74,
85 | 0x00,0x03,0x03,0x03,0x03,0x01,0x68,0x01,0x01,0x01,0x00,0x00,0x00,0x0b,0x53,0x00,
86 | 0x02,0x96,0x03,0xc1,0x01,0x00,0x30,0x00,0x27,0x48,0x80,0x00,0x76,0x53,0x80,0xc0,
87 | 0x4c,0xff,0x49,0xfc,0x4a,0xf8,0x48,0xe0,0x00,0x6c,0x5c,0x00,0x07,0x07,0x49,0x07,
88 | 0x50,0x1f,0x3f,0x00,0x09,0x68,0xff,0xfe,0xfc,0xf0,0xc0,0x00,0x6f,0x50,0x00,0x7f,
89 | 0x00,0x10,0x4b,0xfe,0x4f,0xfe,0x92,0xff,0x54,0xfe,0xfc,0x4a,0x7e,0xc3,0xfe,0x00,
90 | 0x51,0x5f,0x01,0x03,0x07,0x9f,0x7f,0x49,0x3f,0x48,0x3f,0x00,0x0b,0x54,0x3f,0x07,
91 | 0x49,0x00,0x91,0x01,0x9c,0x03,0xc1,0x03,0x00,0x48,0x49,0x80,0x4a,0xfe,0x78,0x7f,
92 | 0x0f,0x07,0x03,0x01,0x00,0x00,0x00,0x0a,0x64,0x01,0x07,0x1f,0x7f,0xc3,0xff,0x48,
93 | 0xe0,0xc2,0x00,0x00,0x55,0x49,0x00,0x52,0x80,0xe7,0x70,0xff,0xc7,0x00,0x00,0x00,
94 | 0x00,0x00,0x10,0x59,0x00,0x81,0xc7,0xc2,0xff,0x68,0x1f,0x07,0x01,0x00,0x00,0x00,
95 | 0x56,0x4a,0x01,0x4d,0x01,0xc2,0x00,0x00,0x0e,0x76,0x00,0x00,0x01,0x01,0x01,0x01,
96 | 0xc1,0x00,0x00,0x30,0x00,0x27,0x48,0x00,0x00,0x79,0x4e,0xf8,0x4c,0xf8,0x48,0xc0,
97 | 0x00,0x6c,0x4a,0x02,0x49,0x07,0x91,0x07,0x50,0x07,0x0f,0x00,0x0c,0x4a,0xf8,0x48,
98 | 0x80,0x00,0x86,0xc1,0xfe,0x00,0x0b,0x57,0x7e,0x3e,0x48,0xfc,0x00,0x12,0x48,0x00,
99 | 0x00,0x3f,0x4e,0xef,0x97,0x3f,0x93,0x3f,0x48,0x3f,0x00,0x0a,0x55,0x1f,0x00,0x4a,
100 | 0x00,0x4b,0x01,0xa3,0x03,0xc1,0x01,0x00,0x44,0x62,0xf0,0xfc,0xff,0xff,0x68,0xff,
101 | 0xff,0x1f,0x01,0x00,0x00,0x0c,0x7c,0x00,0x00,0x03,0x07,0x0f,0x1f,0x7f,0x50,0x80,
102 | 0x00,0x00,0x59,0x5a,0x00,0x87,0xbf,0x58,0x7f,0x1f,0x07,0x00,0x14,0x5c,0x00,0xf0,
103 | 0xfc,0xc1,0x00,0x00,0x58,0x5a,0x00,0x01,0x01,0x48,0x01,0x00,0x16,0x92,0x00,0xc1,
104 | 0x01,0x00,0x36,0x00,0x24,0x49,0x80,0x48,0x80,0x00,0x7f,0x59,0xfe,0xfc,0xfc,0x49,
105 | 0xf0,0x68,0xf0,0xe0,0xe0,0xc0,0x80,0x00,0x6c,0x49,0x0f,0x70,0x0f,0x0f,0x0f,0x0f,
106 | 0x1f,0x7f,0x00,0x0a,0x50,0xff,0xfe,0x00,0x84,0xbe,0xff,0x4a,0xfe,0x49,0xfc,0x53,
107 | 0xfc,0x3c,0x93,0x7e,0xce,0xfe,0x5a,0x7e,0x7e,0x3c,0x48,0x08,0x00,0x3d,0x58,0x81,
108 | 0xc7,0xf7,0x00,0x0e,0x48,0x7f,0x00,0x0f,0x4f,0x7f,0xc2,0x00,0xc9,0x01,0x10,0xc1,
109 | 0x00,0x00,0x40,0x7b,0xe0,0xf8,0x7e,0x3f,0x1f,0x07,0x87,0x50,0x7f,0x03,0x00,0x12,
110 | 0x54,0x9f,0xff,0x48,0xff,0x00,0x59,0x40,0x09,0x3f,0x7f,0x00,0x00,0x80,0xe0,0xff,
111 | 0xff,0x3f,0x0f,0x00,0x11,0x40,0x09,0x78,0x3c,0x1e,0x0f,0x87,0x81,0xc0,0xf9,0xff,
112 | 0x0f,0x00,0x5a,0x93,0x00,0x48,0x01,0x00,0x17,0x4b,0x00,0x48,0x01,0x00,0x35,0x00,
113 | 0x24,0x49,0x00,0x48,0x00,0x00,0x81,0x49,0xf8,0x49,0xf8,0x49,0xe0,0x58,0xc0,0x80,
114 | 0x00,0x00,0x6b,0x4d,0x0f,0x58,0x1f,0x3f,0xff,0x00,0x0a,0x50,0xfc,0xf8,0x00,0x71,
115 | 0x50,0x07,0xff,0x00,0x0f,0xc3,0xfe,0x00,0x07,0xc1,0xfe,0x00,0x0a,0x48,0xfe,0x00,
116 | 0x10,0x49,0x7e,0x49,0x3e,0x58,0x1c,0x0c,0x00,0x00,0x3c,0x66,0x80,0xc3,0xf3,0xff,
117 | 0x50,0xff,0x7f,0x00,0x17,0x50,0xff,0x08,0x00,0x08,0x4e,0x00,0xc4,0x00,0x00,0x40,
118 | 0x79,0xc0,0xf0,0xfc,0x3f,0x3f,0x1f,0x0f,0x4b,0x07,0x58,0xff,0x3f,0x01,0x00,0x0e,
119 | 0x61,0x07,0x8f,0xff,0xff,0x61,0x7f,0x3f,0x7f,0x7f,0x58,0xff,0xf0,0xc0,0x00,0x52,
120 | 0x73,0x70,0x7e,0x7f,0x1f,0x01,0x00,0x51,0x80,0xc0,0x58,0xff,0x3f,0x07,0x00,0x0d,
121 | 0x78,0x70,0x7c,0x3e,0x1f,0x0f,0x07,0x03,0xc2,0x00,0x70,0x80,0x80,0xff,0xff,0x7f,
122 | 0x0f,0x00,0x59,0x52,0x00,0x03,0x48,0x01,0x00,0x17,0x78,0x00,0x00,0x00,0x03,0x01,
123 | 0x01,0x01,0x00,0x32,0x00,0xa0,0x5d,0x80,0xe0,0xf0,0x4a,0xf8,0x4a,0xf0,0x58,0xc0,
124 | 0x80,0x00,0x00,0x6a,0x55,0x06,0x0e,0x58,0x1f,0x3f,0x7f,0x00,0x0a,0x4a,0xfe,0x48,
125 | 0xe0,0x00,0x70,0x48,0x1f,0x00,0x10,0xa7,0xff,0x4e,0xfe,0xc2,0xfe,0x00,0x18,0x58,
126 | 0x1e,0x0e,0x04,0x00,0x3d,0x58,0x00,0x03,0xc7,0x00,0x07,0x48,0xff,0x00,0x07,0x4b,
127 | 0x7f,0x48,0xff,0x00,0x0b,0x5d,0xff,0xfe,0xe0,0x9e,0x01,0xc1,0x01,0x00,0x43,0x40,
128 | 0x0b,0x00,0x80,0xf0,0xf8,0xfe,0x7f,0x3f,0x1f,0x0f,0x07,0x03,0x7f,0x08,0xc2,0xff,
129 | 0x00,0x0c,0x5b,0x07,0x1f,0xff,0x40,0x0b,0x07,0x0f,0x1f,0x3f,0x3f,0x7f,0x7f,0xff,
130 | 0xff,0xf0,0xc0,0xc0,0x00,0x4e,0x72,0x80,0xe0,0xfc,0xff,0x3f,0x07,0xc2,0x00,0x78,
131 | 0x80,0x80,0xe0,0xff,0xff,0x3f,0x0f,0x00,0x09,0x79,0xc0,0xe0,0xf0,0x7c,0x3f,0x1f,
132 | 0x0f,0x4a,0x01,0xc3,0x00,0x70,0x80,0x80,0xc1,0xff,0xff,0x1f,0x00,0x56,0x99,0x00,
133 | 0xc3,0x01,0x00,0x16,0xc3,0x00,0xc4,0x01,0x00,0x2d,0x00,0x9f,0x57,0x00,0xc0,0x68,
134 | 0xfc,0xf0,0xf0,0xe0,0xe0,0x00,0x6d,0x58,0x04,0x0e,0x1e,0xc4,0x1f,0x11,0xff,0x00,
135 | 0x0c,0x48,0xf0,0x00,0x70,0x50,0x01,0x7f,0x00,0x1b,0x94,0xff,0x4a,0xfe,0x60,0xff,
136 | 0xff,0x7f,0x7f,0xc7,0xff,0x18,0xc7,0xff,0x60,0x7f,0x7f,0x3f,0x1f,0x0a,0x06,0x02,
137 | 0x00,0x3c,0x60,0x01,0x07,0x87,0xef,0x00,0x07,0xb3,0xff,0x58,0x7f,0x7f,0xff,0x00,
138 | 0x0d,0x5b,0xff,0xfc,0x80,0x48,0x01,0x00,0x0a,0x48,0x01,0x00,0x43,0x40,0x0d,0x00,
139 | 0x00,0xe0,0xf8,0xfe,0xff,0x7f,0x1f,0x0f,0x07,0x03,0x01,0x00,0x0f,0x08,0xc2,0xff,
140 | 0x00,0x07,0x62,0x07,0x3f,0x7f,0xff,0x52,0x9f,0x07,0x40,0x0b,0x0f,0x1f,0x1f,0x3f,
141 | 0x3f,0x7f,0x7f,0xff,0xfc,0xf0,0xe0,0xe0,0x00,0x4d,0x7b,0xc0,0xe0,0xf8,0xff,0x7f,
142 | 0x1f,0x07,0xc4,0x00,0xc1,0x80,0xc2,0xff,0x4d,0x0e,0x6c,0xc0,0xe0,0xf0,0xf8,0x7e,
143 | 0x4e,0x00,0xc3,0x00,0x48,0x83,0xc2,0xff,0x00,0x4c,0xa7,0x01,0xa1,0x00,0x60,0x01,
144 | 0x03,0x03,0x01,0x00,0x16,0x99,0x00,0x60,0x03,0x03,0x03,0x01,0x00,0x2a
145 | };
146 |
147 | //
148 | // Byte operands for compressing the data
149 | // The first 2 bits are the type, followed by the counts
150 | #define OP_MASK 0xc0
151 | #define OP_SKIPCOPY 0x00
152 | #define OP_COPYSKIP 0x40
153 | #define OP_REPEATSKIP 0x80
154 | #define OP_REPEAT 0xc0
155 |
156 | // Some globals
157 | static int iScreenOffset; // current write offset of screen data
158 | static int iFrameDelay; // milliseconds to pause between frames
159 | static byte oled_addr; // I2C address of the display
160 | static void oledWriteCommand(unsigned char c);
161 | // Hardware ports of the AVR
162 | #define I2CPORT PORTB
163 | // A bit set to 1 in the DDR is an output, 0 is an INPUT
164 | #define I2CDDR DDRB
165 |
166 | // Pin or port numbers for SDA and SCL
167 | #define BB_SDA 0
168 | #define BB_SCL 2
169 | #define DELAY 1
170 | #ifndef DELAY_CYCLES
171 | #define DELAY_CYCLES(n) __builtin_avr_delay_cycles(n)
172 | #endif
173 |
174 | //
175 | // If the display doesn't properly implement the horizontal addressing mode, it requires
176 | // additional effort to transmit the images
177 | //
178 | #define BAD_DISPLAY
179 | //
180 | // Transmit a byte and ack bit
181 | //
182 | static inline void i2cByteOut(byte b)
183 | {
184 | byte i;
185 | byte bOld = I2CPORT & ~((1 << BB_SDA) | (1 << BB_SCL));
186 |
187 | for (i=0; i<8; i++)
188 | {
189 | bOld &= ~(1 << BB_SDA);
190 | if (b & 0x80)
191 | bOld |= (1 << BB_SDA);
192 | I2CPORT = bOld;
193 | DELAY_CYCLES(DELAY);
194 | I2CPORT |= (1 << BB_SCL);
195 | DELAY_CYCLES(DELAY);
196 | I2CPORT = bOld;
197 | b <<= 1;
198 | } // for i
199 | // ack bit
200 | I2CPORT = bOld & ~(1 << BB_SDA); // set data low
201 | DELAY_CYCLES(DELAY);
202 | I2CPORT |= (1 << BB_SCL); // toggle clock
203 | DELAY_CYCLES(DELAY);
204 | I2CPORT = bOld;
205 | } /* i2cByteOut() */
206 |
207 | void i2cBegin(byte addr)
208 | {
209 | I2CPORT |= ((1 << BB_SDA) + (1 << BB_SCL));
210 | I2CDDR |= ((1 << BB_SDA) + (1 << BB_SCL));
211 | I2CPORT &= ~(1 << BB_SDA); // data line low first
212 | DELAY_CYCLES(DELAY);
213 | I2CPORT &= ~(1 << BB_SCL); // then clock line low is a START signal
214 | i2cByteOut(addr << 1); // send the slave address
215 | } /* i2cBegin() */
216 |
217 | void i2cWrite(byte *pData, byte bLen)
218 | {
219 | byte b;
220 |
221 | while (bLen--)
222 | {
223 | b = *pData++;
224 | i2cByteOut(b);
225 | } // for each byte
226 | } /* i2cWrite() */
227 |
228 | //
229 | // Send I2C STOP condition
230 | //
231 | void i2cEnd()
232 | {
233 | I2CPORT &= ~(1 << BB_SDA);
234 | I2CPORT |= (1 << BB_SCL);
235 | I2CPORT |= (1 << BB_SDA);
236 | I2CDDR &= ((1 << BB_SDA) | (1 << BB_SCL)); // let the lines float (tri-state)
237 | } /* i2cEnd() */
238 |
239 | // Wrapper function to write I2C data on Arduino
240 | static void I2CWrite(int iAddr, unsigned char *pData, int iLen)
241 | {
242 | i2cBegin(iAddr);
243 | i2cWrite(pData, iLen);
244 | i2cEnd();
245 | } /* I2CWrite() */
246 | //
247 | // Write a block of flash memory to the display
248 | //
249 | void oledWriteFlashBlock(byte *s, int iLen)
250 | {
251 | int i;
252 | byte b;
253 |
254 | #ifdef BAD_DISPLAY
255 | {
256 | int j;
257 | while (((iScreenOffset & 0x7f) + iLen) >= 128) // if it will hit the page end
258 | {
259 | j = 128 - (iScreenOffset & 0x7f); // amount we can write in one shot
260 | i2cBegin(oled_addr);
261 | i2cByteOut(0x40); // start of data
262 | for (i=0; i> 7));
271 | } // while it needs some help
272 | }
273 | #endif // simpler case and leftover bytes
274 | i2cBegin(oled_addr);
275 | i2cByteOut(0x40); // start of data
276 | for (i=0; i= 128) // if it will hit the page end
296 | {
297 | j = 128 - (iScreenOffset & 0x7f); // amount we can write in one shot
298 | i2cBegin(oled_addr);
299 | i2cByteOut(0x40); // start of data
300 | for (i=0; i> 7));
308 | } // while it needs some help
309 | }
310 | #endif // simpler case and leftover bytes
311 | i2cBegin(oled_addr);
312 | i2cByteOut(0x40); // start of data
313 | for (i=0; i> 4) & 0xf)); // upper col addr
398 | iScreenOffset = (y*128)+x;
399 | }
400 |
401 | void oledPlayAnim(int iRate, int iLoop)
402 | {
403 | byte *s;
404 | byte *pEnd;
405 | int j, l, i;
406 | unsigned char b, bCode;
407 |
408 | iFrameDelay = (1000UL / (long)iRate);
409 | for (l=0; l> 7));
428 | }
429 | else // skip/copy
430 | {
431 | if (bCode & 0x38)
432 | {
433 | i += ((bCode & 0x38) >> 3); // skip amount
434 | oledSetPosition(i & 0x7f, (i >> 7));
435 | }
436 | if (bCode & 7)
437 | {
438 | oledWriteFlashBlock(s, bCode & 7);
439 | s += (bCode & 7);
440 | i += bCode & 7;
441 | }
442 | }
443 | break;
444 | case OP_COPYSKIP: // copy/skip
445 | if (bCode == OP_COPYSKIP) // big copy
446 | {
447 | b = pgm_read_byte(s++);
448 | j = b + 1;
449 | oledWriteFlashBlock(s, j);
450 | s += j;
451 | i += j;
452 | }
453 | else
454 | {
455 | j = ((bCode & 0x38) >> 3);
456 | if (j)
457 | {
458 | oledWriteFlashBlock(s, j);
459 | s += j;
460 | i += j;
461 | }
462 | if (bCode & 7)
463 | {
464 | i += (bCode & 7); // skip
465 | oledSetPosition(i & 0x7f, (i >> 7));
466 | }
467 | }
468 | break;
469 | case OP_REPEATSKIP: // repeat/skip
470 | j = (bCode & 0x38) >> 3; // repeat count
471 | b = pgm_read_byte(s++);
472 | oledRepeatByte(b, j);
473 | i += j;
474 | if (bCode & 7)
475 | {
476 | i += (bCode & 7); // skip amount
477 | oledSetPosition(i & 0x7f, (i >> 7));
478 | }
479 | break;
480 |
481 | case OP_REPEAT:
482 | j = (bCode & 0x3f) + 1;
483 | b = pgm_read_byte(s++);
484 | oledRepeatByte(b, j);
485 | i += j;
486 | break;
487 | } // switch on code type
488 | } // while rendering frame
489 | delay(iFrameDelay);
490 | } // while playing frames
491 | } // for loop count
492 | } /* PlayAnim() */
493 |
494 | //
495 | // Fill the frame buffer with a byte pattern
496 | // e.g. all off (0x00) or all on (0xff)
497 | //
498 | void oledFill(unsigned char ucData)
499 | {
500 | int y;
501 |
502 | for (y=0; y<8; y++)
503 | {
504 | oledSetPosition(0,y); // set to (0,Y)
505 | oledRepeatByte(ucData, 128);
506 | } // for y
507 | } /* oledFill() */
508 |
509 | void setup() {
510 | // put your setup code here, to run once:
511 | delay(50); // wait for the OLED to fully power up
512 | oledInit(0x3c, 0, 0);
513 | oledFill(0);
514 | }
515 |
516 | void loop() {
517 | // put your main code here, to run repeatedly:
518 | oledPlayAnim(30, 5); // play 5 loops at 20FPS
519 | }
520 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | GNU GENERAL PUBLIC LICENSE
2 | Version 3, 29 June 2007
3 |
4 | Copyright (C) 2007 Free Software Foundation, Inc.
5 | Everyone is permitted to copy and distribute verbatim copies
6 | of this license document, but changing it is not allowed.
7 |
8 | Preamble
9 |
10 | The GNU General Public License is a free, copyleft license for
11 | software and other kinds of works.
12 |
13 | The licenses for most software and other practical works are designed
14 | to take away your freedom to share and change the works. By contrast,
15 | the GNU General Public License is intended to guarantee your freedom to
16 | share and change all versions of a program--to make sure it remains free
17 | software for all its users. We, the Free Software Foundation, use the
18 | GNU General Public License for most of our software; it applies also to
19 | any other work released this way by its authors. You can apply it to
20 | your programs, too.
21 |
22 | When we speak of free software, we are referring to freedom, not
23 | price. Our General Public Licenses are designed to make sure that you
24 | have the freedom to distribute copies of free software (and charge for
25 | them if you wish), that you receive source code or can get it if you
26 | want it, that you can change the software or use pieces of it in new
27 | free programs, and that you know you can do these things.
28 |
29 | To protect your rights, we need to prevent others from denying you
30 | these rights or asking you to surrender the rights. Therefore, you have
31 | certain responsibilities if you distribute copies of the software, or if
32 | you modify it: responsibilities to respect the freedom of others.
33 |
34 | For example, if you distribute copies of such a program, whether
35 | gratis or for a fee, you must pass on to the recipients the same
36 | freedoms that you received. You must make sure that they, too, receive
37 | or can get the source code. And you must show them these terms so they
38 | know their rights.
39 |
40 | Developers that use the GNU GPL protect your rights with two steps:
41 | (1) assert copyright on the software, and (2) offer you this License
42 | giving you legal permission to copy, distribute and/or modify it.
43 |
44 | For the developers' and authors' protection, the GPL clearly explains
45 | that there is no warranty for this free software. For both users' and
46 | authors' sake, the GPL requires that modified versions be marked as
47 | changed, so that their problems will not be attributed erroneously to
48 | authors of previous versions.
49 |
50 | Some devices are designed to deny users access to install or run
51 | modified versions of the software inside them, although the manufacturer
52 | can do so. This is fundamentally incompatible with the aim of
53 | protecting users' freedom to change the software. The systematic
54 | pattern of such abuse occurs in the area of products for individuals to
55 | use, which is precisely where it is most unacceptable. Therefore, we
56 | have designed this version of the GPL to prohibit the practice for those
57 | products. If such problems arise substantially in other domains, we
58 | stand ready to extend this provision to those domains in future versions
59 | of the GPL, as needed to protect the freedom of users.
60 |
61 | Finally, every program is threatened constantly by software patents.
62 | States should not allow patents to restrict development and use of
63 | software on general-purpose computers, but in those that do, we wish to
64 | avoid the special danger that patents applied to a free program could
65 | make it effectively proprietary. To prevent this, the GPL assures that
66 | patents cannot be used to render the program non-free.
67 |
68 | The precise terms and conditions for copying, distribution and
69 | modification follow.
70 |
71 | TERMS AND CONDITIONS
72 |
73 | 0. Definitions.
74 |
75 | "This License" refers to version 3 of the GNU General Public License.
76 |
77 | "Copyright" also means copyright-like laws that apply to other kinds of
78 | works, such as semiconductor masks.
79 |
80 | "The Program" refers to any copyrightable work licensed under this
81 | License. Each licensee is addressed as "you". "Licensees" and
82 | "recipients" may be individuals or organizations.
83 |
84 | To "modify" a work means to copy from or adapt all or part of the work
85 | in a fashion requiring copyright permission, other than the making of an
86 | exact copy. The resulting work is called a "modified version" of the
87 | earlier work or a work "based on" the earlier work.
88 |
89 | A "covered work" means either the unmodified Program or a work based
90 | on the Program.
91 |
92 | To "propagate" a work means to do anything with it that, without
93 | permission, would make you directly or secondarily liable for
94 | infringement under applicable copyright law, except executing it on a
95 | computer or modifying a private copy. Propagation includes copying,
96 | distribution (with or without modification), making available to the
97 | public, and in some countries other activities as well.
98 |
99 | To "convey" a work means any kind of propagation that enables other
100 | parties to make or receive copies. Mere interaction with a user through
101 | a computer network, with no transfer of a copy, is not conveying.
102 |
103 | An interactive user interface displays "Appropriate Legal Notices"
104 | to the extent that it includes a convenient and prominently visible
105 | feature that (1) displays an appropriate copyright notice, and (2)
106 | tells the user that there is no warranty for the work (except to the
107 | extent that warranties are provided), that licensees may convey the
108 | work under this License, and how to view a copy of this License. If
109 | the interface presents a list of user commands or options, such as a
110 | menu, a prominent item in the list meets this criterion.
111 |
112 | 1. Source Code.
113 |
114 | The "source code" for a work means the preferred form of the work
115 | for making modifications to it. "Object code" means any non-source
116 | form of a work.
117 |
118 | A "Standard Interface" means an interface that either is an official
119 | standard defined by a recognized standards body, or, in the case of
120 | interfaces specified for a particular programming language, one that
121 | is widely used among developers working in that language.
122 |
123 | The "System Libraries" of an executable work include anything, other
124 | than the work as a whole, that (a) is included in the normal form of
125 | packaging a Major Component, but which is not part of that Major
126 | Component, and (b) serves only to enable use of the work with that
127 | Major Component, or to implement a Standard Interface for which an
128 | implementation is available to the public in source code form. A
129 | "Major Component", in this context, means a major essential component
130 | (kernel, window system, and so on) of the specific operating system
131 | (if any) on which the executable work runs, or a compiler used to
132 | produce the work, or an object code interpreter used to run it.
133 |
134 | The "Corresponding Source" for a work in object code form means all
135 | the source code needed to generate, install, and (for an executable
136 | work) run the object code and to modify the work, including scripts to
137 | control those activities. However, it does not include the work's
138 | System Libraries, or general-purpose tools or generally available free
139 | programs which are used unmodified in performing those activities but
140 | which are not part of the work. For example, Corresponding Source
141 | includes interface definition files associated with source files for
142 | the work, and the source code for shared libraries and dynamically
143 | linked subprograms that the work is specifically designed to require,
144 | such as by intimate data communication or control flow between those
145 | subprograms and other parts of the work.
146 |
147 | The Corresponding Source need not include anything that users
148 | can regenerate automatically from other parts of the Corresponding
149 | Source.
150 |
151 | The Corresponding Source for a work in source code form is that
152 | same work.
153 |
154 | 2. Basic Permissions.
155 |
156 | All rights granted under this License are granted for the term of
157 | copyright on the Program, and are irrevocable provided the stated
158 | conditions are met. This License explicitly affirms your unlimited
159 | permission to run the unmodified Program. The output from running a
160 | covered work is covered by this License only if the output, given its
161 | content, constitutes a covered work. This License acknowledges your
162 | rights of fair use or other equivalent, as provided by copyright law.
163 |
164 | You may make, run and propagate covered works that you do not
165 | convey, without conditions so long as your license otherwise remains
166 | in force. You may convey covered works to others for the sole purpose
167 | of having them make modifications exclusively for you, or provide you
168 | with facilities for running those works, provided that you comply with
169 | the terms of this License in conveying all material for which you do
170 | not control copyright. Those thus making or running the covered works
171 | for you must do so exclusively on your behalf, under your direction
172 | and control, on terms that prohibit them from making any copies of
173 | your copyrighted material outside their relationship with you.
174 |
175 | Conveying under any other circumstances is permitted solely under
176 | the conditions stated below. Sublicensing is not allowed; section 10
177 | makes it unnecessary.
178 |
179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
180 |
181 | No covered work shall be deemed part of an effective technological
182 | measure under any applicable law fulfilling obligations under article
183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or
184 | similar laws prohibiting or restricting circumvention of such
185 | measures.
186 |
187 | When you convey a covered work, you waive any legal power to forbid
188 | circumvention of technological measures to the extent such circumvention
189 | is effected by exercising rights under this License with respect to
190 | the covered work, and you disclaim any intention to limit operation or
191 | modification of the work as a means of enforcing, against the work's
192 | users, your or third parties' legal rights to forbid circumvention of
193 | technological measures.
194 |
195 | 4. Conveying Verbatim Copies.
196 |
197 | You may convey verbatim copies of the Program's source code as you
198 | receive it, in any medium, provided that you conspicuously and
199 | appropriately publish on each copy an appropriate copyright notice;
200 | keep intact all notices stating that this License and any
201 | non-permissive terms added in accord with section 7 apply to the code;
202 | keep intact all notices of the absence of any warranty; and give all
203 | recipients a copy of this License along with the Program.
204 |
205 | You may charge any price or no price for each copy that you convey,
206 | and you may offer support or warranty protection for a fee.
207 |
208 | 5. Conveying Modified Source Versions.
209 |
210 | You may convey a work based on the Program, or the modifications to
211 | produce it from the Program, in the form of source code under the
212 | terms of section 4, provided that you also meet all of these conditions:
213 |
214 | a) The work must carry prominent notices stating that you modified
215 | it, and giving a relevant date.
216 |
217 | b) The work must carry prominent notices stating that it is
218 | released under this License and any conditions added under section
219 | 7. This requirement modifies the requirement in section 4 to
220 | "keep intact all notices".
221 |
222 | c) You must license the entire work, as a whole, under this
223 | License to anyone who comes into possession of a copy. This
224 | License will therefore apply, along with any applicable section 7
225 | additional terms, to the whole of the work, and all its parts,
226 | regardless of how they are packaged. This License gives no
227 | permission to license the work in any other way, but it does not
228 | invalidate such permission if you have separately received it.
229 |
230 | d) If the work has interactive user interfaces, each must display
231 | Appropriate Legal Notices; however, if the Program has interactive
232 | interfaces that do not display Appropriate Legal Notices, your
233 | work need not make them do so.
234 |
235 | A compilation of a covered work with other separate and independent
236 | works, which are not by their nature extensions of the covered work,
237 | and which are not combined with it such as to form a larger program,
238 | in or on a volume of a storage or distribution medium, is called an
239 | "aggregate" if the compilation and its resulting copyright are not
240 | used to limit the access or legal rights of the compilation's users
241 | beyond what the individual works permit. Inclusion of a covered work
242 | in an aggregate does not cause this License to apply to the other
243 | parts of the aggregate.
244 |
245 | 6. Conveying Non-Source Forms.
246 |
247 | You may convey a covered work in object code form under the terms
248 | of sections 4 and 5, provided that you also convey the
249 | machine-readable Corresponding Source under the terms of this License,
250 | in one of these ways:
251 |
252 | a) Convey the object code in, or embodied in, a physical product
253 | (including a physical distribution medium), accompanied by the
254 | Corresponding Source fixed on a durable physical medium
255 | customarily used for software interchange.
256 |
257 | b) Convey the object code in, or embodied in, a physical product
258 | (including a physical distribution medium), accompanied by a
259 | written offer, valid for at least three years and valid for as
260 | long as you offer spare parts or customer support for that product
261 | model, to give anyone who possesses the object code either (1) a
262 | copy of the Corresponding Source for all the software in the
263 | product that is covered by this License, on a durable physical
264 | medium customarily used for software interchange, for a price no
265 | more than your reasonable cost of physically performing this
266 | conveying of source, or (2) access to copy the
267 | Corresponding Source from a network server at no charge.
268 |
269 | c) Convey individual copies of the object code with a copy of the
270 | written offer to provide the Corresponding Source. This
271 | alternative is allowed only occasionally and noncommercially, and
272 | only if you received the object code with such an offer, in accord
273 | with subsection 6b.
274 |
275 | d) Convey the object code by offering access from a designated
276 | place (gratis or for a charge), and offer equivalent access to the
277 | Corresponding Source in the same way through the same place at no
278 | further charge. You need not require recipients to copy the
279 | Corresponding Source along with the object code. If the place to
280 | copy the object code is a network server, the Corresponding Source
281 | may be on a different server (operated by you or a third party)
282 | that supports equivalent copying facilities, provided you maintain
283 | clear directions next to the object code saying where to find the
284 | Corresponding Source. Regardless of what server hosts the
285 | Corresponding Source, you remain obligated to ensure that it is
286 | available for as long as needed to satisfy these requirements.
287 |
288 | e) Convey the object code using peer-to-peer transmission, provided
289 | you inform other peers where the object code and Corresponding
290 | Source of the work are being offered to the general public at no
291 | charge under subsection 6d.
292 |
293 | A separable portion of the object code, whose source code is excluded
294 | from the Corresponding Source as a System Library, need not be
295 | included in conveying the object code work.
296 |
297 | A "User Product" is either (1) a "consumer product", which means any
298 | tangible personal property which is normally used for personal, family,
299 | or household purposes, or (2) anything designed or sold for incorporation
300 | into a dwelling. In determining whether a product is a consumer product,
301 | doubtful cases shall be resolved in favor of coverage. For a particular
302 | product received by a particular user, "normally used" refers to a
303 | typical or common use of that class of product, regardless of the status
304 | of the particular user or of the way in which the particular user
305 | actually uses, or expects or is expected to use, the product. A product
306 | is a consumer product regardless of whether the product has substantial
307 | commercial, industrial or non-consumer uses, unless such uses represent
308 | the only significant mode of use of the product.
309 |
310 | "Installation Information" for a User Product means any methods,
311 | procedures, authorization keys, or other information required to install
312 | and execute modified versions of a covered work in that User Product from
313 | a modified version of its Corresponding Source. The information must
314 | suffice to ensure that the continued functioning of the modified object
315 | code is in no case prevented or interfered with solely because
316 | modification has been made.
317 |
318 | If you convey an object code work under this section in, or with, or
319 | specifically for use in, a User Product, and the conveying occurs as
320 | part of a transaction in which the right of possession and use of the
321 | User Product is transferred to the recipient in perpetuity or for a
322 | fixed term (regardless of how the transaction is characterized), the
323 | Corresponding Source conveyed under this section must be accompanied
324 | by the Installation Information. But this requirement does not apply
325 | if neither you nor any third party retains the ability to install
326 | modified object code on the User Product (for example, the work has
327 | been installed in ROM).
328 |
329 | The requirement to provide Installation Information does not include a
330 | requirement to continue to provide support service, warranty, or updates
331 | for a work that has been modified or installed by the recipient, or for
332 | the User Product in which it has been modified or installed. Access to a
333 | network may be denied when the modification itself materially and
334 | adversely affects the operation of the network or violates the rules and
335 | protocols for communication across the network.
336 |
337 | Corresponding Source conveyed, and Installation Information provided,
338 | in accord with this section must be in a format that is publicly
339 | documented (and with an implementation available to the public in
340 | source code form), and must require no special password or key for
341 | unpacking, reading or copying.
342 |
343 | 7. Additional Terms.
344 |
345 | "Additional permissions" are terms that supplement the terms of this
346 | License by making exceptions from one or more of its conditions.
347 | Additional permissions that are applicable to the entire Program shall
348 | be treated as though they were included in this License, to the extent
349 | that they are valid under applicable law. If additional permissions
350 | apply only to part of the Program, that part may be used separately
351 | under those permissions, but the entire Program remains governed by
352 | this License without regard to the additional permissions.
353 |
354 | When you convey a copy of a covered work, you may at your option
355 | remove any additional permissions from that copy, or from any part of
356 | it. (Additional permissions may be written to require their own
357 | removal in certain cases when you modify the work.) You may place
358 | additional permissions on material, added by you to a covered work,
359 | for which you have or can give appropriate copyright permission.
360 |
361 | Notwithstanding any other provision of this License, for material you
362 | add to a covered work, you may (if authorized by the copyright holders of
363 | that material) supplement the terms of this License with terms:
364 |
365 | a) Disclaiming warranty or limiting liability differently from the
366 | terms of sections 15 and 16 of this License; or
367 |
368 | b) Requiring preservation of specified reasonable legal notices or
369 | author attributions in that material or in the Appropriate Legal
370 | Notices displayed by works containing it; or
371 |
372 | c) Prohibiting misrepresentation of the origin of that material, or
373 | requiring that modified versions of such material be marked in
374 | reasonable ways as different from the original version; or
375 |
376 | d) Limiting the use for publicity purposes of names of licensors or
377 | authors of the material; or
378 |
379 | e) Declining to grant rights under trademark law for use of some
380 | trade names, trademarks, or service marks; or
381 |
382 | f) Requiring indemnification of licensors and authors of that
383 | material by anyone who conveys the material (or modified versions of
384 | it) with contractual assumptions of liability to the recipient, for
385 | any liability that these contractual assumptions directly impose on
386 | those licensors and authors.
387 |
388 | All other non-permissive additional terms are considered "further
389 | restrictions" within the meaning of section 10. If the Program as you
390 | received it, or any part of it, contains a notice stating that it is
391 | governed by this License along with a term that is a further
392 | restriction, you may remove that term. If a license document contains
393 | a further restriction but permits relicensing or conveying under this
394 | License, you may add to a covered work material governed by the terms
395 | of that license document, provided that the further restriction does
396 | not survive such relicensing or conveying.
397 |
398 | If you add terms to a covered work in accord with this section, you
399 | must place, in the relevant source files, a statement of the
400 | additional terms that apply to those files, or a notice indicating
401 | where to find the applicable terms.
402 |
403 | Additional terms, permissive or non-permissive, may be stated in the
404 | form of a separately written license, or stated as exceptions;
405 | the above requirements apply either way.
406 |
407 | 8. Termination.
408 |
409 | You may not propagate or modify a covered work except as expressly
410 | provided under this License. Any attempt otherwise to propagate or
411 | modify it is void, and will automatically terminate your rights under
412 | this License (including any patent licenses granted under the third
413 | paragraph of section 11).
414 |
415 | However, if you cease all violation of this License, then your
416 | license from a particular copyright holder is reinstated (a)
417 | provisionally, unless and until the copyright holder explicitly and
418 | finally terminates your license, and (b) permanently, if the copyright
419 | holder fails to notify you of the violation by some reasonable means
420 | prior to 60 days after the cessation.
421 |
422 | Moreover, your license from a particular copyright holder is
423 | reinstated permanently if the copyright holder notifies you of the
424 | violation by some reasonable means, this is the first time you have
425 | received notice of violation of this License (for any work) from that
426 | copyright holder, and you cure the violation prior to 30 days after
427 | your receipt of the notice.
428 |
429 | Termination of your rights under this section does not terminate the
430 | licenses of parties who have received copies or rights from you under
431 | this License. If your rights have been terminated and not permanently
432 | reinstated, you do not qualify to receive new licenses for the same
433 | material under section 10.
434 |
435 | 9. Acceptance Not Required for Having Copies.
436 |
437 | You are not required to accept this License in order to receive or
438 | run a copy of the Program. Ancillary propagation of a covered work
439 | occurring solely as a consequence of using peer-to-peer transmission
440 | to receive a copy likewise does not require acceptance. However,
441 | nothing other than this License grants you permission to propagate or
442 | modify any covered work. These actions infringe copyright if you do
443 | not accept this License. Therefore, by modifying or propagating a
444 | covered work, you indicate your acceptance of this License to do so.
445 |
446 | 10. Automatic Licensing of Downstream Recipients.
447 |
448 | Each time you convey a covered work, the recipient automatically
449 | receives a license from the original licensors, to run, modify and
450 | propagate that work, subject to this License. You are not responsible
451 | for enforcing compliance by third parties with this License.
452 |
453 | An "entity transaction" is a transaction transferring control of an
454 | organization, or substantially all assets of one, or subdividing an
455 | organization, or merging organizations. If propagation of a covered
456 | work results from an entity transaction, each party to that
457 | transaction who receives a copy of the work also receives whatever
458 | licenses to the work the party's predecessor in interest had or could
459 | give under the previous paragraph, plus a right to possession of the
460 | Corresponding Source of the work from the predecessor in interest, if
461 | the predecessor has it or can get it with reasonable efforts.
462 |
463 | You may not impose any further restrictions on the exercise of the
464 | rights granted or affirmed under this License. For example, you may
465 | not impose a license fee, royalty, or other charge for exercise of
466 | rights granted under this License, and you may not initiate litigation
467 | (including a cross-claim or counterclaim in a lawsuit) alleging that
468 | any patent claim is infringed by making, using, selling, offering for
469 | sale, or importing the Program or any portion of it.
470 |
471 | 11. Patents.
472 |
473 | A "contributor" is a copyright holder who authorizes use under this
474 | License of the Program or a work on which the Program is based. The
475 | work thus licensed is called the contributor's "contributor version".
476 |
477 | A contributor's "essential patent claims" are all patent claims
478 | owned or controlled by the contributor, whether already acquired or
479 | hereafter acquired, that would be infringed by some manner, permitted
480 | by this License, of making, using, or selling its contributor version,
481 | but do not include claims that would be infringed only as a
482 | consequence of further modification of the contributor version. For
483 | purposes of this definition, "control" includes the right to grant
484 | patent sublicenses in a manner consistent with the requirements of
485 | this License.
486 |
487 | Each contributor grants you a non-exclusive, worldwide, royalty-free
488 | patent license under the contributor's essential patent claims, to
489 | make, use, sell, offer for sale, import and otherwise run, modify and
490 | propagate the contents of its contributor version.
491 |
492 | In the following three paragraphs, a "patent license" is any express
493 | agreement or commitment, however denominated, not to enforce a patent
494 | (such as an express permission to practice a patent or covenant not to
495 | sue for patent infringement). To "grant" such a patent license to a
496 | party means to make such an agreement or commitment not to enforce a
497 | patent against the party.
498 |
499 | If you convey a covered work, knowingly relying on a patent license,
500 | and the Corresponding Source of the work is not available for anyone
501 | to copy, free of charge and under the terms of this License, through a
502 | publicly available network server or other readily accessible means,
503 | then you must either (1) cause the Corresponding Source to be so
504 | available, or (2) arrange to deprive yourself of the benefit of the
505 | patent license for this particular work, or (3) arrange, in a manner
506 | consistent with the requirements of this License, to extend the patent
507 | license to downstream recipients. "Knowingly relying" means you have
508 | actual knowledge that, but for the patent license, your conveying the
509 | covered work in a country, or your recipient's use of the covered work
510 | in a country, would infringe one or more identifiable patents in that
511 | country that you have reason to believe are valid.
512 |
513 | If, pursuant to or in connection with a single transaction or
514 | arrangement, you convey, or propagate by procuring conveyance of, a
515 | covered work, and grant a patent license to some of the parties
516 | receiving the covered work authorizing them to use, propagate, modify
517 | or convey a specific copy of the covered work, then the patent license
518 | you grant is automatically extended to all recipients of the covered
519 | work and works based on it.
520 |
521 | A patent license is "discriminatory" if it does not include within
522 | the scope of its coverage, prohibits the exercise of, or is
523 | conditioned on the non-exercise of one or more of the rights that are
524 | specifically granted under this License. You may not convey a covered
525 | work if you are a party to an arrangement with a third party that is
526 | in the business of distributing software, under which you make payment
527 | to the third party based on the extent of your activity of conveying
528 | the work, and under which the third party grants, to any of the
529 | parties who would receive the covered work from you, a discriminatory
530 | patent license (a) in connection with copies of the covered work
531 | conveyed by you (or copies made from those copies), or (b) primarily
532 | for and in connection with specific products or compilations that
533 | contain the covered work, unless you entered into that arrangement,
534 | or that patent license was granted, prior to 28 March 2007.
535 |
536 | Nothing in this License shall be construed as excluding or limiting
537 | any implied license or other defenses to infringement that may
538 | otherwise be available to you under applicable patent law.
539 |
540 | 12. No Surrender of Others' Freedom.
541 |
542 | If conditions are imposed on you (whether by court order, agreement or
543 | otherwise) that contradict the conditions of this License, they do not
544 | excuse you from the conditions of this License. If you cannot convey a
545 | covered work so as to satisfy simultaneously your obligations under this
546 | License and any other pertinent obligations, then as a consequence you may
547 | not convey it at all. For example, if you agree to terms that obligate you
548 | to collect a royalty for further conveying from those to whom you convey
549 | the Program, the only way you could satisfy both those terms and this
550 | License would be to refrain entirely from conveying the Program.
551 |
552 | 13. Use with the GNU Affero General Public License.
553 |
554 | Notwithstanding any other provision of this License, you have
555 | permission to link or combine any covered work with a work licensed
556 | under version 3 of the GNU Affero General Public License into a single
557 | combined work, and to convey the resulting work. The terms of this
558 | License will continue to apply to the part which is the covered work,
559 | but the special requirements of the GNU Affero General Public License,
560 | section 13, concerning interaction through a network will apply to the
561 | combination as such.
562 |
563 | 14. Revised Versions of this License.
564 |
565 | The Free Software Foundation may publish revised and/or new versions of
566 | the GNU General Public License from time to time. Such new versions will
567 | be similar in spirit to the present version, but may differ in detail to
568 | address new problems or concerns.
569 |
570 | Each version is given a distinguishing version number. If the
571 | Program specifies that a certain numbered version of the GNU General
572 | Public License "or any later version" applies to it, you have the
573 | option of following the terms and conditions either of that numbered
574 | version or of any later version published by the Free Software
575 | Foundation. If the Program does not specify a version number of the
576 | GNU General Public License, you may choose any version ever published
577 | by the Free Software Foundation.
578 |
579 | If the Program specifies that a proxy can decide which future
580 | versions of the GNU General Public License can be used, that proxy's
581 | public statement of acceptance of a version permanently authorizes you
582 | to choose that version for the Program.
583 |
584 | Later license versions may give you additional or different
585 | permissions. However, no additional obligations are imposed on any
586 | author or copyright holder as a result of your choosing to follow a
587 | later version.
588 |
589 | 15. Disclaimer of Warranty.
590 |
591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
599 |
600 | 16. Limitation of Liability.
601 |
602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
610 | SUCH DAMAGES.
611 |
612 | 17. Interpretation of Sections 15 and 16.
613 |
614 | If the disclaimer of warranty and limitation of liability provided
615 | above cannot be given local legal effect according to their terms,
616 | reviewing courts shall apply local law that most closely approximates
617 | an absolute waiver of all civil liability in connection with the
618 | Program, unless a warranty or assumption of liability accompanies a
619 | copy of the Program in return for a fee.
620 |
621 | END OF TERMS AND CONDITIONS
622 |
623 | How to Apply These Terms to Your New Programs
624 |
625 | If you develop a new program, and you want it to be of the greatest
626 | possible use to the public, the best way to achieve this is to make it
627 | free software which everyone can redistribute and change under these terms.
628 |
629 | To do so, attach the following notices to the program. It is safest
630 | to attach them to the start of each source file to most effectively
631 | state the exclusion of warranty; and each file should have at least
632 | the "copyright" line and a pointer to where the full notice is found.
633 |
634 | {one line to give the program's name and a brief idea of what it does.}
635 | Copyright (C) {year} {name of author}
636 |
637 | This program is free software: you can redistribute it and/or modify
638 | it under the terms of the GNU General Public License as published by
639 | the Free Software Foundation, either version 3 of the License, or
640 | (at your option) any later version.
641 |
642 | This program is distributed in the hope that it will be useful,
643 | but WITHOUT ANY WARRANTY; without even the implied warranty of
644 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
645 | GNU General Public License for more details.
646 |
647 | You should have received a copy of the GNU General Public License
648 | along with this program. If not, see .
649 |
650 | Also add information on how to contact you by electronic and paper mail.
651 |
652 | If the program does terminal interaction, make it output a short
653 | notice like this when it starts in an interactive mode:
654 |
655 | {project} Copyright (C) {year} {fullname}
656 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
657 | This is free software, and you are welcome to redistribute it
658 | under certain conditions; type `show c' for details.
659 |
660 | The hypothetical commands `show w' and `show c' should show the appropriate
661 | parts of the General Public License. Of course, your program's commands
662 | might be different; for a GUI interface, you would use an "about box".
663 |
664 | You should also get your employer (if you work as a programmer) or school,
665 | if any, to sign a "copyright disclaimer" for the program, if necessary.
666 | For more information on this, and how to apply and follow the GNU GPL, see
667 | .
668 |
669 | The GNU General Public License does not permit incorporating your program
670 | into proprietary programs. If your program is a subroutine library, you
671 | may consider it more useful to permit linking proprietary applications with
672 | the library. If this is what you want to do, use the GNU Lesser General
673 | Public License instead of this License. But first, please read
674 | .
675 |
--------------------------------------------------------------------------------
/Linux/tcomp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bitbank2/oled_animator/bd43e9a4310b196c1a18cadba14e98e0ab998e9a/Linux/tcomp
--------------------------------------------------------------------------------
/MacOS/tcomp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bitbank2/oled_animator/bd43e9a4310b196c1a18cadba14e98e0ab998e9a/MacOS/tcomp
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | CFLAGS=-ggdb -c -Wall -O0
2 | LIBS = -lpil -lm -pthread
3 |
4 | all: tcomp
5 |
6 | tcomp: main.o
7 | $(CC) main.o $(LIBS) -g -o tcomp
8 |
9 | main.o: main.c
10 | $(CC) $(CFLAGS) main.c
11 |
12 | clean:
13 | rm *.o tcomp
14 |
15 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | *** OLED Animator ***
2 |
3 | OLED SSD1306 animation player using the I2C interface
4 | Copyright (c) 2018 BitBank Software, Inc.
5 | Written by Larry Bank (bitbank@pobox.com)
6 | Project started 5/21/2018
7 |
8 | This player can display compressed animation data on a SSD1306 OLED
9 | connected via I2C. The original purpose of the player was to make it easy
10 | to run interesting animations on Arduino AVR microcontrollers. Since AVRs
11 | don't have much memory (either flash or RAM), the goal of the data
12 | compression is to reduce the amount of memory needed for full screen
13 | arbitrary animations and reduce the amount of data written to the display
14 | so that slower, I2C connections could support good framerates.
15 | The compression scheme is my own invention. I'm
16 | not claiming that it can't be improved, but it satisfies the goals of
17 | being byte-oriented, simple to decompress and doesn't require any RAM
18 | on the player side. The data is compressed in 3 ways:
19 | 1) Skip - the bytes are identical to those of the previous frame
20 | 2) Copy - the bytes are different and are copied as-is
21 | 3) Repeat - a repeating byte sequence
22 | In order to not keep a copy of the display memory on the player, the
23 | skip operations just move the write address (cursor position) on the
24 | OLED display. The bytes are packed such that the highest 2 bits of each
25 | command byte determine the treatment. They are:
26 | 00SSSCCC - skip+copy (in that order). The 3 bit lengths of each of the
27 | skip and copy represent 0-7
28 | 00000000 - special case (long skip). The next byte is the len (1-256)
29 | 01CCCSSS - copy+skip (in that order). Same as above
30 | 01000000 - special case (long copy). The next byte is the len (1-256)
31 | 1RRRRRRR - Repeat the next byte 1-128 times.
32 |
33 | With those simple operations, typical animated GIF's get compressed between
34 | 3 and 6 to 1 (each 1024 byte frame becomes 170 to 341 bytes of compressed
35 | data)
36 |
37 | *** Note: ***
38 | The compressor uses my closed-source imaging library to decode animated GIFs. I need to find a solution to this, so in the mean time, the source code is here (minus the imaging library) and I have included pre-built binaries for Debian Linux and MacOS. I'll resolve this soon as well as provide the Arduino version.
39 |
40 |
--------------------------------------------------------------------------------
/grid.bin:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bitbank2/oled_animator/bd43e9a4310b196c1a18cadba14e98e0ab998e9a/grid.bin
--------------------------------------------------------------------------------
/main.c:
--------------------------------------------------------------------------------
1 | //
2 | // Tiny Compressor (tcomp)
3 | //
4 | // Project started 5/13/2018
5 | // Compress bitonal animated GIF into a compact format
6 | // suitable for micontroller playback
7 | //
8 |
9 | #include
10 | #include
11 | #include
12 | #include
13 | #include "pil.h"
14 | #include "pil_io.h"
15 |
16 | #define MAX_PATH 260
17 | static char szIn[MAX_PATH];
18 | static char szOut[MAX_PATH];
19 | static int iTop = -1;
20 | static int iLeft = -1;
21 | static int bC = 0; // write C code instead of binary data to output file
22 | static int bInvert = 0; // invert the bitmap colors
23 | //#define DEBUG_LOG
24 | //#define SAVE_INPUT_FRAMES
25 | //#define SAVE_OUTPUT_FRAMES
26 | //
27 | // Byte operands for compressing the data
28 | // The first 2 bits are the type, followed by the counts
29 | #define OP_MASK 0xc0
30 | #define OP_SKIPCOPY 0x00
31 | #define OP_COPYSKIP 0x40
32 | #define OP_REPEATSKIP 0x80
33 | #define OP_REPEAT 0xc0
34 | //
35 | // ShowHelp
36 | //
37 | // Display the help info when incorrect or no command line parameters are passed
38 | //
39 | void ShowHelp(void)
40 | {
41 | printf(
42 | "tiny_compress - compress bitonal animated GIF\n\n"
43 | "usage: ./tcomp \n"
44 | "valid options:\n\n"
45 | " --in Input file\n"
46 | " --out Output file\n"
47 | " --c Write C code to output file\n"
48 | " --invert Invert bitmap colors\n"
49 | " --top N Top of cropped area\n"
50 | " --left N Left of cropped area\n"
51 | );
52 | }
53 |
54 | static void parse_opts(int argc, char *argv[])
55 | {
56 | // set default options
57 | int i = 1;
58 |
59 | while (i < argc)
60 | {
61 | /* if it isn't a cmdline option, we're done */
62 | if (0 != strncmp("--", argv[i], 2))
63 | break;
64 | /* GNU-style separator to support files with -- prefix
65 | * example for a file named "--baz": ./foo --bar -- --baz
66 | */
67 | if (0 == strcmp("--", argv[i]))
68 | {
69 | i += 1;
70 | break;
71 | }
72 | /* test for each specific flag */
73 | if (0 == strcmp("--in", argv[i])) {
74 | strcpy(szIn, argv[i+1]);
75 | i += 2;
76 | } else if (0 == strcmp("--out", argv[i])) {
77 | strcpy(szOut, argv[i+1]);
78 | i += 2;
79 | } else if (0 == strcmp("--left", argv[i])) {
80 | iLeft = atoi(argv[i+1]);
81 | i += 2;
82 | } else if (0 == strcmp("--top", argv[i])) {
83 | iTop = atoi(argv[i+1]);
84 | i += 2;
85 | } else if (0 == strcmp("--c", argv[i])) {
86 | bC = 1;
87 | i++;
88 | } else if (0 == strcmp("--invert", argv[i])) {
89 | bInvert = 1;
90 | i++;
91 | } else {
92 | fprintf(stderr, "Unknown parameter '%s'\n", argv[i]);
93 | exit(1);
94 | }
95 | }
96 | } /* parse_opts() */
97 | //
98 | // Gather a vertical byte from horizontal pixels
99 | //
100 | unsigned char GetByte(unsigned char *pBuf, int x, int y)
101 | {
102 | int i;
103 | unsigned char *s, b = 0;
104 | unsigned char ucMask = 0x80 >> (x & 7);
105 |
106 | s = pBuf + (y * 16) + (x >> 3);
107 | for (i=0; i<8; i++)
108 | {
109 | if (s[0] & ucMask)
110 | b |= (1 << i);
111 | s += 16; // next line
112 | }
113 | return b;
114 | } /* GetByte() */
115 | //
116 | // For debugging
117 | //
118 | void DumpHex(unsigned char *s, int iLen)
119 | {
120 | int i;
121 | for (i=0; i= 3)
174 | {
175 | j = (x - iStart) - iRepeat; // non-repeats before this section
176 | if (j != 0) // non-repeats before the repeating bytes
177 | {
178 | if (j > 7) // big copy
179 | {
180 | while (j >= 256)
181 | {
182 | #ifdef DEBUG_LOG
183 | printf("big copy 256\n");
184 | #endif
185 | pDest[i++] = OP_COPYSKIP; // big copy
186 | pDest[i++] = 0xff; // max length 256
187 | memcpy(&pDest[i], &pTemp[iStart], 256);
188 | i += 256;
189 | j -= 256;
190 | iStart += 256;
191 | }
192 | if (j > 7)
193 | {
194 | #ifdef DEBUG_LOG
195 | printf("big copy %d,", j);
196 | DumpHex(&pTemp[iStart], j);
197 | #endif
198 | pDest[i++] = OP_COPYSKIP;
199 | pDest[i++] = (unsigned char)(j - 1);
200 | memcpy(&pDest[i], &pTemp[iStart], j);
201 | i += j;
202 | iStart += j;
203 | j = 0;
204 | }
205 | }
206 | if (j > 0 && j <= 7) // short diff
207 | {
208 | #ifdef DEBUG_LOG
209 | printf("short copy %d,", j);
210 | DumpHex(&pTemp[iStart], j);
211 | #endif
212 | if (CheckShortRepeat(&pTemp[iStart], j))
213 | {
214 | pDest[i++] = OP_REPEAT + (j-1);
215 | pDest[i++] = pTemp[iStart];
216 | }
217 | else
218 | {
219 | pDest[i++] = OP_COPYSKIP + (j<<3);
220 | memcpy(&pDest[i], &pTemp[iStart], j);
221 | i += j;
222 | }
223 | iStart += j;
224 | }
225 | }
226 | // now encode the repeat
227 | while (iRepeat >= 64)
228 | {
229 | #ifdef DEBUG_LOG
230 | printf("repeat 64, 0x%02x\n", ucMatch);
231 | #endif
232 | pDest[i++] = OP_REPEAT | 0x3f; // 64
233 | pDest[i++] = ucMatch;
234 | iRepeat -= 64;
235 | iStart += 64;
236 | }
237 | if (iRepeat) // last repeat
238 | {
239 | #ifdef DEBUG_LOG
240 | printf("repeat %d, 0x%02x\n", iRepeat, ucMatch);
241 | #endif
242 | pDest[i++] = OP_REPEAT | (unsigned char)(iRepeat-1);
243 | pDest[i++] = ucMatch;
244 | iStart += iRepeat;
245 | }
246 | } // repeat >= 3
247 | ucMatch = pTemp[x];
248 | iRepeat = 1;
249 | }
250 | } // for x
251 | // Pack the non-repeats and repeats as needed
252 | if (iRepeat >= 3) // pack the last set of repeats
253 | {
254 | j = (x - iStart) - iRepeat; // non-repeats before this section
255 | if (j != 0) // non-repeats before the repeating bytes
256 | {
257 | if (j > 7) // big diff
258 | {
259 | while (j >= 256)
260 | {
261 | #ifdef DEBUG_LOG
262 | printf("big copy 256\n");
263 | #endif
264 | pDest[i++] = OP_COPYSKIP; // big copy
265 | pDest[i++] =0xff; // max length 256
266 | memcpy(&pDest[i], &pTemp[iStart], 256);
267 | i += 256;
268 | j -= 256;
269 | iStart += 256;
270 | }
271 | if (j > 7)
272 | {
273 | #ifdef DEBUG_LOG
274 | printf("big copy %d", j);
275 | DumpHex(&pTemp[iStart], j);
276 | #endif
277 | pDest[i++] = OP_COPYSKIP;
278 | pDest[i++] = (unsigned char)(j - 1);
279 | memcpy(&pDest[i], &pTemp[iStart], j);
280 | i += j;
281 | iStart += j;
282 | j = 0;
283 | }
284 | }
285 | if (j > 0 && j <= 7) // short diff
286 | {
287 | #ifdef DEBUG_LOG
288 | printf("short copy %d,", j);
289 | DumpHex(&pTemp[iStart], j);
290 | #endif
291 | if (CheckShortRepeat(&pTemp[iStart], j))
292 | {
293 | pDest[i++] = OP_REPEAT + (j-1);
294 | pDest[i++] = pTemp[iStart];
295 | }
296 | else
297 | {
298 | pDest[i++] = OP_COPYSKIP + (j<<3);
299 | memcpy(&pDest[i], &pTemp[iStart], j);
300 | i += j;
301 | }
302 | iStart += j;
303 | }
304 | }
305 | // now encode the repeat
306 | while (iRepeat >= 64)
307 | {
308 | #ifdef DEBUG_LOG
309 | printf("repeat 64, 0x%02x\n", ucMatch);
310 | #endif
311 | pDest[i++] = OP_REPEAT | 0x3f; // 64
312 | pDest[i++] = ucMatch;
313 | iRepeat -= 64;
314 | iStart += 64;
315 | }
316 | if (iRepeat)
317 | {
318 | #ifdef DEBUG_LOG
319 | printf("repeat %d, 0x%02x\n", iRepeat, ucMatch);
320 | #endif
321 | pDest[i++] = OP_REPEAT | (iRepeat-1); // big repeat
322 | pDest[i++] = ucMatch;
323 | iStart += iRepeat;
324 | }
325 | } // pack last set of repeats
326 | // we could have lingering non-repeats that we couldn't pack
327 | *iDiffCount -= iStart;
328 | *iLen = i;
329 | return iStart;
330 | } /* TryRepeat() */
331 | //
332 | // Handle a specific set of data to compress
333 | // When entering this function, either there will be both a skip and diff
334 | // count, or it will be the last set of data at the end of the frame
335 | //
336 | void CompressIt(unsigned char *pDest, int *iLen, int *iSkipCount, int *iDiffCount, unsigned char *pTemp, int bFinal)
337 | {
338 | int i = *iLen; // local copy of length
339 |
340 | #ifdef DEBUG_LOG
341 | printf("Entering CompressIt, size = %d\n", i);
342 | #endif
343 |
344 | if (*iSkipCount & 0x8000) // skipped bytes are first
345 | {
346 | *iSkipCount &= 0x7fff;
347 | if (*iSkipCount > 7) // big skip
348 | {
349 | while(*iSkipCount >= 256)
350 | {
351 | #ifdef DEBUG_LOG
352 | printf("BigSkip 256\n");
353 | #endif
354 | pDest[i++] = 0x00; // big skip
355 | pDest[i++] = 0xff; // max skip = 256 at a time
356 | *iSkipCount -= 256;
357 | }
358 | if (*iSkipCount > 7) // another big skip
359 | {
360 | #ifdef DEBUG_LOG
361 | printf("BigSkip %d\n", *iSkipCount);
362 | #endif
363 | pDest[i++] = 0x00; // big skip
364 | pDest[i++] = (unsigned char)(*iSkipCount - 1);
365 | *iSkipCount = 0;
366 | if (!bFinal && *iDiffCount > 0 && *iDiffCount <= 7) // diff count becomes 'first'
367 | {
368 | *iDiffCount |= 0x8000; // diff is now first
369 | *iLen = i;
370 | return;
371 | }
372 | }
373 | } // big skip
374 | if (*iSkipCount <= 7 && *iDiffCount > 0 && *iDiffCount <= 7) // 2 short
375 | { // skip/copy (both short)
376 | #ifdef DEBUG_LOG
377 | printf("skip+copy %d,%d,", *iSkipCount, *iDiffCount);
378 | DumpHex(pTemp, *iDiffCount);
379 | #endif
380 | if (CheckShortRepeat(pTemp, *iDiffCount))
381 | {
382 | if (*iSkipCount)
383 | pDest[i++] = OP_SKIPCOPY | (unsigned char)(*iSkipCount << 3);
384 | pDest[i++] = OP_REPEAT | (*iDiffCount-1); // repeat
385 | pDest[i++] = pTemp[0];
386 | }
387 | else
388 | {
389 | pDest[i++] = OP_SKIPCOPY | (unsigned char)((*iSkipCount << 3) | (*iDiffCount));
390 | memcpy(&pDest[i], pTemp, *iDiffCount);
391 | i += *iDiffCount;
392 | }
393 | *iSkipCount = *iDiffCount = 0; // all handled
394 | *iLen = i;
395 | return;
396 | }
397 | if (*iSkipCount <=7 && *iDiffCount > 7) // need to do a short skip, long diff
398 | {
399 | if (*iSkipCount != 0) // store just the skip by itself
400 | {
401 | #ifdef DEBUG_LOG
402 | printf( "skip+copy %d,0\n", *iSkipCount);
403 | #endif
404 | pDest[i++] = OP_SKIPCOPY | (unsigned char)(*iSkipCount << 3);
405 | *iSkipCount = 0;
406 | }
407 | pTemp += TryRepeat(iDiffCount, pTemp, pDest, &i);
408 | while (*iDiffCount >= 256) // store long diffs
409 | {
410 | #ifdef DEBUG_LOG
411 | printf("big copy 256\n");
412 | #endif
413 | pDest[i++] = OP_COPYSKIP; // big copy
414 | pDest[i++] = 0xff; // max length = 256
415 | memcpy(&pDest[i], pTemp, 256);
416 | i += 256; pTemp += 256;
417 | *iDiffCount -= 256;
418 | } // while >= 256 diff
419 | if (*iDiffCount > 7) // wrap up the rest as a long diff
420 | {
421 | #ifdef DEBUG_LOG
422 | printf("big copy %d,", *iDiffCount);
423 | DumpHex(pTemp, *iDiffCount);
424 | #endif
425 | pDest[i++] = OP_COPYSKIP; // long copy
426 | pDest[i++] = (unsigned char)(*iDiffCount-1);
427 | memcpy(&pDest[i], pTemp, *iDiffCount);
428 | i += *iDiffCount;
429 | *iDiffCount = 0;
430 | }
431 | if (*iDiffCount > 0)
432 | {
433 | #ifdef DEBUG_LOG
434 | printf("short copy %d,", *iDiffCount);
435 | DumpHex(pTemp, *iDiffCount);
436 | #endif
437 | if (CheckShortRepeat(pTemp, *iDiffCount))
438 | {
439 | pDest[i++] = OP_REPEAT + (*iDiffCount-1);
440 | pDest[i++] = pTemp[0];
441 | }
442 | else
443 | {
444 | pDest[i++] = OP_COPYSKIP | (*iDiffCount << 3); // short copy
445 | memcpy(&pDest[i], pTemp, *iDiffCount);
446 | i += *iDiffCount;
447 | }
448 | *iDiffCount = 0;
449 | }
450 | *iLen = i; // return new length
451 | return;
452 | } // short skip, long diff
453 | if (*iSkipCount && *iDiffCount == 0 && bFinal) // write final skip
454 | {
455 | #ifdef DEBUG_LOG
456 | printf("final skip %d\n", *iSkipCount);
457 | #endif
458 | pDest[i++] = OP_SKIPCOPY | (unsigned char)(*iSkipCount << 3);
459 | *iLen = i;
460 | return;
461 | }
462 | if (bFinal) // must write final diffs
463 | {
464 | while (*iDiffCount >= 256)
465 | {
466 | #ifdef DEBUG_LOG
467 | printf("big copy final 256\n");
468 | #endif
469 | pDest[i++] = OP_COPYSKIP; // big copy
470 | pDest[i++] = 0xff; // max length = 256
471 | memcpy(&pDest[i], pTemp, 256);
472 | i += 256; pTemp += 256;
473 | *iDiffCount -= 256;
474 | }
475 | if (*iDiffCount > 7) // wrap up the rest as a long diff
476 | {
477 | #ifdef DEBUG_LOG
478 | printf("big copy final %d,", *iDiffCount);
479 | DumpHex(pTemp, *iDiffCount);
480 | #endif
481 | pDest[i++] = OP_COPYSKIP; // long copy
482 | pDest[i++] = (unsigned char)(*iDiffCount -1);
483 | memcpy(&pDest[i], pTemp, *iDiffCount);
484 | i += *iDiffCount;
485 | *iDiffCount = 0;
486 | }
487 | if (*iDiffCount > 0)
488 | {
489 | #ifdef DEBUG_LOG
490 | printf("short copy %d,", *iDiffCount);
491 | DumpHex(pTemp, *iDiffCount);
492 | #endif
493 | if (CheckShortRepeat(pTemp, *iDiffCount))
494 | {
495 | pDest[i++] = OP_REPEAT | (*iDiffCount-1);
496 | pDest[i++] = pTemp[0];
497 | }
498 | else
499 | {
500 | pDest[i++] = OP_COPYSKIP | (*iDiffCount << 3); // short copy
501 | memcpy(&pDest[i], pTemp, *iDiffCount);
502 | i += *iDiffCount;
503 | }
504 | *iDiffCount = 0;
505 | }
506 | }
507 | if (*iSkipCount == 0 && *iDiffCount > 0) // now diff is first
508 | *iDiffCount |= 0x8000;
509 | } // skip first
510 | else // copy bytes are first
511 | {
512 | *iDiffCount &= 0x7fff;
513 | if (*iDiffCount > 7) // big diff first
514 | {
515 | pTemp += TryRepeat(iDiffCount, pTemp, pDest, &i);
516 | while (*iDiffCount >= 256) // long ones
517 | {
518 | #ifdef DEBUG_LOG
519 | printf("big copy 256\n");
520 | #endif
521 | pDest[i++] = OP_COPYSKIP; // long copy
522 | pDest[i++] = 0xff; // max count = 256
523 | memcpy(&pDest[i], pTemp, 256);
524 | i += 256; pTemp += 256;
525 | *iDiffCount -= 256;
526 | }
527 | if (*iDiffCount > 7) // last long count
528 | {
529 | #ifdef DEBUG_LOG
530 | printf("big copy %d,", *iDiffCount);
531 | DumpHex(pTemp, *iDiffCount);
532 | #endif
533 | pDest[i++] = OP_COPYSKIP;
534 | pDest[i++] = (unsigned char)(*iDiffCount - 1);
535 | memcpy(&pDest[i], pTemp, *iDiffCount);
536 | pTemp += *iDiffCount;
537 | i += *iDiffCount;
538 | *iDiffCount = 0;
539 | }
540 | } // big diff
541 | if (*iDiffCount) // small diff left over?
542 | {
543 | if (*iSkipCount <= 7) // small small
544 | {
545 | #ifdef DEBUG_LOG
546 | printf("copy+skip %d,%d,", *iDiffCount, *iSkipCount);
547 | DumpHex(pTemp, *iDiffCount);
548 | #endif
549 | if (CheckShortRepeat(pTemp, *iDiffCount))
550 | {
551 | pDest[i++] = OP_REPEATSKIP | (unsigned char)((*iDiffCount << 3) + (*iSkipCount));
552 | pDest[i++] = pTemp[0];
553 | pTemp += *iDiffCount;
554 | *iDiffCount = *iSkipCount = 0;
555 | }
556 | if (*iDiffCount || *iSkipCount) // may not have any
557 | {
558 | pDest[i++] = OP_COPYSKIP | (unsigned char)((*iDiffCount << 3) | *iSkipCount);
559 | memcpy(&pDest[i], pTemp, *iDiffCount);
560 | pTemp += *iDiffCount;
561 | i += *iDiffCount;
562 | *iDiffCount = *iSkipCount = 0;
563 | }
564 | }
565 | else // short diff, long skip
566 | {
567 | #ifdef DEBUG_LOG
568 | printf("copy+skip %d,0,", *iDiffCount);
569 | DumpHex(pTemp, *iDiffCount);
570 | #endif
571 | if (CheckShortRepeat(pTemp, *iDiffCount))
572 | {
573 | pDest[i++] = OP_REPEAT + (*iDiffCount-1);
574 | pDest[i++] = pTemp[0];
575 | }
576 | else
577 | {
578 | pDest[i++] = OP_COPYSKIP | (*iDiffCount << 3);
579 | memcpy(&pDest[i], pTemp, *iDiffCount);
580 | i += *iDiffCount;
581 | }
582 | pTemp += *iDiffCount;
583 | *iDiffCount = 0;
584 | while (*iSkipCount >= 256)
585 | {
586 | #ifdef DEBUG_LOG
587 | printf("big skip 256\n");
588 | #endif
589 | pDest[i++] = OP_SKIPCOPY;
590 | pDest[i++] = 0xff; // skip 256
591 | *iSkipCount -= 256;
592 | } // while skip >= 256
593 | if (*iSkipCount > 7) // last big skip
594 | {
595 | #ifdef DEBUG_LOG
596 | printf("big skip %d\n", *iSkipCount);
597 | #endif
598 | pDest[i++] = OP_SKIPCOPY;
599 | pDest[i++] = *iSkipCount - 1;
600 | *iSkipCount = 0;
601 | }
602 | }
603 | }
604 | if (bFinal)
605 | {
606 | while (*iSkipCount >= 256)
607 | {
608 | #ifdef DEBUG_LOG
609 | printf("big skip final 256\n");
610 | #endif
611 | pDest[i++] = OP_SKIPCOPY;
612 | pDest[i++] = 0xff; // skip 256
613 | *iSkipCount -= 256;
614 | } // while skip >= 256
615 | if (*iSkipCount > 0) // last big skip
616 | {
617 | #ifdef DEBUG_LOG
618 | printf("big skip final %d\n", *iSkipCount);
619 | #endif
620 | pDest[i++] = OP_SKIPCOPY;
621 | pDest[i++] = *iSkipCount - 1;
622 | *iSkipCount = 0;
623 | }
624 | }
625 | if (*iDiffCount == 0 && *iSkipCount != 0) // left over skip, now it's first
626 | *iSkipCount |= 0x8000;
627 | } // copy first
628 | *iLen = i;
629 | } /* CompressIt() */
630 | //
631 | // Convert the current GIF frame into 1-bpp by simple thresholding
632 | //
633 | void Make1Bit(unsigned char *pFrame, PIL_PAGE *pp)
634 | {
635 | int y, x, r, g, b;
636 | unsigned char *s, *d;
637 | unsigned char ucMask;
638 |
639 | memset(pFrame, 0, 128*8);
640 | // grab the current frame in "normal" bit/byte order
641 | // simple threshold to 1-bpp
642 | if (pp->cBitsperpixel == 16) // need to co
643 | {
644 | for (y=0; y<64; y++)
645 | {
646 | if (iTop != -1 && iLeft != -1)
647 | s = pp->pData + (iLeft*2) + (y+iTop)*pp->iPitch;
648 | else
649 | s = pp->pData + pp->iPitch * y;
650 | d = &pFrame[y*16];
651 | ucMask = 0x80;
652 | for (x=0; x<128; x++)
653 | {
654 | r = s[1] & 0xf8;
655 | g = (s[0] & 0xe0) >> 3;
656 | g |= ((s[1] & 7) << 5);
657 | b = ((s[0] & 0x1f) << 3);
658 | if ((r + g + b) > 384) // it's white
659 | d[0] |= ucMask;
660 | s += 2;
661 | ucMask >>= 1;
662 | if (ucMask == 0)
663 | {
664 | d++;
665 | ucMask = 0x80;
666 | }
667 | } // for x
668 | } // for y
669 | } // 16-bpp
670 | // Invert if requested
671 | if (bInvert)
672 | {
673 | for (x=0; x<1024; x++)
674 | {
675 | pFrame[x] = ~pFrame[x];
676 | }
677 | }
678 | } /* Make1Bit() */
679 | //
680 | // Compress the current frame against the previous
681 | //
682 | void AddFrame(PIL_PAGE *pp, unsigned char *pPrev, unsigned char *pData, int *iSize, int bFirst)
683 | {
684 | int iLen = *iSize;
685 | unsigned char *pFrame = PILIOAlloc(128*8); // temporary frame
686 | unsigned char ucTemp[1024];
687 | int iDiffCount, iSkipCount;
688 | int x, y;
689 |
690 | Make1Bit(pFrame, pp);
691 |
692 | //
693 | // Compress the data using the pixel layout of the SSD1306
694 | // vertical bytes with the LSB at the top
695 | // 128 bytes per row, 8 rows total
696 | //
697 | if (bFirst) // First frame only has intra coding, not inter
698 | {
699 | iDiffCount = iSkipCount = 0;
700 | for (y = 0; y<64; y+=8)
701 | {
702 | for (x=0; x<128; x++)
703 | {
704 | ucTemp[iDiffCount++] = GetByte(pFrame, x, y);
705 | } // for x
706 | } // for y
707 | iDiffCount |= 0x8000; // mark it as 'first'
708 | CompressIt(pData, &iLen, &iSkipCount, &iDiffCount, ucTemp, 1); // do it in one shot
709 | }
710 | else
711 | { // find differences between the current and previous frame
712 | iSkipCount = 0;
713 | iDiffCount = 0;
714 | x = y = 0;
715 | while (y < 64)
716 | {
717 | while (y < 64 && GetByte(pFrame, x, y) == GetByte(pPrev, x, y)) // unchanged bytes from previous frame
718 | {
719 | if (iDiffCount == 0 && iSkipCount == 0)
720 | iSkipCount = 0x8000; // mark this as being first
721 | iSkipCount++;
722 | x++;
723 | if (x == 128) // next line
724 | {
725 | x = 0;
726 | y += 8;
727 | }
728 | } // while counting "skip" bytes
729 | if ((iSkipCount & 0x7fff) && (iDiffCount & 0x7fff)) // if have both, store them
730 | CompressIt(pData, &iLen, &iSkipCount, &iDiffCount, ucTemp, 0);
731 | while (y < 64 && GetByte(pFrame, x, y) != GetByte(pPrev, x, y)) // changed
732 | {
733 | if (iDiffCount == 0 && iSkipCount == 0)
734 | iDiffCount = 0x8000; // mark this as being first
735 | ucTemp[(iDiffCount & 0x7fff)] = GetByte(pFrame, x, y);
736 | iDiffCount++;
737 | x++;
738 | if (x == 128) // next line
739 | {
740 | x = 0;
741 | y += 8;
742 | }
743 | } // while counting "copy" bytes
744 | if ((iSkipCount & 0x7fff) && (iDiffCount & 0x7fff)) // if have both, store them
745 | CompressIt(pData, &iLen, &iSkipCount, &iDiffCount, ucTemp, 0);
746 | } // while compressing frame
747 | CompressIt(pData, &iLen, &iSkipCount, &iDiffCount, ucTemp, 1); // compress last part
748 | } // not the first frame
749 | memcpy(pPrev, pFrame, 128*8); // old becomes the current
750 | PILIOFree(pFrame);
751 | *iSize = iLen;
752 | } /* AddFrame() */
753 | //
754 | // Play the frames back into destination image to test
755 | //
756 | void PlayBack(unsigned char *pData, int iLen)
757 | {
758 | int x, y;
759 | int iFrame, i, j, iOff;
760 | unsigned char b, bCode;
761 | unsigned char ucScreen[2024]; // destination bitmap
762 | unsigned char ucBMP[1024]; // for generating output BMP
763 |
764 | iFrame = iOff = 0;
765 | while (iOff < iLen) // process all compressed data
766 | {
767 | i = 0; // graphics offset on SSD1306
768 | while (i < 1024) // while decompressing the current frame
769 | {
770 | bCode = pData[iOff++];
771 | switch (bCode & 0xc0) // different compression types
772 | {
773 | case OP_SKIPCOPY: // skip/copy
774 | if (bCode == OP_SKIPCOPY) // big skip
775 | {
776 | b = pData[iOff++];
777 | i += b + 1;
778 | }
779 | else // skip/copy
780 | {
781 | i += ((bCode & 0x38) >> 3); // skip amount
782 | memcpy(&ucScreen[i], &pData[iOff], bCode & 7);
783 | iOff += (bCode & 7);
784 | i += bCode & 7;
785 | }
786 | break;
787 | case OP_COPYSKIP: // copy/skip
788 | if (bCode == OP_COPYSKIP) // big copy
789 | {
790 | b = pData[iOff++];
791 | j = b + 1;
792 | memcpy(&ucScreen[i], &pData[iOff], j); // copy
793 | iOff += j;
794 | i += j;
795 | }
796 | else
797 | {
798 | j = ((bCode & 0x38) >> 3);
799 | memcpy(&ucScreen[i], &pData[iOff], j); // copy
800 | iOff += j;
801 | i += j;
802 | i += (bCode & 7); // skip
803 | }
804 | break;
805 | case OP_REPEATSKIP:
806 | j = ((bCode & 0x38) >> 3); // repeat
807 | b = pData[iOff++];
808 | memset(&ucScreen[i], b, j);
809 | i += j;
810 | i += (bCode & 7); // skip
811 | break;
812 | case OP_REPEAT:
813 | j = (bCode & 0x3f) + 1;
814 | b = pData[iOff++];
815 | memset(&ucScreen[i], b, j);
816 | i += j;
817 | break;
818 | } // switch on code type
819 | } // while decompressing the current frame
820 | // Convert SSD1306 style bytes into "normal" byte order
821 | memset(ucBMP, 0, 1024);
822 | i = 0;
823 | for (y=0; y<64; y+=8)
824 | {
825 | for (x=0; x<128; x++)
826 | {
827 | bCode = 0x80 >> (x & 7);
828 | b = ucScreen[i];
829 | for (j=0; j<8; j++)
830 | {
831 | if (b & 1) // LSB first
832 | ucBMP[(x>>3) + ((y+j)*16)] |= bCode;
833 | b >>= 1;
834 | }
835 | i++; // next byte column
836 | }
837 | } // for y
838 | #ifdef SAVE_OUTPUT_FRAMES
839 | // Write it to a file
840 | {
841 | PIL_FILE pf;
842 | PIL_PAGE pp;
843 | char szName[32];
844 | memset(&pp, 0, sizeof(pp));
845 | pp.iWidth = 128;
846 | pp.iHeight = 64;
847 | pp.iPitch = 16;
848 | pp.cBitsperpixel = 1;
849 | pp.iDataSize = 1024;
850 | pp.cCompression = PIL_COMP_NONE;
851 | pp.pData = ucBMP;
852 | pp.cFlags = PIL_PAGEFLAGS_TOPDOWN;
853 | sprintf(szName, "out%d.bmp", iFrame);
854 | PILCreate(szName, &pf, 0, PIL_FILE_WINBMP);
855 | PILWrite(&pf, &pp, 0);
856 | PILClose(&pf);
857 | }
858 | #endif // SAVE_OUTPUT_FRAMES
859 | iFrame++;
860 | } // while processing compressed data
861 | } /* PlayBack() */
862 |
863 | //
864 | // Write the binary data as C statements
865 | // ready to drop into an Arduino project
866 | //
867 | void MakeCode(void *ohandle, unsigned char *pData, int iLen)
868 | {
869 | int i;
870 | char szLine[256], szTemp[16];
871 |
872 | PILIOWrite(ohandle, "const byte bAnimation[] PROGMEM = {\n", 36);
873 | for (i=0; i 200) pf.iPageTotal = 200;
927 | for (i=0; i.
48 | //
49 |
50 | #include
51 | #include
52 | #include
53 | #include
54 | #include
55 | #include
56 | #include
57 | #include "oled96.h"
58 |
59 | // Masks defining the upper 2 bit "commands" for the compressed data
60 | #define OP_MASK 0xc0
61 | #define OP_SKIPCOPY 0x00
62 | #define OP_COPYSKIP 0x40
63 | #define OP_REPEATSKIP 0x80
64 | #define OP_REPEAT 0xc0
65 |
66 | static int file_i2c = 0;
67 | static int iOffset;
68 | static int bBadDisplay = 0;
69 | static int bLoop = 0;
70 | static char szIn[512];
71 | static int iChannel = 1; // default I2C channel
72 | static int iAddress = 0x3c; // default I2C address
73 | static int iFrameRate = 15; // 15 FPS
74 | static int iDelay; // based on framerate
75 |
76 | static void oledWriteCommand(unsigned char);
77 | //
78 | // Opens a file system handle to the I2C device
79 | // Initializes the OLED controller into "page mode"
80 | // Prepares the font data for the orientation of the display
81 | // Returns 0 for success, 1 for failure
82 | //
83 | int oledInit(int iChannel, int iAddr, int bFlip, int bInvert)
84 | {
85 | const unsigned char initbuf[]={0x00,0xae,0xa8,0x3f,0xd3,0x00,0x40,0xa1,0xc8,
86 | 0xda,0x12,0x81,0xff,0xa4,0xa6,0xd5,0x80,0x8d,0x14,
87 | 0xaf,0x20,0x00};
88 | char filename[32];
89 | int rc;
90 | unsigned char uc[4];
91 |
92 | sprintf(filename, "/dev/i2c-%d", iChannel);
93 | if ((file_i2c = open(filename, O_RDWR)) < 0)
94 | {
95 | fprintf(stderr, "Failed to open the i2c bus\n");
96 | file_i2c = 0;
97 | return 1;
98 | }
99 |
100 | if (ioctl(file_i2c, I2C_SLAVE, iAddr) < 0)
101 | {
102 | fprintf(stderr, "Failed to acquire bus access or talk to slave\n");
103 | file_i2c = 0;
104 | return 1;
105 | }
106 |
107 | rc = write(file_i2c, initbuf, sizeof(initbuf));
108 | if (rc != sizeof(initbuf))
109 | return 1;
110 | if (bInvert)
111 | {
112 | uc[0] = 0; // command
113 | uc[1] = 0xa7; // invert command
114 | rc = write(file_i2c, uc, 2);
115 | }
116 | if (bFlip) // rotate display 180
117 | {
118 | uc[0] = 0; // command
119 | uc[1] = 0xa0;
120 | rc = write(file_i2c, uc, 2);
121 | uc[1] = 0xc0;
122 | rc = write(file_i2c, uc, 2);
123 | }
124 | return 0;
125 | } /* oledInit() */
126 |
127 | // Sends a command to turn off the OLED display
128 | // Closes the I2C file handle
129 | void oledShutdown()
130 | {
131 | if (file_i2c != 0)
132 | {
133 | oledWriteCommand(0xaE); // turn off OLED
134 | close(file_i2c);
135 | file_i2c = 0;
136 | }
137 | }
138 |
139 | // Send a single byte command to the OLED controller
140 | static void oledWriteCommand(unsigned char c)
141 | {
142 | unsigned char buf[2];
143 | int rc;
144 |
145 | buf[0] = 0x00; // command introducer
146 | buf[1] = c;
147 | rc = write(file_i2c, buf, 2);
148 | if (rc) {} // suppress warning
149 | } /* oledWriteCommand() */
150 |
151 | static void oledWriteCommand2(unsigned char c, unsigned char d)
152 | {
153 | unsigned char buf[3];
154 | int rc;
155 |
156 | buf[0] = 0x00;
157 | buf[1] = c;
158 | buf[2] = d;
159 | rc = write(file_i2c, buf, 3);
160 | if (rc) {} // suppress warning
161 | } /* oledWriteCommand2() */
162 |
163 | int oledSetContrast(unsigned char ucContrast)
164 | {
165 | if (file_i2c == 0)
166 | return -1;
167 |
168 | oledWriteCommand2(0x81, ucContrast);
169 | return 0;
170 | } /* oledSetContrast() */
171 |
172 | // Send commands to position the "cursor" to the given
173 | // row and column
174 | static void oledSetPosition(int x, int y)
175 | {
176 | oledWriteCommand(0xb0 | y); // go to page Y
177 | oledWriteCommand(0x00 | (x & 0xf)); // // lower col addr
178 | oledWriteCommand(0x10 | ((x >> 4) & 0xf)); // upper col addr
179 | iOffset = (y<<7)+x;
180 | }
181 |
182 | // Write a block of pixel data to the OLED
183 | // Length can be anything from 1 to 1024 (whole display)
184 | static void oledWriteDataBlock(unsigned char *ucBuf, int iLen)
185 | {
186 | unsigned char ucTemp[1028];
187 | int rc;
188 |
189 | ucTemp[0] = 0x40; // data command
190 | //
191 | // Badly behaving horizontal addressing mode
192 | // basically behaves the same as page mode (needs to be explicitly sent to
193 | // the next page instead of auto-incrementing)
194 | //
195 | if (bBadDisplay)
196 | {
197 | int j, i = 0;
198 | while (((iOffset & 0x7f) + iLen) >= 128) // if it will hit the page end
199 | {
200 | j = 128 - (iOffset & 0x7f); // amount we can write
201 | memcpy(&ucTemp[1], &ucBuf[i], j);
202 | rc = write(file_i2c, ucTemp, j+1);
203 | i += j; iLen -= j;
204 | iOffset = (iOffset + j) & 0x3ff;
205 | oledSetPosition(iOffset & 0x7f, (iOffset >> 7));
206 | } // while it needs help
207 | if (iLen)
208 | {
209 | memcpy(&ucTemp[1], &ucBuf[i], iLen);
210 | rc = write(file_i2c, ucTemp, iLen+1);
211 | iOffset += iLen;
212 | }
213 | }
214 | else // can write in one shot
215 | {
216 | memcpy(&ucTemp[1], ucBuf, iLen);
217 | rc = write(file_i2c, ucTemp, iLen+1);
218 | iOffset += iLen;
219 | iOffset &= 0x3ff;
220 | }
221 | if (rc) {} // suppress warning
222 | }
223 |
224 | // Fill the frame buffer with a byte pattern
225 | // e.g. all off (0x00) or all on (0xff)
226 | int oledFill(unsigned char ucData)
227 | {
228 | int y;
229 | unsigned char temp[128];
230 |
231 | if (file_i2c == 0) return -1; // not initialized
232 |
233 | memset(temp, ucData, 128);
234 | for (y=0; y<8; y++)
235 | {
236 | oledSetPosition(0,y); // set to (0,Y)
237 | oledWriteDataBlock(temp, 128); // fill with data byte
238 | } // for y
239 | return 0;
240 | } /* oledFill() */
241 |
242 | void PlayAnimation(unsigned char *pData, int iSize)
243 | {
244 | unsigned char *s, *pEnd;
245 | int j, i;
246 | unsigned char b, bCode;
247 | unsigned char ucTemp[256];
248 |
249 | do {
250 | s = pData;
251 | pEnd = &s[iSize];
252 | while (s < pEnd)
253 | {
254 | i = 0;
255 | oledSetPosition(0,0);
256 | while (i < 1024) // try one frame
257 | {
258 | bCode = *s++;
259 | switch (bCode & OP_MASK) // different compression types
260 | {
261 | case OP_SKIPCOPY: // skip/copy
262 | if (bCode == OP_SKIPCOPY) // big skip
263 | {
264 | b = *s++;
265 | i += b + 1;
266 | oledSetPosition(i & 0x7f, (i >> 7));
267 | }
268 | else // skip/copy
269 | {
270 | if (bCode & 0x38)
271 | {
272 | i += ((bCode & 0x38) >> 3); // skip amount
273 | oledSetPosition(i & 0x7f, (i >> 7));
274 | }
275 | if (bCode & 7)
276 | {
277 | oledWriteDataBlock(s, bCode & 7);
278 | s += (bCode & 7);
279 | i += bCode & 7;
280 | }
281 | }
282 | break;
283 | case OP_COPYSKIP: // copy/skip
284 | if (bCode == OP_COPYSKIP) // big copy
285 | {
286 | b = *s++;
287 | j = b + 1;
288 | oledWriteDataBlock(s, j);
289 | s += j;
290 | i += j;
291 | }
292 | else
293 | {
294 | j = ((bCode & 0x38) >> 3);
295 | if (j)
296 | {
297 | oledWriteDataBlock(s, j);
298 | s += j;
299 | i += j;
300 | }
301 | if (bCode & 7)
302 | {
303 | i += (bCode & 7); // skip
304 | oledSetPosition(i & 0x7f, (i >> 7));
305 | }
306 | }
307 | break;
308 |
309 | case OP_REPEATSKIP: // repeat+skip
310 | j = (bCode & 0x38) >> 3; // repeat count
311 | b = *s++;
312 | memset(ucTemp, b, j);
313 | oledWriteDataBlock(ucTemp, j);
314 | i += j;
315 | if (bCode & 7)
316 | {
317 | i += (bCode & 7); // skip amount
318 | oledSetPosition(i & 0x7f, (i >> 7));
319 | }
320 | break;
321 |
322 | case OP_REPEAT:
323 | j = (bCode & 0x3f) + 1;
324 | b = *s++;
325 | memset(ucTemp, b, j);
326 | oledWriteDataBlock(ucTemp, j);
327 | i += j;
328 | break;
329 | } // switch on code type
330 | } // while rendering frame
331 | usleep(iDelay);
332 | } // while playing frames
333 | } while (bLoop);
334 | } /* PlayAnimation() */
335 |
336 | static void parse_opts(int argc, char *argv[])
337 | {
338 | // set default options
339 | int i = 1;
340 |
341 | while (i < argc)
342 | {
343 | /* if it isn't a cmdline option, we're done */
344 | if (0 != strncmp("--", argv[i], 2))
345 | break;
346 | /* GNU-style separator to support files with -- prefix
347 | * example for a file named "--baz": ./foo --bar -- --baz
348 | */
349 | if (0 == strcmp("--", argv[i]))
350 | {
351 | i += 1;
352 | break;
353 | }
354 | /* test for each specific flag */
355 | if (0 == strcmp("--in", argv[i])) {
356 | strcpy(szIn, argv[i+1]);
357 | i += 2;
358 | } else if (0 == strcmp("--addr", argv[i])) {
359 | iAddress = strtol(argv[i+1], NULL, 16);;
360 | i += 2;
361 | } else if (0 == strcmp("--rate", argv[i])) {
362 | iFrameRate = atoi(argv[i+1]);
363 | i += 2;
364 | } else if (0 == strcmp("--bad", argv[i])) {
365 | bBadDisplay = 1;
366 | i++;
367 | } else if (0 == strcmp("--loop", argv[i])) {
368 | bLoop = 1;
369 | i++;
370 | } else if (0 == strcmp("--chan", argv[i])) {
371 | iChannel = atoi(argv[i+1]);
372 | i += 2;
373 | } else {
374 | fprintf(stderr, "Unknown parameter '%s'\n", argv[i]);
375 | exit(1);
376 | }
377 | }
378 | } /* parse_opts() */
379 |
380 | int main(int argc, char *argv[])
381 | {
382 | FILE *pf;
383 | int iSize, i;
384 | unsigned char *pData;
385 |
386 | if (argc < 2)
387 | {
388 | printf("oledplay - SSD1306 animation player\n");
389 | printf("written by Larry Bank 5/21/18\n");
390 | printf("usage:\n\n");
391 | printf("./oledplay \n\n");
392 | printf("--in input file\n");
393 | printf("--chan optional I2C channel; defaults to 1\n");
394 | printf("--addr optional hex I2C addess; defaults to 0x3c\n");
395 | printf("--rate optional framerate; defaults to 15FPS\n");
396 | printf("--loop loops animation until CTRL-C is pressed\n");
397 | printf("--bad indicates the display doesn't support horizontal address mode\n");
398 | return -1;
399 | }
400 | parse_opts(argc, argv);
401 | iDelay = 1000000 / iFrameRate;
402 | i = oledInit(iChannel, iAddress, 0, 0);
403 | if (i)
404 | {
405 | printf("Error initializing OLED; are you running as sudo?\n");
406 | return -1;
407 | }
408 | pf = fopen(szIn, "rb");
409 | if (pf == NULL)
410 | {
411 | printf("Error opening %s\n", szIn);
412 | oledShutdown();
413 | return -1;
414 | }
415 | fseek(pf, 0L, SEEK_END);
416 | iSize = (int)ftell(pf);
417 | fseek(pf, 0L, SEEK_SET);
418 | pData = malloc(iSize);
419 | fread(pData, iSize, 1, pf);
420 | fclose(pf);
421 | PlayAnimation(pData, iSize);
422 | oledShutdown();
423 | return 0;
424 | } /* main() */
425 |
--------------------------------------------------------------------------------
/pokemon.bin:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bitbank2/oled_animator/bd43e9a4310b196c1a18cadba14e98e0ab998e9a/pokemon.bin
--------------------------------------------------------------------------------
/swirl.bin:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bitbank2/oled_animator/bd43e9a4310b196c1a18cadba14e98e0ab998e9a/swirl.bin
--------------------------------------------------------------------------------
/wolf.bin:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bitbank2/oled_animator/bd43e9a4310b196c1a18cadba14e98e0ab998e9a/wolf.bin
--------------------------------------------------------------------------------