it's #else not #elif (fix red)
[Rockbox.git] / apps / plugins / lib / grey_core.c
blobe2260cdf11b4f8181f2f948755da67b1527b7dc8
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * New greyscale framework
11 * Core & miscellaneous functions
13 * This is a generic framework to display 129 shades of grey on low-depth
14 * bitmap LCDs (Archos b&w, Iriver & Ipod 4-grey) within plugins.
16 * Copyright (C) 2008 Jens Arnold
18 * All files in this archive are subject to the GNU General Public License.
19 * See the file COPYING in the source tree root for full license agreement.
21 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
22 * KIND, either express or implied.
24 ****************************************************************************/
26 #include "plugin.h"
27 #include "grey.h"
29 #if defined(HAVE_ADJUSTABLE_CPU_FREQ) && \
30 (defined(CPU_PP) || (CONFIG_LCD == LCD_TL0350A))
31 #define NEED_BOOST
32 #endif
34 #ifndef SIMULATOR
36 #if defined ARCHOS_RECORDER /* verified */ \
37 || defined ARCHOS_FMRECORDER /* should be identical */ \
38 || defined ARCHOS_RECORDERV2 /* should be identical */ \
39 || defined ARCHOS_ONDIOFM /* verified */ \
40 || defined ARCHOS_ONDIOSP /* verified */
41 /* Average measurements of a Recorder v1, an Ondio FM, a backlight-modded
42 * Ondio FM, and an Ondio SP. */
43 static const unsigned char lcdlinear[256] = {
44 5, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 29, 31, 33, 35,
45 37, 39, 40, 42, 43, 45, 46, 48, 49, 50, 51, 53, 54, 55, 57, 58,
46 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 68, 69, 70, 71, 71, 72,
47 73, 74, 74, 75, 76, 77, 77, 78, 79, 79, 80, 80, 81, 81, 82, 82,
48 83, 84, 84, 85, 86, 86, 87, 87, 88, 88, 89, 89, 90, 90, 91, 91,
49 92, 92, 93, 93, 94, 94, 95, 95, 96, 96, 97, 98, 98, 99, 100, 100,
50 101, 101, 102, 103, 103, 104, 105, 105, 106, 106, 107, 107, 108, 108, 109, 109,
51 110, 110, 111, 112, 112, 113, 114, 114, 115, 115, 116, 117, 117, 118, 119, 119,
52 120, 120, 121, 122, 123, 123, 124, 125, 126, 126, 127, 128, 129, 129, 130, 131,
53 132, 132, 133, 134, 135, 135, 136, 137, 138, 138, 139, 140, 140, 141, 141, 142,
54 143, 144, 145, 146, 147, 147, 148, 149, 150, 151, 152, 153, 154, 154, 155, 156,
55 157, 158, 159, 160, 161, 161, 162, 163, 164, 165, 166, 167, 168, 168, 169, 170,
56 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 184, 185, 186, 187,
57 188, 189, 191, 192, 194, 195, 197, 198, 199, 200, 202, 203, 204, 205, 207, 208,
58 209, 210, 212, 213, 215, 216, 218, 219, 220, 221, 222, 223, 225, 226, 227, 228,
59 229, 230, 232, 233, 234, 235, 237, 238, 239, 240, 242, 243, 244, 246, 247, 248
61 /* The actual LCD scanrate varies a lot with temperature on these targets */
62 #define LCD_SCANRATE 67 /* Hz */
64 #elif defined IAUDIO_M3 /* verified */
65 /* Average measurements of 2 iAudio remotes connected to an M3. */
66 static const unsigned char lcdlinear[256] = {
67 5, 9, 13, 17, 21, 26, 30, 34, 38, 42, 46, 50, 54, 58, 62, 66,
68 70, 73, 76, 78, 80, 82, 84, 86, 88, 90, 91, 92, 94, 95, 96, 97,
69 98, 99, 99, 100, 101, 102, 102, 103, 104, 104, 105, 105, 106, 107, 107, 108,
70 109, 109, 110, 110, 111, 111, 112, 112, 113, 113, 114, 114, 115, 115, 116, 116,
71 117, 117, 118, 118, 119, 119, 120, 120, 121, 121, 121, 122, 122, 123, 123, 123,
72 124, 124, 124, 125, 125, 126, 126, 126, 127, 127, 127, 128, 128, 129, 129, 129,
73 130, 130, 131, 131, 132, 132, 133, 133, 134, 134, 134, 135, 135, 136, 136, 136,
74 137, 137, 137, 138, 138, 139, 139, 139, 140, 140, 141, 141, 142, 142, 143, 143,
75 144, 144, 145, 145, 146, 147, 147, 148, 149, 149, 150, 150, 151, 151, 152, 152,
76 153, 153, 154, 154, 155, 155, 156, 156, 157, 157, 158, 158, 159, 160, 160, 161,
77 162, 162, 163, 164, 164, 165, 166, 167, 168, 168, 169, 169, 170, 171, 171, 172,
78 173, 173, 174, 175, 176, 176, 177, 178, 179, 179, 180, 181, 182, 182, 183, 184,
79 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 198, 199, 200, 201,
80 202, 203, 204, 205, 207, 208, 209, 210, 211, 212, 213, 214, 216, 217, 218, 219,
81 220, 221, 222, 223, 225, 226, 227, 228, 229, 230, 231, 232, 234, 235, 236, 237,
82 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 249, 250, 251, 252
84 /* The actual LCD scanrate is twice as high, but we cannot transfer fast enough
85 * for 150Hz. Even at 75Hz, greyscale display is very smooth. Average from
86 * 2 iAudio remotes. */
87 #define LCD_SCANRATE 75 /* Hz */
89 #elif defined IAUDIO_M5 /* verified */
90 /* Measurement of one iAudio M5L */
91 static const unsigned char lcdlinear[256] = {
92 4, 6, 8, 10, 11, 13, 15, 17, 19, 21, 22, 24, 25, 27, 28, 30,
93 32, 33, 35, 36, 37, 39, 40, 42, 43, 44, 45, 46, 48, 49, 50, 51,
94 52, 52, 53, 54, 55, 55, 56, 57, 58, 58, 59, 60, 61, 61, 62, 63,
95 64, 64, 65, 65, 66, 66, 67, 67, 68, 68, 69, 70, 70, 71, 72, 72,
96 73, 73, 74, 75, 75, 76, 77, 77, 78, 78, 79, 79, 80, 80, 81, 81,
97 82, 82, 83, 84, 84, 85, 86, 86, 87, 87, 88, 89, 89, 90, 91, 91,
98 92, 92, 93, 93, 94, 94, 95, 95, 96, 96, 97, 98, 98, 99, 100, 100,
99 101, 101, 102, 102, 103, 103, 104, 104, 105, 105, 106, 106, 107, 107, 108, 108,
100 109, 109, 110, 110, 111, 111, 112, 112, 113, 113, 114, 114, 115, 115, 116, 116,
101 117, 117, 118, 119, 119, 120, 121, 121, 122, 122, 123, 124, 124, 125, 126, 126,
102 127, 127, 128, 129, 130, 130, 131, 132, 133, 133, 134, 135, 135, 136, 137, 137,
103 138, 139, 140, 141, 142, 142, 143, 144, 145, 146, 147, 148, 149, 149, 150, 151,
104 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 163, 164, 165, 167, 168, 169,
105 170, 172, 173, 175, 177, 179, 180, 182, 184, 186, 188, 190, 192, 194, 196, 198,
106 200, 202, 204, 205, 207, 209, 210, 212, 214, 216, 218, 219, 221, 223, 224, 226,
107 228, 230, 231, 233, 235, 236, 237, 239, 241, 243, 244, 246, 248, 249, 250, 252
109 #define LCD_SCANRATE 73 /* Hz */
111 #elif defined IPOD_1G2G /* verified */
112 /* Average measurements of an iPod 1st Gen (0x00010001) and an iPod 2nd Gen
113 * (0x00020000), measured with both backlight off & backlight on (flipped
114 * curves) and medium load (white background when measuring with backlight on),
115 * as the curve is load dependent (the controller's step-up converter doesn't
116 * provide enough juice). Table is for backlight_off state. */
117 static const unsigned char lcdlinear[256] = {
118 4, 6, 8, 9, 11, 13, 14, 16, 17, 18, 20, 21, 23, 24, 26, 27,
119 29, 30, 31, 32, 34, 35, 36, 37, 38, 39, 40, 41, 41, 42, 43, 44,
120 45, 45, 46, 47, 47, 48, 49, 49, 50, 50, 51, 51, 52, 52, 53, 53,
121 54, 54, 54, 55, 55, 56, 56, 56, 57, 57, 57, 58, 58, 59, 59, 59,
122 60, 60, 60, 61, 61, 62, 62, 62, 63, 63, 63, 64, 64, 65, 65, 65,
123 66, 66, 67, 67, 68, 68, 69, 69, 70, 70, 71, 71, 72, 72, 73, 73,
124 74, 74, 74, 75, 75, 76, 76, 76, 77, 77, 78, 78, 79, 79, 80, 80,
125 81, 81, 82, 82, 83, 83, 84, 84, 85, 85, 86, 86, 87, 87, 88, 88,
126 89, 89, 90, 91, 92, 92, 93, 94, 95, 95, 96, 97, 97, 98, 99, 99,
127 100, 100, 101, 102, 102, 103, 104, 104, 105, 105, 106, 107, 107, 108, 109, 109,
128 110, 110, 111, 112, 113, 113, 114, 115, 116, 116, 117, 118, 119, 119, 120, 121,
129 122, 122, 123, 124, 125, 125, 126, 127, 128, 129, 130, 131, 131, 132, 133, 134,
130 135, 137, 138, 139, 141, 142, 144, 145, 146, 147, 149, 150, 151, 152, 154, 155,
131 156, 158, 159, 161, 162, 164, 165, 167, 169, 171, 172, 174, 175, 177, 178, 180,
132 182, 184, 186, 188, 189, 191, 193, 195, 197, 199, 201, 203, 206, 208, 210, 212,
133 214, 217, 219, 221, 224, 226, 229, 231, 233, 236, 238, 240, 243, 245, 247, 250
135 /* Average from an iPod 1st Gen and an iPod 2nd Gen */
136 #define LCD_SCANRATE 96 /* Hz */
138 #elif defined IPOD_MINI2G /* verified */ \
139 || defined IPOD_MINI /* should be identical */ \
140 || defined IPOD_3G /* TODO: verify */ \
141 || defined IPOD_4G /* TODO: verify */
142 /* Measurement of one iPod Mini G2 */
143 static const unsigned char lcdlinear[256] = {
144 2, 5, 7, 10, 12, 15, 17, 20, 22, 24, 26, 28, 30, 32, 34, 36,
145 38, 40, 41, 42, 44, 45, 46, 47, 48, 49, 50, 50, 51, 52, 52, 53,
146 54, 54, 55, 55, 56, 56, 57, 57, 58, 58, 58, 59, 59, 60, 60, 60,
147 61, 61, 61, 62, 62, 63, 63, 63, 64, 64, 64, 64, 65, 65, 65, 65,
148 66, 66, 66, 66, 67, 67, 67, 67, 68, 68, 68, 68, 69, 69, 69, 69,
149 70, 70, 70, 70, 71, 71, 71, 71, 72, 72, 72, 73, 73, 74, 74, 74,
150 75, 75, 75, 75, 76, 76, 76, 76, 77, 77, 77, 78, 78, 79, 79, 79,
151 80, 80, 80, 81, 81, 82, 82, 82, 83, 83, 83, 84, 84, 85, 85, 85,
152 86, 86, 86, 87, 87, 88, 88, 88, 89, 89, 90, 90, 91, 91, 92, 92,
153 93, 93, 94, 94, 95, 95, 96, 96, 97, 97, 98, 99, 99, 100, 101, 101,
154 102, 102, 103, 104, 104, 105, 106, 106, 107, 108, 109, 110, 110, 111, 112, 113,
155 114, 115, 115, 116, 117, 118, 118, 119, 120, 121, 121, 122, 123, 124, 124, 125,
156 126, 127, 128, 129, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140,
157 141, 142, 143, 144, 146, 147, 148, 149, 150, 151, 153, 154, 155, 156, 158, 159,
158 160, 162, 163, 165, 166, 168, 169, 171, 172, 175, 177, 180, 182, 185, 187, 190,
159 192, 196, 199, 203, 206, 210, 213, 217, 220, 223, 227, 230, 234, 238, 242, 246
161 /* Average of an iPod Mini G2 and 2 3rd Gen iPods. */
162 #define LCD_SCANRATE 87 /* Hz */
164 #elif defined IRIVER_H100_SERIES /* verified */
165 /* Measurement of one Iriver H140 */
166 static const unsigned char lcdlinear[256] = {
167 5, 8, 12, 15, 18, 22, 25, 28, 31, 34, 36, 39, 42, 44, 47, 50,
168 53, 55, 57, 59, 62, 64, 66, 68, 70, 71, 72, 73, 75, 76, 77, 78,
169 79, 80, 80, 81, 82, 83, 83, 84, 85, 85, 86, 86, 87, 87, 88, 88,
170 89, 89, 90, 90, 91, 91, 92, 92, 93, 93, 93, 94, 94, 95, 95, 95,
171 96, 96, 96, 97, 97, 98, 98, 98, 99, 99, 99, 100, 100, 101, 101, 101,
172 102, 102, 102, 103, 103, 104, 104, 104, 105, 105, 106, 106, 107, 107, 108, 108,
173 109, 109, 109, 110, 110, 111, 111, 111, 112, 112, 113, 113, 114, 114, 115, 115,
174 116, 116, 117, 117, 118, 118, 119, 119, 120, 120, 121, 121, 122, 122, 123, 123,
175 124, 124, 125, 125, 126, 127, 127, 128, 129, 129, 130, 130, 131, 131, 132, 132,
176 133, 133, 134, 135, 135, 136, 137, 137, 138, 138, 139, 139, 140, 140, 141, 141,
177 142, 142, 143, 143, 144, 145, 145, 146, 147, 147, 148, 148, 149, 150, 150, 151,
178 152, 152, 153, 153, 154, 155, 155, 156, 157, 157, 158, 159, 160, 160, 161, 162,
179 163, 164, 165, 166, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177,
180 178, 179, 181, 182, 183, 184, 186, 187, 188, 189, 191, 192, 193, 194, 196, 197,
181 198, 200, 202, 203, 205, 207, 208, 210, 212, 214, 215, 217, 218, 220, 221, 223,
182 224, 226, 228, 229, 231, 233, 235, 236, 238, 240, 241, 242, 244, 245, 246, 248
184 #define LCD_SCANRATE 70 /* Hz */
186 #elif defined MROBE_100 /* verified */
187 /* Average measurements of 2 m:robe 100 s */
188 static const unsigned char lcdlinear[256] = {
189 10, 14, 18, 22, 26, 30, 34, 38, 42, 46, 49, 53, 56, 60, 63, 67,
190 70, 73, 76, 79, 81, 84, 87, 90, 92, 95, 97, 100, 102, 105, 107, 110,
191 112, 114, 116, 118, 119, 121, 123, 125, 126, 128, 130, 131, 133, 135, 136, 138,
192 139, 141, 142, 143, 144, 146, 147, 148, 149, 150, 151, 152, 154, 155, 156, 157,
193 158, 159, 160, 161, 161, 162, 163, 164, 165, 166, 167, 168, 168, 169, 170, 171,
194 172, 172, 173, 173, 174, 174, 175, 175, 176, 176, 177, 178, 178, 179, 180, 180,
195 181, 181, 182, 182, 183, 183, 184, 184, 185, 185, 186, 186, 187, 187, 188, 188,
196 189, 189, 190, 190, 191, 191, 192, 192, 193, 193, 193, 194, 194, 195, 195, 195,
197 196, 196, 197, 197, 198, 198, 199, 199, 200, 200, 200, 201, 201, 202, 202, 202,
198 203, 203, 204, 204, 205, 205, 206, 206, 207, 207, 207, 208, 208, 209, 209, 209,
199 210, 210, 210, 211, 211, 212, 212, 212, 213, 213, 213, 214, 214, 215, 215, 215,
200 216, 216, 216, 217, 217, 218, 218, 218, 219, 219, 219, 220, 220, 221, 221, 221,
201 222, 222, 222, 223, 223, 224, 224, 224, 225, 225, 225, 226, 226, 227, 227, 227,
202 228, 228, 229, 229, 230, 230, 231, 231, 232, 232, 232, 233, 233, 234, 234, 234,
203 235, 235, 235, 236, 236, 237, 237, 237, 238, 238, 238, 239, 239, 240, 240, 240,
204 241, 241, 242, 242, 243, 243, 244, 244, 247, 248, 248, 249, 250, 250, 251, 252
206 #define LCD_SCANRATE 51 /* Hz */
208 #else /* not yet calibrated targets - generic linear mapping */
209 /* TODO: calibrate iFP7xx */
210 static const unsigned char lcdlinear[256] = {
211 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
212 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
213 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
214 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
215 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
216 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
217 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
218 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127,
219 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143,
220 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159,
221 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175,
222 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191,
223 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207,
224 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223,
225 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239,
226 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255
228 /* generic default */
229 #define LCD_SCANRATE 70 /* Hz */
231 #endif
232 #else /* SIMULATOR */
233 /* undo a (generic) PC display gamma of 2.0 to simulate target behaviour */
234 static const unsigned char lcdlinear[256] = {
235 0, 16, 23, 28, 32, 36, 39, 42, 45, 48, 50, 53, 55, 58, 60, 62,
236 64, 66, 68, 70, 71, 73, 75, 77, 78, 80, 81, 83, 84, 86, 87, 89,
237 90, 92, 93, 94, 96, 97, 98, 100, 101, 102, 103, 105, 106, 107, 108, 109,
238 111, 112, 113, 114, 115, 116, 117, 118, 119, 121, 122, 123, 124, 125, 126, 127,
239 128, 129, 130, 131, 132, 133, 134, 135, 135, 136, 137, 138, 139, 140, 141, 142,
240 143, 144, 145, 145, 146, 147, 148, 149, 150, 151, 151, 152, 153, 154, 155, 156,
241 156, 157, 158, 159, 160, 160, 161, 162, 163, 164, 164, 165, 166, 167, 167, 168,
242 169, 170, 170, 171, 172, 173, 173, 174, 175, 176, 176, 177, 178, 179, 179, 180,
243 181, 181, 182, 183, 183, 184, 185, 186, 186, 187, 188, 188, 189, 190, 190, 191,
244 192, 192, 193, 194, 194, 195, 196, 196, 197, 198, 198, 199, 199, 200, 201, 201,
245 202, 203, 203, 204, 204, 205, 206, 206, 207, 208, 208, 209, 209, 210, 211, 211,
246 212, 212, 213, 214, 214, 215, 215, 216, 217, 217, 218, 218, 219, 220, 220, 221,
247 221, 222, 222, 223, 224, 224, 225, 225, 226, 226, 227, 228, 228, 229, 229, 230,
248 230, 231, 231, 232, 233, 233, 234, 234, 235, 235, 236, 236, 237, 237, 238, 238,
249 239, 240, 240, 241, 241, 242, 242, 243, 243, 244, 244, 245, 245, 246, 246, 247,
250 247, 248, 248, 249, 249, 250, 250, 251, 251, 252, 252, 253, 253, 254, 254, 255
252 #endif /* SIMULATOR */
254 /* Prototypes */
255 static inline void _deferred_update(void) __attribute__ ((always_inline));
256 static int exp_s16p16(int x);
257 static int log_s16p16(int x);
258 static void grey_screendump_hook(int fd);
259 static void fill_gvalues(void);
260 #ifdef SIMULATOR
261 static unsigned long _grey_get_pixel(int x, int y);
262 #else
263 static void _timer_isr(void);
264 #endif
267 #if defined(HAVE_BACKLIGHT_INVERSION) && !defined(SIMULATOR)
268 static void invert_gvalues(void)
270 unsigned char *val, *end;
271 unsigned char rev_tab[256];
272 unsigned i;
273 unsigned last_i = 0;
274 unsigned x = 0;
275 unsigned last_x;
277 /* Step 1: Calculate a transposed table for undoing the old mapping */
278 for (i = 0; i < 256; i++)
280 last_x = x;
281 x = _grey_info.gvalue[i];
282 if (x > last_x)
284 rev_tab[last_x++] = (last_i + i) / 2;
285 while (x > last_x)
286 rev_tab[last_x++] = i;
287 last_i = i;
290 rev_tab[last_x++] = (last_i + 255) / 2;
291 while (256 > last_x)
292 rev_tab[last_x++] = 255;
294 /* Step 2: Calculate new mapping */
295 fill_gvalues();
297 /* Step 3: Transpose all pixel values */
298 val = _grey_info.values;
299 end = val + _GREY_MULUQ(_grey_info.width, _grey_info.height);
302 *val = _grey_info.gvalue[rev_tab[*val]];
303 while (++val < end);
305 #endif
307 /* Update LCD areas not covered by the greyscale overlay */
308 static inline void _deferred_update(void)
310 int x1 = MAX(_grey_info.x, 0);
311 int x2 = MIN(_grey_info.x + _grey_info.width, LCD_WIDTH);
312 int y1 = MAX(_grey_info.y, 0);
313 int y2 = MIN(_grey_info.y + _grey_info.height, LCD_HEIGHT);
315 if (y1 > 0) /* refresh part above overlay, full width */
316 _grey_info.rb->lcd_update_rect(0, 0, LCD_WIDTH, y1);
318 if (y2 < LCD_HEIGHT) /* refresh part below overlay, full width */
319 _grey_info.rb->lcd_update_rect(0, y2, LCD_WIDTH, LCD_HEIGHT - y2);
321 if (x1 > 0) /* refresh part to the left of overlay */
322 _grey_info.rb->lcd_update_rect(0, y1, x1, y2 - y1);
324 if (x2 < LCD_WIDTH) /* refresh part to the right of overlay */
325 _grey_info.rb->lcd_update_rect(x2, y1, LCD_WIDTH - x2, y2 - y1);
328 #ifdef SIMULATOR
330 /* Callback function for grey_ub_gray_bitmap_part() to read a pixel from the
331 * greybuffer. Note that x and y are in LCD coordinates, not greybuffer
332 * coordinates! */
333 static unsigned long _grey_get_pixel(int x, int y)
335 int xg = x - _grey_info.x;
336 int yg = y - _grey_info.y;
337 #if LCD_PIXELFORMAT == HORIZONTAL_PACKING
338 int idx = _grey_info.width * yg + xg;
339 #else /* vertical packing or vertical interleaved */
340 int idx = _grey_info.width * (yg & ~_GREY_BMASK)
341 + (xg << _GREY_BSHIFT) + (~yg & _GREY_BMASK);
342 #endif
344 return _grey_info.values[idx] + (1 << LCD_DEPTH);
347 #else /* !SIMULATOR */
349 /* Timer interrupt handler: display next frame */
350 static void _timer_isr(void)
352 #if defined(HAVE_BACKLIGHT_INVERSION) && !defined(SIMULATOR)
353 unsigned long check = _grey_info.rb->is_backlight_on(true)
354 ? 0 : _GREY_BACKLIGHT_ON;
356 if ((_grey_info.flags & (_GREY_BACKLIGHT_ON|GREY_RAWMAPPED)) == check)
358 _grey_info.flags ^= _GREY_BACKLIGHT_ON;
359 invert_gvalues();
360 return; /* don't overload this timer slot */
362 #endif
363 #if LCD_PIXELFORMAT == HORIZONTAL_PACKING
364 _grey_info.rb->lcd_blit_grey_phase(_grey_info.values, _grey_info.phases,
365 _grey_info.bx, _grey_info.y,
366 _grey_info.bwidth, _grey_info.height,
367 _grey_info.width);
368 #else /* vertical packing or vertical interleaved */
369 _grey_info.rb->lcd_blit_grey_phase(_grey_info.values, _grey_info.phases,
370 _grey_info.x, _grey_info.by,
371 _grey_info.width, _grey_info.bheight,
372 _grey_info.width);
373 #endif
375 if (_grey_info.flags & _GREY_DEFERRED_UPDATE) /* lcd_update() requested? */
377 _deferred_update();
378 _grey_info.flags &= ~_GREY_DEFERRED_UPDATE; /* clear request */
382 #endif /* !SIMULATOR */
384 /* fixed point exp() */
385 static int exp_s16p16(int x)
387 int t;
388 int y = 0x00010000;
390 if (x < 0) x += 0xb1721, y >>= 16;
391 t = x - 0x58b91; if (t >= 0) x = t, y <<= 8;
392 t = x - 0x2c5c8; if (t >= 0) x = t, y <<= 4;
393 t = x - 0x162e4; if (t >= 0) x = t, y <<= 2;
394 t = x - 0x0b172; if (t >= 0) x = t, y <<= 1;
395 t = x - 0x067cd; if (t >= 0) x = t, y += y >> 1;
396 t = x - 0x03920; if (t >= 0) x = t, y += y >> 2;
397 t = x - 0x01e27; if (t >= 0) x = t, y += y >> 3;
398 t = x - 0x00f85; if (t >= 0) x = t, y += y >> 4;
399 t = x - 0x007e1; if (t >= 0) x = t, y += y >> 5;
400 t = x - 0x003f8; if (t >= 0) x = t, y += y >> 6;
401 t = x - 0x001fe; if (t >= 0) x = t, y += y >> 7;
402 y += ((y >> 8) * x) >> 8;
404 return y;
407 /* fixed point log() */
408 static int log_s16p16(int x)
410 int t;
411 int y = 0xa65af;
413 if (x < 0x00008000) x <<=16, y -= 0xb1721;
414 if (x < 0x00800000) x <<= 8, y -= 0x58b91;
415 if (x < 0x08000000) x <<= 4, y -= 0x2c5c8;
416 if (x < 0x20000000) x <<= 2, y -= 0x162e4;
417 if (x < 0x40000000) x <<= 1, y -= 0x0b172;
418 t = x + (x >> 1); if ((t & 0x80000000) == 0) x = t, y -= 0x067cd;
419 t = x + (x >> 2); if ((t & 0x80000000) == 0) x = t, y -= 0x03920;
420 t = x + (x >> 3); if ((t & 0x80000000) == 0) x = t, y -= 0x01e27;
421 t = x + (x >> 4); if ((t & 0x80000000) == 0) x = t, y -= 0x00f85;
422 t = x + (x >> 5); if ((t & 0x80000000) == 0) x = t, y -= 0x007e1;
423 t = x + (x >> 6); if ((t & 0x80000000) == 0) x = t, y -= 0x003f8;
424 t = x + (x >> 7); if ((t & 0x80000000) == 0) x = t, y -= 0x001fe;
425 x = 0x80000000 - x;
426 y -= x >> 15;
428 return y;
431 static void fill_gvalues(void)
433 int i;
434 unsigned data;
436 #if defined(HAVE_BACKLIGHT_INVERSION) && !defined(SIMULATOR)
437 unsigned imask = (_grey_info.flags & _GREY_BACKLIGHT_ON) ? 0xff : 0;
438 #else
439 const unsigned imask = 0;
440 #endif
441 for (i = 0; i < 256; i++)
443 data = exp_s16p16((_GREY_GAMMA * log_s16p16(i * 257 + 1)) >> 8) + 128;
444 data = (data - (data >> 8)) >> 8; /* approx. data /= 257 */
445 data = ((lcdlinear[data ^ imask] ^ imask) << 7) + 127;
446 _grey_info.gvalue[i] = (data + (data >> 8)) >> 8;
447 /* approx. data / 255 */
451 /* Initialise the framework and prepare the greyscale display buffer
453 arguments:
454 newrb = pointer to plugin api
455 gbuf = pointer to the memory area to use (e.g. plugin buffer)
456 gbuf_size = max usable size of the buffer
457 features = flags for requesting features
458 GREY_BUFFERED: use chunky pixel buffering
459 This allows to use all drawing functions, but needs more
460 memory. Unbuffered operation provides only a subset of
461 drawing functions. (only grey_bitmap drawing and scrolling)
462 GREY_RAWMAPPED: no LCD linearisation and gamma correction
463 width = width in pixels (1..LCD_WIDTH)
464 height = height in pixels (1..LCD_HEIGHT)
465 Note that depending on the target LCD, either height or
466 width are rounded up to a multiple of 4 or 8.
468 result:
469 true on success, false on failure
471 If you need info about the memory taken by the greyscale buffer, supply a
472 long* as the last parameter. This long will then contain the number of bytes
473 used. The total memory needed can be calculated as follows:
474 total_mem =
475 width * height * 2 [grey display data]
476 + buffered ? (width * height) : 0 [chunky buffer]
477 + 0..3 [alignment]
479 The function is authentic regarding memory usage on the simulator, even
480 if it doesn't use all of the allocated memory. */
481 bool grey_init(struct plugin_api* newrb, unsigned char *gbuf, long gbuf_size,
482 unsigned features, int width, int height, long *buf_taken)
484 int bdim, i;
485 long plane_size, buftaken;
486 unsigned data;
487 #ifndef SIMULATOR
488 unsigned *dst, *end;
489 #endif
491 _grey_info.rb = newrb;
493 if ((unsigned) width > LCD_WIDTH
494 || (unsigned) height > LCD_HEIGHT)
495 return false;
497 #if LCD_PIXELFORMAT == HORIZONTAL_PACKING
498 bdim = (width + 7) >> 3;
499 width = bdim << 3;
500 #else /* vertical packing or vertical interleaved */
501 #if (LCD_DEPTH == 1) || (LCD_PIXELFORMAT == VERTICAL_INTERLEAVED)
502 bdim = (height + 7) >> 3;
503 height = bdim << 3;
504 #elif LCD_DEPTH == 2
505 bdim = (height + 3) >> 2;
506 height = bdim << 2;
507 #endif
508 #endif
510 plane_size = _GREY_MULUQ(width, height);
511 #if defined(CPU_COLDFIRE) /* Buffers should be line aligned */ \
512 || defined(CPU_PP) && (NUM_CORES > 1) /* Buffers must be cache line aligned */
513 plane_size += (-plane_size) & 0xf;
514 buftaken = (-(long)gbuf) & 0xf;
515 #else /* Buffers must be 32 bit aligned. */
516 buftaken = (-(long)gbuf) & 3;
517 #endif
518 gbuf += buftaken;
520 if (features & GREY_BUFFERED) /* chunky buffer */
522 _grey_info.buffer = gbuf;
523 gbuf += plane_size;
524 buftaken += plane_size;
526 #if NUM_CORES > 1 /* Values and phases must be uncached when running on COP */
527 if (features & GREY_ON_COP)
528 gbuf = UNCACHED_ADDR(gbuf);
529 #endif
530 _grey_info.values = gbuf;
531 gbuf += plane_size;
532 _grey_info.phases = gbuf;
533 buftaken += 2 * plane_size;
535 if (buftaken > gbuf_size)
536 return false;
538 /* Init to white */
539 _grey_info.rb->memset(_grey_info.values, 0x80, plane_size);
541 #ifndef SIMULATOR
542 /* Init phases with random bits */
543 dst = (unsigned*)(_grey_info.phases);
544 end = (unsigned*)(_grey_info.phases + plane_size);
547 *dst++ = _grey_info.rb->rand();
548 while (dst < end);
549 #endif
551 _grey_info.x = 0;
552 _grey_info.y = 0;
553 _grey_info.width = width;
554 _grey_info.height = height;
555 #if LCD_PIXELFORMAT == HORIZONTAL_PACKING
556 _grey_info.bx = 0;
557 _grey_info.bwidth = bdim;
558 #else /* vertical packing or vertical interleaved */
559 _grey_info.by = 0;
560 _grey_info.bheight = bdim;
561 #endif
562 _grey_info.flags = features & 0xff;
563 _grey_info.fg_brightness = 0;
564 _grey_info.bg_brightness = 255;
565 _grey_info.drawmode = DRMODE_SOLID;
566 _grey_info.curfont = FONT_SYSFIXED;
568 /* precalculate the value -> pattern index conversion table, taking
569 linearisation and gamma correction into account */
570 if (features & GREY_RAWMAPPED)
572 for (i = 0; i < 256; i++)
574 data = i << 7;
575 _grey_info.gvalue[i] = (data + (data >> 8)) >> 8;
578 else
580 #if defined(HAVE_BACKLIGHT_INVERSION) && !defined(SIMULATOR)
581 if (_grey_info.rb->is_backlight_on(true))
582 _grey_info.flags |= _GREY_BACKLIGHT_ON;
583 #endif
584 fill_gvalues();
587 if (buf_taken) /* caller requested info about space taken */
588 *buf_taken = buftaken;
590 return true;
593 /* Release the greyscale display buffer and the library
594 DO CALL either this function or at least grey_show_display(false)
595 before you exit, otherwise nasty things may happen. */
596 void grey_release(void)
598 grey_show(false);
601 /* Switch the greyscale overlay on or off
602 DO NOT call lcd_update() or any other api function that directly accesses
603 the lcd while the greyscale overlay is running! If you need to do
604 lcd_update() to update something outside the greyscale overlay area, use
605 grey_deferred_update() instead.
607 Other functions to avoid are:
608 lcd_blit_mono(), lcd_update_rect(), lcd_set_contrast(),
609 lcd_set_invert_display(), lcd_set_flip() */
610 void grey_show(bool enable)
612 if (enable && !(_grey_info.flags & _GREY_RUNNING))
614 _grey_info.flags |= _GREY_RUNNING;
615 #ifdef SIMULATOR
616 _grey_info.rb->sim_lcd_ex_init(129, _grey_get_pixel);
617 _grey_info.rb->sim_lcd_ex_update_rect(_grey_info.x, _grey_info.y,
618 _grey_info.width, _grey_info.height);
619 #else /* !SIMULATOR */
620 #ifdef NEED_BOOST
621 _grey_info.rb->cpu_boost(true);
622 #endif
623 #if NUM_CORES > 1
624 _grey_info.rb->timer_register(1, NULL, TIMER_FREQ / LCD_SCANRATE,
625 1, _timer_isr,
626 (_grey_info.flags & GREY_ON_COP) ? COP : CPU);
627 #else
628 _grey_info.rb->timer_register(1, NULL, TIMER_FREQ / LCD_SCANRATE, 1,
629 _timer_isr);
630 #endif
631 #endif /* !SIMULATOR */
632 _grey_info.rb->screen_dump_set_hook(grey_screendump_hook);
634 else if (!enable && (_grey_info.flags & _GREY_RUNNING))
636 #ifdef SIMULATOR
637 _grey_info.rb->sim_lcd_ex_init(0, NULL);
638 #else /* !SIMULATOR */
639 _grey_info.rb->timer_unregister();
640 #if NUM_CORES > 1 /* Make sure the ISR has finished before calling lcd_update() */
641 _grey_info.rb->sleep(HZ/100);
642 #endif
643 #ifdef NEED_BOOST
644 _grey_info.rb->cpu_boost(false);
645 #endif
646 #endif /* !SIMULATOR */
647 _grey_info.flags &= ~_GREY_RUNNING;
648 _grey_info.rb->screen_dump_set_hook(NULL);
649 _grey_info.rb->lcd_update(); /* restore whatever there was before */
653 void grey_update_rect(int x, int y, int width, int height)
655 grey_ub_gray_bitmap_part(_grey_info.buffer, x, y, _grey_info.width,
656 x, y, width, height);
659 /* Update the whole greyscale overlay */
660 void grey_update(void)
662 grey_ub_gray_bitmap_part(_grey_info.buffer, 0, 0, _grey_info.width,
663 0, 0, _grey_info.width, _grey_info.height);
666 /* Do an lcd_update() to show changes done by rb->lcd_xxx() functions
667 (in areas of the screen not covered by the greyscale overlay). */
668 void grey_deferred_lcd_update(void)
670 if (_grey_info.flags & _GREY_RUNNING)
672 #ifdef SIMULATOR
673 _deferred_update();
674 #else
675 _grey_info.flags |= _GREY_DEFERRED_UPDATE;
676 #endif
678 else
679 _grey_info.rb->lcd_update();
682 /*** Screenshot ***/
684 #define BMP_FIXEDCOLORS (1 << LCD_DEPTH)
685 #define BMP_VARCOLORS 129
686 #define BMP_NUMCOLORS (BMP_FIXEDCOLORS + BMP_VARCOLORS)
687 #define BMP_BPP 8
688 #define BMP_LINESIZE ((LCD_WIDTH + 3) & ~3)
689 #define BMP_HEADERSIZE (54 + 4 * BMP_NUMCOLORS)
690 #define BMP_DATASIZE (BMP_LINESIZE * LCD_HEIGHT)
691 #define BMP_TOTALSIZE (BMP_HEADERSIZE + BMP_DATASIZE)
693 #define LE16_CONST(x) (x)&0xff, ((x)>>8)&0xff
694 #define LE32_CONST(x) (x)&0xff, ((x)>>8)&0xff, ((x)>>16)&0xff, ((x)>>24)&0xff
696 static const unsigned char bmpheader[] =
698 0x42, 0x4d, /* 'BM' */
699 LE32_CONST(BMP_TOTALSIZE), /* Total file size */
700 0x00, 0x00, 0x00, 0x00, /* Reserved */
701 LE32_CONST(BMP_HEADERSIZE), /* Offset to start of pixel data */
703 0x28, 0x00, 0x00, 0x00, /* Size of (2nd) header */
704 LE32_CONST(LCD_WIDTH), /* Width in pixels */
705 LE32_CONST(LCD_HEIGHT), /* Height in pixels */
706 0x01, 0x00, /* Number of planes (always 1) */
707 LE16_CONST(BMP_BPP), /* Bits per pixel 1/4/8/16/24 */
708 0x00, 0x00, 0x00, 0x00, /* Compression mode, 0 = none */
709 LE32_CONST(BMP_DATASIZE), /* Size of bitmap data */
710 0xc4, 0x0e, 0x00, 0x00, /* Horizontal resolution (pixels/meter) */
711 0xc4, 0x0e, 0x00, 0x00, /* Vertical resolution (pixels/meter) */
712 LE32_CONST(BMP_NUMCOLORS), /* Number of used colours */
713 LE32_CONST(BMP_NUMCOLORS), /* Number of important colours */
715 /* Fixed colours */
716 #if LCD_DEPTH == 1
717 0x90, 0xee, 0x90, 0x00, /* Colour #0 */
718 0x00, 0x00, 0x00, 0x00 /* Colour #1 */
719 #elif LCD_DEPTH == 2
720 0xe6, 0xd8, 0xad, 0x00, /* Colour #0 */
721 0x99, 0x90, 0x73, 0x00, /* Colour #1 */
722 0x4c, 0x48, 0x39, 0x00, /* Colour #2 */
723 0x00, 0x00, 0x00, 0x00 /* Colour #3 */
724 #endif
727 #if LCD_DEPTH == 1
728 #ifdef MROBE_100
729 #define BMP_RED 241
730 #define BMP_GREEN 6
731 #define BMP_BLUE 3
732 #define BMP_RED_BASE 94
733 #define BMP_GREEN_BASE 2
734 #define BMP_BLUE_BASE 2
735 #else
736 #define BMP_RED 0x90
737 #define BMP_GREEN 0xee
738 #define BMP_BLUE 0x90
739 #endif
740 #elif LCD_DEPTH == 2
741 #define BMP_RED 0xad
742 #define BMP_GREEN 0xd8
743 #define BMP_BLUE 0xe6
744 #endif
746 /* Hook function for core screen_dump() to save the current display
747 content (b&w and greyscale overlay) to an 8-bit BMP file. */
748 static void grey_screendump_hook(int fd)
750 int i;
751 int x, y, gx, gy;
752 #if LCD_PIXELFORMAT == VERTICAL_PACKING
753 #if LCD_DEPTH == 1
754 unsigned mask;
755 #elif LCD_DEPTH == 2
756 int shift;
757 #endif
758 #elif LCD_PIXELFORMAT == VERTICAL_INTERLEAVED
759 unsigned data;
760 int shift;
761 #endif /* LCD_PIXELFORMAT */
762 fb_data *lcdptr;
763 unsigned char *clut_entry;
764 unsigned char linebuf[MAX(4*BMP_VARCOLORS,BMP_LINESIZE)];
766 _grey_info.rb->write(fd, bmpheader, sizeof(bmpheader)); /* write header */
768 /* build clut */
769 _grey_info.rb->memset(linebuf, 0, 4*BMP_VARCOLORS);
770 clut_entry = linebuf;
772 for (i = 0; i <= 128; i++)
774 #ifdef MROBE_100
775 *clut_entry++ = (_GREY_MULUQ(BMP_BLUE-BMP_BLUE_BASE, i) >> 7) +
776 BMP_BLUE_BASE;
777 *clut_entry++ = (_GREY_MULUQ(BMP_GREEN-BMP_GREEN_BASE, i) >> 7) +
778 BMP_GREEN_BASE;
779 *clut_entry++ = (_GREY_MULUQ(BMP_RED-BMP_RED_BASE, i) >> 7) +
780 BMP_RED_BASE;
781 #else
782 *clut_entry++ = _GREY_MULUQ(BMP_BLUE, i) >> 7;
783 *clut_entry++ = _GREY_MULUQ(BMP_GREEN, i) >> 7;
784 *clut_entry++ = _GREY_MULUQ(BMP_RED, i) >> 7;
785 #endif
786 clut_entry++;
788 _grey_info.rb->write(fd, linebuf, 4*BMP_VARCOLORS);
790 /* BMP image goes bottom -> top */
791 for (y = LCD_HEIGHT - 1; y >= 0; y--)
793 _grey_info.rb->memset(linebuf, 0, BMP_LINESIZE);
795 gy = y - _grey_info.y;
796 #if LCD_PIXELFORMAT == HORIZONTAL_PACKING
797 #if LCD_DEPTH == 2
798 lcdptr = _grey_info.rb->lcd_framebuffer + _GREY_MULUQ(LCD_FBWIDTH, y);
800 for (x = 0; x < LCD_WIDTH; x += 4)
802 gx = x - _grey_info.x;
804 if (((unsigned)gy < (unsigned)_grey_info.height)
805 && ((unsigned)gx < (unsigned)_grey_info.width))
807 unsigned char *src = _grey_info.values
808 + _GREY_MULUQ(_grey_info.width, gy) + gx;
809 for (i = 0; i < 4; i++)
810 linebuf[x + i] = BMP_FIXEDCOLORS + *src++;
812 else
814 unsigned data = *lcdptr;
815 linebuf[x] = (data >> 6) & 3;
816 linebuf[x + 1] = (data >> 4) & 3;
817 linebuf[x + 2] = (data >> 2) & 3;
818 linebuf[x + 3] = data & 3;
820 lcdptr++;
822 #endif /* LCD_DEPTH */
823 #elif LCD_PIXELFORMAT == VERTICAL_PACKING
824 #if LCD_DEPTH == 1
825 mask = 1 << (y & 7);
826 lcdptr = _grey_info.rb->lcd_framebuffer + _GREY_MULUQ(LCD_WIDTH, y >> 3);
828 for (x = 0; x < LCD_WIDTH; x++)
830 gx = x - _grey_info.x;
832 if (((unsigned)gy < (unsigned)_grey_info.height)
833 && ((unsigned)gx < (unsigned)_grey_info.width))
835 linebuf[x] = BMP_FIXEDCOLORS
836 + _grey_info.values[_GREY_MULUQ(_grey_info.width,
837 gy & ~_GREY_BMASK)
838 + (gx << _GREY_BSHIFT)
839 + (~gy & _GREY_BMASK)];
841 else
843 linebuf[x] = (*lcdptr & mask) ? 1 : 0;
845 lcdptr++;
847 #elif LCD_DEPTH == 2
848 shift = 2 * (y & 3);
849 lcdptr = _grey_info.rb->lcd_framebuffer + _GREY_MULUQ(LCD_WIDTH, y >> 2);
851 for (x = 0; x < LCD_WIDTH; x++)
853 gx = x - _grey_info.x;
855 if (((unsigned)gy < (unsigned)_grey_info.height)
856 && ((unsigned)gx < (unsigned)_grey_info.width))
858 linebuf[x] = BMP_FIXEDCOLORS
859 + _grey_info.values[_GREY_MULUQ(_grey_info.width,
860 gy & ~_GREY_BMASK)
861 + (gx << _GREY_BSHIFT)
862 + (~gy & _GREY_BMASK)];
864 else
866 linebuf[x] = (*lcdptr >> shift) & 3;
868 lcdptr++;
870 #endif /* LCD_DEPTH */
871 #elif LCD_PIXELFORMAT == VERTICAL_INTERLEAVED
872 #if LCD_DEPTH == 2
873 shift = y & 7;
874 lcdptr = _grey_info.rb->lcd_framebuffer + _GREY_MULUQ(LCD_WIDTH, y >> 3);
876 for (x = 0; x < LCD_WIDTH; x++)
878 gx = x - _grey_info.x;
880 if (((unsigned)gy < (unsigned)_grey_info.height)
881 && ((unsigned)gx < (unsigned)_grey_info.width))
883 linebuf[x] = BMP_FIXEDCOLORS
884 + _grey_info.values[_GREY_MULUQ(_grey_info.width,
885 gy & ~_GREY_BMASK)
886 + (gx << _GREY_BSHIFT)
887 + (~gy & _GREY_BMASK)];
889 else
891 data = (*lcdptr >> shift) & 0x0101;
892 linebuf[x] = ((data >> 7) | data) & 3;
894 lcdptr++;
896 #endif /* LCD_DEPTH */
897 #endif /* LCD_PIXELFORMAT */
899 _grey_info.rb->write(fd, linebuf, BMP_LINESIZE);