Prepare new maemo release
[maemo-rb.git] / apps / plugins / lib / grey_core.c
blob047e4cc160a2cfb5ce0b8cddc0f803b11091750c
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 * This program is free software; you can redistribute it and/or
19 * modify it under the terms of the GNU General Public License
20 * as published by the Free Software Foundation; either version 2
21 * of the License, or (at your option) any later version.
23 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
24 * KIND, either express or implied.
26 ****************************************************************************/
28 #include "plugin.h"
29 #include "grey.h"
31 #if defined(HAVE_ADJUSTABLE_CPU_FREQ) && \
32 (defined(CPU_PP) || (CONFIG_LCD == LCD_TL0350A))
33 #define NEED_BOOST
34 #endif
36 #ifndef SIMULATOR
38 #if defined ARCHOS_RECORDER /* verified */ \
39 || defined ARCHOS_FMRECORDER /* should be identical */ \
40 || defined ARCHOS_RECORDERV2 /* should be identical */ \
41 || defined ARCHOS_ONDIOFM /* verified */ \
42 || defined ARCHOS_ONDIOSP /* verified */
43 /* Average measurements of a Recorder v1, an Ondio FM, a backlight-modded
44 * Ondio FM, and an Ondio SP. */
45 static const unsigned char lcdlinear[256] = {
46 5, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 29, 31, 33, 35,
47 37, 39, 40, 42, 43, 45, 46, 48, 49, 50, 51, 53, 54, 55, 57, 58,
48 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 68, 69, 70, 71, 71, 72,
49 73, 74, 74, 75, 76, 77, 77, 78, 79, 79, 80, 80, 81, 81, 82, 82,
50 83, 84, 84, 85, 86, 86, 87, 87, 88, 88, 89, 89, 90, 90, 91, 91,
51 92, 92, 93, 93, 94, 94, 95, 95, 96, 96, 97, 98, 98, 99, 100, 100,
52 101, 101, 102, 103, 103, 104, 105, 105, 106, 106, 107, 107, 108, 108, 109, 109,
53 110, 110, 111, 112, 112, 113, 114, 114, 115, 115, 116, 117, 117, 118, 119, 119,
54 120, 120, 121, 122, 123, 123, 124, 125, 126, 126, 127, 128, 129, 129, 130, 131,
55 132, 132, 133, 134, 135, 135, 136, 137, 138, 138, 139, 140, 140, 141, 141, 142,
56 143, 144, 145, 146, 147, 147, 148, 149, 150, 151, 152, 153, 154, 154, 155, 156,
57 157, 158, 159, 160, 161, 161, 162, 163, 164, 165, 166, 167, 168, 168, 169, 170,
58 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 184, 185, 186, 187,
59 188, 189, 191, 192, 194, 195, 197, 198, 199, 200, 202, 203, 204, 205, 207, 208,
60 209, 210, 212, 213, 215, 216, 218, 219, 220, 221, 222, 223, 225, 226, 227, 228,
61 229, 230, 232, 233, 234, 235, 237, 238, 239, 240, 242, 243, 244, 246, 247, 248
63 /* The actual LCD scanrate varies a lot with temperature on these targets */
64 #define LCD_SCANRATE 67 /* Hz */
66 #elif defined IAUDIO_M3 /* verified */
67 /* Average measurements of 2 iAudio remotes connected to an M3. */
68 static const unsigned char lcdlinear[256] = {
69 5, 9, 13, 17, 21, 26, 30, 34, 38, 42, 46, 50, 54, 58, 62, 66,
70 70, 73, 76, 78, 80, 82, 84, 86, 88, 90, 91, 92, 94, 95, 96, 97,
71 98, 99, 99, 100, 101, 102, 102, 103, 104, 104, 105, 105, 106, 107, 107, 108,
72 109, 109, 110, 110, 111, 111, 112, 112, 113, 113, 114, 114, 115, 115, 116, 116,
73 117, 117, 118, 118, 119, 119, 120, 120, 121, 121, 121, 122, 122, 123, 123, 123,
74 124, 124, 124, 125, 125, 126, 126, 126, 127, 127, 127, 128, 128, 129, 129, 129,
75 130, 130, 131, 131, 132, 132, 133, 133, 134, 134, 134, 135, 135, 136, 136, 136,
76 137, 137, 137, 138, 138, 139, 139, 139, 140, 140, 141, 141, 142, 142, 143, 143,
77 144, 144, 145, 145, 146, 147, 147, 148, 149, 149, 150, 150, 151, 151, 152, 152,
78 153, 153, 154, 154, 155, 155, 156, 156, 157, 157, 158, 158, 159, 160, 160, 161,
79 162, 162, 163, 164, 164, 165, 166, 167, 168, 168, 169, 169, 170, 171, 171, 172,
80 173, 173, 174, 175, 176, 176, 177, 178, 179, 179, 180, 181, 182, 182, 183, 184,
81 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 198, 199, 200, 201,
82 202, 203, 204, 205, 207, 208, 209, 210, 211, 212, 213, 214, 216, 217, 218, 219,
83 220, 221, 222, 223, 225, 226, 227, 228, 229, 230, 231, 232, 234, 235, 236, 237,
84 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 249, 250, 251, 252
86 /* The actual LCD scanrate is 3x as high, but 150 Hz or 75 Hz cause a too high
87 * CPU load (> 50 %). Even at 50Hz, greyscale display is rather smooth. Average
88 * from 2 iAudio remotes. */
89 #define LCD_SCANRATE 50 /* Hz */
91 #elif defined IAUDIO_M5 /* verified */
92 /* Measurement of one iAudio M5L */
93 static const unsigned char lcdlinear[256] = {
94 4, 6, 8, 10, 11, 13, 15, 17, 19, 21, 22, 24, 25, 27, 28, 30,
95 32, 33, 35, 36, 37, 39, 40, 42, 43, 44, 45, 46, 48, 49, 50, 51,
96 52, 52, 53, 54, 55, 55, 56, 57, 58, 58, 59, 60, 61, 61, 62, 63,
97 64, 64, 65, 65, 66, 66, 67, 67, 68, 68, 69, 70, 70, 71, 72, 72,
98 73, 73, 74, 75, 75, 76, 77, 77, 78, 78, 79, 79, 80, 80, 81, 81,
99 82, 82, 83, 84, 84, 85, 86, 86, 87, 87, 88, 89, 89, 90, 91, 91,
100 92, 92, 93, 93, 94, 94, 95, 95, 96, 96, 97, 98, 98, 99, 100, 100,
101 101, 101, 102, 102, 103, 103, 104, 104, 105, 105, 106, 106, 107, 107, 108, 108,
102 109, 109, 110, 110, 111, 111, 112, 112, 113, 113, 114, 114, 115, 115, 116, 116,
103 117, 117, 118, 119, 119, 120, 121, 121, 122, 122, 123, 124, 124, 125, 126, 126,
104 127, 127, 128, 129, 130, 130, 131, 132, 133, 133, 134, 135, 135, 136, 137, 137,
105 138, 139, 140, 141, 142, 142, 143, 144, 145, 146, 147, 148, 149, 149, 150, 151,
106 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 163, 164, 165, 167, 168, 169,
107 170, 172, 173, 175, 177, 179, 180, 182, 184, 186, 188, 190, 192, 194, 196, 198,
108 200, 202, 204, 205, 207, 209, 210, 212, 214, 216, 218, 219, 221, 223, 224, 226,
109 228, 230, 231, 233, 235, 236, 237, 239, 241, 243, 244, 246, 248, 249, 250, 252
111 #define LCD_SCANRATE 73 /* Hz */
113 #elif defined IPOD_1G2G /* verified */
114 /* Average measurements of an iPod 1st Gen (0x00010001) and an iPod 2nd Gen
115 * (0x00020000), measured with both backlight off & backlight on (flipped
116 * curves) and medium load (white background when measuring with backlight on),
117 * as the curve is load dependent (the controller's step-up converter doesn't
118 * provide enough juice). Table is for backlight_off state. */
119 static const unsigned char lcdlinear[256] = {
120 4, 6, 8, 9, 11, 13, 14, 16, 17, 18, 20, 21, 23, 24, 26, 27,
121 29, 30, 31, 32, 34, 35, 36, 37, 38, 39, 40, 41, 41, 42, 43, 44,
122 45, 45, 46, 47, 47, 48, 49, 49, 50, 50, 51, 51, 52, 52, 53, 53,
123 54, 54, 54, 55, 55, 56, 56, 56, 57, 57, 57, 58, 58, 59, 59, 59,
124 60, 60, 60, 61, 61, 62, 62, 62, 63, 63, 63, 64, 64, 65, 65, 65,
125 66, 66, 67, 67, 68, 68, 69, 69, 70, 70, 71, 71, 72, 72, 73, 73,
126 74, 74, 74, 75, 75, 76, 76, 76, 77, 77, 78, 78, 79, 79, 80, 80,
127 81, 81, 82, 82, 83, 83, 84, 84, 85, 85, 86, 86, 87, 87, 88, 88,
128 89, 89, 90, 91, 92, 92, 93, 94, 95, 95, 96, 97, 97, 98, 99, 99,
129 100, 100, 101, 102, 102, 103, 104, 104, 105, 105, 106, 107, 107, 108, 109, 109,
130 110, 110, 111, 112, 113, 113, 114, 115, 116, 116, 117, 118, 119, 119, 120, 121,
131 122, 122, 123, 124, 125, 125, 126, 127, 128, 129, 130, 131, 131, 132, 133, 134,
132 135, 137, 138, 139, 141, 142, 144, 145, 146, 147, 149, 150, 151, 152, 154, 155,
133 156, 158, 159, 161, 162, 164, 165, 167, 169, 171, 172, 174, 175, 177, 178, 180,
134 182, 184, 186, 188, 189, 191, 193, 195, 197, 199, 201, 203, 206, 208, 210, 212,
135 214, 217, 219, 221, 224, 226, 229, 231, 233, 236, 238, 240, 243, 245, 247, 250
137 /* Average from an iPod 1st Gen and an iPod 2nd Gen */
138 #define LCD_SCANRATE 96 /* Hz */
140 #elif defined IPOD_MINI2G /* verified */ \
141 || defined IPOD_MINI /* should be identical */ \
142 || defined IPOD_3G /* TODO: verify */ \
143 || defined IPOD_4G /* TODO: verify */
144 /* Measurement of one iPod Mini G2 */
145 static const unsigned char lcdlinear[256] = {
146 2, 5, 7, 10, 12, 15, 17, 20, 22, 24, 26, 28, 30, 32, 34, 36,
147 38, 40, 41, 42, 44, 45, 46, 47, 48, 49, 50, 50, 51, 52, 52, 53,
148 54, 54, 55, 55, 56, 56, 57, 57, 58, 58, 58, 59, 59, 60, 60, 60,
149 61, 61, 61, 62, 62, 63, 63, 63, 64, 64, 64, 64, 65, 65, 65, 65,
150 66, 66, 66, 66, 67, 67, 67, 67, 68, 68, 68, 68, 69, 69, 69, 69,
151 70, 70, 70, 70, 71, 71, 71, 71, 72, 72, 72, 73, 73, 74, 74, 74,
152 75, 75, 75, 75, 76, 76, 76, 76, 77, 77, 77, 78, 78, 79, 79, 79,
153 80, 80, 80, 81, 81, 82, 82, 82, 83, 83, 83, 84, 84, 85, 85, 85,
154 86, 86, 86, 87, 87, 88, 88, 88, 89, 89, 90, 90, 91, 91, 92, 92,
155 93, 93, 94, 94, 95, 95, 96, 96, 97, 97, 98, 99, 99, 100, 101, 101,
156 102, 102, 103, 104, 104, 105, 106, 106, 107, 108, 109, 110, 110, 111, 112, 113,
157 114, 115, 115, 116, 117, 118, 118, 119, 120, 121, 121, 122, 123, 124, 124, 125,
158 126, 127, 128, 129, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140,
159 141, 142, 143, 144, 146, 147, 148, 149, 150, 151, 153, 154, 155, 156, 158, 159,
160 160, 162, 163, 165, 166, 168, 169, 171, 172, 175, 177, 180, 182, 185, 187, 190,
161 192, 196, 199, 203, 206, 210, 213, 217, 220, 223, 227, 230, 234, 238, 242, 246
163 /* Average of an iPod Mini G2 and 2 3rd Gen iPods. */
164 #define LCD_SCANRATE 87 /* Hz */
166 #elif defined IRIVER_H100_SERIES /* verified */
167 /* Measurement of one Iriver H140 */
168 static const unsigned char lcdlinear[256] = {
169 5, 8, 12, 15, 18, 22, 25, 28, 31, 34, 36, 39, 42, 44, 47, 50,
170 53, 55, 57, 59, 62, 64, 66, 68, 70, 71, 72, 73, 75, 76, 77, 78,
171 79, 80, 80, 81, 82, 83, 83, 84, 85, 85, 86, 86, 87, 87, 88, 88,
172 89, 89, 90, 90, 91, 91, 92, 92, 93, 93, 93, 94, 94, 95, 95, 95,
173 96, 96, 96, 97, 97, 98, 98, 98, 99, 99, 99, 100, 100, 101, 101, 101,
174 102, 102, 102, 103, 103, 104, 104, 104, 105, 105, 106, 106, 107, 107, 108, 108,
175 109, 109, 109, 110, 110, 111, 111, 111, 112, 112, 113, 113, 114, 114, 115, 115,
176 116, 116, 117, 117, 118, 118, 119, 119, 120, 120, 121, 121, 122, 122, 123, 123,
177 124, 124, 125, 125, 126, 127, 127, 128, 129, 129, 130, 130, 131, 131, 132, 132,
178 133, 133, 134, 135, 135, 136, 137, 137, 138, 138, 139, 139, 140, 140, 141, 141,
179 142, 142, 143, 143, 144, 145, 145, 146, 147, 147, 148, 148, 149, 150, 150, 151,
180 152, 152, 153, 153, 154, 155, 155, 156, 157, 157, 158, 159, 160, 160, 161, 162,
181 163, 164, 165, 166, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177,
182 178, 179, 181, 182, 183, 184, 186, 187, 188, 189, 191, 192, 193, 194, 196, 197,
183 198, 200, 202, 203, 205, 207, 208, 210, 212, 214, 215, 217, 218, 220, 221, 223,
184 224, 226, 228, 229, 231, 233, 235, 236, 238, 240, 241, 242, 244, 245, 246, 248
186 #define LCD_SCANRATE 70 /* Hz */
188 #elif defined MROBE_100 /* verified */
189 /* Average measurements of 2 m:robe 100 s */
190 static const unsigned char lcdlinear[256] = {
191 10, 14, 18, 22, 26, 30, 34, 38, 42, 46, 49, 53, 56, 60, 63, 67,
192 70, 73, 76, 79, 81, 84, 87, 90, 92, 95, 97, 100, 102, 105, 107, 110,
193 112, 114, 116, 118, 119, 121, 123, 125, 126, 128, 130, 131, 133, 135, 136, 138,
194 139, 141, 142, 143, 144, 146, 147, 148, 149, 150, 151, 152, 154, 155, 156, 157,
195 158, 159, 160, 161, 161, 162, 163, 164, 165, 166, 167, 168, 168, 169, 170, 171,
196 172, 172, 173, 173, 174, 174, 175, 175, 176, 176, 177, 178, 178, 179, 180, 180,
197 181, 181, 182, 182, 183, 183, 184, 184, 185, 185, 186, 186, 187, 187, 188, 188,
198 189, 189, 190, 190, 191, 191, 192, 192, 193, 193, 193, 194, 194, 195, 195, 195,
199 196, 196, 197, 197, 198, 198, 199, 199, 200, 200, 200, 201, 201, 202, 202, 202,
200 203, 203, 204, 204, 205, 205, 206, 206, 207, 207, 207, 208, 208, 209, 209, 209,
201 210, 210, 210, 211, 211, 212, 212, 212, 213, 213, 213, 214, 214, 215, 215, 215,
202 216, 216, 216, 217, 217, 218, 218, 218, 219, 219, 219, 220, 220, 221, 221, 221,
203 222, 222, 222, 223, 223, 224, 224, 224, 225, 225, 225, 226, 226, 227, 227, 227,
204 228, 228, 229, 229, 230, 230, 231, 231, 232, 232, 232, 233, 233, 234, 234, 234,
205 235, 235, 235, 236, 236, 237, 237, 237, 238, 238, 238, 239, 239, 240, 240, 240,
206 241, 241, 242, 242, 243, 243, 244, 244, 247, 248, 248, 249, 250, 250, 251, 252
208 #define LCD_SCANRATE 51 /* Hz */
210 #elif defined SANSA_CLIP /* TODO: calibrate */
211 static const unsigned char lcdlinear[256] = {
212 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
213 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
214 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
215 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
216 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
217 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
218 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
219 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127,
220 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143,
221 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159,
222 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175,
223 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191,
224 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207,
225 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223,
226 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239,
227 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255
229 #define LCD_SCANRATE 78 /* Hz */
231 #elif defined SANSA_CLIPV2 /* TODO: calibrate */
232 static const unsigned char lcdlinear[256] = {
233 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
234 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
235 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
236 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
237 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
238 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
239 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
240 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127,
241 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143,
242 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159,
243 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175,
244 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191,
245 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207,
246 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223,
247 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239,
248 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255
250 #define LCD_SCANRATE 74 /* Hz */
252 #elif defined SANSA_CLIPPLUS /* TODO: calibrate */
253 static const unsigned char lcdlinear[256] = {
254 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
255 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
256 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
257 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
258 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
259 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
260 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
261 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127,
262 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143,
263 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159,
264 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175,
265 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191,
266 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207,
267 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223,
268 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239,
269 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255
271 #define LCD_SCANRATE 80 /* Hz */
273 #elif defined MPIO_HD200
274 /* matrix generated in the following way
275 * 1) run 5 times test_grey
276 * 2) average results (joint points)
277 * 3) plot full matrix obtained by natural cubic b-spline interpolation
278 * 4) hand tweak joint points to smooth the curve
279 * 5) repeat steps 3 and 4 until interpolated curve is smooth
281 static const unsigned char lcdlinear[256] = {
282 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7,
283 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15,
284 16, 16, 16, 17, 17, 18, 18, 18, 19, 19, 20, 20, 20, 21, 21, 21,
285 22, 22, 22, 22, 23, 23, 23, 24, 24, 24, 24, 25, 25, 25, 26, 26,
286 27, 27, 27, 28, 28, 29, 29, 30, 30, 31, 31, 32, 32, 33, 33, 34,
287 35, 35, 36, 36, 37, 37, 38, 39, 39, 40, 41, 41, 42, 43, 43, 44,
288 45, 45, 46, 46, 47, 48, 49, 49, 50, 51, 51, 52, 53, 53, 54, 55,
289 56, 56, 57, 58, 58, 59, 60, 61, 61, 62, 63, 64, 64, 65, 66, 67,
290 68, 68, 69, 70, 71, 71, 72, 73, 74, 75, 75, 76, 77, 78, 79, 80,
291 81, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
292 96, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 108, 109, 110, 111,
293 113, 114, 115, 117, 118, 120, 121, 123, 125, 126, 128, 130, 131, 133, 135, 137,
294 139, 140, 142, 144, 146, 147, 149, 151, 152, 154, 156, 157, 159, 161, 162, 164,
295 166, 167, 169, 170, 172, 173, 175, 176, 177, 179, 180, 182, 183, 184, 186, 187,
296 189, 190, 191, 193, 194, 195, 197, 198, 199, 201, 202, 203, 205, 206, 207, 208,
297 210, 211, 212, 213, 214, 215, 217, 218, 219, 220, 221, 222, 223, 224, 225, 227
299 #define LCD_SCANRATE 153 /* Hz */
301 #elif defined MPIO_HD300 /* verified */
302 /* Measurement of one iAudio M5L */
303 static const unsigned char lcdlinear[256] = {
304 4, 6, 8, 10, 11, 13, 15, 17, 19, 21, 22, 24, 25, 27, 28, 30,
305 32, 33, 35, 36, 37, 39, 40, 42, 43, 44, 45, 46, 48, 49, 50, 51,
306 52, 52, 53, 54, 55, 55, 56, 57, 58, 58, 59, 60, 61, 61, 62, 63,
307 64, 64, 65, 65, 66, 66, 67, 67, 68, 68, 69, 70, 70, 71, 72, 72,
308 73, 73, 74, 75, 75, 76, 77, 77, 78, 78, 79, 79, 80, 80, 81, 81,
309 82, 82, 83, 84, 84, 85, 86, 86, 87, 87, 88, 89, 89, 90, 91, 91,
310 92, 92, 93, 93, 94, 94, 95, 95, 96, 96, 97, 98, 98, 99, 100, 100,
311 101, 101, 102, 102, 103, 103, 104, 104, 105, 105, 106, 106, 107, 107, 108, 108,
312 109, 109, 110, 110, 111, 111, 112, 112, 113, 113, 114, 114, 115, 115, 116, 116,
313 117, 117, 118, 119, 119, 120, 121, 121, 122, 122, 123, 124, 124, 125, 126, 126,
314 127, 127, 128, 129, 130, 130, 131, 132, 133, 133, 134, 135, 135, 136, 137, 137,
315 138, 139, 140, 141, 142, 142, 143, 144, 145, 146, 147, 148, 149, 149, 150, 151,
316 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 163, 164, 165, 167, 168, 169,
317 170, 172, 173, 175, 177, 179, 180, 182, 184, 186, 188, 190, 192, 194, 196, 198,
318 200, 202, 204, 205, 207, 209, 210, 212, 214, 216, 218, 219, 221, 223, 224, 226,
319 228, 230, 231, 233, 235, 236, 237, 239, 241, 243, 244, 246, 248, 249, 250, 252
321 #define LCD_SCANRATE 73 /* Hz */
323 #else /* not yet calibrated targets - generic linear mapping */
324 /* TODO: calibrate iFP7xx */
325 static const unsigned char lcdlinear[256] = {
326 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
327 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
328 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
329 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
330 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
331 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
332 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
333 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127,
334 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143,
335 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159,
336 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175,
337 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191,
338 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207,
339 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223,
340 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239,
341 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255
343 /* generic default */
344 #define LCD_SCANRATE 70 /* Hz */
346 #endif
347 #else /* SIMULATOR */
348 /* undo a (generic) PC display gamma of 2.0 to simulate target behaviour */
349 static const unsigned char lcdlinear[256] = {
350 0, 16, 23, 28, 32, 36, 39, 42, 45, 48, 50, 53, 55, 58, 60, 62,
351 64, 66, 68, 70, 71, 73, 75, 77, 78, 80, 81, 83, 84, 86, 87, 89,
352 90, 92, 93, 94, 96, 97, 98, 100, 101, 102, 103, 105, 106, 107, 108, 109,
353 111, 112, 113, 114, 115, 116, 117, 118, 119, 121, 122, 123, 124, 125, 126, 127,
354 128, 129, 130, 131, 132, 133, 134, 135, 135, 136, 137, 138, 139, 140, 141, 142,
355 143, 144, 145, 145, 146, 147, 148, 149, 150, 151, 151, 152, 153, 154, 155, 156,
356 156, 157, 158, 159, 160, 160, 161, 162, 163, 164, 164, 165, 166, 167, 167, 168,
357 169, 170, 170, 171, 172, 173, 173, 174, 175, 176, 176, 177, 178, 179, 179, 180,
358 181, 181, 182, 183, 183, 184, 185, 186, 186, 187, 188, 188, 189, 190, 190, 191,
359 192, 192, 193, 194, 194, 195, 196, 196, 197, 198, 198, 199, 199, 200, 201, 201,
360 202, 203, 203, 204, 204, 205, 206, 206, 207, 208, 208, 209, 209, 210, 211, 211,
361 212, 212, 213, 214, 214, 215, 215, 216, 217, 217, 218, 218, 219, 220, 220, 221,
362 221, 222, 222, 223, 224, 224, 225, 225, 226, 226, 227, 228, 228, 229, 229, 230,
363 230, 231, 231, 232, 233, 233, 234, 234, 235, 235, 236, 236, 237, 237, 238, 238,
364 239, 240, 240, 241, 241, 242, 242, 243, 243, 244, 244, 245, 245, 246, 246, 247,
365 247, 248, 248, 249, 249, 250, 250, 251, 251, 252, 252, 253, 253, 254, 254, 255
367 #endif /* SIMULATOR */
369 /* Prototypes */
370 static inline void _deferred_update(void) __attribute__ ((always_inline));
371 static int exp_s16p16(int x);
372 static int log_s16p16(int x);
373 static void grey_screendump_hook(int fd);
374 static void fill_gvalues(void);
375 #ifdef SIMULATOR
376 static unsigned long _grey_get_pixel(int x, int y);
377 #else
378 static void _timer_isr(void);
379 #endif
382 #if defined(HAVE_BACKLIGHT_INVERSION) && !defined(SIMULATOR)
383 static void invert_gvalues(void)
385 unsigned char *val, *end;
386 unsigned char rev_tab[256];
387 unsigned i;
388 unsigned last_i = 0;
389 unsigned x = 0;
390 unsigned last_x;
392 /* Step 1: Calculate a transposed table for undoing the old mapping */
393 for (i = 0; i < 256; i++)
395 last_x = x;
396 x = _grey_info.gvalue[i];
397 if (x > last_x)
399 rev_tab[last_x++] = (last_i + i) / 2;
400 while (x > last_x)
401 rev_tab[last_x++] = i;
402 last_i = i;
405 rev_tab[last_x++] = (last_i + 255) / 2;
406 while (256 > last_x)
407 rev_tab[last_x++] = 255;
409 /* Step 2: Calculate new mapping */
410 fill_gvalues();
412 /* Step 3: Transpose all pixel values */
413 val = _grey_info.values;
414 end = val + _GREY_MULUQ(_grey_info.width, _grey_info.height);
417 *val = _grey_info.gvalue[rev_tab[*val]];
418 while (++val < end);
420 #endif
422 /* Update LCD areas not covered by the greyscale overlay */
423 static inline void _deferred_update(void)
425 int x1 = MAX(_grey_info.x, 0);
426 int x2 = MIN(_grey_info.x + _grey_info.width, LCD_WIDTH);
427 int y1 = MAX(_grey_info.y, 0);
428 int y2 = MIN(_grey_info.y + _grey_info.height, LCD_HEIGHT);
430 if (y1 > 0) /* refresh part above overlay, full width */
431 rb->lcd_update_rect(0, 0, LCD_WIDTH, y1);
433 if (y2 < LCD_HEIGHT) /* refresh part below overlay, full width */
434 rb->lcd_update_rect(0, y2, LCD_WIDTH, LCD_HEIGHT - y2);
436 if (x1 > 0) /* refresh part to the left of overlay */
437 rb->lcd_update_rect(0, y1, x1, y2 - y1);
439 if (x2 < LCD_WIDTH) /* refresh part to the right of overlay */
440 rb->lcd_update_rect(x2, y1, LCD_WIDTH - x2, y2 - y1);
443 #ifdef SIMULATOR
445 /* Callback function for grey_ub_gray_bitmap_part() to read a pixel from the
446 * greybuffer. Note that x and y are in LCD coordinates, not greybuffer
447 * coordinates! */
448 static unsigned long _grey_get_pixel(int x, int y)
450 long val;
451 int xg = x - _grey_info.x;
452 int yg = y - _grey_info.y;
453 #if LCD_PIXELFORMAT == HORIZONTAL_PACKING
454 int idx = _grey_info.width * yg + xg;
455 #else /* vertical packing or vertical interleaved */
456 int idx = _grey_info.width * (yg & ~_GREY_BMASK)
457 + (xg << _GREY_BSHIFT) + (~yg & _GREY_BMASK);
458 #endif
460 val = _grey_info.values[idx];
461 #ifdef HAVE_LCD_SPLIT
462 val -= val >> 7;
463 #endif
464 return val;
467 #else /* !SIMULATOR */
469 /* Timer interrupt handler: display next frame */
470 static void _timer_isr(void)
472 #if defined(HAVE_BACKLIGHT_INVERSION) && !defined(SIMULATOR)
473 unsigned long check = rb->is_backlight_on(true)
474 ? 0 : _GREY_BACKLIGHT_ON;
476 if ((_grey_info.flags & (_GREY_BACKLIGHT_ON|GREY_RAWMAPPED)) == check)
478 _grey_info.flags ^= _GREY_BACKLIGHT_ON;
479 invert_gvalues();
480 return; /* don't overload this timer slot */
482 #endif
483 #if LCD_PIXELFORMAT == HORIZONTAL_PACKING
484 rb->lcd_blit_grey_phase(_grey_info.values, _grey_info.phases,
485 _grey_info.bx, _grey_info.y,
486 _grey_info.bwidth, _grey_info.height,
487 _grey_info.width);
488 #else /* vertical packing or vertical interleaved */
489 rb->lcd_blit_grey_phase(_grey_info.values, _grey_info.phases,
490 _grey_info.x, _grey_info.by,
491 _grey_info.width, _grey_info.bheight,
492 _grey_info.width);
493 #endif
495 if (_grey_info.flags & _GREY_DEFERRED_UPDATE) /* lcd_update() requested? */
497 _deferred_update();
498 _grey_info.flags &= ~_GREY_DEFERRED_UPDATE; /* clear request */
502 #endif /* !SIMULATOR */
504 /* fixed point exp() */
505 static int exp_s16p16(int x)
507 int t;
508 int y = 0x00010000;
510 if (x < 0) x += 0xb1721, y >>= 16;
511 t = x - 0x58b91; if (t >= 0) x = t, y <<= 8;
512 t = x - 0x2c5c8; if (t >= 0) x = t, y <<= 4;
513 t = x - 0x162e4; if (t >= 0) x = t, y <<= 2;
514 t = x - 0x0b172; if (t >= 0) x = t, y <<= 1;
515 t = x - 0x067cd; if (t >= 0) x = t, y += y >> 1;
516 t = x - 0x03920; if (t >= 0) x = t, y += y >> 2;
517 t = x - 0x01e27; if (t >= 0) x = t, y += y >> 3;
518 t = x - 0x00f85; if (t >= 0) x = t, y += y >> 4;
519 t = x - 0x007e1; if (t >= 0) x = t, y += y >> 5;
520 t = x - 0x003f8; if (t >= 0) x = t, y += y >> 6;
521 t = x - 0x001fe; if (t >= 0) x = t, y += y >> 7;
522 y += ((y >> 8) * x) >> 8;
524 return y;
527 /* fixed point log() */
528 static int log_s16p16(int x)
530 int t;
531 int y = 0xa65af;
533 if (x < 0x00008000) x <<=16, y -= 0xb1721;
534 if (x < 0x00800000) x <<= 8, y -= 0x58b91;
535 if (x < 0x08000000) x <<= 4, y -= 0x2c5c8;
536 if (x < 0x20000000) x <<= 2, y -= 0x162e4;
537 if (x < 0x40000000) x <<= 1, y -= 0x0b172;
538 t = x + (x >> 1); if ((t & 0x80000000) == 0) x = t, y -= 0x067cd;
539 t = x + (x >> 2); if ((t & 0x80000000) == 0) x = t, y -= 0x03920;
540 t = x + (x >> 3); if ((t & 0x80000000) == 0) x = t, y -= 0x01e27;
541 t = x + (x >> 4); if ((t & 0x80000000) == 0) x = t, y -= 0x00f85;
542 t = x + (x >> 5); if ((t & 0x80000000) == 0) x = t, y -= 0x007e1;
543 t = x + (x >> 6); if ((t & 0x80000000) == 0) x = t, y -= 0x003f8;
544 t = x + (x >> 7); if ((t & 0x80000000) == 0) x = t, y -= 0x001fe;
545 x = 0x80000000 - x;
546 y -= x >> 15;
548 return y;
551 static void fill_gvalues(void)
553 int i;
554 unsigned data;
556 #if defined(HAVE_BACKLIGHT_INVERSION) && !defined(SIMULATOR)
557 unsigned imask = (_grey_info.flags & _GREY_BACKLIGHT_ON) ? 0xff : 0;
558 #else
559 const unsigned imask = 0;
560 #endif
561 for (i = 0; i < 256; i++)
563 data = exp_s16p16((_GREY_GAMMA * log_s16p16(i * 257 + 1)) >> 8) + 128;
564 data = (data - (data >> 8)) >> 8; /* approx. data /= 257 */
565 data = ((lcdlinear[data ^ imask] ^ imask) << 7) + 127;
566 _grey_info.gvalue[i] = (data + (data >> 8)) >> 8;
567 /* approx. data / 255 */
571 /* Initialise the framework and prepare the greyscale display buffer
573 arguments:
574 gbuf = pointer to the memory area to use (e.g. plugin buffer)
575 gbuf_size = max usable size of the buffer
576 features = flags for requesting features
577 GREY_BUFFERED: use chunky pixel buffering
578 This allows to use all drawing functions, but needs more
579 memory. Unbuffered operation provides only a subset of
580 drawing functions. (only grey_bitmap drawing and scrolling)
581 GREY_RAWMAPPED: no LCD linearisation and gamma correction
582 width = width in pixels (1..LCD_WIDTH)
583 height = height in pixels (1..LCD_HEIGHT)
584 Note that depending on the target LCD, either height or
585 width are rounded up to a multiple of 4 or 8.
587 result:
588 true on success, false on failure
590 If you need info about the memory taken by the greyscale buffer, supply a
591 long* as the last parameter. This long will then contain the number of bytes
592 used. The total memory needed can be calculated as follows:
593 total_mem =
594 width * height * 2 [grey display data]
595 + buffered ? (width * height) : 0 [chunky buffer]
596 + 0..3 [alignment]
598 The function is authentic regarding memory usage on the simulator, even
599 if it doesn't use all of the allocated memory. */
600 bool grey_init(unsigned char *gbuf, long gbuf_size,
601 unsigned features, int width, int height, long *buf_taken)
603 int bdim, i;
604 long plane_size, buftaken;
605 unsigned data;
606 #ifndef SIMULATOR
607 unsigned *dst, *end;
608 #endif
610 if ((unsigned) width > LCD_WIDTH
611 || (unsigned) height > LCD_HEIGHT)
612 return false;
614 #if LCD_PIXELFORMAT == HORIZONTAL_PACKING
615 bdim = (width + 7) >> 3;
616 width = bdim << 3;
617 #else /* vertical packing or vertical interleaved */
618 #if (LCD_DEPTH == 1) || (LCD_PIXELFORMAT == VERTICAL_INTERLEAVED)
619 bdim = (height + 7) >> 3;
620 height = bdim << 3;
621 #elif LCD_DEPTH == 2
622 bdim = (height + 3) >> 2;
623 height = bdim << 2;
624 #endif
625 #endif
627 plane_size = _GREY_MULUQ(width, height);
628 #if defined(CPU_COLDFIRE) /* Buffers should be line aligned */ \
629 || defined(CPU_PP) && (NUM_CORES > 1) /* Buffers must be cache line aligned */
630 plane_size += (-plane_size) & 0xf;
631 buftaken = (-(long)gbuf) & 0xf;
632 #else /* Buffers must be 32 bit aligned. */
633 buftaken = (-(long)gbuf) & 3;
634 #endif
635 gbuf += buftaken;
637 if (features & GREY_BUFFERED) /* chunky buffer */
639 _grey_info.buffer = gbuf;
640 gbuf += plane_size;
641 buftaken += plane_size;
643 #if NUM_CORES > 1 /* Values and phases must be uncached when running on COP */
644 if (features & GREY_ON_COP)
645 gbuf = UNCACHED_ADDR(gbuf);
646 #endif
647 _grey_info.values = gbuf;
648 gbuf += plane_size;
649 _grey_info.phases = gbuf;
650 buftaken += 2 * plane_size;
652 if (buftaken > gbuf_size)
653 return false;
655 /* Init to white */
656 rb->memset(_grey_info.values, 0x80, plane_size);
658 #ifndef SIMULATOR
659 /* Init phases with random bits */
660 dst = (unsigned*)(_grey_info.phases);
661 end = (unsigned*)(_grey_info.phases + plane_size);
664 *dst++ = rb->rand();
665 while (dst < end);
666 #endif
668 _grey_info.x = 0;
669 _grey_info.y = 0;
670 _grey_info.width = width;
671 _grey_info.height = height;
672 #if LCD_PIXELFORMAT == HORIZONTAL_PACKING
673 _grey_info.bx = 0;
674 _grey_info.bwidth = bdim;
675 #else /* vertical packing or vertical interleaved */
676 _grey_info.by = 0;
677 _grey_info.bheight = bdim;
678 #endif
679 _grey_info.flags = features & 0xff;
681 /* default viewport and settings */
682 grey_set_viewport(NULL);
683 grey_viewport_set_fullscreen(NULL, SCREEN_MAIN);
684 grey_set_framebuffer(NULL);
686 /* precalculate the value -> pattern index conversion table, taking
687 linearisation and gamma correction into account */
688 if (features & GREY_RAWMAPPED)
690 for (i = 0; i < 256; i++)
692 data = i << 7;
693 _grey_info.gvalue[i] = (data + (data >> 8)) >> 8;
696 else
698 #if defined(HAVE_BACKLIGHT_INVERSION) && !defined(SIMULATOR)
699 if (rb->is_backlight_on(true))
700 _grey_info.flags |= _GREY_BACKLIGHT_ON;
701 #endif
702 fill_gvalues();
705 if (buf_taken) /* caller requested info about space taken */
706 *buf_taken = buftaken;
708 return true;
711 /* Release the greyscale display buffer and the library
712 DO CALL either this function or at least grey_show_display(false)
713 before you exit, otherwise nasty things may happen. */
714 void grey_release(void)
716 grey_show(false);
719 /* Switch the greyscale overlay on or off
720 DO NOT call lcd_update() or any other api function that directly accesses
721 the lcd while the greyscale overlay is running! If you need to do
722 lcd_update() to update something outside the greyscale overlay area, use
723 grey_deferred_update() instead.
725 Other functions to avoid are:
726 lcd_blit_mono(), lcd_update_rect(), lcd_set_contrast(),
727 lcd_set_invert_display(), lcd_set_flip() */
728 void grey_show(bool enable)
730 if (enable && !(_grey_info.flags & _GREY_RUNNING))
732 _grey_info.flags |= _GREY_RUNNING;
733 #ifdef SIMULATOR
734 rb->sim_lcd_ex_init(_grey_get_pixel);
735 rb->sim_lcd_ex_update_rect(_grey_info.x, _grey_info.y,
736 _grey_info.width, _grey_info.height);
737 #else /* !SIMULATOR */
738 #ifdef NEED_BOOST
739 rb->cpu_boost(true);
740 #endif
741 #if NUM_CORES > 1
742 rb->timer_register(1, NULL, TIMER_FREQ / LCD_SCANRATE,
743 _timer_isr,
744 (_grey_info.flags & GREY_ON_COP) ? COP : CPU);
745 #else
746 rb->timer_register(1, NULL, TIMER_FREQ / LCD_SCANRATE, _timer_isr);
747 #endif
748 #endif /* !SIMULATOR */
749 rb->screen_dump_set_hook(grey_screendump_hook);
751 else if (!enable && (_grey_info.flags & _GREY_RUNNING))
753 #ifdef SIMULATOR
754 rb->sim_lcd_ex_init(NULL);
755 #else /* !SIMULATOR */
756 rb->timer_unregister();
757 #if NUM_CORES > 1 /* Make sure the ISR has finished before calling lcd_update() */
758 rb->sleep(HZ/100);
759 #endif
760 #ifdef NEED_BOOST
761 rb->cpu_boost(false);
762 #endif
763 #endif /* !SIMULATOR */
764 _grey_info.flags &= ~_GREY_RUNNING;
765 rb->screen_dump_set_hook(NULL);
766 rb->lcd_update(); /* restore whatever there was before */
770 void grey_update_rect(int x, int y, int width, int height)
772 grey_ub_gray_bitmap_part(_grey_info.buffer, x, y, _grey_info.width,
773 x, y, width, height);
776 /* Update the whole greyscale overlay */
777 void grey_update(void)
779 grey_ub_gray_bitmap_part(_grey_info.buffer, 0, 0, _grey_info.width,
780 0, 0, _grey_info.width, _grey_info.height);
783 /* Do an lcd_update() to show changes done by rb->lcd_xxx() functions
784 (in areas of the screen not covered by the greyscale overlay). */
785 void grey_deferred_lcd_update(void)
787 if (_grey_info.flags & _GREY_RUNNING)
789 #ifdef SIMULATOR
790 _deferred_update();
791 #else
792 _grey_info.flags |= _GREY_DEFERRED_UPDATE;
793 #endif
795 else
796 rb->lcd_update();
799 /*** Screenshot ***/
801 #ifdef HAVE_LCD_SPLIT
802 #define NUM_SHADES 128
803 #define BMP_NUMCOLORS 256
804 #else
805 #define NUM_SHADES 129
806 #define BMP_NUMCOLORS 129
807 #endif
809 #define BMP_BPP 8
810 #define BMP_LINESIZE ((LCD_WIDTH + 3) & ~3)
811 #define BMP_HEADERSIZE (54 + 4 * BMP_NUMCOLORS)
812 #define BMP_DATASIZE (BMP_LINESIZE * (LCD_HEIGHT+LCD_SPLIT_LINES))
813 #define BMP_TOTALSIZE (BMP_HEADERSIZE + BMP_DATASIZE)
815 static const unsigned char bmpheader[] =
817 0x42, 0x4d, /* 'BM' */
818 LE32_CONST(BMP_TOTALSIZE), /* Total file size */
819 0x00, 0x00, 0x00, 0x00, /* Reserved */
820 LE32_CONST(BMP_HEADERSIZE), /* Offset to start of pixel data */
822 0x28, 0x00, 0x00, 0x00, /* Size of (2nd) header */
823 LE32_CONST(LCD_WIDTH), /* Width in pixels */
824 LE32_CONST(LCD_HEIGHT+LCD_SPLIT_LINES), /* Height in pixels */
825 0x01, 0x00, /* Number of planes (always 1) */
826 LE16_CONST(BMP_BPP), /* Bits per pixel 1/4/8/16/24 */
827 0x00, 0x00, 0x00, 0x00, /* Compression mode, 0 = none */
828 LE32_CONST(BMP_DATASIZE), /* Size of bitmap data */
829 0xc4, 0x0e, 0x00, 0x00, /* Horizontal resolution (pixels/meter) */
830 0xc4, 0x0e, 0x00, 0x00, /* Vertical resolution (pixels/meter) */
831 LE32_CONST(BMP_NUMCOLORS), /* Number of used colours */
832 LE32_CONST(BMP_NUMCOLORS), /* Number of important colours */
835 #if LCD_DEPTH == 2
836 /* Only defined for positive, non-split LCD for now */
837 static const unsigned char colorindex[4] = {128, 85, 43, 0};
838 #endif
840 /* Hook function for core screen_dump() to save the current display
841 content (b&w and greyscale overlay) to an 8-bit BMP file. */
842 static void grey_screendump_hook(int fd)
844 int i;
845 int y, gx, gy;
846 #if LCD_PIXELFORMAT == VERTICAL_PACKING
847 #if LCD_DEPTH == 1
848 unsigned val;
849 unsigned mask;
850 #elif LCD_DEPTH == 2
851 int shift;
852 #endif
853 #elif LCD_PIXELFORMAT == VERTICAL_INTERLEAVED
854 unsigned data;
855 int shift;
856 #endif /* LCD_PIXELFORMAT */
857 fb_data *src;
858 unsigned char *gsrc;
859 unsigned char *dst, *dst_end;
860 unsigned char linebuf[MAX(4*NUM_SHADES,BMP_LINESIZE)];
862 rb->write(fd, bmpheader, sizeof(bmpheader)); /* write header */
864 /* build clut */
865 rb->memset(linebuf, 0, 4*NUM_SHADES);
866 dst = linebuf;
868 for (i = 0; i < NUM_SHADES; i++)
870 *dst++ = (_GREY_MULUQ(BLUE_CMP(LCD_BL_BRIGHTCOLOR)
871 -BLUE_CMP(LCD_BL_DARKCOLOR), i) >> 7)
872 + BLUE_CMP(LCD_BL_DARKCOLOR);
873 *dst++ = (_GREY_MULUQ(GREEN_CMP(LCD_BL_BRIGHTCOLOR)
874 -GREEN_CMP(LCD_BL_DARKCOLOR), i) >> 7)
875 + GREEN_CMP(LCD_BL_DARKCOLOR);
876 *dst++ = (_GREY_MULUQ(RED_CMP(LCD_BL_BRIGHTCOLOR)
877 -RED_CMP(LCD_BL_DARKCOLOR), i) >> 7)
878 + RED_CMP(LCD_BL_DARKCOLOR);
879 dst++;
881 rb->write(fd, linebuf, 4*NUM_SHADES);
883 #ifdef HAVE_LCD_SPLIT
884 dst = linebuf;
886 for (i = 0; i <= NUM_SHADES; i++)
888 *dst++ = (_GREY_MULUQ(BLUE_CMP(LCD_BL_BRIGHTCOLOR_2)
889 -BLUE_CMP(LCD_BL_DARKCOLOR_2), i) >> 7)
890 + BLUE_CMP(LCD_BL_DARKCOLOR_2);
891 *dst++ = (_GREY_MULUQ(GREEN_CMP(LCD_BL_BRIGHTCOLOR_2)
892 -GREEN_CMP(LCD_BL_DARKCOLOR_2), i) >> 7)
893 + GREEN_CMP(LCD_BL_DARKCOLOR_2);
894 *dst++ = (_GREY_MULUQ(RED_CMP(LCD_BL_BRIGHTCOLOR_2)
895 -RED_CMP(LCD_BL_DARKCOLOR_2), i) >> 7)
896 + RED_CMP(LCD_BL_DARKCOLOR_2);
897 dst++;
899 rb->write(fd, linebuf, 4*NUM_SHADES);
900 #endif
902 /* BMP image goes bottom -> top */
903 for (y = LCD_HEIGHT - 1; y >= 0; y--)
905 rb->memset(linebuf, 0, BMP_LINESIZE);
907 #if defined(HAVE_LCD_SPLIT) && (LCD_SPLIT_LINES == 2)
908 if (y == LCD_SPLIT_POS - 1)
910 rb->write(fd, linebuf, BMP_LINESIZE);
911 rb->write(fd, linebuf, BMP_LINESIZE);
913 #endif
915 dst = linebuf;
916 dst_end = dst + LCD_WIDTH;
917 gy = y - _grey_info.y;
918 gx = -_grey_info.x;
920 #if LCD_PIXELFORMAT == HORIZONTAL_PACKING
921 gsrc = _grey_info.values + _GREY_MULUQ(_grey_info.width, gy);
923 #if LCD_DEPTH == 2
924 src = rb->lcd_framebuffer + _GREY_MULUQ(LCD_FBWIDTH, y);
928 if (((unsigned)gy < (unsigned)_grey_info.height)
929 && ((unsigned)gx < (unsigned)_grey_info.width))
931 *dst++ = *gsrc++;
932 *dst++ = *gsrc++;
933 *dst++ = *gsrc++;
934 *dst++ = *gsrc++;
936 else
938 unsigned data = *src;
939 *dst++ = colorindex[(data >> 6) & 3];
940 *dst++ = colorindex[(data >> 4) & 3];
941 *dst++ = colorindex[(data >> 2) & 3];
942 *dst++ = colorindex[data & 3];
944 gx++, src++;
946 while (dst < dst_end);
948 #endif /* LCD_DEPTH */
949 #elif LCD_PIXELFORMAT == VERTICAL_PACKING
950 gsrc = _grey_info.values + (~gy & _GREY_BMASK)
951 + _GREY_MULUQ(_grey_info.width, gy & ~_GREY_BMASK);
953 #if LCD_DEPTH == 1
954 mask = BIT_N(y & 7);
955 src = rb->lcd_framebuffer + _GREY_MULUQ(LCD_WIDTH, y >> 3);
959 if (((unsigned)gy < (unsigned)_grey_info.height)
960 && ((unsigned)gx < (unsigned)_grey_info.width))
962 val = *gsrc;
963 #ifdef HAVE_LCD_SPLIT
964 val -= val >> 7;
965 #endif
966 gsrc += _GREY_BSIZE;
968 else
970 #ifdef HAVE_NEGATIVE_LCD
971 val = (*src & mask) ? (NUM_SHADES-1) : 0;
972 #else
973 val = (*src & mask) ? 0 : (NUM_SHADES-1);
974 #endif
976 #ifdef HAVE_LCD_SPLIT
977 if (y < LCD_SPLIT_POS)
978 val |= 0x80;
979 #endif
980 *dst++ = val;
981 gx++, src++;
983 while (dst < dst_end);
985 #elif LCD_DEPTH == 2
986 shift = 2 * (y & 3);
987 src = rb->lcd_framebuffer + _GREY_MULUQ(LCD_WIDTH, y >> 2);
991 if (((unsigned)gy < (unsigned)_grey_info.height)
992 && ((unsigned)gx < (unsigned)_grey_info.width))
994 *dst++ = *gsrc;
995 gsrc += _GREY_BSIZE;
997 else
999 *dst++ = colorindex[(*src >> shift) & 3];
1001 gx++, src++;
1003 while (dst < dst_end);
1005 #endif /* LCD_DEPTH */
1006 #elif LCD_PIXELFORMAT == VERTICAL_INTERLEAVED
1007 gsrc = _grey_info.values + (~gy & _GREY_BMASK)
1008 + _GREY_MULUQ(_grey_info.width, gy & ~_GREY_BMASK);
1010 #if LCD_DEPTH == 2
1011 shift = y & 7;
1012 src = rb->lcd_framebuffer + _GREY_MULUQ(LCD_WIDTH, y >> 3);
1016 if (((unsigned)gy < (unsigned)_grey_info.height)
1017 && ((unsigned)gx < (unsigned)_grey_info.width))
1019 *dst++ = *gsrc;
1020 gsrc += _GREY_BSIZE;
1022 else
1024 data = (*src >> shift) & 0x0101;
1025 *dst++ = colorindex[((data >> 7) | data) & 3];
1027 gx++, src++;
1029 while (dst < dst_end);
1031 #endif /* LCD_DEPTH */
1032 #endif /* LCD_PIXELFORMAT */
1034 rb->write(fd, linebuf, BMP_LINESIZE);