blob: 1acaaafba6997fd8cbe03df4acca36c0b314b3eb [file] [log] [blame]
Jens Arnold7ddcce12009-02-10 23:47:24 +00001/***************************************************************************
Franklin Wei17ee90c2015-02-24 16:35:17 -05002 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
Jens Arnold7ddcce12009-02-10 23:47:24 +00008 * $Id$
9 *
10 * Copyright (C) 2009 by Jens Arnold
11 *
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.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22#include "config.h"
23#include "screendump.h"
Lorenzo Mioric300c1b2013-07-26 21:21:21 +020024#include "rbpaths.h"
Jens Arnold7ddcce12009-02-10 23:47:24 +000025
26#include "file.h"
27#include "general.h"
28#include "lcd.h"
29#include "stdlib.h"
30#include "string.h"
31#include "system.h"
32
33#ifdef HAVE_REMOTE_LCD
34#include "lcd-remote.h"
Franklin Wei17ee90c2015-02-24 16:35:17 -050035#endif
Jens Arnold7ddcce12009-02-10 23:47:24 +000036
37#if LCD_DEPTH == 16
38#define BMP_COMPRESSION 3 /* BI_BITFIELDS */
39#define BMP_NUMCOLORS 3
40#else /* LCD_DEPTH != 16 */
41#define BMP_COMPRESSION 0 /* BI_RGB */
42#if LCD_DEPTH <= 8
43#ifdef HAVE_LCD_SPLIT
44#define BMP_NUMCOLORS (2 << LCD_DEPTH)
45#else
46#define BMP_NUMCOLORS (1 << LCD_DEPTH)
47#endif
48#else /* LCD_DEPTH > 8 */
49#define BMP_NUMCOLORS 0
50#endif /* LCD_DEPTH > 8 */
51#endif /* LCD_DEPTH != 16 */
52
Jens Arnold7ddcce12009-02-10 23:47:24 +000053#define BMP_HEADERSIZE (54 + 4 * BMP_NUMCOLORS)
Michael Sparmann77129ad2010-10-25 12:52:02 +000054#define BMP_DATASIZE (DUMP_BMP_LINESIZE * (LCD_HEIGHT+LCD_SPLIT_LINES))
Jens Arnold7ddcce12009-02-10 23:47:24 +000055#define BMP_TOTALSIZE (BMP_HEADERSIZE + BMP_DATASIZE)
56
57static const unsigned char bmpheader[] =
58{
59 0x42, 0x4d, /* 'BM' */
60 LE32_CONST(BMP_TOTALSIZE), /* Total file size */
61 0x00, 0x00, 0x00, 0x00, /* Reserved */
62 LE32_CONST(BMP_HEADERSIZE), /* Offset to start of pixel data */
63
64 0x28, 0x00, 0x00, 0x00, /* Size of (2nd) header */
65 LE32_CONST(LCD_WIDTH), /* Width in pixels */
66 LE32_CONST(LCD_HEIGHT+LCD_SPLIT_LINES), /* Height in pixels */
67 0x01, 0x00, /* Number of planes (always 1) */
Michael Sparmann77129ad2010-10-25 12:52:02 +000068 LE16_CONST(DUMP_BMP_BPP), /* Bits per pixel 1/4/8/16/24 */
Jens Arnold7ddcce12009-02-10 23:47:24 +000069 LE32_CONST(BMP_COMPRESSION),/* Compression mode */
70 LE32_CONST(BMP_DATASIZE), /* Size of bitmap data */
71 0xc4, 0x0e, 0x00, 0x00, /* Horizontal resolution (pixels/meter) */
72 0xc4, 0x0e, 0x00, 0x00, /* Vertical resolution (pixels/meter) */
73 LE32_CONST(BMP_NUMCOLORS), /* Number of used colours */
74 LE32_CONST(BMP_NUMCOLORS), /* Number of important colours */
75
76#if LCD_DEPTH == 1
77#ifdef HAVE_NEGATIVE_LCD
78 BMP_COLOR(LCD_BL_DARKCOLOR),
79 BMP_COLOR(LCD_BL_BRIGHTCOLOR),
80#ifdef HAVE_LCD_SPLIT
81 BMP_COLOR(LCD_BL_DARKCOLOR_2),
82 BMP_COLOR(LCD_BL_BRIGHTCOLOR_2),
83#endif
84#else /* positive display */
85 BMP_COLOR(LCD_BL_BRIGHTCOLOR),
86 BMP_COLOR(LCD_BL_DARKCOLOR),
87#endif /* positive display */
88#elif LCD_DEPTH == 2
89 BMP_COLOR(LCD_BL_BRIGHTCOLOR),
90 BMP_COLOR_MIX(LCD_BL_BRIGHTCOLOR, LCD_BL_DARKCOLOR, 1, 3),
91 BMP_COLOR_MIX(LCD_BL_BRIGHTCOLOR, LCD_BL_DARKCOLOR, 2, 3),
92 BMP_COLOR(LCD_BL_DARKCOLOR),
93#elif LCD_DEPTH == 16
94 0x00, 0xf8, 0x00, 0x00, /* red bitfield mask */
95 0xe0, 0x07, 0x00, 0x00, /* green bitfield mask */
96 0x1f, 0x00, 0x00, 0x00, /* blue bitfield mask */
97#endif
98};
99
100static void (*screen_dump_hook)(int fh) = NULL;
101
102void screen_dump(void)
103{
104 int fd, y;
Michael Sparmann01cdb6a2010-10-25 12:36:57 +0000105 char filename[32];
Jens Arnold7ddcce12009-02-10 23:47:24 +0000106
107 fb_data *src;
108#if LCD_DEPTH == 1
109 unsigned mask;
110 unsigned val;
111#elif (LCD_DEPTH == 2) && (LCD_PIXELFORMAT != HORIZONTAL_PACKING)
112 int shift;
113 unsigned val;
114#endif
115#if LCD_DEPTH <= 8
116 unsigned char *dst, *dst_end;
Michael Sparmann77129ad2010-10-25 12:52:02 +0000117 unsigned char linebuf[DUMP_BMP_LINESIZE];
Jens Arnold7ddcce12009-02-10 23:47:24 +0000118#elif LCD_DEPTH <= 16
119 unsigned short *dst, *dst_end;
Michael Sparmann77129ad2010-10-25 12:52:02 +0000120 unsigned short linebuf[DUMP_BMP_LINESIZE/2];
Thomas Martitza1842c02014-06-18 07:15:00 +0200121#else /* 24bit */
122 unsigned char *dst, *dst_end;
123 unsigned char linebuf[DUMP_BMP_LINESIZE * 3];
Jens Arnold7ddcce12009-02-10 23:47:24 +0000124#endif
125
126#if CONFIG_RTC
Lorenzo Mioric300c1b2013-07-26 21:21:21 +0200127 create_datetime_filename(filename, HOME_DIR, "dump ", ".bmp", false);
Jens Arnold7ddcce12009-02-10 23:47:24 +0000128#else
Lorenzo Mioric300c1b2013-07-26 21:21:21 +0200129 create_numbered_filename(filename, HOME_DIR, "dump_", ".bmp", 4
Jens Arnold7ddcce12009-02-10 23:47:24 +0000130 IF_CNFN_NUM_(, NULL));
131#endif
132
Thomas Martitzc61e89c2010-05-06 17:35:04 +0000133 fd = creat(filename, 0666);
Jens Arnold7ddcce12009-02-10 23:47:24 +0000134 if (fd < 0)
135 return;
136
137 if (screen_dump_hook)
138 {
139 screen_dump_hook(fd);
140 }
141 else
142 {
Franklin Wei55f1d942015-02-24 16:55:26 -0500143 if(write(fd, bmpheader, sizeof(bmpheader)) != sizeof(bmpheader))
144 {
145 close(fd);
146 return;
147 }
Jens Arnold7ddcce12009-02-10 23:47:24 +0000148
149 /* BMP image goes bottom up */
150 for (y = LCD_HEIGHT - 1; y >= 0; y--)
Franklin Wei17ee90c2015-02-24 16:35:17 -0500151 {
Michael Sparmann77129ad2010-10-25 12:52:02 +0000152 memset(linebuf, 0, DUMP_BMP_LINESIZE);
Jens Arnold7ddcce12009-02-10 23:47:24 +0000153
154#if defined(HAVE_LCD_SPLIT) && (LCD_SPLIT_LINES == 2)
155 if (y == LCD_SPLIT_POS - 1)
156 {
Michael Sparmann77129ad2010-10-25 12:52:02 +0000157 write(fd, linebuf, DUMP_BMP_LINESIZE);
158 write(fd, linebuf, DUMP_BMP_LINESIZE);
Jens Arnold7ddcce12009-02-10 23:47:24 +0000159 }
Franklin Wei17ee90c2015-02-24 16:35:17 -0500160#endif
Jens Arnold7ddcce12009-02-10 23:47:24 +0000161 dst = linebuf;
162
163#if LCD_DEPTH == 1
164 dst_end = dst + LCD_WIDTH/2;
Jonathan Gordonb37e6bc2012-02-22 21:18:05 +1100165 src = FBADDR(0, y >> 3);
Jens Arnold1d6df542009-06-07 21:27:05 +0000166 mask = BIT_N(y & 7);
Jens Arnold7ddcce12009-02-10 23:47:24 +0000167
168 do
169 {
170 val = (*src++ & mask) ? 0x10 : 0;
171 val |= (*src++ & mask) ? 0x01 : 0;
172#ifdef HAVE_LCD_SPLIT
173 if (y < LCD_SPLIT_POS)
174 val |= 0x22;
175#endif
176 *dst++ = val;
177 }
178 while (dst < dst_end);
179
180#elif LCD_DEPTH == 2
181 dst_end = dst + LCD_WIDTH/2;
182
183#if LCD_PIXELFORMAT == HORIZONTAL_PACKING
Jonathan Gordonb37e6bc2012-02-22 21:18:05 +1100184 src = FBADDR(0, y);
Jens Arnold7ddcce12009-02-10 23:47:24 +0000185
186 do
187 {
188 unsigned data = *src++;
189
190 *dst++ = ((data >> 2) & 0x30) | ((data >> 4) & 0x03);
191 *dst++ = ((data << 2) & 0x30) | (data & 0x03);
192 }
193 while (dst < dst_end);
194
195#elif LCD_PIXELFORMAT == VERTICAL_PACKING
Jonathan Gordonb37e6bc2012-02-22 21:18:05 +1100196 src = FBADDR(0, y >> 2);
Jens Arnold7ddcce12009-02-10 23:47:24 +0000197 shift = 2 * (y & 3);
198
199 do
200 {
201 val = ((*src++ >> shift) & 3) << 4;
202 val |= ((*src++ >> shift) & 3);
203 *dst++ = val;
204 }
205 while (dst < dst_end);
206
207#elif LCD_PIXELFORMAT == VERTICAL_INTERLEAVED
Jonathan Gordonb37e6bc2012-02-22 21:18:05 +1100208 src = FBADDR(0, y >> 3);
Jens Arnold7ddcce12009-02-10 23:47:24 +0000209 shift = y & 7;
210
211 do
212 {
213 unsigned data = (*src++ >> shift) & 0x0101;
214
215 val = (((data >> 7) | data) & 3) << 4;
216 data = (*src++ >> shift) & 0x0101;
217 val |= ((data >> 7) | data) & 3;
218 *dst++ = val;
219 }
220 while (dst < dst_end);
221
222#endif
223#elif LCD_DEPTH == 16
224 dst_end = dst + LCD_WIDTH;
Jonathan Gordonb37e6bc2012-02-22 21:18:05 +1100225 src = FBADDR(0, y);
Franklin Wei17ee90c2015-02-24 16:35:17 -0500226
Jens Arnold7ddcce12009-02-10 23:47:24 +0000227 do
228 {
229#if (LCD_PIXELFORMAT == RGB565SWAPPED)
230 /* iPod LCD data is big endian although the CPU is not */
231 *dst++ = htobe16(*src++);
232#else
233 *dst++ = htole16(*src++);
234#endif
235 }
236 while (dst < dst_end);
Marcin Bukatd5568092017-04-27 11:36:40 +0200237#elif LCD_DEPTH >= 24
238 dst_end = dst + LCD_WIDTH*sizeof(fb_data);
Thomas Martitza1842c02014-06-18 07:15:00 +0200239 src = FBADDR(0, y);
240 do
241 {
242 *dst++ = src->b;
243 *dst++ = src->g;
244 *dst++ = src->r;
245 ++src;
246 }
247 while (dst < dst_end);
Jens Arnold7ddcce12009-02-10 23:47:24 +0000248
249#endif /* LCD_DEPTH */
Franklin Wei55f1d942015-02-24 16:55:26 -0500250 if(write(fd, linebuf, DUMP_BMP_LINESIZE) != DUMP_BMP_LINESIZE)
251 {
252 close(fd);
253 return;
254 }
Jens Arnold7ddcce12009-02-10 23:47:24 +0000255 }
256 }
257 close(fd);
258}
259
260void screen_dump_set_hook(void (*hook)(int fh))
261{
262 screen_dump_hook = hook;
263}
264
265#ifdef HAVE_REMOTE_LCD
266
267#define RBMP_COMPRESSION 0 /* BI_RGB */
268#define RBMP_NUMCOLORS (1 << LCD_REMOTE_DEPTH)
269#define RBMP_BPP 4
270#define RBMP_LINESIZE ((LCD_REMOTE_WIDTH/2 + 3) & ~3)
271
272#define RBMP_HEADERSIZE (54 + 4 * RBMP_NUMCOLORS)
273#define RBMP_DATASIZE (RBMP_LINESIZE * LCD_REMOTE_HEIGHT)
274#define RBMP_TOTALSIZE (RBMP_HEADERSIZE + RBMP_DATASIZE)
275
276static const unsigned char rbmpheader[] =
277{
278 0x42, 0x4d, /* 'BM' */
279 LE32_CONST(RBMP_TOTALSIZE), /* Total file size */
280 0x00, 0x00, 0x00, 0x00, /* Reserved */
281 LE32_CONST(RBMP_HEADERSIZE), /* Offset to start of pixel data */
282
283 0x28, 0x00, 0x00, 0x00, /* Size of (2nd) header */
284 LE32_CONST(LCD_REMOTE_WIDTH), /* Width in pixels */
285 LE32_CONST(LCD_REMOTE_HEIGHT), /* Height in pixels */
286 0x01, 0x00, /* Number of planes (always 1) */
287 LE16_CONST(RBMP_BPP), /* Bits per pixel 1/4/8/16/24 */
288 LE32_CONST(RBMP_COMPRESSION), /* Compression mode */
289 LE32_CONST(RBMP_DATASIZE), /* Size of bitmap data */
290 0xc4, 0x0e, 0x00, 0x00, /* Horizontal resolution (pixels/meter) */
291 0xc4, 0x0e, 0x00, 0x00, /* Vertical resolution (pixels/meter) */
292 LE32_CONST(RBMP_NUMCOLORS), /* Number of used colours */
293 LE32_CONST(RBMP_NUMCOLORS), /* Number of important colours */
294
295#if LCD_REMOTE_DEPTH == 1
296 BMP_COLOR(LCD_REMOTE_BL_BRIGHTCOLOR),
297 BMP_COLOR(LCD_REMOTE_BL_DARKCOLOR),
298#elif LCD_REMOTE_DEPTH == 2
299 BMP_COLOR(LCD_REMOTE_BL_BRIGHTCOLOR),
300 BMP_COLOR_MIX(LCD_REMOTE_BL_BRIGHTCOLOR, LCD_REMOTE_BL_DARKCOLOR, 1, 3),
301 BMP_COLOR_MIX(LCD_REMOTE_BL_BRIGHTCOLOR, LCD_REMOTE_BL_DARKCOLOR, 2, 3),
302 BMP_COLOR(LCD_REMOTE_BL_DARKCOLOR),
303#endif
304};
305
306void remote_screen_dump(void)
307{
308 int fd, y;
Frank Gevaerts700e3602011-12-04 17:17:45 +0000309 char filename[32];
Jens Arnold7ddcce12009-02-10 23:47:24 +0000310
311 fb_remote_data *src;
312#if LCD_REMOTE_DEPTH == 1
313 unsigned mask;
314 unsigned val;
315#elif LCD_REMOTE_DEPTH == 2
316 int shift;
317 unsigned val;
318#endif
319 unsigned char *dst, *dst_end;
320 unsigned char linebuf[RBMP_LINESIZE];
321
322#if CONFIG_RTC
323 create_datetime_filename(filename, "", "rdump ", ".bmp", false);
324#else
325 create_numbered_filename(filename, "", "rdump_", ".bmp", 4
326 IF_CNFN_NUM_(, NULL));
327#endif
328
Thomas Martitzc61e89c2010-05-06 17:35:04 +0000329 fd = creat(filename, 0666);
Jens Arnold7ddcce12009-02-10 23:47:24 +0000330 if (fd < 0)
331 return;
332
333 write(fd, rbmpheader, sizeof(rbmpheader));
334
335 /* BMP image goes bottom up */
336 for (y = LCD_REMOTE_HEIGHT - 1; y >= 0; y--)
337 {
338 memset(linebuf, 0, RBMP_LINESIZE);
339
340 dst = linebuf;
341
342#if LCD_REMOTE_DEPTH == 1
343 dst_end = dst + LCD_REMOTE_WIDTH/2;
Jonathan Gordonb37e6bc2012-02-22 21:18:05 +1100344 src = FBREMOTEADDR(0, y >> 3);
Jens Arnold1d6df542009-06-07 21:27:05 +0000345 mask = BIT_N(y & 7);
Jens Arnold7ddcce12009-02-10 23:47:24 +0000346
347 do
348 {
349 val = (*src++ & mask) ? 0x10 : 0;
350 val |= (*src++ & mask) ? 0x01 : 0;
351 *dst++ = val;
352 }
353 while (dst < dst_end);
354
355#elif LCD_REMOTE_DEPTH == 2
356 dst_end = dst + LCD_REMOTE_WIDTH/2;
357
358#if LCD_REMOTE_PIXELFORMAT == VERTICAL_INTERLEAVED
Jonathan Gordonb37e6bc2012-02-22 21:18:05 +1100359 src = FBREMOTEADDR(0, (y >> 3));
Jens Arnold7ddcce12009-02-10 23:47:24 +0000360 shift = y & 7;
361
362 do
363 {
364 unsigned data = (*src++ >> shift) & 0x0101;
365
366 val = (((data >> 7) | data) & 3) << 4;
367 data = (*src++ >> shift) & 0x0101;
368 val |= ((data >> 7) | data) & 3;
369 *dst++ = val;
370 }
371 while (dst < dst_end);
372
373#endif
374#endif /* LCD_REMOTE_DEPTH */
375 write(fd, linebuf, RBMP_LINESIZE);
376 }
377 close(fd);
378}
379
380#endif /* HAVE_REMOTE_LCD */