summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apps/misc.c330
-rw-r--r--apps/misc.h50
-rw-r--r--apps/plugin.h1
-rw-r--r--apps/plugins/lib/grey_core.c5
-rw-r--r--apps/recorder/radio.c1
-rw-r--r--apps/recorder/recording.c1
-rw-r--r--apps/settings.c1
-rw-r--r--firmware/SOURCES5
-rw-r--r--firmware/backlight.c10
-rw-r--r--firmware/export/general.h35
-rw-r--r--firmware/general.c117
-rw-r--r--firmware/usb.c11
-rw-r--r--uisimulator/sdl/lcd-bitmap.c8
-rw-r--r--uisimulator/sdl/lcd-charcells.c3
-rw-r--r--uisimulator/sdl/lcd-remote-bitmap.c12
15 files changed, 181 insertions, 409 deletions
diff --git a/apps/misc.c b/apps/misc.c
index b1d795708c..872d91592d 100644
--- a/apps/misc.c
+++ b/apps/misc.c
@@ -135,109 +135,6 @@ char *output_dyn_value(char *buf, int buf_size, int value,
135 return buf; 135 return buf;
136} 136}
137 137
138/* Create a filename with a number part in a way that the number is 1
139 * higher than the highest numbered file matching the same pattern.
140 * It is allowed that buffer and path point to the same memory location,
141 * saving a strcpy(). Path must always be given without trailing slash.
142 * "num" can point to an int specifying the number to use or NULL or a value
143 * less than zero to number automatically. The final number used will also
144 * be returned in *num. If *num is >= 0 then *num will be incremented by
145 * one. */
146char *create_numbered_filename(char *buffer, const char *path,
147 const char *prefix, const char *suffix,
148 int numberlen IF_CNFN_NUM_(, int *num))
149{
150 DIR *dir;
151 struct dirent *entry;
152 int max_num;
153 int pathlen;
154 int prefixlen = strlen(prefix);
155 char fmtstring[12];
156
157 if (buffer != path)
158 strncpy(buffer, path, MAX_PATH);
159
160 pathlen = strlen(buffer);
161
162#ifdef IF_CNFN_NUM
163 if (num && *num >= 0)
164 {
165 /* number specified */
166 max_num = *num;
167 }
168 else
169#endif
170 {
171 /* automatic numbering */
172 max_num = 0;
173
174 dir = opendir(pathlen ? buffer : "/");
175 if (!dir)
176 return NULL;
177
178 while ((entry = readdir(dir)))
179 {
180 int curr_num;
181
182 if (strncasecmp((char *)entry->d_name, prefix, prefixlen)
183 || strcasecmp((char *)entry->d_name + prefixlen + numberlen, suffix))
184 continue;
185
186 curr_num = atoi((char *)entry->d_name + prefixlen);
187 if (curr_num > max_num)
188 max_num = curr_num;
189 }
190
191 closedir(dir);
192 }
193
194 max_num++;
195
196 snprintf(fmtstring, sizeof(fmtstring), "/%%s%%0%dd%%s", numberlen);
197 snprintf(buffer + pathlen, MAX_PATH - pathlen, fmtstring, prefix,
198 max_num, suffix);
199
200#ifdef IF_CNFN_NUM
201 if (num)
202 *num = max_num;
203#endif
204
205 return buffer;
206}
207
208
209#if CONFIG_RTC
210/* Create a filename with a date+time part.
211 It is allowed that buffer and path point to the same memory location,
212 saving a strcpy(). Path must always be given without trailing slash.
213 unique_time as true makes the function wait until the current time has
214 changed. */
215char *create_datetime_filename(char *buffer, const char *path,
216 const char *prefix, const char *suffix,
217 bool unique_time)
218{
219 struct tm *tm = get_time();
220 static struct tm last_tm;
221 int pathlen;
222
223 while (unique_time && !memcmp(get_time(), &last_tm, sizeof (struct tm)))
224 sleep(HZ/10);
225
226 last_tm = *tm;
227
228 if (buffer != path)
229 strncpy(buffer, path, MAX_PATH);
230
231 pathlen = strlen(buffer);
232 snprintf(buffer + pathlen, MAX_PATH - pathlen,
233 "/%s%02d%02d%02d-%02d%02d%02d%s", prefix,
234 tm->tm_year % 100, tm->tm_mon + 1, tm->tm_mday,
235 tm->tm_hour, tm->tm_min, tm->tm_sec, suffix);
236
237 return buffer;
238}
239#endif /* CONFIG_RTC */
240
241/* Ask the user if they really want to erase the current dynamic playlist 138/* Ask the user if they really want to erase the current dynamic playlist
242 * returns true if the playlist should be replaced */ 139 * returns true if the playlist should be replaced */
243bool warn_on_pl_erase(void) 140bool warn_on_pl_erase(void)
@@ -339,233 +236,6 @@ int fast_readline(int fd, char *buf, int buf_size, void *parameters,
339 return 0; 236 return 0;
340} 237}
341 238
342#ifdef HAVE_LCD_BITMAP
343
344#if LCD_DEPTH == 16
345#define BMP_COMPRESSION 3 /* BI_BITFIELDS */
346#define BMP_NUMCOLORS 3
347#else /* LCD_DEPTH != 16 */
348#define BMP_COMPRESSION 0 /* BI_RGB */
349#if LCD_DEPTH <= 8
350#ifdef HAVE_LCD_SPLIT
351#define BMP_NUMCOLORS (2 << LCD_DEPTH)
352#else
353#define BMP_NUMCOLORS (1 << LCD_DEPTH)
354#endif
355#else /* LCD_DEPTH > 8 */
356#define BMP_NUMCOLORS 0
357#endif /* LCD_DEPTH > 8 */
358#endif /* LCD_DEPTH != 16 */
359
360#if LCD_DEPTH <= 4
361#define BMP_BPP 4
362#define BMP_LINESIZE ((LCD_WIDTH/2 + 3) & ~3)
363#elif LCD_DEPTH <= 8
364#define BMP_BPP 8
365#define BMP_LINESIZE ((LCD_WIDTH + 3) & ~3)
366#elif LCD_DEPTH <= 16
367#define BMP_BPP 16
368#define BMP_LINESIZE ((LCD_WIDTH*2 + 3) & ~3)
369#else
370#define BMP_BPP 24
371#define BMP_LINESIZE ((LCD_WIDTH*3 + 3) & ~3)
372#endif
373
374#define BMP_HEADERSIZE (54 + 4 * BMP_NUMCOLORS)
375#define BMP_DATASIZE (BMP_LINESIZE * LCD_HEIGHT)
376#define BMP_TOTALSIZE (BMP_HEADERSIZE + BMP_DATASIZE)
377
378#define LE16_CONST(x) (x)&0xff, ((x)>>8)&0xff
379#define LE32_CONST(x) (x)&0xff, ((x)>>8)&0xff, ((x)>>16)&0xff, ((x)>>24)&0xff
380
381static const unsigned char bmpheader[] =
382{
383 0x42, 0x4d, /* 'BM' */
384 LE32_CONST(BMP_TOTALSIZE), /* Total file size */
385 0x00, 0x00, 0x00, 0x00, /* Reserved */
386 LE32_CONST(BMP_HEADERSIZE), /* Offset to start of pixel data */
387
388 0x28, 0x00, 0x00, 0x00, /* Size of (2nd) header */
389 LE32_CONST(LCD_WIDTH), /* Width in pixels */
390 LE32_CONST(LCD_HEIGHT+LCD_SPLIT_LINES), /* Height in pixels */
391 0x01, 0x00, /* Number of planes (always 1) */
392 LE16_CONST(BMP_BPP), /* Bits per pixel 1/4/8/16/24 */
393 LE32_CONST(BMP_COMPRESSION),/* Compression mode */
394 LE32_CONST(BMP_DATASIZE), /* Size of bitmap data */
395 0xc4, 0x0e, 0x00, 0x00, /* Horizontal resolution (pixels/meter) */
396 0xc4, 0x0e, 0x00, 0x00, /* Vertical resolution (pixels/meter) */
397 LE32_CONST(BMP_NUMCOLORS), /* Number of used colours */
398 LE32_CONST(BMP_NUMCOLORS), /* Number of important colours */
399
400#if LCD_DEPTH == 1
401#ifdef HAVE_NEGATIVE_LCD
402 BMP_COLOR(LCD_BL_DARKCOLOR),
403 BMP_COLOR(LCD_BL_BRIGHTCOLOR),
404#ifdef HAVE_LCD_SPLIT
405 BMP_COLOR(LCD_BL_DARKCOLOR_2),
406 BMP_COLOR(LCD_BL_BRIGHTCOLOR_2),
407#endif
408#else /* positive display */
409 BMP_COLOR(LCD_BL_BRIGHTCOLOR),
410 BMP_COLOR(LCD_BL_DARKCOLOR),
411#endif /* positive display */
412#elif LCD_DEPTH == 2
413 BMP_COLOR(LCD_BL_BRIGHTCOLOR),
414 BMP_COLOR_MIX(LCD_BL_BRIGHTCOLOR, LCD_BL_DARKCOLOR, 1, 3),
415 BMP_COLOR_MIX(LCD_BL_BRIGHTCOLOR, LCD_BL_DARKCOLOR, 2, 3),
416 BMP_COLOR(LCD_BL_DARKCOLOR),
417#elif LCD_DEPTH == 16
418 0x00, 0xf8, 0x00, 0x00, /* red bitfield mask */
419 0xe0, 0x07, 0x00, 0x00, /* green bitfield mask */
420 0x1f, 0x00, 0x00, 0x00, /* blue bitfield mask */
421#endif
422};
423
424static void (*screen_dump_hook)(int fh) = NULL;
425
426void screen_dump(void)
427{
428 int fd, y;
429 char filename[MAX_PATH];
430
431 fb_data *src;
432#if LCD_DEPTH == 1
433 unsigned mask;
434 unsigned val;
435#elif (LCD_DEPTH == 2) && (LCD_PIXELFORMAT != HORIZONTAL_PACKING)
436 int shift;
437 unsigned val;
438#endif
439#if LCD_DEPTH <= 8
440 unsigned char *dst, *dst_end;
441 unsigned char linebuf[BMP_LINESIZE];
442#elif LCD_DEPTH <= 16
443 unsigned short *dst, *dst_end;
444 unsigned short linebuf[BMP_LINESIZE/2];
445#endif
446
447#if CONFIG_RTC
448 create_datetime_filename(filename, "", "dump ", ".bmp", false);
449#else
450 create_numbered_filename(filename, "", "dump_", ".bmp", 4
451 IF_CNFN_NUM_(, NULL));
452#endif
453
454 fd = creat(filename);
455 if (fd < 0)
456 return;
457
458 if (screen_dump_hook)
459 {
460 screen_dump_hook(fd);
461 }
462 else
463 {
464 write(fd, bmpheader, sizeof(bmpheader));
465
466 /* BMP image goes bottom up */
467 for (y = LCD_HEIGHT - 1; y >= 0; y--)
468 {
469 memset(linebuf, 0, BMP_LINESIZE);
470
471#if defined(HAVE_LCD_SPLIT) && (LCD_SPLIT_LINES == 2)
472 if (y == LCD_SPLIT_POS - 1)
473 {
474 write(fd, linebuf, BMP_LINESIZE);
475 write(fd, linebuf, BMP_LINESIZE);
476 }
477#endif
478 dst = linebuf;
479
480#if LCD_DEPTH == 1
481 dst_end = dst + LCD_WIDTH/2;
482 src = lcd_framebuffer[y >> 3];
483 mask = 1 << (y & 7);
484
485 do
486 {
487 val = (*src++ & mask) ? 0x10 : 0;
488 val |= (*src++ & mask) ? 0x01 : 0;
489#ifdef HAVE_LCD_SPLIT
490 if (y < LCD_SPLIT_POS)
491 val |= 0x22;
492#endif
493 *dst++ = val;
494 }
495 while (dst < dst_end);
496
497#elif LCD_DEPTH == 2
498 dst_end = dst + LCD_WIDTH/2;
499
500#if LCD_PIXELFORMAT == HORIZONTAL_PACKING
501 src = lcd_framebuffer[y];
502
503 do
504 {
505 unsigned data = *src++;
506
507 *dst++ = ((data >> 2) & 0x30) | ((data >> 4) & 0x03);
508 *dst++ = ((data << 2) & 0x30) | (data & 0x03);
509 }
510 while (dst < dst_end);
511
512#elif LCD_PIXELFORMAT == VERTICAL_PACKING
513 src = lcd_framebuffer[y >> 2];
514 shift = 2 * (y & 3);
515
516 do
517 {
518 val = ((*src++ >> shift) & 3) << 4;
519 val |= ((*src++ >> shift) & 3);
520 *dst++ = val;
521 }
522 while (dst < dst_end);
523
524#elif LCD_PIXELFORMAT == VERTICAL_INTERLEAVED
525 src = lcd_framebuffer[y >> 3];
526 shift = y & 7;
527
528 do
529 {
530 unsigned data = (*src++ >> shift) & 0x0101;
531
532 val = (((data >> 7) | data) & 3) << 4;
533 data = (*src++ >> shift) & 0x0101;
534 val |= ((data >> 7) | data) & 3;
535 *dst++ = val;
536 }
537 while (dst < dst_end);
538
539#endif
540#elif LCD_DEPTH == 16
541 dst_end = dst + LCD_WIDTH;
542 src = lcd_framebuffer[y];
543
544 do
545 {
546#if (LCD_PIXELFORMAT == RGB565SWAPPED)
547 /* iPod LCD data is big endian although the CPU is not */
548 *dst++ = htobe16(*src++);
549#else
550 *dst++ = htole16(*src++);
551#endif
552 }
553 while (dst < dst_end);
554
555#endif /* LCD_DEPTH */
556 write(fd, linebuf, BMP_LINESIZE);
557 }
558 }
559 close(fd);
560}
561
562void screen_dump_set_hook(void (*hook)(int fh))
563{
564 screen_dump_hook = hook;
565}
566
567#endif /* HAVE_LCD_BITMAP */
568
569/* parse a line from a configuration file. the line format is: 239/* parse a line from a configuration file. the line format is:
570 240
571 name: value 241 name: value
diff --git a/apps/misc.h b/apps/misc.h
index 99e709c2c8..998ee9ea8f 100644
--- a/apps/misc.h
+++ b/apps/misc.h
@@ -33,27 +33,6 @@
33char *output_dyn_value(char *buf, int buf_size, int value, 33char *output_dyn_value(char *buf, int buf_size, int value,
34 const unsigned char **units, bool bin_scale); 34 const unsigned char **units, bool bin_scale);
35 35
36/* Create a filename with a number part in a way that the number is 1
37 * higher than the highest numbered file matching the same pattern.
38 * It is allowed that buffer and path point to the same memory location,
39 * saving a strcpy(). Path must always be given without trailing slash.
40 *
41 * "num" can point to an int specifying the number to use or NULL or a value
42 * less than zero to number automatically. The final number used will also
43 * be returned in *num. If *num is >= 0 then *num will be incremented by
44 * one. */
45#if defined(HAVE_RECORDING) && (CONFIG_RTC == 0)
46/* this feature is needed by recording without a RTC to prevent disk access
47 when changing files */
48#define IF_CNFN_NUM_(...) __VA_ARGS__
49#define IF_CNFN_NUM
50#else
51#define IF_CNFN_NUM_(...)
52#endif
53char *create_numbered_filename(char *buffer, const char *path,
54 const char *prefix, const char *suffix,
55 int numberlen IF_CNFN_NUM_(, int *num));
56
57/* Format time into buf. 36/* Format time into buf.
58 * 37 *
59 * buf - buffer to format to. 38 * buf - buffer to format to.
@@ -62,17 +41,6 @@ char *create_numbered_filename(char *buffer, const char *path,
62 */ 41 */
63void format_time(char* buf, int buf_size, long t); 42void format_time(char* buf, int buf_size, long t);
64 43
65#if CONFIG_RTC
66/* Create a filename with a date+time part.
67 It is allowed that buffer and path point to the same memory location,
68 saving a strcpy(). Path must always be given without trailing slash.
69 unique_time as true makes the function wait until the current time has
70 changed. */
71char *create_datetime_filename(char *buffer, const char *path,
72 const char *prefix, const char *suffix,
73 bool unique_time);
74#endif /* CONFIG_RTC */
75
76/* Ask the user if they really want to erase the current dynamic playlist 44/* Ask the user if they really want to erase the current dynamic playlist
77 * returns true if the playlist should be replaced */ 45 * returns true if the playlist should be replaced */
78bool warn_on_pl_erase(void); 46bool warn_on_pl_erase(void);
@@ -87,24 +55,6 @@ int read_line(int fd, char* buffer, int buffer_size);
87int fast_readline(int fd, char *buf, int buf_size, void *parameters, 55int fast_readline(int fd, char *buf, int buf_size, void *parameters,
88 int (*callback)(int n, const char *buf, void *parameters)); 56 int (*callback)(int n, const char *buf, void *parameters));
89 57
90#ifdef HAVE_LCD_BITMAP
91/* Save a .BMP file containing the current screen contents. */
92void screen_dump(void);
93void screen_dump_set_hook(void (*hook)(int fh));
94#endif
95
96/* Make BMP colour map entries from R, G, B triples, without and with blending.
97 * Not within HAVE_LCD_BITMAP because it is also used for the Player sim */
98#define RED_CMP(c) (((c) >> 16) & 0xff)
99#define GREEN_CMP(c) (((c) >> 8) & 0xff)
100#define BLUE_CMP(c) ((c) & 0xff)
101
102#define BMP_COLOR(c) BLUE_CMP(c), GREEN_CMP(c), RED_CMP(c), 0
103#define BMP_COLOR_MIX(c1, c2, num, den) \
104 (BLUE_CMP(c2) - BLUE_CMP(c1)) * (num) / (den) + BLUE_CMP(c1), \
105 (GREEN_CMP(c2) - GREEN_CMP(c1)) * (num) / (den) + GREEN_CMP(c1), \
106 (RED_CMP(c2) - RED_CMP(c1)) * (num) / (den) + RED_CMP(c1), 0
107
108bool settings_parseline(char* line, char** name, char** value); 58bool settings_parseline(char* line, char** name, char** value);
109long default_event_handler_ex(long event, void (*callback)(void *), void *parameter); 59long default_event_handler_ex(long event, void (*callback)(void *), void *parameter);
110long default_event_handler(long event); 60long default_event_handler(long event);
diff --git a/apps/plugin.h b/apps/plugin.h
index 82ce0d6ddf..9ebf793d3f 100644
--- a/apps/plugin.h
+++ b/apps/plugin.h
@@ -77,6 +77,7 @@ void* plugin_get_buffer(size_t *buffer_size);
77#include "timer.h" 77#include "timer.h"
78#include "playlist.h" 78#include "playlist.h"
79#ifdef HAVE_LCD_BITMAP 79#ifdef HAVE_LCD_BITMAP
80#include "screendump.h"
80#include "scrollbar.h" 81#include "scrollbar.h"
81#include "../recorder/bmp.h" 82#include "../recorder/bmp.h"
82#endif 83#endif
diff --git a/apps/plugins/lib/grey_core.c b/apps/plugins/lib/grey_core.c
index 88becb1336..18b2716d4d 100644
--- a/apps/plugins/lib/grey_core.c
+++ b/apps/plugins/lib/grey_core.c
@@ -718,12 +718,9 @@ void grey_deferred_lcd_update(void)
718#define BMP_BPP 8 718#define BMP_BPP 8
719#define BMP_LINESIZE ((LCD_WIDTH + 3) & ~3) 719#define BMP_LINESIZE ((LCD_WIDTH + 3) & ~3)
720#define BMP_HEADERSIZE (54 + 4 * BMP_NUMCOLORS) 720#define BMP_HEADERSIZE (54 + 4 * BMP_NUMCOLORS)
721#define BMP_DATASIZE (BMP_LINESIZE * LCD_HEIGHT) 721#define BMP_DATASIZE (BMP_LINESIZE * (LCD_HEIGHT+LCD_SPLIT_LINES))
722#define BMP_TOTALSIZE (BMP_HEADERSIZE + BMP_DATASIZE) 722#define BMP_TOTALSIZE (BMP_HEADERSIZE + BMP_DATASIZE)
723 723
724#define LE16_CONST(x) (x)&0xff, ((x)>>8)&0xff
725#define LE32_CONST(x) (x)&0xff, ((x)>>8)&0xff, ((x)>>16)&0xff, ((x)>>24)&0xff
726
727static const unsigned char bmpheader[] = 724static const unsigned char bmpheader[] =
728{ 725{
729 0x42, 0x4d, /* 'BM' */ 726 0x42, 0x4d, /* 'BM' */
diff --git a/apps/recorder/radio.c b/apps/recorder/radio.c
index 8c8c56cb34..f3270d1f5d 100644
--- a/apps/recorder/radio.c
+++ b/apps/recorder/radio.c
@@ -34,6 +34,7 @@
34#include "mp3_playback.h" 34#include "mp3_playback.h"
35#include "ctype.h" 35#include "ctype.h"
36#include "file.h" 36#include "file.h"
37#include "general.h"
37#include "errno.h" 38#include "errno.h"
38#include "string.h" 39#include "string.h"
39#include "system.h" 40#include "system.h"
diff --git a/apps/recorder/recording.c b/apps/recorder/recording.c
index c660867f2f..de979dda50 100644
--- a/apps/recorder/recording.c
+++ b/apps/recorder/recording.c
@@ -77,6 +77,7 @@
77#include "sound_menu.h" 77#include "sound_menu.h"
78#include "viewport.h" 78#include "viewport.h"
79#include "list.h" 79#include "list.h"
80#include "general.h"
80 81
81#ifdef HAVE_RECORDING 82#ifdef HAVE_RECORDING
82/* This array holds the record timer interval lengths, in seconds */ 83/* This array holds the record timer interval lengths, in seconds */
diff --git a/apps/settings.c b/apps/settings.c
index 506fd5b59d..30b056da53 100644
--- a/apps/settings.c
+++ b/apps/settings.c
@@ -43,6 +43,7 @@
43#include "ctype.h" 43#include "ctype.h"
44#include "file.h" 44#include "file.h"
45#include "system.h" 45#include "system.h"
46#include "general.h"
46#include "misc.h" 47#include "misc.h"
47#ifdef HAVE_LCD_BITMAP 48#ifdef HAVE_LCD_BITMAP
48#include "icons.h" 49#include "icons.h"
diff --git a/firmware/SOURCES b/firmware/SOURCES
index a9a0b17632..4d33c7949b 100644
--- a/firmware/SOURCES
+++ b/firmware/SOURCES
@@ -2,6 +2,7 @@ ata_idle_notify.c
2events.c 2events.c
3backlight.c 3backlight.c
4buffer.c 4buffer.c
5general.c
5powermgmt.c 6powermgmt.c
6system.c 7system.c
7usb.c 8usb.c
@@ -73,6 +74,9 @@ font_cache.c
73font.c 74font.c
74hangul.c 75hangul.c
75lru.c 76lru.c
77#ifndef BOOTLOADER
78screendump.c
79#endif
76#if LCD_DEPTH == 1 80#if LCD_DEPTH == 1
77drivers/lcd-1bit-vert.c 81drivers/lcd-1bit-vert.c
78#elif LCD_DEPTH == 2 82#elif LCD_DEPTH == 2
@@ -201,7 +205,6 @@ sound.c
201#if CONFIG_CODEC == SWCODEC 205#if CONFIG_CODEC == SWCODEC
202 206
203#ifndef BOOTLOADER 207#ifndef BOOTLOADER
204general.c
205pcm_sampr.c 208pcm_sampr.c
206pcm.c 209pcm.c
207#ifdef HAVE_RECORDING 210#ifdef HAVE_RECORDING
diff --git a/firmware/backlight.c b/firmware/backlight.c
index 9c153e885a..513f643171 100644
--- a/firmware/backlight.c
+++ b/firmware/backlight.c
@@ -35,6 +35,7 @@
35#include "timer.h" 35#include "timer.h"
36#include "backlight.h" 36#include "backlight.h"
37#include "lcd.h" 37#include "lcd.h"
38#include "screendump.h"
38 39
39#ifdef HAVE_REMOTE_LCD 40#ifdef HAVE_REMOTE_LCD
40#include "lcd-remote.h" 41#include "lcd-remote.h"
@@ -57,9 +58,6 @@ int backlight_brightness = DEFAULT_BRIGHTNESS_SETTING;
57#include "backlight-sw-fading.h" 58#include "backlight-sw-fading.h"
58#endif 59#endif
59#ifdef SIMULATOR 60#ifdef SIMULATOR
60/* TODO: find a better way to do it but we need a kernel thread somewhere to
61 handle this */
62extern void screen_dump(void);
63 61
64static inline void _backlight_on(void) 62static inline void _backlight_on(void)
65{ 63{
@@ -600,9 +598,13 @@ void backlight_thread(void)
600#endif /* HAVE_REMOTE_LCD/ HAVE_REMOTE_LCD_AS_MAIN */ 598#endif /* HAVE_REMOTE_LCD/ HAVE_REMOTE_LCD_AS_MAIN */
601#endif /* !SIMULATOR */ 599#endif /* !SIMULATOR */
602#ifdef SIMULATOR 600#ifdef SIMULATOR
603 /* This one here too for lack of a better place */ 601 /* TODO: find a better way to do it but we need
602 * a kernel thread somewhere to handle this */
604 case SYS_SCREENDUMP: 603 case SYS_SCREENDUMP:
605 screen_dump(); 604 screen_dump();
605#ifdef HAVE_REMOTE_LCD
606 remote_screen_dump();
607#endif
606 break; 608 break;
607#endif 609#endif
608 case SYS_USB_CONNECTED: 610 case SYS_USB_CONNECTED:
diff --git a/firmware/export/general.h b/firmware/export/general.h
index d1bd14558c..8da4a0ad59 100644
--- a/firmware/export/general.h
+++ b/firmware/export/general.h
@@ -24,7 +24,9 @@
24 24
25#include <stdbool.h> 25#include <stdbool.h>
26#include <stddef.h> 26#include <stddef.h>
27#include "config.h"
27 28
29#if CONFIG_CODEC == SWCODEC
28/* round a signed/unsigned 32bit value to the closest of a list of values */ 30/* round a signed/unsigned 32bit value to the closest of a list of values */
29/* returns the index of the closest value */ 31/* returns the index of the closest value */
30int round_value_to_list32(unsigned long value, 32int round_value_to_list32(unsigned long value,
@@ -36,5 +38,38 @@ int make_list_from_caps32(unsigned long src_mask,
36 const unsigned long *src_list, 38 const unsigned long *src_list,
37 unsigned long caps_mask, 39 unsigned long caps_mask,
38 unsigned long *caps_list); 40 unsigned long *caps_list);
41#endif /* CONFIG_CODEC == SWCODEC */
42
43/* Create a filename with a number part in a way that the number is 1
44 * higher than the highest numbered file matching the same pattern.
45 * It is allowed that buffer and path point to the same memory location,
46 * saving a strcpy(). Path must always be given without trailing slash.
47 *
48 * "num" can point to an int specifying the number to use or NULL or a value
49 * less than zero to number automatically. The final number used will also
50 * be returned in *num. If *num is >= 0 then *num will be incremented by
51 * one. */
52#if defined(HAVE_RECORDING) && (CONFIG_RTC == 0)
53/* this feature is needed by recording without a RTC to prevent disk access
54 when changing files */
55#define IF_CNFN_NUM_(...) __VA_ARGS__
56#define IF_CNFN_NUM
57#else
58#define IF_CNFN_NUM_(...)
59#endif
60char *create_numbered_filename(char *buffer, const char *path,
61 const char *prefix, const char *suffix,
62 int numberlen IF_CNFN_NUM_(, int *num));
63
64#if CONFIG_RTC
65/* Create a filename with a date+time part.
66 It is allowed that buffer and path point to the same memory location,
67 saving a strcpy(). Path must always be given without trailing slash.
68 unique_time as true makes the function wait until the current time has
69 changed. */
70char *create_datetime_filename(char *buffer, const char *path,
71 const char *prefix, const char *suffix,
72 bool unique_time);
73#endif /* CONFIG_RTC */
39 74
40#endif /* GENERAL_H */ 75#endif /* GENERAL_H */
diff --git a/firmware/general.c b/firmware/general.c
index ff6594086e..1ff3340d27 100644
--- a/firmware/general.c
+++ b/firmware/general.c
@@ -18,11 +18,20 @@
18 * KIND, either express or implied. 18 * KIND, either express or implied.
19 * 19 *
20 ****************************************************************************/ 20 ****************************************************************************/
21#include <limits.h> 21
22#include "system.h"
23#include "config.h" 22#include "config.h"
24#include "general.h" 23#include "general.h"
25 24
25#include "dir.h"
26#include "limits.h"
27#include "sprintf.h"
28#include "stdlib.h"
29#include "string.h"
30#include "system.h"
31#include "time.h"
32#include "timefuncs.h"
33
34#if CONFIG_CODEC == SWCODEC
26int round_value_to_list32(unsigned long value, 35int round_value_to_list32(unsigned long value,
27 const unsigned long list[], 36 const unsigned long list[],
28 int count, 37 int count,
@@ -78,3 +87,107 @@ int make_list_from_caps32(unsigned long src_mask,
78 87
79 return count; 88 return count;
80} /* make_list_from_caps32 */ 89} /* make_list_from_caps32 */
90#endif /* CONFIG_CODEC == SWCODEC */
91
92/* Create a filename with a number part in a way that the number is 1
93 * higher than the highest numbered file matching the same pattern.
94 * It is allowed that buffer and path point to the same memory location,
95 * saving a strcpy(). Path must always be given without trailing slash.
96 * "num" can point to an int specifying the number to use or NULL or a value
97 * less than zero to number automatically. The final number used will also
98 * be returned in *num. If *num is >= 0 then *num will be incremented by
99 * one. */
100char *create_numbered_filename(char *buffer, const char *path,
101 const char *prefix, const char *suffix,
102 int numberlen IF_CNFN_NUM_(, int *num))
103{
104 DIR *dir;
105 struct dirent *entry;
106 int max_num;
107 int pathlen;
108 int prefixlen = strlen(prefix);
109 char fmtstring[12];
110
111 if (buffer != path)
112 strncpy(buffer, path, MAX_PATH);
113
114 pathlen = strlen(buffer);
115
116#ifdef IF_CNFN_NUM
117 if (num && *num >= 0)
118 {
119 /* number specified */
120 max_num = *num;
121 }
122 else
123#endif
124 {
125 /* automatic numbering */
126 max_num = 0;
127
128 dir = opendir(pathlen ? buffer : "/");
129 if (!dir)
130 return NULL;
131
132 while ((entry = readdir(dir)))
133 {
134 int curr_num;
135
136 if (strncasecmp((char *)entry->d_name, prefix, prefixlen)
137 || strcasecmp((char *)entry->d_name + prefixlen + numberlen, suffix))
138 continue;
139
140 curr_num = atoi((char *)entry->d_name + prefixlen);
141 if (curr_num > max_num)
142 max_num = curr_num;
143 }
144
145 closedir(dir);
146 }
147
148 max_num++;
149
150 snprintf(fmtstring, sizeof(fmtstring), "/%%s%%0%dd%%s", numberlen);
151 snprintf(buffer + pathlen, MAX_PATH - pathlen, fmtstring, prefix,
152 max_num, suffix);
153
154#ifdef IF_CNFN_NUM
155 if (num)
156 *num = max_num;
157#endif
158
159 return buffer;
160}
161
162
163#if CONFIG_RTC
164/* Create a filename with a date+time part.
165 It is allowed that buffer and path point to the same memory location,
166 saving a strcpy(). Path must always be given without trailing slash.
167 unique_time as true makes the function wait until the current time has
168 changed. */
169char *create_datetime_filename(char *buffer, const char *path,
170 const char *prefix, const char *suffix,
171 bool unique_time)
172{
173 struct tm *tm = get_time();
174 static struct tm last_tm;
175 int pathlen;
176
177 while (unique_time && !memcmp(get_time(), &last_tm, sizeof (struct tm)))
178 sleep(HZ/10);
179
180 last_tm = *tm;
181
182 if (buffer != path)
183 strncpy(buffer, path, MAX_PATH);
184
185 pathlen = strlen(buffer);
186 snprintf(buffer + pathlen, MAX_PATH - pathlen,
187 "/%s%02d%02d%02d-%02d%02d%02d%s", prefix,
188 tm->tm_year % 100, tm->tm_mon + 1, tm->tm_mday,
189 tm->tm_hour, tm->tm_min, tm->tm_sec, suffix);
190
191 return buffer;
192}
193#endif /* CONFIG_RTC */
diff --git a/firmware/usb.c b/firmware/usb.c
index a1e552a321..a720215731 100644
--- a/firmware/usb.c
+++ b/firmware/usb.c
@@ -42,7 +42,8 @@
42#ifdef HAVE_USBSTACK 42#ifdef HAVE_USBSTACK
43#include "usb_core.h" 43#include "usb_core.h"
44#endif 44#endif
45#include "logf.h" 45#include "logf.h"
46#include "screendump.h"
46 47
47/* Conditions under which we want the entire driver */ 48/* Conditions under which we want the entire driver */
48#if !defined(BOOTLOADER) || (CONFIG_CPU == SH7034) || \ 49#if !defined(BOOTLOADER) || (CONFIG_CPU == SH7034) || \
@@ -55,11 +56,6 @@
55 56
56#ifdef HAVE_LCD_BITMAP 57#ifdef HAVE_LCD_BITMAP
57bool do_screendump_instead_of_usb = false; 58bool do_screendump_instead_of_usb = false;
58#if defined(USB_FULL_INIT) && defined(BOOTLOADER)
59static void screen_dump(void) {}
60#else
61void screen_dump(void); /* Nasty again. Defined in apps/ too */
62#endif
63#endif 59#endif
64 60
65#if !defined(SIMULATOR) && !defined(USB_NONE) 61#if !defined(SIMULATOR) && !defined(USB_NONE)
@@ -262,6 +258,9 @@ static void usb_thread(void)
262 { 258 {
263 usb_state = USB_SCREENDUMP; 259 usb_state = USB_SCREENDUMP;
264 screen_dump(); 260 screen_dump();
261#ifdef HAVE_REMOTE_LCD
262 remote_screen_dump();
263#endif
265 break; 264 break;
266 } 265 }
267#endif 266#endif
diff --git a/uisimulator/sdl/lcd-bitmap.c b/uisimulator/sdl/lcd-bitmap.c
index 8caac784ef..378889c417 100644
--- a/uisimulator/sdl/lcd-bitmap.c
+++ b/uisimulator/sdl/lcd-bitmap.c
@@ -22,7 +22,7 @@
22#include "debug.h" 22#include "debug.h"
23#include "uisdl.h" 23#include "uisdl.h"
24#include "lcd-sdl.h" 24#include "lcd-sdl.h"
25#include "misc.h" 25#include "screendump.h"
26 26
27SDL_Surface* lcd_surface; 27SDL_Surface* lcd_surface;
28 28
@@ -166,14 +166,12 @@ void sim_lcd_init(void)
166 SIM_LCD_WIDTH * display_zoom, 166 SIM_LCD_WIDTH * display_zoom,
167 SIM_LCD_HEIGHT * display_zoom, 167 SIM_LCD_HEIGHT * display_zoom,
168 LCD_DEPTH, 0, 0, 0, 0); 168 LCD_DEPTH, 0, 0, 0, 0);
169#else 169#elif LCD_DEPTH <= 8
170 lcd_surface = SDL_CreateRGBSurface(SDL_SWSURFACE, 170 lcd_surface = SDL_CreateRGBSurface(SDL_SWSURFACE,
171 SIM_LCD_WIDTH * display_zoom, 171 SIM_LCD_WIDTH * display_zoom,
172 SIM_LCD_HEIGHT * display_zoom, 172 SIM_LCD_HEIGHT * display_zoom,
173 8, 0, 0, 0, 0); 173 8, 0, 0, 0, 0);
174#endif
175 174
176#if LCD_DEPTH <= 8
177#ifdef HAVE_BACKLIGHT 175#ifdef HAVE_BACKLIGHT
178 sdl_set_gradient(lcd_surface, &lcd_bl_color_dark, 176 sdl_set_gradient(lcd_surface, &lcd_bl_color_dark,
179 &lcd_bl_color_bright, 0, NUM_SHADES); 177 &lcd_bl_color_bright, 0, NUM_SHADES);
@@ -189,7 +187,7 @@ void sim_lcd_init(void)
189 &lcd_color2_bright, NUM_SHADES, NUM_SHADES); 187 &lcd_color2_bright, NUM_SHADES, NUM_SHADES);
190#endif 188#endif
191#endif /* !HAVE_BACKLIGHT */ 189#endif /* !HAVE_BACKLIGHT */
192#endif /* LCD_DEPTH < 8 */ 190#endif /* LCD_DEPTH */
193} 191}
194 192
195#if LCD_DEPTH < 8 193#if LCD_DEPTH < 8
diff --git a/uisimulator/sdl/lcd-charcells.c b/uisimulator/sdl/lcd-charcells.c
index 19d27d5152..30aa0a6a81 100644
--- a/uisimulator/sdl/lcd-charcells.c
+++ b/uisimulator/sdl/lcd-charcells.c
@@ -22,7 +22,8 @@
22#include "debug.h" 22#include "debug.h"
23#include "lcd.h" 23#include "lcd.h"
24#include "lcd-charcell.h" 24#include "lcd-charcell.h"
25#include "misc.h" 25#inclued "screendump.h"
26#include "misc.h"
26#include <string.h> 27#include <string.h>
27#include <unistd.h> 28#include <unistd.h>
28#include <fcntl.h> 29#include <fcntl.h>
diff --git a/uisimulator/sdl/lcd-remote-bitmap.c b/uisimulator/sdl/lcd-remote-bitmap.c
index f5c2225ab2..ecb9904a40 100644
--- a/uisimulator/sdl/lcd-remote-bitmap.c
+++ b/uisimulator/sdl/lcd-remote-bitmap.c
@@ -22,7 +22,7 @@
22#include "uisdl.h" 22#include "uisdl.h"
23#include "lcd-sdl.h" 23#include "lcd-sdl.h"
24#include "lcd-remote-bitmap.h" 24#include "lcd-remote-bitmap.h"
25#include "misc.h" 25#include "screendump.h"
26 26
27SDL_Surface *remote_surface; 27SDL_Surface *remote_surface;
28 28
@@ -39,7 +39,7 @@ SDL_Color remote_color_bright = {RED_CMP(LCD_REMOTE_BRIGHTCOLOR),
39 GREEN_CMP(LCD_REMOTE_BRIGHTCOLOR), 39 GREEN_CMP(LCD_REMOTE_BRIGHTCOLOR),
40 BLUE_CMP(LCD_REMOTE_BRIGHTCOLOR), 0}; 40 BLUE_CMP(LCD_REMOTE_BRIGHTCOLOR), 0};
41 41
42#define GRADIENT_MAX 128 42#define NUM_SHADES 129
43 43
44#if LCD_REMOTE_DEPTH == 2 44#if LCD_REMOTE_DEPTH == 2
45/* Only defined for positive, non-split LCD for now */ 45/* Only defined for positive, non-split LCD for now */
@@ -49,7 +49,7 @@ static const unsigned char colorindex[4] = {128, 85, 43, 0};
49static unsigned long get_lcd_remote_pixel(int x, int y) 49static unsigned long get_lcd_remote_pixel(int x, int y)
50{ 50{
51#if LCD_REMOTE_DEPTH == 1 51#if LCD_REMOTE_DEPTH == 1
52 return lcd_remote_framebuffer[y/8][x] & (1 << (y & 7)) ? 0 : GRADIENT_MAX; 52 return lcd_remote_framebuffer[y/8][x] & (1 << (y & 7)) ? 0 : (NUM_SHADES-1);
53#elif LCD_REMOTE_DEPTH == 2 53#elif LCD_REMOTE_DEPTH == 2
54#if LCD_REMOTE_PIXELFORMAT == VERTICAL_INTERLEAVED 54#if LCD_REMOTE_PIXELFORMAT == VERTICAL_INTERLEAVED
55 unsigned bits = (lcd_remote_framebuffer[y/8][x] >> (y & 7)) & 0x0101; 55 unsigned bits = (lcd_remote_framebuffer[y/8][x] >> (y & 7)) & 0x0101;
@@ -76,10 +76,10 @@ void sim_remote_backlight(int value)
76{ 76{
77 if (value > 0) { 77 if (value > 0) {
78 sdl_set_gradient(remote_surface, &remote_bl_color_dark, 78 sdl_set_gradient(remote_surface, &remote_bl_color_dark,
79 &remote_bl_color_bright, 0, GRADIENT_MAX+1); 79 &remote_bl_color_bright, 0, NUM_SHADES);
80 } else { 80 } else {
81 sdl_set_gradient(remote_surface, &remote_color_dark, 81 sdl_set_gradient(remote_surface, &remote_color_dark,
82 &remote_color_bright, 0, GRADIENT_MAX+1); 82 &remote_color_bright, 0, NUM_SHADES);
83 } 83 }
84 84
85 sdl_gui_update(remote_surface, 0, 0, LCD_REMOTE_WIDTH, LCD_REMOTE_HEIGHT, 85 sdl_gui_update(remote_surface, 0, 0, LCD_REMOTE_WIDTH, LCD_REMOTE_HEIGHT,
@@ -97,6 +97,6 @@ void sim_lcd_remote_init(void)
97 8, 0, 0, 0, 0); 97 8, 0, 0, 0, 0);
98 98
99 sdl_set_gradient(remote_surface, &remote_bl_color_dark, 99 sdl_set_gradient(remote_surface, &remote_bl_color_dark,
100 &remote_bl_color_bright, 0, GRADIENT_MAX+1); 100 &remote_bl_color_bright, 0, NUM_SHADES);
101} 101}
102 102