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