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
, _timer_isr
);
656 #endif /* !SIMULATOR */
657 rb
->screen_dump_set_hook(grey_screendump_hook
);
659 else if (!enable
&& (_grey_info
.flags
& _GREY_RUNNING
))
662 rb
->sim_lcd_ex_init(NULL
);
663 #else /* !SIMULATOR */
664 rb
->timer_unregister();
665 #if NUM_CORES > 1 /* Make sure the ISR has finished before calling lcd_update() */
669 rb
->cpu_boost(false);
671 #endif /* !SIMULATOR */
672 _grey_info
.flags
&= ~_GREY_RUNNING
;
673 rb
->screen_dump_set_hook(NULL
);
674 rb
->lcd_update(); /* restore whatever there was before */
678 void grey_update_rect(int x
, int y
, int width
, int height
)
680 grey_ub_gray_bitmap_part(_grey_info
.buffer
, x
, y
, _grey_info
.width
,
681 x
, y
, width
, height
);
684 /* Update the whole greyscale overlay */
685 void grey_update(void)
687 grey_ub_gray_bitmap_part(_grey_info
.buffer
, 0, 0, _grey_info
.width
,
688 0, 0, _grey_info
.width
, _grey_info
.height
);
691 /* Do an lcd_update() to show changes done by rb->lcd_xxx() functions
692 (in areas of the screen not covered by the greyscale overlay). */
693 void grey_deferred_lcd_update(void)
695 if (_grey_info
.flags
& _GREY_RUNNING
)
700 _grey_info
.flags
|= _GREY_DEFERRED_UPDATE
;
709 #ifdef HAVE_LCD_SPLIT
710 #define NUM_SHADES 128
711 #define BMP_NUMCOLORS 256
713 #define NUM_SHADES 129
714 #define BMP_NUMCOLORS 129
718 #define BMP_LINESIZE ((LCD_WIDTH + 3) & ~3)
719 #define BMP_HEADERSIZE (54 + 4 * BMP_NUMCOLORS)
720 #define BMP_DATASIZE (BMP_LINESIZE * (LCD_HEIGHT+LCD_SPLIT_LINES))
721 #define BMP_TOTALSIZE (BMP_HEADERSIZE + BMP_DATASIZE)
723 static const unsigned char bmpheader
[] =
725 0x42, 0x4d, /* 'BM' */
726 LE32_CONST(BMP_TOTALSIZE
), /* Total file size */
727 0x00, 0x00, 0x00, 0x00, /* Reserved */
728 LE32_CONST(BMP_HEADERSIZE
), /* Offset to start of pixel data */
730 0x28, 0x00, 0x00, 0x00, /* Size of (2nd) header */
731 LE32_CONST(LCD_WIDTH
), /* Width in pixels */
732 LE32_CONST(LCD_HEIGHT
+LCD_SPLIT_LINES
), /* Height in pixels */
733 0x01, 0x00, /* Number of planes (always 1) */
734 LE16_CONST(BMP_BPP
), /* Bits per pixel 1/4/8/16/24 */
735 0x00, 0x00, 0x00, 0x00, /* Compression mode, 0 = none */
736 LE32_CONST(BMP_DATASIZE
), /* Size of bitmap data */
737 0xc4, 0x0e, 0x00, 0x00, /* Horizontal resolution (pixels/meter) */
738 0xc4, 0x0e, 0x00, 0x00, /* Vertical resolution (pixels/meter) */
739 LE32_CONST(BMP_NUMCOLORS
), /* Number of used colours */
740 LE32_CONST(BMP_NUMCOLORS
), /* Number of important colours */
744 /* Only defined for positive, non-split LCD for now */
745 static const unsigned char colorindex
[4] = {128, 85, 43, 0};
748 /* Hook function for core screen_dump() to save the current display
749 content (b&w and greyscale overlay) to an 8-bit BMP file. */
750 static void grey_screendump_hook(int fd
)
754 #if LCD_PIXELFORMAT == VERTICAL_PACKING
761 #elif LCD_PIXELFORMAT == VERTICAL_INTERLEAVED
764 #endif /* LCD_PIXELFORMAT */
767 unsigned char *dst
, *dst_end
;
768 unsigned char linebuf
[MAX(4*NUM_SHADES
,BMP_LINESIZE
)];
770 rb
->write(fd
, bmpheader
, sizeof(bmpheader
)); /* write header */
773 rb
->memset(linebuf
, 0, 4*NUM_SHADES
);
776 for (i
= 0; i
< NUM_SHADES
; i
++)
778 *dst
++ = (_GREY_MULUQ(BLUE_CMP(LCD_BL_BRIGHTCOLOR
)
779 -BLUE_CMP(LCD_BL_DARKCOLOR
), i
) >> 7)
780 + BLUE_CMP(LCD_BL_DARKCOLOR
);
781 *dst
++ = (_GREY_MULUQ(GREEN_CMP(LCD_BL_BRIGHTCOLOR
)
782 -GREEN_CMP(LCD_BL_DARKCOLOR
), i
) >> 7)
783 + GREEN_CMP(LCD_BL_DARKCOLOR
);
784 *dst
++ = (_GREY_MULUQ(RED_CMP(LCD_BL_BRIGHTCOLOR
)
785 -RED_CMP(LCD_BL_DARKCOLOR
), i
) >> 7)
786 + RED_CMP(LCD_BL_DARKCOLOR
);
789 rb
->write(fd
, linebuf
, 4*NUM_SHADES
);
791 #ifdef HAVE_LCD_SPLIT
794 for (i
= 0; i
<= NUM_SHADES
; i
++)
796 *dst
++ = (_GREY_MULUQ(BLUE_CMP(LCD_BL_BRIGHTCOLOR_2
)
797 -BLUE_CMP(LCD_BL_DARKCOLOR_2
), i
) >> 7)
798 + BLUE_CMP(LCD_BL_DARKCOLOR_2
);
799 *dst
++ = (_GREY_MULUQ(GREEN_CMP(LCD_BL_BRIGHTCOLOR_2
)
800 -GREEN_CMP(LCD_BL_DARKCOLOR_2
), i
) >> 7)
801 + GREEN_CMP(LCD_BL_DARKCOLOR_2
);
802 *dst
++ = (_GREY_MULUQ(RED_CMP(LCD_BL_BRIGHTCOLOR_2
)
803 -RED_CMP(LCD_BL_DARKCOLOR_2
), i
) >> 7)
804 + RED_CMP(LCD_BL_DARKCOLOR_2
);
807 rb
->write(fd
, linebuf
, 4*NUM_SHADES
);
810 /* BMP image goes bottom -> top */
811 for (y
= LCD_HEIGHT
- 1; y
>= 0; y
--)
813 rb
->memset(linebuf
, 0, BMP_LINESIZE
);
815 #if defined(HAVE_LCD_SPLIT) && (LCD_SPLIT_LINES == 2)
816 if (y
== LCD_SPLIT_POS
- 1)
818 rb
->write(fd
, linebuf
, BMP_LINESIZE
);
819 rb
->write(fd
, linebuf
, BMP_LINESIZE
);
824 dst_end
= dst
+ LCD_WIDTH
;
825 gy
= y
- _grey_info
.y
;
828 #if LCD_PIXELFORMAT == HORIZONTAL_PACKING
829 gsrc
= _grey_info
.values
+ _GREY_MULUQ(_grey_info
.width
, gy
);
832 src
= rb
->lcd_framebuffer
+ _GREY_MULUQ(LCD_FBWIDTH
, y
);
836 if (((unsigned)gy
< (unsigned)_grey_info
.height
)
837 && ((unsigned)gx
< (unsigned)_grey_info
.width
))
846 unsigned data
= *src
;
847 *dst
++ = colorindex
[(data
>> 6) & 3];
848 *dst
++ = colorindex
[(data
>> 4) & 3];
849 *dst
++ = colorindex
[(data
>> 2) & 3];
850 *dst
++ = colorindex
[data
& 3];
854 while (dst
< dst_end
);
856 #endif /* LCD_DEPTH */
857 #elif LCD_PIXELFORMAT == VERTICAL_PACKING
858 gsrc
= _grey_info
.values
+ (~gy
& _GREY_BMASK
)
859 + _GREY_MULUQ(_grey_info
.width
, gy
& ~_GREY_BMASK
);
863 src
= rb
->lcd_framebuffer
+ _GREY_MULUQ(LCD_WIDTH
, y
>> 3);
867 if (((unsigned)gy
< (unsigned)_grey_info
.height
)
868 && ((unsigned)gx
< (unsigned)_grey_info
.width
))
871 #ifdef HAVE_LCD_SPLIT
878 #ifdef HAVE_NEGATIVE_LCD
879 val
= (*src
& mask
) ? (NUM_SHADES
-1) : 0;
881 val
= (*src
& mask
) ? 0 : (NUM_SHADES
-1);
884 #ifdef HAVE_LCD_SPLIT
885 if (y
< LCD_SPLIT_POS
)
891 while (dst
< dst_end
);
895 src
= rb
->lcd_framebuffer
+ _GREY_MULUQ(LCD_WIDTH
, y
>> 2);
899 if (((unsigned)gy
< (unsigned)_grey_info
.height
)
900 && ((unsigned)gx
< (unsigned)_grey_info
.width
))
907 *dst
++ = colorindex
[(*src
>> shift
) & 3];
911 while (dst
< dst_end
);
913 #endif /* LCD_DEPTH */
914 #elif LCD_PIXELFORMAT == VERTICAL_INTERLEAVED
915 gsrc
= _grey_info
.values
+ (~gy
& _GREY_BMASK
)
916 + _GREY_MULUQ(_grey_info
.width
, gy
& ~_GREY_BMASK
);
920 src
= rb
->lcd_framebuffer
+ _GREY_MULUQ(LCD_WIDTH
, y
>> 3);
924 if (((unsigned)gy
< (unsigned)_grey_info
.height
)
925 && ((unsigned)gx
< (unsigned)_grey_info
.width
))
932 data
= (*src
>> shift
) & 0x0101;
933 *dst
++ = colorindex
[((data
>> 7) | data
) & 3];
937 while (dst
< dst_end
);
939 #endif /* LCD_DEPTH */
940 #endif /* LCD_PIXELFORMAT */
942 rb
->write(fd
, linebuf
, BMP_LINESIZE
);