1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
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 ****************************************************************************/
31 #if defined(HAVE_ADJUSTABLE_CPU_FREQ) && \
32 (defined(CPU_PP) || (CONFIG_LCD == LCD_TL0350A))
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 /* NOT verified */
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 #else /* not yet calibrated targets - generic linear mapping */
232 /* TODO: calibrate iFP7xx */
233 static const unsigned char lcdlinear
[256] = {
234 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
235 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
236 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
237 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
238 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
239 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
240 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
241 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127,
242 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143,
243 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159,
244 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175,
245 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191,
246 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207,
247 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223,
248 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239,
249 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255
251 /* generic default */
252 #define LCD_SCANRATE 70 /* Hz */
255 #else /* SIMULATOR */
256 /* undo a (generic) PC display gamma of 2.0 to simulate target behaviour */
257 static const unsigned char lcdlinear
[256] = {
258 0, 16, 23, 28, 32, 36, 39, 42, 45, 48, 50, 53, 55, 58, 60, 62,
259 64, 66, 68, 70, 71, 73, 75, 77, 78, 80, 81, 83, 84, 86, 87, 89,
260 90, 92, 93, 94, 96, 97, 98, 100, 101, 102, 103, 105, 106, 107, 108, 109,
261 111, 112, 113, 114, 115, 116, 117, 118, 119, 121, 122, 123, 124, 125, 126, 127,
262 128, 129, 130, 131, 132, 133, 134, 135, 135, 136, 137, 138, 139, 140, 141, 142,
263 143, 144, 145, 145, 146, 147, 148, 149, 150, 151, 151, 152, 153, 154, 155, 156,
264 156, 157, 158, 159, 160, 160, 161, 162, 163, 164, 164, 165, 166, 167, 167, 168,
265 169, 170, 170, 171, 172, 173, 173, 174, 175, 176, 176, 177, 178, 179, 179, 180,
266 181, 181, 182, 183, 183, 184, 185, 186, 186, 187, 188, 188, 189, 190, 190, 191,
267 192, 192, 193, 194, 194, 195, 196, 196, 197, 198, 198, 199, 199, 200, 201, 201,
268 202, 203, 203, 204, 204, 205, 206, 206, 207, 208, 208, 209, 209, 210, 211, 211,
269 212, 212, 213, 214, 214, 215, 215, 216, 217, 217, 218, 218, 219, 220, 220, 221,
270 221, 222, 222, 223, 224, 224, 225, 225, 226, 226, 227, 228, 228, 229, 229, 230,
271 230, 231, 231, 232, 233, 233, 234, 234, 235, 235, 236, 236, 237, 237, 238, 238,
272 239, 240, 240, 241, 241, 242, 242, 243, 243, 244, 244, 245, 245, 246, 246, 247,
273 247, 248, 248, 249, 249, 250, 250, 251, 251, 252, 252, 253, 253, 254, 254, 255
275 #endif /* SIMULATOR */
278 static inline void _deferred_update(void) __attribute__ ((always_inline
));
279 static int exp_s16p16(int x
);
280 static int log_s16p16(int x
);
281 static void grey_screendump_hook(int fd
);
282 static void fill_gvalues(void);
284 static unsigned long _grey_get_pixel(int x
, int y
);
286 static void _timer_isr(void);
290 #if defined(HAVE_BACKLIGHT_INVERSION) && !defined(SIMULATOR)
291 static void invert_gvalues(void)
293 unsigned char *val
, *end
;
294 unsigned char rev_tab
[256];
300 /* Step 1: Calculate a transposed table for undoing the old mapping */
301 for (i
= 0; i
< 256; i
++)
304 x
= _grey_info
.gvalue
[i
];
307 rev_tab
[last_x
++] = (last_i
+ i
) / 2;
309 rev_tab
[last_x
++] = i
;
313 rev_tab
[last_x
++] = (last_i
+ 255) / 2;
315 rev_tab
[last_x
++] = 255;
317 /* Step 2: Calculate new mapping */
320 /* Step 3: Transpose all pixel values */
321 val
= _grey_info
.values
;
322 end
= val
+ _GREY_MULUQ(_grey_info
.width
, _grey_info
.height
);
325 *val
= _grey_info
.gvalue
[rev_tab
[*val
]];
330 /* Update LCD areas not covered by the greyscale overlay */
331 static inline void _deferred_update(void)
333 int x1
= MAX(_grey_info
.x
, 0);
334 int x2
= MIN(_grey_info
.x
+ _grey_info
.width
, LCD_WIDTH
);
335 int y1
= MAX(_grey_info
.y
, 0);
336 int y2
= MIN(_grey_info
.y
+ _grey_info
.height
, LCD_HEIGHT
);
338 if (y1
> 0) /* refresh part above overlay, full width */
339 rb
->lcd_update_rect(0, 0, LCD_WIDTH
, y1
);
341 if (y2
< LCD_HEIGHT
) /* refresh part below overlay, full width */
342 rb
->lcd_update_rect(0, y2
, LCD_WIDTH
, LCD_HEIGHT
- y2
);
344 if (x1
> 0) /* refresh part to the left of overlay */
345 rb
->lcd_update_rect(0, y1
, x1
, y2
- y1
);
347 if (x2
< LCD_WIDTH
) /* refresh part to the right of overlay */
348 rb
->lcd_update_rect(x2
, y1
, LCD_WIDTH
- x2
, y2
- y1
);
353 /* Callback function for grey_ub_gray_bitmap_part() to read a pixel from the
354 * greybuffer. Note that x and y are in LCD coordinates, not greybuffer
356 static unsigned long _grey_get_pixel(int x
, int y
)
359 int xg
= x
- _grey_info
.x
;
360 int yg
= y
- _grey_info
.y
;
361 #if LCD_PIXELFORMAT == HORIZONTAL_PACKING
362 int idx
= _grey_info
.width
* yg
+ xg
;
363 #else /* vertical packing or vertical interleaved */
364 int idx
= _grey_info
.width
* (yg
& ~_GREY_BMASK
)
365 + (xg
<< _GREY_BSHIFT
) + (~yg
& _GREY_BMASK
);
368 val
= _grey_info
.values
[idx
];
369 #ifdef HAVE_LCD_SPLIT
375 #else /* !SIMULATOR */
377 /* Timer interrupt handler: display next frame */
378 static void _timer_isr(void)
380 #if defined(HAVE_BACKLIGHT_INVERSION) && !defined(SIMULATOR)
381 unsigned long check
= rb
->is_backlight_on(true)
382 ? 0 : _GREY_BACKLIGHT_ON
;
384 if ((_grey_info
.flags
& (_GREY_BACKLIGHT_ON
|GREY_RAWMAPPED
)) == check
)
386 _grey_info
.flags
^= _GREY_BACKLIGHT_ON
;
388 return; /* don't overload this timer slot */
391 #if LCD_PIXELFORMAT == HORIZONTAL_PACKING
392 rb
->lcd_blit_grey_phase(_grey_info
.values
, _grey_info
.phases
,
393 _grey_info
.bx
, _grey_info
.y
,
394 _grey_info
.bwidth
, _grey_info
.height
,
396 #else /* vertical packing or vertical interleaved */
397 rb
->lcd_blit_grey_phase(_grey_info
.values
, _grey_info
.phases
,
398 _grey_info
.x
, _grey_info
.by
,
399 _grey_info
.width
, _grey_info
.bheight
,
403 if (_grey_info
.flags
& _GREY_DEFERRED_UPDATE
) /* lcd_update() requested? */
406 _grey_info
.flags
&= ~_GREY_DEFERRED_UPDATE
; /* clear request */
410 #endif /* !SIMULATOR */
412 /* fixed point exp() */
413 static int exp_s16p16(int x
)
418 if (x
< 0) x
+= 0xb1721, y
>>= 16;
419 t
= x
- 0x58b91; if (t
>= 0) x
= t
, y
<<= 8;
420 t
= x
- 0x2c5c8; if (t
>= 0) x
= t
, y
<<= 4;
421 t
= x
- 0x162e4; if (t
>= 0) x
= t
, y
<<= 2;
422 t
= x
- 0x0b172; if (t
>= 0) x
= t
, y
<<= 1;
423 t
= x
- 0x067cd; if (t
>= 0) x
= t
, y
+= y
>> 1;
424 t
= x
- 0x03920; if (t
>= 0) x
= t
, y
+= y
>> 2;
425 t
= x
- 0x01e27; if (t
>= 0) x
= t
, y
+= y
>> 3;
426 t
= x
- 0x00f85; if (t
>= 0) x
= t
, y
+= y
>> 4;
427 t
= x
- 0x007e1; if (t
>= 0) x
= t
, y
+= y
>> 5;
428 t
= x
- 0x003f8; if (t
>= 0) x
= t
, y
+= y
>> 6;
429 t
= x
- 0x001fe; if (t
>= 0) x
= t
, y
+= y
>> 7;
430 y
+= ((y
>> 8) * x
) >> 8;
435 /* fixed point log() */
436 static int log_s16p16(int x
)
441 if (x
< 0x00008000) x
<<=16, y
-= 0xb1721;
442 if (x
< 0x00800000) x
<<= 8, y
-= 0x58b91;
443 if (x
< 0x08000000) x
<<= 4, y
-= 0x2c5c8;
444 if (x
< 0x20000000) x
<<= 2, y
-= 0x162e4;
445 if (x
< 0x40000000) x
<<= 1, y
-= 0x0b172;
446 t
= x
+ (x
>> 1); if ((t
& 0x80000000) == 0) x
= t
, y
-= 0x067cd;
447 t
= x
+ (x
>> 2); if ((t
& 0x80000000) == 0) x
= t
, y
-= 0x03920;
448 t
= x
+ (x
>> 3); if ((t
& 0x80000000) == 0) x
= t
, y
-= 0x01e27;
449 t
= x
+ (x
>> 4); if ((t
& 0x80000000) == 0) x
= t
, y
-= 0x00f85;
450 t
= x
+ (x
>> 5); if ((t
& 0x80000000) == 0) x
= t
, y
-= 0x007e1;
451 t
= x
+ (x
>> 6); if ((t
& 0x80000000) == 0) x
= t
, y
-= 0x003f8;
452 t
= x
+ (x
>> 7); if ((t
& 0x80000000) == 0) x
= t
, y
-= 0x001fe;
459 static void fill_gvalues(void)
464 #if defined(HAVE_BACKLIGHT_INVERSION) && !defined(SIMULATOR)
465 unsigned imask
= (_grey_info
.flags
& _GREY_BACKLIGHT_ON
) ? 0xff : 0;
467 const unsigned imask
= 0;
469 for (i
= 0; i
< 256; i
++)
471 data
= exp_s16p16((_GREY_GAMMA
* log_s16p16(i
* 257 + 1)) >> 8) + 128;
472 data
= (data
- (data
>> 8)) >> 8; /* approx. data /= 257 */
473 data
= ((lcdlinear
[data
^ imask
] ^ imask
) << 7) + 127;
474 _grey_info
.gvalue
[i
] = (data
+ (data
>> 8)) >> 8;
475 /* approx. data / 255 */
479 /* Initialise the framework and prepare the greyscale display buffer
482 newrb = pointer to plugin api
483 gbuf = pointer to the memory area to use (e.g. plugin buffer)
484 gbuf_size = max usable size of the buffer
485 features = flags for requesting features
486 GREY_BUFFERED: use chunky pixel buffering
487 This allows to use all drawing functions, but needs more
488 memory. Unbuffered operation provides only a subset of
489 drawing functions. (only grey_bitmap drawing and scrolling)
490 GREY_RAWMAPPED: no LCD linearisation and gamma correction
491 width = width in pixels (1..LCD_WIDTH)
492 height = height in pixels (1..LCD_HEIGHT)
493 Note that depending on the target LCD, either height or
494 width are rounded up to a multiple of 4 or 8.
497 true on success, false on failure
499 If you need info about the memory taken by the greyscale buffer, supply a
500 long* as the last parameter. This long will then contain the number of bytes
501 used. The total memory needed can be calculated as follows:
503 width * height * 2 [grey display data]
504 + buffered ? (width * height) : 0 [chunky buffer]
507 The function is authentic regarding memory usage on the simulator, even
508 if it doesn't use all of the allocated memory. */
509 bool grey_init(unsigned char *gbuf
, long gbuf_size
,
510 unsigned features
, int width
, int height
, long *buf_taken
)
513 long plane_size
, buftaken
;
519 if ((unsigned) width
> LCD_WIDTH
520 || (unsigned) height
> LCD_HEIGHT
)
523 #if LCD_PIXELFORMAT == HORIZONTAL_PACKING
524 bdim
= (width
+ 7) >> 3;
526 #else /* vertical packing or vertical interleaved */
527 #if (LCD_DEPTH == 1) || (LCD_PIXELFORMAT == VERTICAL_INTERLEAVED)
528 bdim
= (height
+ 7) >> 3;
531 bdim
= (height
+ 3) >> 2;
536 plane_size
= _GREY_MULUQ(width
, height
);
537 #if defined(CPU_COLDFIRE) /* Buffers should be line aligned */ \
538 || defined(CPU_PP) && (NUM_CORES > 1) /* Buffers must be cache line aligned */
539 plane_size
+= (-plane_size
) & 0xf;
540 buftaken
= (-(long)gbuf
) & 0xf;
541 #else /* Buffers must be 32 bit aligned. */
542 buftaken
= (-(long)gbuf
) & 3;
546 if (features
& GREY_BUFFERED
) /* chunky buffer */
548 _grey_info
.buffer
= gbuf
;
550 buftaken
+= plane_size
;
552 #if NUM_CORES > 1 /* Values and phases must be uncached when running on COP */
553 if (features
& GREY_ON_COP
)
554 gbuf
= UNCACHED_ADDR(gbuf
);
556 _grey_info
.values
= gbuf
;
558 _grey_info
.phases
= gbuf
;
559 buftaken
+= 2 * plane_size
;
561 if (buftaken
> gbuf_size
)
565 rb
->memset(_grey_info
.values
, 0x80, plane_size
);
568 /* Init phases with random bits */
569 dst
= (unsigned*)(_grey_info
.phases
);
570 end
= (unsigned*)(_grey_info
.phases
+ plane_size
);
579 _grey_info
.width
= width
;
580 _grey_info
.height
= height
;
581 #if LCD_PIXELFORMAT == HORIZONTAL_PACKING
583 _grey_info
.bwidth
= bdim
;
584 #else /* vertical packing or vertical interleaved */
586 _grey_info
.bheight
= bdim
;
588 _grey_info
.flags
= features
& 0xff;
589 _grey_info
.fg_brightness
= 0;
590 _grey_info
.bg_brightness
= 255;
591 _grey_info
.drawmode
= DRMODE_SOLID
;
592 _grey_info
.curfont
= FONT_SYSFIXED
;
594 /* precalculate the value -> pattern index conversion table, taking
595 linearisation and gamma correction into account */
596 if (features
& GREY_RAWMAPPED
)
598 for (i
= 0; i
< 256; i
++)
601 _grey_info
.gvalue
[i
] = (data
+ (data
>> 8)) >> 8;
606 #if defined(HAVE_BACKLIGHT_INVERSION) && !defined(SIMULATOR)
607 if (rb
->is_backlight_on(true))
608 _grey_info
.flags
|= _GREY_BACKLIGHT_ON
;
613 if (buf_taken
) /* caller requested info about space taken */
614 *buf_taken
= buftaken
;
619 /* Release the greyscale display buffer and the library
620 DO CALL either this function or at least grey_show_display(false)
621 before you exit, otherwise nasty things may happen. */
622 void grey_release(void)
627 /* Switch the greyscale overlay on or off
628 DO NOT call lcd_update() or any other api function that directly accesses
629 the lcd while the greyscale overlay is running! If you need to do
630 lcd_update() to update something outside the greyscale overlay area, use
631 grey_deferred_update() instead.
633 Other functions to avoid are:
634 lcd_blit_mono(), lcd_update_rect(), lcd_set_contrast(),
635 lcd_set_invert_display(), lcd_set_flip() */
636 void grey_show(bool enable
)
638 if (enable
&& !(_grey_info
.flags
& _GREY_RUNNING
))
640 _grey_info
.flags
|= _GREY_RUNNING
;
642 rb
->sim_lcd_ex_init(_grey_get_pixel
);
643 rb
->sim_lcd_ex_update_rect(_grey_info
.x
, _grey_info
.y
,
644 _grey_info
.width
, _grey_info
.height
);
645 #else /* !SIMULATOR */
650 rb
->timer_register(1, NULL
, TIMER_FREQ
/ LCD_SCANRATE
,
652 (_grey_info
.flags
& GREY_ON_COP
) ? COP
: CPU
);
654 rb
->timer_register(1, NULL
, TIMER_FREQ
/ LCD_SCANRATE
, 1,
657 #endif /* !SIMULATOR */
658 rb
->screen_dump_set_hook(grey_screendump_hook
);
660 else if (!enable
&& (_grey_info
.flags
& _GREY_RUNNING
))
663 rb
->sim_lcd_ex_init(NULL
);
664 #else /* !SIMULATOR */
665 rb
->timer_unregister();
666 #if NUM_CORES > 1 /* Make sure the ISR has finished before calling lcd_update() */
670 rb
->cpu_boost(false);
672 #endif /* !SIMULATOR */
673 _grey_info
.flags
&= ~_GREY_RUNNING
;
674 rb
->screen_dump_set_hook(NULL
);
675 rb
->lcd_update(); /* restore whatever there was before */
679 void grey_update_rect(int x
, int y
, int width
, int height
)
681 grey_ub_gray_bitmap_part(_grey_info
.buffer
, x
, y
, _grey_info
.width
,
682 x
, y
, width
, height
);
685 /* Update the whole greyscale overlay */
686 void grey_update(void)
688 grey_ub_gray_bitmap_part(_grey_info
.buffer
, 0, 0, _grey_info
.width
,
689 0, 0, _grey_info
.width
, _grey_info
.height
);
692 /* Do an lcd_update() to show changes done by rb->lcd_xxx() functions
693 (in areas of the screen not covered by the greyscale overlay). */
694 void grey_deferred_lcd_update(void)
696 if (_grey_info
.flags
& _GREY_RUNNING
)
701 _grey_info
.flags
|= _GREY_DEFERRED_UPDATE
;
710 #ifdef HAVE_LCD_SPLIT
711 #define NUM_SHADES 128
712 #define BMP_NUMCOLORS 256
714 #define NUM_SHADES 129
715 #define BMP_NUMCOLORS 129
719 #define BMP_LINESIZE ((LCD_WIDTH + 3) & ~3)
720 #define BMP_HEADERSIZE (54 + 4 * BMP_NUMCOLORS)
721 #define BMP_DATASIZE (BMP_LINESIZE * (LCD_HEIGHT+LCD_SPLIT_LINES))
722 #define BMP_TOTALSIZE (BMP_HEADERSIZE + BMP_DATASIZE)
724 static const unsigned char bmpheader
[] =
726 0x42, 0x4d, /* 'BM' */
727 LE32_CONST(BMP_TOTALSIZE
), /* Total file size */
728 0x00, 0x00, 0x00, 0x00, /* Reserved */
729 LE32_CONST(BMP_HEADERSIZE
), /* Offset to start of pixel data */
731 0x28, 0x00, 0x00, 0x00, /* Size of (2nd) header */
732 LE32_CONST(LCD_WIDTH
), /* Width in pixels */
733 LE32_CONST(LCD_HEIGHT
+LCD_SPLIT_LINES
), /* Height in pixels */
734 0x01, 0x00, /* Number of planes (always 1) */
735 LE16_CONST(BMP_BPP
), /* Bits per pixel 1/4/8/16/24 */
736 0x00, 0x00, 0x00, 0x00, /* Compression mode, 0 = none */
737 LE32_CONST(BMP_DATASIZE
), /* Size of bitmap data */
738 0xc4, 0x0e, 0x00, 0x00, /* Horizontal resolution (pixels/meter) */
739 0xc4, 0x0e, 0x00, 0x00, /* Vertical resolution (pixels/meter) */
740 LE32_CONST(BMP_NUMCOLORS
), /* Number of used colours */
741 LE32_CONST(BMP_NUMCOLORS
), /* Number of important colours */
745 /* Only defined for positive, non-split LCD for now */
746 static const unsigned char colorindex
[4] = {128, 85, 43, 0};
749 /* Hook function for core screen_dump() to save the current display
750 content (b&w and greyscale overlay) to an 8-bit BMP file. */
751 static void grey_screendump_hook(int fd
)
755 #if LCD_PIXELFORMAT == VERTICAL_PACKING
762 #elif LCD_PIXELFORMAT == VERTICAL_INTERLEAVED
765 #endif /* LCD_PIXELFORMAT */
768 unsigned char *dst
, *dst_end
;
769 unsigned char linebuf
[MAX(4*NUM_SHADES
,BMP_LINESIZE
)];
771 rb
->write(fd
, bmpheader
, sizeof(bmpheader
)); /* write header */
774 rb
->memset(linebuf
, 0, 4*NUM_SHADES
);
777 for (i
= 0; i
< NUM_SHADES
; i
++)
779 *dst
++ = (_GREY_MULUQ(BLUE_CMP(LCD_BL_BRIGHTCOLOR
)
780 -BLUE_CMP(LCD_BL_DARKCOLOR
), i
) >> 7)
781 + BLUE_CMP(LCD_BL_DARKCOLOR
);
782 *dst
++ = (_GREY_MULUQ(GREEN_CMP(LCD_BL_BRIGHTCOLOR
)
783 -GREEN_CMP(LCD_BL_DARKCOLOR
), i
) >> 7)
784 + GREEN_CMP(LCD_BL_DARKCOLOR
);
785 *dst
++ = (_GREY_MULUQ(RED_CMP(LCD_BL_BRIGHTCOLOR
)
786 -RED_CMP(LCD_BL_DARKCOLOR
), i
) >> 7)
787 + RED_CMP(LCD_BL_DARKCOLOR
);
790 rb
->write(fd
, linebuf
, 4*NUM_SHADES
);
792 #ifdef HAVE_LCD_SPLIT
795 for (i
= 0; i
<= NUM_SHADES
; i
++)
797 *dst
++ = (_GREY_MULUQ(BLUE_CMP(LCD_BL_BRIGHTCOLOR_2
)
798 -BLUE_CMP(LCD_BL_DARKCOLOR_2
), i
) >> 7)
799 + BLUE_CMP(LCD_BL_DARKCOLOR_2
);
800 *dst
++ = (_GREY_MULUQ(GREEN_CMP(LCD_BL_BRIGHTCOLOR_2
)
801 -GREEN_CMP(LCD_BL_DARKCOLOR_2
), i
) >> 7)
802 + GREEN_CMP(LCD_BL_DARKCOLOR_2
);
803 *dst
++ = (_GREY_MULUQ(RED_CMP(LCD_BL_BRIGHTCOLOR_2
)
804 -RED_CMP(LCD_BL_DARKCOLOR_2
), i
) >> 7)
805 + RED_CMP(LCD_BL_DARKCOLOR_2
);
808 rb
->write(fd
, linebuf
, 4*NUM_SHADES
);
811 /* BMP image goes bottom -> top */
812 for (y
= LCD_HEIGHT
- 1; y
>= 0; y
--)
814 rb
->memset(linebuf
, 0, BMP_LINESIZE
);
816 #if defined(HAVE_LCD_SPLIT) && (LCD_SPLIT_LINES == 2)
817 if (y
== LCD_SPLIT_POS
- 1)
819 rb
->write(fd
, linebuf
, BMP_LINESIZE
);
820 rb
->write(fd
, linebuf
, BMP_LINESIZE
);
825 dst_end
= dst
+ LCD_WIDTH
;
826 gy
= y
- _grey_info
.y
;
829 #if LCD_PIXELFORMAT == HORIZONTAL_PACKING
830 gsrc
= _grey_info
.values
+ _GREY_MULUQ(_grey_info
.width
, gy
);
833 src
= rb
->lcd_framebuffer
+ _GREY_MULUQ(LCD_FBWIDTH
, y
);
837 if (((unsigned)gy
< (unsigned)_grey_info
.height
)
838 && ((unsigned)gx
< (unsigned)_grey_info
.width
))
847 unsigned data
= *src
;
848 *dst
++ = colorindex
[(data
>> 6) & 3];
849 *dst
++ = colorindex
[(data
>> 4) & 3];
850 *dst
++ = colorindex
[(data
>> 2) & 3];
851 *dst
++ = colorindex
[data
& 3];
855 while (dst
< dst_end
);
857 #endif /* LCD_DEPTH */
858 #elif LCD_PIXELFORMAT == VERTICAL_PACKING
859 gsrc
= _grey_info
.values
+ (~gy
& _GREY_BMASK
)
860 + _GREY_MULUQ(_grey_info
.width
, gy
& ~_GREY_BMASK
);
864 src
= rb
->lcd_framebuffer
+ _GREY_MULUQ(LCD_WIDTH
, y
>> 3);
868 if (((unsigned)gy
< (unsigned)_grey_info
.height
)
869 && ((unsigned)gx
< (unsigned)_grey_info
.width
))
872 #ifdef HAVE_LCD_SPLIT
879 #ifdef HAVE_NEGATIVE_LCD
880 val
= (*src
& mask
) ? (NUM_SHADES
-1) : 0;
882 val
= (*src
& mask
) ? 0 : (NUM_SHADES
-1);
885 #ifdef HAVE_LCD_SPLIT
886 if (y
< LCD_SPLIT_POS
)
892 while (dst
< dst_end
);
896 src
= rb
->lcd_framebuffer
+ _GREY_MULUQ(LCD_WIDTH
, y
>> 2);
900 if (((unsigned)gy
< (unsigned)_grey_info
.height
)
901 && ((unsigned)gx
< (unsigned)_grey_info
.width
))
908 *dst
++ = colorindex
[(*src
>> shift
) & 3];
912 while (dst
< dst_end
);
914 #endif /* LCD_DEPTH */
915 #elif LCD_PIXELFORMAT == VERTICAL_INTERLEAVED
916 gsrc
= _grey_info
.values
+ (~gy
& _GREY_BMASK
)
917 + _GREY_MULUQ(_grey_info
.width
, gy
& ~_GREY_BMASK
);
921 src
= rb
->lcd_framebuffer
+ _GREY_MULUQ(LCD_WIDTH
, y
>> 3);
925 if (((unsigned)gy
< (unsigned)_grey_info
.height
)
926 && ((unsigned)gx
< (unsigned)_grey_info
.width
))
933 data
= (*src
>> shift
) & 0x0101;
934 *dst
++ = colorindex
[((data
>> 7) | data
) & 3];
938 while (dst
< dst_end
);
940 #endif /* LCD_DEPTH */
941 #endif /* LCD_PIXELFORMAT */
943 rb
->write(fd
, linebuf
, BMP_LINESIZE
);