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 * 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 ****************************************************************************/
29 #if defined(CPU_PP) && defined(HAVE_ADJUSTABLE_CPU_FREQ)
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
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 */
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
);
191 static unsigned long _grey_get_pixel(int x
, int y
);
193 static void _timer_isr(void);
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
);
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
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
;
229 int idx
= _grey_info
.width
* (yg
& ~_GREY_BMASK
)
230 + (xg
<< _GREY_BSHIFT
) + (~yg
& _GREY_BMASK
);
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
,
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
,
253 if (_grey_info
.flags
& _GREY_DEFERRED_UPDATE
) /* lcd_update() requested? */
256 _grey_info
.flags
&= ~_GREY_DEFERRED_UPDATE
; /* clear request */
260 #endif /* !SIMULATOR */
262 /* fixed point exp() */
263 static int exp_s16p16(int x
)
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;
285 /* fixed point log() */
286 static int log_s16p16(int x
)
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;
309 /* Initialise the framework and prepare the greyscale display buffer
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.
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:
331 width * height * 2 [grey display data]
332 + buffered ? (width * height) : 0 [chunky buffer]
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
)
341 long plane_size
, buftaken
;
347 _grey_info
.rb
= newrb
;
349 if ((unsigned) width
> LCD_WIDTH
350 || (unsigned) height
> LCD_HEIGHT
)
353 #if LCD_PIXELFORMAT == HORIZONTAL_PACKING
354 bdim
= (width
+ 7) >> 3;
356 #else /* vertical packing */
358 bdim
= (height
+ 7) >> 3;
361 bdim
= (height
+ 3) >> 2;
366 plane_size
= _GREY_MULUQ(width
, height
);
368 plane_size
+= (-plane_size
) & 0xf; /* All buffers should be line aligned */
369 buftaken
= (-(long)gbuf
) & 0xf;
371 buftaken
= (-(long)gbuf
) & 3; /* All buffers must be long aligned. */
375 if (buffered
) /* chunky buffer */
377 _grey_info
.buffer
= gbuf
;
379 buftaken
+= plane_size
;
381 _grey_info
.values
= gbuf
;
383 _grey_info
.phases
= gbuf
;
384 buftaken
+= 2 * plane_size
;
386 if (buftaken
> gbuf_size
)
390 _grey_info
.rb
->memset(_grey_info
.values
, 0x80, plane_size
);
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();
404 _grey_info
.width
= width
;
405 _grey_info
.height
= height
;
406 #if LCD_PIXELFORMAT == HORIZONTAL_PACKING
408 _grey_info
.bwidth
= bdim
;
411 _grey_info
.bheight
= bdim
;
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
;
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)
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
;
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 */
464 _grey_info
.rb
->cpu_boost(true);
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
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 */
476 /* FIXME: verify value */
477 _grey_info
.rb
->timer_register(1, NULL
, TIMER_FREQ
/ 80, 1, _timer_isr
);
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
))
492 _grey_info
.rb
->sim_lcd_ex_init(0, NULL
);
494 _grey_info
.rb
->timer_unregister();
496 _grey_info
.rb
->cpu_boost(false);
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
)
527 _grey_info
.flags
|= _GREY_DEFERRED_UPDATE
;
531 _grey_info
.rb
->lcd_update();
536 #define BMP_FIXEDCOLORS (1 << LCD_DEPTH)
537 #define BMP_VARCOLORS 129
538 #define BMP_NUMCOLORS (BMP_FIXEDCOLORS + BMP_VARCOLORS)
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 */
569 0x90, 0xee, 0x90, 0x00, /* Colour #0 */
570 0x00, 0x00, 0x00, 0x00 /* Colour #1 */
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 */
581 #define BMP_GREEN 0xee
582 #define BMP_BLUE 0x90
585 #define BMP_GREEN 0xd8
586 #define BMP_BLUE 0xe6
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
)
595 #if LCD_PIXELFORMAT == VERTICAL_PACKING
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 */
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;
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
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
++;
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;
653 #endif /* LCD_DEPTH */
654 #else /* LCD_PIXELFORMAT == VERTICAL_PACKING */
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
,
669 + (gx
<< _GREY_BSHIFT
)
670 + (~gy
& _GREY_BMASK
)];
674 linebuf
[x
] = (*lcdptr
& mask
) ? 1 : 0;
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
,
692 + (gx
<< _GREY_BSHIFT
)
693 + (~gy
& _GREY_BMASK
)];
697 linebuf
[x
] = (*lcdptr
>> shift
) & 3;
701 #endif /* LCD_DEPTH */
702 #endif /* LCD_PIXELFORMAT */
704 _grey_info
.rb
->write(fd
, linebuf
, BMP_LINESIZE
);