Fix mistake on targets without frequency scaling.
[kugel-rb.git] / firmware / screendump.c
blob30b9539732d525640b1393f057312ac7604a5ab3
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 #define BMP_HEADERSIZE (54 + 4 * BMP_NUMCOLORS)
53 #define BMP_DATASIZE (DUMP_BMP_LINESIZE * (LCD_HEIGHT+LCD_SPLIT_LINES))
54 #define BMP_TOTALSIZE (BMP_HEADERSIZE + BMP_DATASIZE)
56 static const unsigned char bmpheader[] =
58 0x42, 0x4d, /* 'BM' */
59 LE32_CONST(BMP_TOTALSIZE), /* Total file size */
60 0x00, 0x00, 0x00, 0x00, /* Reserved */
61 LE32_CONST(BMP_HEADERSIZE), /* Offset to start of pixel data */
63 0x28, 0x00, 0x00, 0x00, /* Size of (2nd) header */
64 LE32_CONST(LCD_WIDTH), /* Width in pixels */
65 LE32_CONST(LCD_HEIGHT+LCD_SPLIT_LINES), /* Height in pixels */
66 0x01, 0x00, /* Number of planes (always 1) */
67 LE16_CONST(DUMP_BMP_BPP), /* Bits per pixel 1/4/8/16/24 */
68 LE32_CONST(BMP_COMPRESSION),/* Compression mode */
69 LE32_CONST(BMP_DATASIZE), /* Size of bitmap data */
70 0xc4, 0x0e, 0x00, 0x00, /* Horizontal resolution (pixels/meter) */
71 0xc4, 0x0e, 0x00, 0x00, /* Vertical resolution (pixels/meter) */
72 LE32_CONST(BMP_NUMCOLORS), /* Number of used colours */
73 LE32_CONST(BMP_NUMCOLORS), /* Number of important colours */
75 #if LCD_DEPTH == 1
76 #ifdef HAVE_NEGATIVE_LCD
77 BMP_COLOR(LCD_BL_DARKCOLOR),
78 BMP_COLOR(LCD_BL_BRIGHTCOLOR),
79 #ifdef HAVE_LCD_SPLIT
80 BMP_COLOR(LCD_BL_DARKCOLOR_2),
81 BMP_COLOR(LCD_BL_BRIGHTCOLOR_2),
82 #endif
83 #else /* positive display */
84 BMP_COLOR(LCD_BL_BRIGHTCOLOR),
85 BMP_COLOR(LCD_BL_DARKCOLOR),
86 #endif /* positive display */
87 #elif LCD_DEPTH == 2
88 BMP_COLOR(LCD_BL_BRIGHTCOLOR),
89 BMP_COLOR_MIX(LCD_BL_BRIGHTCOLOR, LCD_BL_DARKCOLOR, 1, 3),
90 BMP_COLOR_MIX(LCD_BL_BRIGHTCOLOR, LCD_BL_DARKCOLOR, 2, 3),
91 BMP_COLOR(LCD_BL_DARKCOLOR),
92 #elif LCD_DEPTH == 16
93 0x00, 0xf8, 0x00, 0x00, /* red bitfield mask */
94 0xe0, 0x07, 0x00, 0x00, /* green bitfield mask */
95 0x1f, 0x00, 0x00, 0x00, /* blue bitfield mask */
96 #endif
99 static void (*screen_dump_hook)(int fh) = NULL;
101 void screen_dump(void)
103 int fd, y;
104 char filename[32];
106 fb_data *src;
107 #if LCD_DEPTH == 1
108 unsigned mask;
109 unsigned val;
110 #elif (LCD_DEPTH == 2) && (LCD_PIXELFORMAT != HORIZONTAL_PACKING)
111 int shift;
112 unsigned val;
113 #endif
114 #if LCD_DEPTH <= 8
115 unsigned char *dst, *dst_end;
116 unsigned char linebuf[DUMP_BMP_LINESIZE];
117 #elif LCD_DEPTH <= 16
118 unsigned short *dst, *dst_end;
119 unsigned short linebuf[DUMP_BMP_LINESIZE/2];
120 #endif
122 #if CONFIG_RTC
123 create_datetime_filename(filename, "", "dump ", ".bmp", false);
124 #else
125 create_numbered_filename(filename, "", "dump_", ".bmp", 4
126 IF_CNFN_NUM_(, NULL));
127 #endif
129 fd = creat(filename, 0666);
130 if (fd < 0)
131 return;
133 if (screen_dump_hook)
135 screen_dump_hook(fd);
137 else
139 write(fd, bmpheader, sizeof(bmpheader));
141 /* BMP image goes bottom up */
142 for (y = LCD_HEIGHT - 1; y >= 0; y--)
144 memset(linebuf, 0, DUMP_BMP_LINESIZE);
146 #if defined(HAVE_LCD_SPLIT) && (LCD_SPLIT_LINES == 2)
147 if (y == LCD_SPLIT_POS - 1)
149 write(fd, linebuf, DUMP_BMP_LINESIZE);
150 write(fd, linebuf, DUMP_BMP_LINESIZE);
152 #endif
153 dst = linebuf;
155 #if LCD_DEPTH == 1
156 dst_end = dst + LCD_WIDTH/2;
157 src = lcd_framebuffer[y >> 3];
158 mask = BIT_N(y & 7);
162 val = (*src++ & mask) ? 0x10 : 0;
163 val |= (*src++ & mask) ? 0x01 : 0;
164 #ifdef HAVE_LCD_SPLIT
165 if (y < LCD_SPLIT_POS)
166 val |= 0x22;
167 #endif
168 *dst++ = val;
170 while (dst < dst_end);
172 #elif LCD_DEPTH == 2
173 dst_end = dst + LCD_WIDTH/2;
175 #if LCD_PIXELFORMAT == HORIZONTAL_PACKING
176 src = lcd_framebuffer[y];
180 unsigned data = *src++;
182 *dst++ = ((data >> 2) & 0x30) | ((data >> 4) & 0x03);
183 *dst++ = ((data << 2) & 0x30) | (data & 0x03);
185 while (dst < dst_end);
187 #elif LCD_PIXELFORMAT == VERTICAL_PACKING
188 src = lcd_framebuffer[y >> 2];
189 shift = 2 * (y & 3);
193 val = ((*src++ >> shift) & 3) << 4;
194 val |= ((*src++ >> shift) & 3);
195 *dst++ = val;
197 while (dst < dst_end);
199 #elif LCD_PIXELFORMAT == VERTICAL_INTERLEAVED
200 src = lcd_framebuffer[y >> 3];
201 shift = y & 7;
205 unsigned data = (*src++ >> shift) & 0x0101;
207 val = (((data >> 7) | data) & 3) << 4;
208 data = (*src++ >> shift) & 0x0101;
209 val |= ((data >> 7) | data) & 3;
210 *dst++ = val;
212 while (dst < dst_end);
214 #endif
215 #elif LCD_DEPTH == 16
216 dst_end = dst + LCD_WIDTH;
217 src = lcd_framebuffer[y];
221 #if (LCD_PIXELFORMAT == RGB565SWAPPED)
222 /* iPod LCD data is big endian although the CPU is not */
223 *dst++ = htobe16(*src++);
224 #else
225 *dst++ = htole16(*src++);
226 #endif
228 while (dst < dst_end);
230 #endif /* LCD_DEPTH */
231 write(fd, linebuf, DUMP_BMP_LINESIZE);
234 close(fd);
237 void screen_dump_set_hook(void (*hook)(int fh))
239 screen_dump_hook = hook;
242 #ifdef HAVE_REMOTE_LCD
244 #define RBMP_COMPRESSION 0 /* BI_RGB */
245 #define RBMP_NUMCOLORS (1 << LCD_REMOTE_DEPTH)
246 #define RBMP_BPP 4
247 #define RBMP_LINESIZE ((LCD_REMOTE_WIDTH/2 + 3) & ~3)
249 #define RBMP_HEADERSIZE (54 + 4 * RBMP_NUMCOLORS)
250 #define RBMP_DATASIZE (RBMP_LINESIZE * LCD_REMOTE_HEIGHT)
251 #define RBMP_TOTALSIZE (RBMP_HEADERSIZE + RBMP_DATASIZE)
253 static const unsigned char rbmpheader[] =
255 0x42, 0x4d, /* 'BM' */
256 LE32_CONST(RBMP_TOTALSIZE), /* Total file size */
257 0x00, 0x00, 0x00, 0x00, /* Reserved */
258 LE32_CONST(RBMP_HEADERSIZE), /* Offset to start of pixel data */
260 0x28, 0x00, 0x00, 0x00, /* Size of (2nd) header */
261 LE32_CONST(LCD_REMOTE_WIDTH), /* Width in pixels */
262 LE32_CONST(LCD_REMOTE_HEIGHT), /* Height in pixels */
263 0x01, 0x00, /* Number of planes (always 1) */
264 LE16_CONST(RBMP_BPP), /* Bits per pixel 1/4/8/16/24 */
265 LE32_CONST(RBMP_COMPRESSION), /* Compression mode */
266 LE32_CONST(RBMP_DATASIZE), /* Size of bitmap data */
267 0xc4, 0x0e, 0x00, 0x00, /* Horizontal resolution (pixels/meter) */
268 0xc4, 0x0e, 0x00, 0x00, /* Vertical resolution (pixels/meter) */
269 LE32_CONST(RBMP_NUMCOLORS), /* Number of used colours */
270 LE32_CONST(RBMP_NUMCOLORS), /* Number of important colours */
272 #if LCD_REMOTE_DEPTH == 1
273 BMP_COLOR(LCD_REMOTE_BL_BRIGHTCOLOR),
274 BMP_COLOR(LCD_REMOTE_BL_DARKCOLOR),
275 #elif LCD_REMOTE_DEPTH == 2
276 BMP_COLOR(LCD_REMOTE_BL_BRIGHTCOLOR),
277 BMP_COLOR_MIX(LCD_REMOTE_BL_BRIGHTCOLOR, LCD_REMOTE_BL_DARKCOLOR, 1, 3),
278 BMP_COLOR_MIX(LCD_REMOTE_BL_BRIGHTCOLOR, LCD_REMOTE_BL_DARKCOLOR, 2, 3),
279 BMP_COLOR(LCD_REMOTE_BL_DARKCOLOR),
280 #endif
283 void remote_screen_dump(void)
285 int fd, y;
286 char filename[MAX_PATH];
288 fb_remote_data *src;
289 #if LCD_REMOTE_DEPTH == 1
290 unsigned mask;
291 unsigned val;
292 #elif LCD_REMOTE_DEPTH == 2
293 int shift;
294 unsigned val;
295 #endif
296 unsigned char *dst, *dst_end;
297 unsigned char linebuf[RBMP_LINESIZE];
299 #if CONFIG_RTC
300 create_datetime_filename(filename, "", "rdump ", ".bmp", false);
301 #else
302 create_numbered_filename(filename, "", "rdump_", ".bmp", 4
303 IF_CNFN_NUM_(, NULL));
304 #endif
306 fd = creat(filename, 0666);
307 if (fd < 0)
308 return;
310 write(fd, rbmpheader, sizeof(rbmpheader));
312 /* BMP image goes bottom up */
313 for (y = LCD_REMOTE_HEIGHT - 1; y >= 0; y--)
315 memset(linebuf, 0, RBMP_LINESIZE);
317 dst = linebuf;
319 #if LCD_REMOTE_DEPTH == 1
320 dst_end = dst + LCD_REMOTE_WIDTH/2;
321 src = lcd_remote_framebuffer[y >> 3];
322 mask = BIT_N(y & 7);
326 val = (*src++ & mask) ? 0x10 : 0;
327 val |= (*src++ & mask) ? 0x01 : 0;
328 *dst++ = val;
330 while (dst < dst_end);
332 #elif LCD_REMOTE_DEPTH == 2
333 dst_end = dst + LCD_REMOTE_WIDTH/2;
335 #if LCD_REMOTE_PIXELFORMAT == VERTICAL_INTERLEAVED
336 src = lcd_remote_framebuffer[y >> 3];
337 shift = y & 7;
341 unsigned data = (*src++ >> shift) & 0x0101;
343 val = (((data >> 7) | data) & 3) << 4;
344 data = (*src++ >> shift) & 0x0101;
345 val |= ((data >> 7) | data) & 3;
346 *dst++ = val;
348 while (dst < dst_end);
350 #endif
351 #endif /* LCD_REMOTE_DEPTH */
352 write(fd, linebuf, RBMP_LINESIZE);
354 close(fd);
357 #endif /* HAVE_REMOTE_LCD */