Trim down peak calculation a bit.
[kugel-rb.git] / firmware / screendump.c
blob1876df8ac05247c1df244b86ff4c591fe8c85756
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2009 by Jens Arnold
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
22 #include "config.h"
23 #include "screendump.h"
25 #include "file.h"
26 #include "general.h"
27 #include "lcd.h"
28 #include "stdlib.h"
29 #include "string.h"
30 #include "system.h"
32 #ifdef HAVE_REMOTE_LCD
33 #include "lcd-remote.h"
34 #endif
36 #if LCD_DEPTH == 16
37 #define BMP_COMPRESSION 3 /* BI_BITFIELDS */
38 #define BMP_NUMCOLORS 3
39 #else /* LCD_DEPTH != 16 */
40 #define BMP_COMPRESSION 0 /* BI_RGB */
41 #if LCD_DEPTH <= 8
42 #ifdef HAVE_LCD_SPLIT
43 #define BMP_NUMCOLORS (2 << LCD_DEPTH)
44 #else
45 #define BMP_NUMCOLORS (1 << LCD_DEPTH)
46 #endif
47 #else /* LCD_DEPTH > 8 */
48 #define BMP_NUMCOLORS 0
49 #endif /* LCD_DEPTH > 8 */
50 #endif /* LCD_DEPTH != 16 */
52 #if LCD_DEPTH <= 4
53 #define BMP_BPP 4
54 #define BMP_LINESIZE ((LCD_WIDTH/2 + 3) & ~3)
55 #elif LCD_DEPTH <= 8
56 #define BMP_BPP 8
57 #define BMP_LINESIZE ((LCD_WIDTH + 3) & ~3)
58 #elif LCD_DEPTH <= 16
59 #define BMP_BPP 16
60 #define BMP_LINESIZE ((LCD_WIDTH*2 + 3) & ~3)
61 #else
62 #define BMP_BPP 24
63 #define BMP_LINESIZE ((LCD_WIDTH*3 + 3) & ~3)
64 #endif
66 #define BMP_HEADERSIZE (54 + 4 * BMP_NUMCOLORS)
67 #define BMP_DATASIZE (BMP_LINESIZE * (LCD_HEIGHT+LCD_SPLIT_LINES))
68 #define BMP_TOTALSIZE (BMP_HEADERSIZE + BMP_DATASIZE)
70 static const unsigned char bmpheader[] =
72 0x42, 0x4d, /* 'BM' */
73 LE32_CONST(BMP_TOTALSIZE), /* Total file size */
74 0x00, 0x00, 0x00, 0x00, /* Reserved */
75 LE32_CONST(BMP_HEADERSIZE), /* Offset to start of pixel data */
77 0x28, 0x00, 0x00, 0x00, /* Size of (2nd) header */
78 LE32_CONST(LCD_WIDTH), /* Width in pixels */
79 LE32_CONST(LCD_HEIGHT+LCD_SPLIT_LINES), /* Height in pixels */
80 0x01, 0x00, /* Number of planes (always 1) */
81 LE16_CONST(BMP_BPP), /* Bits per pixel 1/4/8/16/24 */
82 LE32_CONST(BMP_COMPRESSION),/* Compression mode */
83 LE32_CONST(BMP_DATASIZE), /* Size of bitmap data */
84 0xc4, 0x0e, 0x00, 0x00, /* Horizontal resolution (pixels/meter) */
85 0xc4, 0x0e, 0x00, 0x00, /* Vertical resolution (pixels/meter) */
86 LE32_CONST(BMP_NUMCOLORS), /* Number of used colours */
87 LE32_CONST(BMP_NUMCOLORS), /* Number of important colours */
89 #if LCD_DEPTH == 1
90 #ifdef HAVE_NEGATIVE_LCD
91 BMP_COLOR(LCD_BL_DARKCOLOR),
92 BMP_COLOR(LCD_BL_BRIGHTCOLOR),
93 #ifdef HAVE_LCD_SPLIT
94 BMP_COLOR(LCD_BL_DARKCOLOR_2),
95 BMP_COLOR(LCD_BL_BRIGHTCOLOR_2),
96 #endif
97 #else /* positive display */
98 BMP_COLOR(LCD_BL_BRIGHTCOLOR),
99 BMP_COLOR(LCD_BL_DARKCOLOR),
100 #endif /* positive display */
101 #elif LCD_DEPTH == 2
102 BMP_COLOR(LCD_BL_BRIGHTCOLOR),
103 BMP_COLOR_MIX(LCD_BL_BRIGHTCOLOR, LCD_BL_DARKCOLOR, 1, 3),
104 BMP_COLOR_MIX(LCD_BL_BRIGHTCOLOR, LCD_BL_DARKCOLOR, 2, 3),
105 BMP_COLOR(LCD_BL_DARKCOLOR),
106 #elif LCD_DEPTH == 16
107 0x00, 0xf8, 0x00, 0x00, /* red bitfield mask */
108 0xe0, 0x07, 0x00, 0x00, /* green bitfield mask */
109 0x1f, 0x00, 0x00, 0x00, /* blue bitfield mask */
110 #endif
113 static void (*screen_dump_hook)(int fh) = NULL;
115 void screen_dump(void)
117 int fd, y;
118 char filename[MAX_PATH];
120 fb_data *src;
121 #if LCD_DEPTH == 1
122 unsigned mask;
123 unsigned val;
124 #elif (LCD_DEPTH == 2) && (LCD_PIXELFORMAT != HORIZONTAL_PACKING)
125 int shift;
126 unsigned val;
127 #endif
128 #if LCD_DEPTH <= 8
129 unsigned char *dst, *dst_end;
130 unsigned char linebuf[BMP_LINESIZE];
131 #elif LCD_DEPTH <= 16
132 unsigned short *dst, *dst_end;
133 unsigned short linebuf[BMP_LINESIZE/2];
134 #endif
136 #if CONFIG_RTC
137 create_datetime_filename(filename, "", "dump ", ".bmp", false);
138 #else
139 create_numbered_filename(filename, "", "dump_", ".bmp", 4
140 IF_CNFN_NUM_(, NULL));
141 #endif
143 fd = creat(filename, 0666);
144 if (fd < 0)
145 return;
147 if (screen_dump_hook)
149 screen_dump_hook(fd);
151 else
153 write(fd, bmpheader, sizeof(bmpheader));
155 /* BMP image goes bottom up */
156 for (y = LCD_HEIGHT - 1; y >= 0; y--)
158 memset(linebuf, 0, BMP_LINESIZE);
160 #if defined(HAVE_LCD_SPLIT) && (LCD_SPLIT_LINES == 2)
161 if (y == LCD_SPLIT_POS - 1)
163 write(fd, linebuf, BMP_LINESIZE);
164 write(fd, linebuf, BMP_LINESIZE);
166 #endif
167 dst = linebuf;
169 #if LCD_DEPTH == 1
170 dst_end = dst + LCD_WIDTH/2;
171 src = lcd_framebuffer[y >> 3];
172 mask = BIT_N(y & 7);
176 val = (*src++ & mask) ? 0x10 : 0;
177 val |= (*src++ & mask) ? 0x01 : 0;
178 #ifdef HAVE_LCD_SPLIT
179 if (y < LCD_SPLIT_POS)
180 val |= 0x22;
181 #endif
182 *dst++ = val;
184 while (dst < dst_end);
186 #elif LCD_DEPTH == 2
187 dst_end = dst + LCD_WIDTH/2;
189 #if LCD_PIXELFORMAT == HORIZONTAL_PACKING
190 src = lcd_framebuffer[y];
194 unsigned data = *src++;
196 *dst++ = ((data >> 2) & 0x30) | ((data >> 4) & 0x03);
197 *dst++ = ((data << 2) & 0x30) | (data & 0x03);
199 while (dst < dst_end);
201 #elif LCD_PIXELFORMAT == VERTICAL_PACKING
202 src = lcd_framebuffer[y >> 2];
203 shift = 2 * (y & 3);
207 val = ((*src++ >> shift) & 3) << 4;
208 val |= ((*src++ >> shift) & 3);
209 *dst++ = val;
211 while (dst < dst_end);
213 #elif LCD_PIXELFORMAT == VERTICAL_INTERLEAVED
214 src = lcd_framebuffer[y >> 3];
215 shift = y & 7;
219 unsigned data = (*src++ >> shift) & 0x0101;
221 val = (((data >> 7) | data) & 3) << 4;
222 data = (*src++ >> shift) & 0x0101;
223 val |= ((data >> 7) | data) & 3;
224 *dst++ = val;
226 while (dst < dst_end);
228 #endif
229 #elif LCD_DEPTH == 16
230 dst_end = dst + LCD_WIDTH;
231 src = lcd_framebuffer[y];
235 #if (LCD_PIXELFORMAT == RGB565SWAPPED)
236 /* iPod LCD data is big endian although the CPU is not */
237 *dst++ = htobe16(*src++);
238 #else
239 *dst++ = htole16(*src++);
240 #endif
242 while (dst < dst_end);
244 #endif /* LCD_DEPTH */
245 write(fd, linebuf, BMP_LINESIZE);
248 close(fd);
251 void screen_dump_set_hook(void (*hook)(int fh))
253 screen_dump_hook = hook;
256 #ifdef HAVE_REMOTE_LCD
258 #define RBMP_COMPRESSION 0 /* BI_RGB */
259 #define RBMP_NUMCOLORS (1 << LCD_REMOTE_DEPTH)
260 #define RBMP_BPP 4
261 #define RBMP_LINESIZE ((LCD_REMOTE_WIDTH/2 + 3) & ~3)
263 #define RBMP_HEADERSIZE (54 + 4 * RBMP_NUMCOLORS)
264 #define RBMP_DATASIZE (RBMP_LINESIZE * LCD_REMOTE_HEIGHT)
265 #define RBMP_TOTALSIZE (RBMP_HEADERSIZE + RBMP_DATASIZE)
267 static const unsigned char rbmpheader[] =
269 0x42, 0x4d, /* 'BM' */
270 LE32_CONST(RBMP_TOTALSIZE), /* Total file size */
271 0x00, 0x00, 0x00, 0x00, /* Reserved */
272 LE32_CONST(RBMP_HEADERSIZE), /* Offset to start of pixel data */
274 0x28, 0x00, 0x00, 0x00, /* Size of (2nd) header */
275 LE32_CONST(LCD_REMOTE_WIDTH), /* Width in pixels */
276 LE32_CONST(LCD_REMOTE_HEIGHT), /* Height in pixels */
277 0x01, 0x00, /* Number of planes (always 1) */
278 LE16_CONST(RBMP_BPP), /* Bits per pixel 1/4/8/16/24 */
279 LE32_CONST(RBMP_COMPRESSION), /* Compression mode */
280 LE32_CONST(RBMP_DATASIZE), /* Size of bitmap data */
281 0xc4, 0x0e, 0x00, 0x00, /* Horizontal resolution (pixels/meter) */
282 0xc4, 0x0e, 0x00, 0x00, /* Vertical resolution (pixels/meter) */
283 LE32_CONST(RBMP_NUMCOLORS), /* Number of used colours */
284 LE32_CONST(RBMP_NUMCOLORS), /* Number of important colours */
286 #if LCD_REMOTE_DEPTH == 1
287 BMP_COLOR(LCD_REMOTE_BL_BRIGHTCOLOR),
288 BMP_COLOR(LCD_REMOTE_BL_DARKCOLOR),
289 #elif LCD_REMOTE_DEPTH == 2
290 BMP_COLOR(LCD_REMOTE_BL_BRIGHTCOLOR),
291 BMP_COLOR_MIX(LCD_REMOTE_BL_BRIGHTCOLOR, LCD_REMOTE_BL_DARKCOLOR, 1, 3),
292 BMP_COLOR_MIX(LCD_REMOTE_BL_BRIGHTCOLOR, LCD_REMOTE_BL_DARKCOLOR, 2, 3),
293 BMP_COLOR(LCD_REMOTE_BL_DARKCOLOR),
294 #endif
297 void remote_screen_dump(void)
299 int fd, y;
300 char filename[MAX_PATH];
302 fb_remote_data *src;
303 #if LCD_REMOTE_DEPTH == 1
304 unsigned mask;
305 unsigned val;
306 #elif LCD_REMOTE_DEPTH == 2
307 int shift;
308 unsigned val;
309 #endif
310 unsigned char *dst, *dst_end;
311 unsigned char linebuf[RBMP_LINESIZE];
313 #if CONFIG_RTC
314 create_datetime_filename(filename, "", "rdump ", ".bmp", false);
315 #else
316 create_numbered_filename(filename, "", "rdump_", ".bmp", 4
317 IF_CNFN_NUM_(, NULL));
318 #endif
320 fd = creat(filename, 0666);
321 if (fd < 0)
322 return;
324 write(fd, rbmpheader, sizeof(rbmpheader));
326 /* BMP image goes bottom up */
327 for (y = LCD_REMOTE_HEIGHT - 1; y >= 0; y--)
329 memset(linebuf, 0, RBMP_LINESIZE);
331 dst = linebuf;
333 #if LCD_REMOTE_DEPTH == 1
334 dst_end = dst + LCD_REMOTE_WIDTH/2;
335 src = lcd_remote_framebuffer[y >> 3];
336 mask = BIT_N(y & 7);
340 val = (*src++ & mask) ? 0x10 : 0;
341 val |= (*src++ & mask) ? 0x01 : 0;
342 *dst++ = val;
344 while (dst < dst_end);
346 #elif LCD_REMOTE_DEPTH == 2
347 dst_end = dst + LCD_REMOTE_WIDTH/2;
349 #if LCD_REMOTE_PIXELFORMAT == VERTICAL_INTERLEAVED
350 src = lcd_remote_framebuffer[y >> 3];
351 shift = y & 7;
355 unsigned data = (*src++ >> shift) & 0x0101;
357 val = (((data >> 7) | data) & 3) << 4;
358 data = (*src++ >> shift) & 0x0101;
359 val |= ((data >> 7) | data) & 3;
360 *dst++ = val;
362 while (dst < dst_end);
364 #endif
365 #endif /* LCD_REMOTE_DEPTH */
366 write(fd, linebuf, RBMP_LINESIZE);
368 close(fd);
371 #endif /* HAVE_REMOTE_LCD */