diff options
Diffstat (limited to 'apps/plugins/lib/grey_core.c')
-rw-r--r-- | apps/plugins/lib/grey_core.c | 767 |
1 files changed, 767 insertions, 0 deletions
diff --git a/apps/plugins/lib/grey_core.c b/apps/plugins/lib/grey_core.c new file mode 100644 index 0000000000..b3ab640602 --- /dev/null +++ b/apps/plugins/lib/grey_core.c | |||
@@ -0,0 +1,767 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * New greyscale framework | ||
11 | * Core & miscellaneous functions | ||
12 | * | ||
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. | ||
15 | * | ||
16 | * Copyright (C) 2008 Jens Arnold | ||
17 | * | ||
18 | * All files in this archive are subject to the GNU General Public License. | ||
19 | * See the file COPYING in the source tree root for full license agreement. | ||
20 | * | ||
21 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
22 | * KIND, either express or implied. | ||
23 | * | ||
24 | ****************************************************************************/ | ||
25 | |||
26 | #include "plugin.h" | ||
27 | #include "grey.h" | ||
28 | |||
29 | #if defined(CPU_PP) && defined(HAVE_ADJUSTABLE_CPU_FREQ) | ||
30 | #define NEED_BOOST | ||
31 | #endif | ||
32 | |||
33 | /* Global variables */ | ||
34 | struct plugin_api *_grey_rb = NULL; /* global api struct pointer */ | ||
35 | struct _grey_info _grey_info; /* global info structure */ | ||
36 | |||
37 | #ifndef SIMULATOR | ||
38 | |||
39 | #if CONFIG_LCD == LCD_SSD1815 || CONFIG_LCD == LCD_IFP7XX | ||
40 | /* measured and interpolated curve */ | ||
41 | /* TODO: check for iFP */ | ||
42 | static const unsigned char lcdlinear[256] = { | ||
43 | 0, 3, 5, 8, 11, 13, 16, 18, | ||
44 | 21, 23, 26, 28, 31, 33, 36, 38, | ||
45 | 40, 42, 45, 47, 49, 51, 53, 55, | ||
46 | 57, 59, 60, 62, 64, 66, 67, 69, | ||
47 | 70, 72, 73, 74, 76, 77, 78, 79, | ||
48 | 81, 82, 83, 84, 85, 86, 87, 88, | ||
49 | 88, 89, 90, 91, 92, 92, 93, 94, | ||
50 | 95, 95, 96, 97, 97, 98, 99, 99, | ||
51 | 100, 101, 102, 102, 103, 104, 104, 105, | ||
52 | 106, 106, 107, 107, 108, 109, 109, 110, | ||
53 | 111, 111, 112, 113, 113, 114, 114, 115, | ||
54 | 116, 116, 117, 117, 118, 119, 119, 120, | ||
55 | 120, 121, 121, 122, 122, 123, 123, 124, | ||
56 | 124, 125, 125, 126, 126, 127, 127, 128, | ||
57 | 128, 128, 129, 129, 130, 130, 131, 131, | ||
58 | 132, 132, 133, 133, 133, 134, 134, 135, | ||
59 | 135, 136, 136, 137, 137, 138, 138, 138, | ||
60 | 139, 139, 140, 140, 141, 141, 142, 142, | ||
61 | 143, 143, 144, 144, 145, 145, 146, 146, | ||
62 | 147, 147, 148, 148, 148, 149, 149, 150, | ||
63 | 150, 151, 151, 152, 152, 153, 153, 153, | ||
64 | 154, 154, 155, 155, 156, 156, 157, 157, | ||
65 | 158, 158, 158, 159, 159, 160, 160, 161, | ||
66 | 161, 162, 162, 163, 163, 164, 164, 165, | ||
67 | 165, 166, 167, 167, 168, 168, 169, 169, | ||
68 | 170, 171, 171, 172, 173, 173, 174, 175, | ||
69 | 176, 176, 177, 178, 179, 180, 181, 181, | ||
70 | 182, 183, 184, 185, 186, 188, 189, 190, | ||
71 | 191, 192, 194, 195, 196, 198, 199, 201, | ||
72 | 202, 204, 205, 207, 209, 211, 213, 215, | ||
73 | 217, 219, 222, 224, 226, 229, 231, 234, | ||
74 | 236, 239, 242, 244, 247, 250, 252, 255 | ||
75 | }; | ||
76 | #elif CONFIG_LCD == LCD_S1D15E06 | ||
77 | /* measured and interpolated curve */ | ||
78 | static const unsigned char lcdlinear[256] = { | ||
79 | 0, 5, 11, 16, 21, 27, 32, 37, | ||
80 | 42, 47, 51, 56, 60, 64, 68, 72, | ||
81 | 75, 78, 81, 84, 87, 89, 91, 93, | ||
82 | 95, 96, 98, 99, 101, 102, 103, 104, | ||
83 | 105, 106, 107, 108, 109, 110, 111, 111, | ||
84 | 112, 113, 113, 114, 115, 115, 116, 117, | ||
85 | 117, 118, 118, 119, 119, 120, 120, 121, | ||
86 | 121, 122, 122, 123, 123, 124, 124, 125, | ||
87 | 125, 126, 126, 127, 127, 127, 128, 128, | ||
88 | 129, 129, 130, 130, 131, 131, 132, 132, | ||
89 | 133, 133, 134, 134, 135, 135, 136, 136, | ||
90 | 137, 137, 138, 138, 138, 139, 139, 140, | ||
91 | 140, 141, 141, 141, 142, 142, 143, 143, | ||
92 | 143, 144, 144, 145, 145, 145, 146, 146, | ||
93 | 146, 147, 147, 147, 148, 148, 149, 149, | ||
94 | 149, 150, 150, 150, 151, 151, 151, 152, | ||
95 | 152, 153, 153, 153, 154, 154, 155, 155, | ||
96 | 155, 156, 156, 157, 157, 157, 158, 158, | ||
97 | 159, 159, 159, 160, 160, 161, 161, 162, | ||
98 | 162, 162, 163, 163, 164, 164, 164, 165, | ||
99 | 165, 166, 166, 167, 167, 167, 168, 168, | ||
100 | 169, 169, 170, 170, 170, 171, 171, 172, | ||
101 | 172, 173, 173, 174, 174, 175, 175, 176, | ||
102 | 176, 177, 177, 178, 178, 179, 179, 180, | ||
103 | 180, 181, 182, 182, 183, 184, 184, 185, | ||
104 | 186, 186, 187, 188, 188, 189, 190, 191, | ||
105 | 191, 192, 193, 194, 195, 196, 196, 197, | ||
106 | 198, 199, 200, 201, 202, 203, 204, 205, | ||
107 | 206, 207, 208, 209, 210, 211, 213, 214, | ||
108 | 215, 216, 218, 219, 220, 222, 223, 225, | ||
109 | 227, 228, 230, 232, 233, 235, 237, 239, | ||
110 | 241, 243, 245, 247, 249, 251, 253, 255 | ||
111 | }; | ||
112 | #elif (CONFIG_LCD == LCD_IPOD2BPP) || (CONFIG_LCD == LCD_IPODMINI) | ||
113 | /* measured and interpolated curve for mini LCD */ | ||
114 | /* TODO: verify this curve on the fullsize greyscale LCD */ | ||
115 | static const unsigned char lcdlinear[256] = { | ||
116 | 0, 3, 6, 8, 11, 14, 17, 19, | ||
117 | 22, 24, 27, 29, 32, 34, 36, 38, | ||
118 | 40, 42, 44, 45, 47, 48, 50, 51, | ||
119 | 52, 54, 55, 56, 57, 58, 58, 59, | ||
120 | 60, 61, 62, 62, 63, 64, 64, 65, | ||
121 | 66, 66, 67, 67, 68, 68, 69, 69, | ||
122 | 70, 70, 70, 71, 71, 71, 72, 72, | ||
123 | 73, 73, 73, 74, 74, 74, 74, 75, | ||
124 | 75, 75, 76, 76, 76, 77, 77, 77, | ||
125 | 78, 78, 78, 79, 79, 79, 80, 80, | ||
126 | 80, 80, 81, 81, 81, 82, 82, 82, | ||
127 | 83, 83, 83, 84, 84, 84, 85, 85, | ||
128 | 85, 85, 86, 86, 86, 87, 87, 87, | ||
129 | 87, 88, 88, 88, 89, 89, 89, 89, | ||
130 | 90, 90, 90, 91, 91, 91, 92, 92, | ||
131 | 92, 93, 93, 93, 94, 94, 94, 95, | ||
132 | 95, 96, 96, 96, 97, 97, 98, 98, | ||
133 | 99, 99, 99, 100, 100, 101, 101, 102, | ||
134 | 102, 103, 103, 104, 104, 105, 105, 106, | ||
135 | 106, 107, 107, 108, 108, 109, 109, 110, | ||
136 | 110, 111, 111, 112, 113, 113, 114, 114, | ||
137 | 115, 115, 116, 117, 117, 118, 118, 119, | ||
138 | 120, 120, 121, 122, 122, 123, 124, 124, | ||
139 | 125, 126, 126, 127, 128, 128, 129, 130, | ||
140 | 131, 131, 132, 133, 134, 134, 135, 136, | ||
141 | 137, 138, 139, 140, 141, 142, 143, 144, | ||
142 | 145, 146, 147, 148, 149, 150, 152, 153, | ||
143 | 154, 156, 157, 159, 160, 162, 163, 165, | ||
144 | 167, 168, 170, 172, 174, 176, 178, 180, | ||
145 | 182, 184, 187, 189, 192, 194, 197, 200, | ||
146 | 203, 206, 209, 212, 215, 219, 222, 226, | ||
147 | 229, 233, 236, 240, 244, 248, 251, 255 | ||
148 | }; | ||
149 | #endif | ||
150 | #else /* SIMULATOR */ | ||
151 | /* undo a (generic) PC display gamma of 2.0 to simulate target behaviour */ | ||
152 | static const unsigned char lcdlinear[256] = { | ||
153 | 0, 16, 23, 28, 32, 36, 39, 42, | ||
154 | 45, 48, 50, 53, 55, 58, 60, 62, | ||
155 | 64, 66, 68, 70, 71, 73, 75, 77, | ||
156 | 78, 80, 81, 83, 84, 86, 87, 89, | ||
157 | 90, 92, 93, 94, 96, 97, 98, 100, | ||
158 | 101, 102, 103, 105, 106, 107, 108, 109, | ||
159 | 111, 112, 113, 114, 115, 116, 117, 118, | ||
160 | 119, 121, 122, 123, 124, 125, 126, 127, | ||
161 | 128, 129, 130, 131, 132, 133, 134, 135, | ||
162 | 135, 136, 137, 138, 139, 140, 141, 142, | ||
163 | 143, 144, 145, 145, 146, 147, 148, 149, | ||
164 | 150, 151, 151, 152, 153, 154, 155, 156, | ||
165 | 156, 157, 158, 159, 160, 160, 161, 162, | ||
166 | 163, 164, 164, 165, 166, 167, 167, 168, | ||
167 | 169, 170, 170, 171, 172, 173, 173, 174, | ||
168 | 175, 176, 176, 177, 178, 179, 179, 180, | ||
169 | 181, 181, 182, 183, 183, 184, 185, 186, | ||
170 | 186, 187, 188, 188, 189, 190, 190, 191, | ||
171 | 192, 192, 193, 194, 194, 195, 196, 196, | ||
172 | 197, 198, 198, 199, 199, 200, 201, 201, | ||
173 | 202, 203, 203, 204, 204, 205, 206, 206, | ||
174 | 207, 208, 208, 209, 209, 210, 211, 211, | ||
175 | 212, 212, 213, 214, 214, 215, 215, 216, | ||
176 | 217, 217, 218, 218, 219, 220, 220, 221, | ||
177 | 221, 222, 222, 223, 224, 224, 225, 225, | ||
178 | 226, 226, 227, 228, 228, 229, 229, 230, | ||
179 | 230, 231, 231, 232, 233, 233, 234, 234, | ||
180 | 235, 235, 236, 236, 237, 237, 238, 238, | ||
181 | 239, 240, 240, 241, 241, 242, 242, 243, | ||
182 | 243, 244, 244, 245, 245, 246, 246, 247, | ||
183 | 247, 248, 248, 249, 249, 250, 250, 251, | ||
184 | 251, 252, 252, 253, 253, 254, 254, 255 | ||
185 | }; | ||
186 | #endif /* SIMULATOR */ | ||
187 | |||
188 | /* Prototypes */ | ||
189 | static inline void _deferred_update(void) __attribute__ ((always_inline)); | ||
190 | static int exp_s16p16(int x); | ||
191 | static int log_s16p16(int x); | ||
192 | static void grey_screendump_hook(int fd); | ||
193 | #ifdef SIMULATOR | ||
194 | static unsigned long _grey_get_pixel(int x, int y); | ||
195 | #else | ||
196 | static void _timer_isr(void); | ||
197 | #endif | ||
198 | |||
199 | /* Update LCD areas not covered by the greyscale overlay */ | ||
200 | static inline void _deferred_update(void) | ||
201 | { | ||
202 | int x1 = MAX(_grey_info.x, 0); | ||
203 | int x2 = MIN(_grey_info.x + _grey_info.width, LCD_WIDTH); | ||
204 | int y1 = MAX(_grey_info.y, 0); | ||
205 | int y2 = MIN(_grey_info.y + _grey_info.height, LCD_HEIGHT); | ||
206 | |||
207 | if (y1 > 0) /* refresh part above overlay, full width */ | ||
208 | _grey_rb->lcd_update_rect(0, 0, LCD_WIDTH, y1); | ||
209 | |||
210 | if (y2 < LCD_HEIGHT) /* refresh part below overlay, full width */ | ||
211 | _grey_rb->lcd_update_rect(0, y2, LCD_WIDTH, LCD_HEIGHT - y2); | ||
212 | |||
213 | if (x1 > 0) /* refresh part to the left of overlay */ | ||
214 | _grey_rb->lcd_update_rect(0, y1, x1, y2 - y1); | ||
215 | |||
216 | if (x2 < LCD_WIDTH) /* refresh part to the right of overlay */ | ||
217 | _grey_rb->lcd_update_rect(x2, y1, LCD_WIDTH - x2, y2 - y1); | ||
218 | } | ||
219 | |||
220 | #ifndef SIMULATOR | ||
221 | /* Timer interrupt handler: display next frame */ | ||
222 | static void _timer_isr(void) | ||
223 | { | ||
224 | #if LCD_PIXELFORMAT == HORIZONTAL_PACKING | ||
225 | _grey_rb->lcd_grey_phase_blit(_grey_info.data, _grey_info.bx, _grey_info.y, | ||
226 | _grey_info.bwidth, _grey_info.height, | ||
227 | _grey_info.width); | ||
228 | #else | ||
229 | _grey_rb->lcd_grey_phase_blit(_grey_info.data, _grey_info.x, _grey_info.by, | ||
230 | _grey_info.width, _grey_info.bheight, | ||
231 | _grey_info.width); | ||
232 | #endif | ||
233 | |||
234 | if (_grey_info.flags & _GREY_DEFERRED_UPDATE) /* lcd_update() requested? */ | ||
235 | { | ||
236 | _deferred_update(); | ||
237 | _grey_info.flags &= ~_GREY_DEFERRED_UPDATE; /* clear request */ | ||
238 | } | ||
239 | } | ||
240 | #endif /* !SIMULATOR */ | ||
241 | |||
242 | /* fixed point exp() */ | ||
243 | static int exp_s16p16(int x) | ||
244 | { | ||
245 | int t; | ||
246 | int y = 0x00010000; | ||
247 | |||
248 | if (x < 0) x += 0xb1721, y >>= 16; | ||
249 | t = x - 0x58b91; if (t >= 0) x = t, y <<= 8; | ||
250 | t = x - 0x2c5c8; if (t >= 0) x = t, y <<= 4; | ||
251 | t = x - 0x162e4; if (t >= 0) x = t, y <<= 2; | ||
252 | t = x - 0x0b172; if (t >= 0) x = t, y <<= 1; | ||
253 | t = x - 0x067cd; if (t >= 0) x = t, y += y >> 1; | ||
254 | t = x - 0x03920; if (t >= 0) x = t, y += y >> 2; | ||
255 | t = x - 0x01e27; if (t >= 0) x = t, y += y >> 3; | ||
256 | t = x - 0x00f85; if (t >= 0) x = t, y += y >> 4; | ||
257 | t = x - 0x007e1; if (t >= 0) x = t, y += y >> 5; | ||
258 | t = x - 0x003f8; if (t >= 0) x = t, y += y >> 6; | ||
259 | t = x - 0x001fe; if (t >= 0) x = t, y += y >> 7; | ||
260 | y += ((y >> 8) * x) >> 8; | ||
261 | |||
262 | return y; | ||
263 | } | ||
264 | |||
265 | /* fixed point log() */ | ||
266 | static int log_s16p16(int x) | ||
267 | { | ||
268 | int t; | ||
269 | int y = 0xa65af; | ||
270 | |||
271 | if (x < 0x00008000) x <<=16, y -= 0xb1721; | ||
272 | if (x < 0x00800000) x <<= 8, y -= 0x58b91; | ||
273 | if (x < 0x08000000) x <<= 4, y -= 0x2c5c8; | ||
274 | if (x < 0x20000000) x <<= 2, y -= 0x162e4; | ||
275 | if (x < 0x40000000) x <<= 1, y -= 0x0b172; | ||
276 | t = x + (x >> 1); if ((t & 0x80000000) == 0) x = t, y -= 0x067cd; | ||
277 | t = x + (x >> 2); if ((t & 0x80000000) == 0) x = t, y -= 0x03920; | ||
278 | t = x + (x >> 3); if ((t & 0x80000000) == 0) x = t, y -= 0x01e27; | ||
279 | t = x + (x >> 4); if ((t & 0x80000000) == 0) x = t, y -= 0x00f85; | ||
280 | t = x + (x >> 5); if ((t & 0x80000000) == 0) x = t, y -= 0x007e1; | ||
281 | t = x + (x >> 6); if ((t & 0x80000000) == 0) x = t, y -= 0x003f8; | ||
282 | t = x + (x >> 7); if ((t & 0x80000000) == 0) x = t, y -= 0x001fe; | ||
283 | x = 0x80000000 - x; | ||
284 | y -= x >> 15; | ||
285 | |||
286 | return y; | ||
287 | } | ||
288 | |||
289 | /* Initialise the framework and prepare the greyscale display buffer | ||
290 | |||
291 | arguments: | ||
292 | newrb = pointer to plugin api | ||
293 | gbuf = pointer to the memory area to use (e.g. plugin buffer) | ||
294 | gbuf_size = max usable size of the buffer | ||
295 | buffered = use chunky pixel buffering? | ||
296 | This allows to use all drawing functions, but needs more | ||
297 | memory. Unbuffered operation provides only a subset of | ||
298 | drawing functions. (only grey_bitmap drawing and scrolling) | ||
299 | width = width in pixels (1..LCD_WIDTH) | ||
300 | height = height in pixels (1..LCD_HEIGHT) | ||
301 | Note that depending on the target LCD, either height or | ||
302 | width are rounded up to a multiple of 4 or 8. | ||
303 | |||
304 | result: | ||
305 | true on success, false on failure | ||
306 | |||
307 | If you need info about the memory taken by the greyscale buffer, supply a | ||
308 | long* as the last parameter. This long will then contain the number of bytes | ||
309 | used. The total memory needed can be calculated as follows: | ||
310 | total_mem = | ||
311 | width * height * 2 [grey display data] | ||
312 | + buffered ? (width * height) : 0 [chunky buffer] | ||
313 | + 0..3 [alignment] | ||
314 | |||
315 | The function is authentic regarding memory usage on the simulator, even | ||
316 | if it doesn't use all of the allocated memory. */ | ||
317 | bool grey_init(struct plugin_api* newrb, unsigned char *gbuf, long gbuf_size, | ||
318 | bool buffered, int width, int height, long *buf_taken) | ||
319 | { | ||
320 | int bdim, i; | ||
321 | long plane_size, buftaken; | ||
322 | unsigned data; | ||
323 | #ifndef SIMULATOR | ||
324 | struct grey_data *grey_data, *grey_end; | ||
325 | #endif | ||
326 | |||
327 | _grey_rb = newrb; | ||
328 | |||
329 | if ((unsigned) width > LCD_WIDTH | ||
330 | || (unsigned) height > LCD_HEIGHT) | ||
331 | return false; | ||
332 | |||
333 | #if LCD_PIXELFORMAT == HORIZONTAL_PACKING | ||
334 | bdim = (width + 7) >> 3; | ||
335 | width = bdim << 3; | ||
336 | #else /* vertical packing */ | ||
337 | #if LCD_DEPTH == 1 | ||
338 | bdim = (height + 7) >> 3; | ||
339 | height = bdim << 3; | ||
340 | #elif LCD_DEPTH == 2 | ||
341 | bdim = (height + 3) >> 2; | ||
342 | height = bdim << 2; | ||
343 | #endif | ||
344 | #endif | ||
345 | |||
346 | /* the buffer has to be long aligned */ | ||
347 | buftaken = (-(long)gbuf) & 3; | ||
348 | gbuf += buftaken; | ||
349 | |||
350 | plane_size = _GREY_MULUQ(width, height); | ||
351 | |||
352 | if (buffered) /* chunky buffer */ | ||
353 | { | ||
354 | buftaken += plane_size; | ||
355 | _grey_info.buffer = gbuf; | ||
356 | gbuf += plane_size; | ||
357 | } | ||
358 | buftaken += sizeof(struct grey_data) * plane_size; | ||
359 | if (buftaken > gbuf_size) | ||
360 | return false; | ||
361 | |||
362 | #ifdef SIMULATOR | ||
363 | _grey_info.buffer = gbuf; | ||
364 | #else | ||
365 | grey_data = (struct grey_data *)gbuf; | ||
366 | grey_end = grey_data + plane_size; | ||
367 | _grey_info.data = grey_data; | ||
368 | |||
369 | while (grey_data < grey_end) | ||
370 | { | ||
371 | grey_data->phase = _grey_rb->rand() & 0xff; | ||
372 | grey_data->value = 128; /* init to white */ | ||
373 | grey_data++; | ||
374 | } | ||
375 | #endif | ||
376 | |||
377 | _grey_info.x = 0; | ||
378 | _grey_info.y = 0; | ||
379 | _grey_info.width = width; | ||
380 | _grey_info.height = height; | ||
381 | #if LCD_PIXELFORMAT == HORIZONTAL_PACKING | ||
382 | _grey_info.bx = 0; | ||
383 | _grey_info.bwidth = bdim; | ||
384 | #else | ||
385 | _grey_info.by = 0; | ||
386 | _grey_info.bheight = bdim; | ||
387 | #endif | ||
388 | _grey_info.flags = 0; | ||
389 | _grey_info.fg_val = 0; | ||
390 | _grey_info.bg_val = 128; | ||
391 | _grey_info.fg_brightness = 0; | ||
392 | _grey_info.bg_brightness = 255; | ||
393 | _grey_info.drawmode = DRMODE_SOLID; | ||
394 | _grey_info.curfont = FONT_SYSFIXED; | ||
395 | |||
396 | |||
397 | /* precalculate the value -> pattern index conversion table, taking | ||
398 | linearisation and gamma correction into account */ | ||
399 | for (i = 0; i < 256; i++) | ||
400 | { | ||
401 | data = exp_s16p16(((2<<8) * log_s16p16(i * 257 + 1)) >> 8) + 128; | ||
402 | data = (data - (data >> 8)) >> 8; /* approx. data /= 257 */ | ||
403 | data = (lcdlinear[data] << 7) + 127; | ||
404 | _grey_info.gvalue[i] = (data + (data >> 8)) >> 8; | ||
405 | /* approx. data / 255 */ | ||
406 | } | ||
407 | |||
408 | if (buf_taken) /* caller requested info about space taken */ | ||
409 | *buf_taken = buftaken; | ||
410 | |||
411 | return true; | ||
412 | } | ||
413 | |||
414 | /* Release the greyscale display buffer and the library | ||
415 | DO CALL either this function or at least grey_show_display(false) | ||
416 | before you exit, otherwise nasty things may happen. */ | ||
417 | void grey_release(void) | ||
418 | { | ||
419 | grey_show(false); | ||
420 | } | ||
421 | |||
422 | /* Switch the greyscale overlay on or off | ||
423 | DO NOT call lcd_update() or any other api function that directly accesses | ||
424 | the lcd while the greyscale overlay is running! If you need to do | ||
425 | lcd_update() to update something outside the greyscale overlay area, use | ||
426 | grey_deferred_update() instead. | ||
427 | |||
428 | Other functions to avoid are: | ||
429 | lcd_blit() (obviously), lcd_update_rect(), lcd_set_contrast(), | ||
430 | lcd_set_invert_display(), lcd_set_flip() */ | ||
431 | void grey_show(bool enable) | ||
432 | { | ||
433 | if (enable && !(_grey_info.flags & _GREY_RUNNING)) | ||
434 | { | ||
435 | _grey_info.flags |= _GREY_RUNNING; | ||
436 | #ifdef SIMULATOR | ||
437 | _grey_rb->sim_lcd_ex_init(129, _grey_get_pixel); | ||
438 | grey_update(); | ||
439 | #else /* !SIMULATOR */ | ||
440 | #ifdef NEED_BOOST | ||
441 | _grey_rb->cpu_boost(true); | ||
442 | #endif | ||
443 | #if CONFIG_LCD == LCD_SSD1815 | ||
444 | _grey_rb->timer_register(1, NULL, TIMER_FREQ / 67, 1, _timer_isr); | ||
445 | #elif CONFIG_LCD == LCD_S1D15E06 | ||
446 | _grey_rb->timer_register(1, NULL, TIMER_FREQ / 70, 1, _timer_isr); | ||
447 | #elif CONFIG_LCD == LCD_IPOD2BPP | ||
448 | #ifdef IPOD_1G2G | ||
449 | _grey_rb->timer_register(1, NULL, TIMER_FREQ / 95, 1, _timer_isr); /* verified */ | ||
450 | #elif defined IPOD_3G | ||
451 | _grey_rb->timer_register(1, NULL, TIMER_FREQ / 87, 1, _timer_isr); /* verified */ | ||
452 | #else | ||
453 | /* FIXME: verify value */ | ||
454 | _grey_rb->timer_register(1, NULL, TIMER_FREQ / 80, 1, _timer_isr); | ||
455 | #endif | ||
456 | #elif CONFIG_LCD == LCD_IPODMINI | ||
457 | _grey_rb->timer_register(1, NULL, TIMER_FREQ / 88, 1, _timer_isr); | ||
458 | #elif CONFIG_LCD == LCD_IFP7XX | ||
459 | _grey_rb->timer_register(1, NULL, TIMER_FREQ / 83, 1, _timer_isr); | ||
460 | #endif /* CONFIG_LCD */ | ||
461 | #endif /* !SIMULATOR */ | ||
462 | _grey_rb->screen_dump_set_hook(grey_screendump_hook); | ||
463 | } | ||
464 | else if (!enable && (_grey_info.flags & _GREY_RUNNING)) | ||
465 | { | ||
466 | #ifdef SIMULATOR | ||
467 | _grey_rb->sim_lcd_ex_init(0, NULL); | ||
468 | #else | ||
469 | _grey_rb->timer_unregister(); | ||
470 | #ifdef NEED_BOOST | ||
471 | _grey_rb->cpu_boost(false); | ||
472 | #endif | ||
473 | #endif | ||
474 | _grey_info.flags &= ~_GREY_RUNNING; | ||
475 | _grey_rb->screen_dump_set_hook(NULL); | ||
476 | _grey_rb->lcd_update(); /* restore whatever there was before */ | ||
477 | } | ||
478 | } | ||
479 | |||
480 | #ifdef SIMULATOR | ||
481 | /* Callback function for grey_update_rect() to read a pixel from the greybuffer. | ||
482 | Note that x and y are in LCD coordinates, not greybuffer coordinates! */ | ||
483 | static unsigned long _grey_get_pixel(int x, int y) | ||
484 | { | ||
485 | return _grey_info.buffer[(y - _grey_info.y) * _grey_info.width | ||
486 | + x - _grey_info.x] + (1 << LCD_DEPTH); | ||
487 | } | ||
488 | |||
489 | /* Update a rectangular area of the greyscale overlay */ | ||
490 | void grey_update_rect(int x, int y, int width, int height) | ||
491 | { | ||
492 | if (x + width > _grey_info.width) | ||
493 | width = _grey_info.width - x; | ||
494 | if (y + height > _grey_info.height) | ||
495 | height = _grey_info.height - y; | ||
496 | |||
497 | x += _grey_info.x; | ||
498 | y += _grey_info.y; | ||
499 | |||
500 | if (x + width > LCD_WIDTH) | ||
501 | width = LCD_WIDTH - x; | ||
502 | if (y + height > LCD_HEIGHT) | ||
503 | height = LCD_HEIGHT - y; | ||
504 | |||
505 | _grey_rb->sim_lcd_ex_update_rect(x, y, width, height); | ||
506 | } | ||
507 | |||
508 | #else /* !SIMULATOR */ | ||
509 | |||
510 | void grey_update_rect(int x, int y, int width, int height) | ||
511 | { | ||
512 | unsigned char *src; | ||
513 | |||
514 | if ((width <= 0) || (height <= 0)) | ||
515 | return; /* nothing to do */ | ||
516 | |||
517 | if (y + height > _grey_info.height) | ||
518 | height = _grey_info.height - y; | ||
519 | if (x + width > _grey_info.width) | ||
520 | width = _grey_info.width - x; | ||
521 | |||
522 | src = _grey_info.buffer + _GREY_MULUQ(_grey_info.width, y) + x; | ||
523 | |||
524 | do | ||
525 | { | ||
526 | #if LCD_PIXELFORMAT == HORIZONTAL_PACKING | ||
527 | int idx = _GREY_MULUQ(_grey_info.width, y) + x; | ||
528 | #else | ||
529 | #if LCD_DEPTH == 1 | ||
530 | int idx = _GREY_MULUQ(_grey_info.width, y & ~7) + (x << 3) + (~y & 7); | ||
531 | #elif LCD_DEPTH == 2 | ||
532 | int idx = _GREY_MULUQ(_grey_info.width, y & ~3) + (x << 2) + (~y & 3); | ||
533 | #endif | ||
534 | #endif /* LCD_PIXELFORMAT */ | ||
535 | unsigned char *dst_row = &_grey_info.data[idx].value; | ||
536 | unsigned char *src_row = src; | ||
537 | unsigned char *src_end = src + width; | ||
538 | |||
539 | do | ||
540 | { | ||
541 | *dst_row = *src_row++; | ||
542 | dst_row += _GREY_X_ADVANCE; | ||
543 | } | ||
544 | while (src_row < src_end); | ||
545 | |||
546 | y++; | ||
547 | src += _grey_info.width; | ||
548 | } | ||
549 | while (--height > 0); | ||
550 | } | ||
551 | |||
552 | #endif /* !SIMULATOR */ | ||
553 | |||
554 | /* Update the whole greyscale overlay */ | ||
555 | void grey_update(void) | ||
556 | { | ||
557 | grey_update_rect(0, 0, _grey_info.width, _grey_info.height); | ||
558 | } | ||
559 | |||
560 | /* Do an lcd_update() to show changes done by rb->lcd_xxx() functions | ||
561 | (in areas of the screen not covered by the greyscale overlay). */ | ||
562 | void grey_deferred_lcd_update(void) | ||
563 | { | ||
564 | if (_grey_info.flags & _GREY_RUNNING) | ||
565 | { | ||
566 | #ifdef SIMULATOR | ||
567 | _deferred_update(); | ||
568 | #else | ||
569 | _grey_info.flags |= _GREY_DEFERRED_UPDATE; | ||
570 | #endif | ||
571 | } | ||
572 | else | ||
573 | _grey_rb->lcd_update(); | ||
574 | } | ||
575 | |||
576 | /*** Screenshot ***/ | ||
577 | |||
578 | #define BMP_FIXEDCOLORS (1 << LCD_DEPTH) | ||
579 | #define BMP_VARCOLORS 129 | ||
580 | #define BMP_NUMCOLORS (BMP_FIXEDCOLORS + BMP_VARCOLORS) | ||
581 | #define BMP_BPP 8 | ||
582 | #define BMP_LINESIZE ((LCD_WIDTH + 3) & ~3) | ||
583 | #define BMP_HEADERSIZE (54 + 4 * BMP_NUMCOLORS) | ||
584 | #define BMP_DATASIZE (BMP_LINESIZE * LCD_HEIGHT) | ||
585 | #define BMP_TOTALSIZE (BMP_HEADERSIZE + BMP_DATASIZE) | ||
586 | |||
587 | #define LE16_CONST(x) (x)&0xff, ((x)>>8)&0xff | ||
588 | #define LE32_CONST(x) (x)&0xff, ((x)>>8)&0xff, ((x)>>16)&0xff, ((x)>>24)&0xff | ||
589 | |||
590 | static const unsigned char bmpheader[] = | ||
591 | { | ||
592 | 0x42, 0x4d, /* 'BM' */ | ||
593 | LE32_CONST(BMP_TOTALSIZE), /* Total file size */ | ||
594 | 0x00, 0x00, 0x00, 0x00, /* Reserved */ | ||
595 | LE32_CONST(BMP_HEADERSIZE), /* Offset to start of pixel data */ | ||
596 | |||
597 | 0x28, 0x00, 0x00, 0x00, /* Size of (2nd) header */ | ||
598 | LE32_CONST(LCD_WIDTH), /* Width in pixels */ | ||
599 | LE32_CONST(LCD_HEIGHT), /* Height in pixels */ | ||
600 | 0x01, 0x00, /* Number of planes (always 1) */ | ||
601 | LE16_CONST(BMP_BPP), /* Bits per pixel 1/4/8/16/24 */ | ||
602 | 0x00, 0x00, 0x00, 0x00, /* Compression mode, 0 = none */ | ||
603 | LE32_CONST(BMP_DATASIZE), /* Size of bitmap data */ | ||
604 | 0xc4, 0x0e, 0x00, 0x00, /* Horizontal resolution (pixels/meter) */ | ||
605 | 0xc4, 0x0e, 0x00, 0x00, /* Vertical resolution (pixels/meter) */ | ||
606 | LE32_CONST(BMP_NUMCOLORS), /* Number of used colours */ | ||
607 | LE32_CONST(BMP_NUMCOLORS), /* Number of important colours */ | ||
608 | |||
609 | /* Fixed colours */ | ||
610 | #if LCD_DEPTH == 1 | ||
611 | 0x90, 0xee, 0x90, 0x00, /* Colour #0 */ | ||
612 | 0x00, 0x00, 0x00, 0x00 /* Colour #1 */ | ||
613 | #elif LCD_DEPTH == 2 | ||
614 | 0xe6, 0xd8, 0xad, 0x00, /* Colour #0 */ | ||
615 | 0x99, 0x90, 0x73, 0x00, /* Colour #1 */ | ||
616 | 0x4c, 0x48, 0x39, 0x00, /* Colour #2 */ | ||
617 | 0x00, 0x00, 0x00, 0x00 /* Colour #3 */ | ||
618 | #endif | ||
619 | }; | ||
620 | |||
621 | #if LCD_DEPTH == 1 | ||
622 | #define BMP_RED 0x90 | ||
623 | #define BMP_GREEN 0xee | ||
624 | #define BMP_BLUE 0x90 | ||
625 | #elif LCD_DEPTH == 2 | ||
626 | #define BMP_RED 0xad | ||
627 | #define BMP_GREEN 0xd8 | ||
628 | #define BMP_BLUE 0xe6 | ||
629 | #endif | ||
630 | |||
631 | /* Hook function for core screen_dump() to save the current display | ||
632 | content (b&w and greyscale overlay) to an 8-bit BMP file. */ | ||
633 | static void grey_screendump_hook(int fd) | ||
634 | { | ||
635 | int i; | ||
636 | int x, y, gx, gy; | ||
637 | #if LCD_PIXELFORMAT == VERTICAL_PACKING | ||
638 | #if LCD_DEPTH == 1 | ||
639 | unsigned mask; | ||
640 | #elif LCD_DEPTH == 2 | ||
641 | int shift; | ||
642 | #endif | ||
643 | #endif /* LCD_PIXELFORMAT == VERTICAL_PACKING */ | ||
644 | unsigned char *lcdptr; | ||
645 | unsigned char *clut_entry; | ||
646 | unsigned char linebuf[MAX(4*BMP_VARCOLORS,BMP_LINESIZE)]; | ||
647 | |||
648 | _grey_rb->write(fd, bmpheader, sizeof(bmpheader)); /* write header */ | ||
649 | |||
650 | /* build clut */ | ||
651 | _grey_rb->memset(linebuf, 0, 4*BMP_VARCOLORS); | ||
652 | clut_entry = linebuf; | ||
653 | |||
654 | for (i = 0; i <= 128; i++) | ||
655 | { | ||
656 | *clut_entry++ = _GREY_MULUQ(BMP_BLUE, i) >> 7; | ||
657 | *clut_entry++ = _GREY_MULUQ(BMP_GREEN, i) >> 7; | ||
658 | *clut_entry++ = _GREY_MULUQ(BMP_RED, i) >> 7; | ||
659 | clut_entry++; | ||
660 | } | ||
661 | _grey_rb->write(fd, linebuf, 4*BMP_VARCOLORS); | ||
662 | |||
663 | /* BMP image goes bottom -> top */ | ||
664 | for (y = LCD_HEIGHT - 1; y >= 0; y--) | ||
665 | { | ||
666 | _grey_rb->memset(linebuf, 0, BMP_LINESIZE); | ||
667 | |||
668 | gy = y - _grey_info.y; | ||
669 | #if LCD_PIXELFORMAT == HORIZONTAL_PACKING | ||
670 | #if LCD_DEPTH == 2 | ||
671 | lcdptr = _grey_rb->lcd_framebuffer + _GREY_MULUQ(LCD_FBWIDTH, y); | ||
672 | |||
673 | for (x = 0; x < LCD_WIDTH; x += 4) | ||
674 | { | ||
675 | gx = x - _grey_info.x; | ||
676 | |||
677 | if (((unsigned)gy < (unsigned)_grey_info.height) | ||
678 | && ((unsigned)gx < (unsigned)_grey_info.width)) | ||
679 | { | ||
680 | #ifdef SIMULATOR | ||
681 | unsigned char *src = _grey_info.buffer | ||
682 | + _GREY_MULUQ(_grey_info.width, gy) + gx; | ||
683 | |||
684 | for (i = 0; i < 4; i++) | ||
685 | linebuf[x + i] = BMP_FIXEDCOLORS + *src++; | ||
686 | #else | ||
687 | unsigned char *src = &_grey_info.data[_GREY_MULUQ(_grey_info.width, | ||
688 | gy) + gx].value; | ||
689 | for (i = 0; i < 4; i++) | ||
690 | { | ||
691 | linebuf[x + i] = BMP_FIXEDCOLORS + *src; | ||
692 | src += _GREY_X_ADVANCE; | ||
693 | } | ||
694 | #endif | ||
695 | } | ||
696 | else | ||
697 | { | ||
698 | unsigned data = *lcdptr; | ||
699 | linebuf[x] = (data >> 6) & 3; | ||
700 | linebuf[x + 1] = (data >> 4) & 3; | ||
701 | linebuf[x + 2] = (data >> 2) & 3; | ||
702 | linebuf[x + 3] = data & 3; | ||
703 | } | ||
704 | lcdptr++; | ||
705 | } | ||
706 | #endif /* LCD_DEPTH */ | ||
707 | #else /* LCD_PIXELFORMAT == VERTICAL_PACKING */ | ||
708 | #if LCD_DEPTH == 1 | ||
709 | mask = 1 << (y & 7); | ||
710 | lcdptr = _grey_rb->lcd_framebuffer + _GREY_MULUQ(LCD_WIDTH, y >> 3); | ||
711 | |||
712 | for (x = 0; x < LCD_WIDTH; x++) | ||
713 | { | ||
714 | gx = x - _grey_info.x; | ||
715 | |||
716 | if (((unsigned)gy < (unsigned)_grey_info.height) | ||
717 | && ((unsigned)gx < (unsigned)_grey_info.width)) | ||
718 | { | ||
719 | #ifdef SIMULATOR | ||
720 | linebuf[x] = BMP_FIXEDCOLORS | ||
721 | + _grey_info.buffer[_GREY_MULUQ(_grey_info.width, | ||
722 | gy) + gx]; | ||
723 | #else | ||
724 | linebuf[x] = BMP_FIXEDCOLORS | ||
725 | + _grey_info.data[_GREY_MULUQ(_grey_info.width, | ||
726 | gy & ~7) + (gx << 3) + (~gy & 7)].value; | ||
727 | #endif | ||
728 | } | ||
729 | else | ||
730 | { | ||
731 | linebuf[x] = (*lcdptr & mask) ? 1 : 0; | ||
732 | } | ||
733 | lcdptr++; | ||
734 | } | ||
735 | #elif LCD_DEPTH == 2 | ||
736 | shift = 2 * (y & 3); | ||
737 | lcdptr = _grey_rb->lcd_framebuffer + _GREY_MULUQ(LCD_WIDTH, y >> 2); | ||
738 | |||
739 | for (x = 0; x < LCD_WIDTH; x++) | ||
740 | { | ||
741 | gx = x - _grey_info.x; | ||
742 | |||
743 | if (((unsigned)gy < (unsigned)_grey_info.height) | ||
744 | && ((unsigned)gx < (unsigned)_grey_info.width)) | ||
745 | { | ||
746 | #ifdef SIMULATOR | ||
747 | linebuf[x] = BMP_FIXEDCOLORS | ||
748 | + _grey_info.buffer[_GREY_MULUQ(_grey_info.width, | ||
749 | gy) + gx]; | ||
750 | #else | ||
751 | linebuf[x] = BMP_FIXEDCOLORS | ||
752 | + _grey_info.data[_GREY_MULUQ(_grey_info.width, | ||
753 | gy & ~3) + (gx << 2) + (~gy & 7)].value; | ||
754 | #endif | ||
755 | } | ||
756 | else | ||
757 | { | ||
758 | linebuf[x] = (*lcdptr >> shift) & 3; | ||
759 | } | ||
760 | lcdptr++; | ||
761 | } | ||
762 | #endif /* LCD_DEPTH */ | ||
763 | #endif /* LCD_PIXELFORMAT */ | ||
764 | |||
765 | _grey_rb->write(fd, linebuf, BMP_LINESIZE); | ||
766 | } | ||
767 | } | ||