2 * Linux program to take screenshot from the DROPS console
15 #include <l4/l4con/l4con.h>
16 #include <l4/l4con/l4con-client.h>
17 #include <l4/names/libnames.h>
18 #include <l4/dm_phys/dm_phys.h>
19 #include <l4/sys/syscalls.h>
20 #include <l4/dm_mem/dm_mem.h>
21 #include <l4/util/l4_macros.h>
23 #define MY_SBUF_SIZE 65536
26 l4_threadid_t con_l4id; /* con at names */
27 l4_threadid_t vc_l4id; /* partner VC */
31 char opt_write_fb = 0;
33 char opt_delete_raw = 1;
34 char opt_process_raw_input_only = 0;
36 char get_vc = 0; /* 0 ... current foreground VC */
38 #define INFO(format, args...) { if (opt_verbose) printf(format, ## args); \
41 #define PRINT(format, args...) { if (!opt_quiet) printf(format, ## args); \
44 #define FILENAME_LEN 196
45 #define FILEEXT_LEN 10
46 #define RAW_EXT ".raw"
48 #define STD_EXT ".png"
49 #define PROGNAME "dropsshot"
51 char filename[FILENAME_LEN];
52 char raw_filename[FILENAME_LEN];
53 char fb_filename[FILENAME_LEN];
54 char file_ext[FILEEXT_LEN] = "";
55 l4_uint32_t xres, yres, bpp;
58 char *fb_mem, *raw_pic_mem;
60 typedef char l4_page_t[L4_PAGESIZE];
61 static l4_page_t map_page __attribute__ ((aligned(L4_PAGESIZE)));
63 typedef struct bpp_15 {
64 unsigned short blue:5;
65 unsigned short green:5;
67 unsigned short reserved:1;
68 } __attribute__((packed)) bpp_15_t;
70 typedef struct bpp_16 {
71 unsigned short blue:5;
72 unsigned short green:6;
74 } __attribute__((packed)) bpp_16_t;
76 typedef struct bpp_24 {
77 unsigned char blue, green, red;
80 typedef struct bpp_32 {
81 unsigned char blue, green, red;
82 unsigned char pad; /* so that this struct is 4 bytes... */
86 unsigned char red, green, blue;
89 /* pseudo short options for long options */
91 OPTION_GETRAWFB = 256,
93 static struct option long_options[] = {
94 {"verbose", 0, 0, 'v'},
97 {"keep-raw", 0, 0, 'r'},
98 {"noconvert", 0, 0, 'n'},
100 {"processraw", 0, 0, 'p'},
103 {"get-fb", 0, 0, OPTION_GETRAWFB},
107 void static usage(void)
109 printf("Usage: %s [options] [picname.ext]\n"
112 " -v, --verbose Tell what's going on.\n"
113 " -q, --quiet Be quiet and say nothing.\n"
114 " -e, --ext=GRAPHICTYPE Graphics type (png, jpg, bmp, ...).\n"
116 " -r, --keep-raw Keep raw data.\n"
117 " -n, --noconvert Don't call \"convert\", includes \"-r\".\n"
118 " --get-fb Get plain framebuffer data.\n"
119 " --processraw Don't take a screenshot, instead\n"
120 " only convert raw data to pictures.\n"
121 " Give picture name as argument.\n"
122 " Includes \"-r\".\n"
123 " -s, --size Size for \"-p\" option.\n"
124 " -i, --vc Choose VC, 0 for current foreground VC.\n"
125 " -h, --help This help screen.\n"
130 static void decode_size(char *size_str)
150 fprintf(stderr, "size string is wrong.\n");
156 xres = strtol(xx, &t, 10);
157 if (t != NULL && *t) {
158 fprintf(stderr, "x part of size is wrong.\n");
161 yres = strtol(yy, &t, 10);
162 if (t != NULL && *t) {
163 fprintf(stderr, "y part of size is wrong.\n");
169 static int process_args(int argc, char **argv)
172 int option_index = 0;
174 while ((c = getopt_long(argc, argv, "vqe:nrhps:i:",
175 long_options, &option_index)) != -1) {
185 strcpy(file_ext, ".");
186 strncat(file_ext, optarg, FILEEXT_LEN-1);
188 case OPTION_GETRAWFB:
199 opt_process_raw_input_only = 1;
206 get_vc = atol(optarg);
212 printf("Unknown option.\n");
221 void static inline col15_to_raw(bpp_15_t *c, raw_t *r)
223 r->red = c->red << 3;
224 r->green = c->green << 3;
225 r->blue = c->blue << 3;
227 void static inline col16_to_raw(bpp_16_t *c, raw_t *r)
229 r->red = (unsigned char)c->red << 3;
230 r->green = (unsigned char)c->green << 2;
231 r->blue = (unsigned char)c->blue << 3;
234 void static inline col24_to_raw(bpp_24_t *c, raw_t *r)
241 void static inline col32_to_raw(bpp_32_t *c, raw_t *r)
248 static void convert_raw_to_pic(char *filename, char *raw_filename,
254 if (xres == 0 || yres == 0) {
255 fprintf(stderr, "Width or height seems to be wrong.\n");
259 len = snprintf(exec_str, sizeof(exec_str),
260 "convert -depth 8 -size %dx%d rgb:%s %s\n",
261 xres, yres, raw_filename, filename);
262 if (len > sizeof(exec_str)) {
263 fprintf(stderr, "exec string is too big!");
266 INFO("Exec string: %s\n", exec_str);
268 PRINT("Converting raw data to picture... ");
269 if (system(exec_str)) {
270 fprintf(stderr, "Error while converting.\n");
273 INFO("Pictures converted, result in %s\n", filename);
277 static void write_fb(char *fb_mem, int size)
281 if ((fb_fd = open(fb_filename, O_RDWR|O_CREAT, 0666)) == -1) {
286 if (write(fb_fd, fb_mem, size) != size) {
287 fprintf(stderr, "Error writing fb file (%s)\n", fb_filename);
290 if (close(fb_fd) == -1) {
296 static void write_raw(char *raw_pic_mem, int raw_pic_size)
300 if ((raw_fd = open(raw_filename, O_RDWR|O_CREAT, 0666)) == -1) {
301 perror(raw_filename);
305 if (write(raw_fd, raw_pic_mem, raw_pic_size) != raw_pic_size) {
306 fprintf(stderr, "Error writing raw file (%s)\n", raw_filename);
309 if (close(raw_fd) == -1) {
315 static void get_fb(void)
317 l4_addr_t fpage_addr;
318 l4_size_t fpage_size;
320 CORBA_Environment env = dice_default_environment;
324 /* check if we're running under L4Linux */
325 if (stat("/proc/l4", &st) == -1) {
326 fprintf(stderr, "Error: /proc/l4 doesn't exist, not running on L4Linux?!\n");
330 /* ask for 'con' (timeout = 5000 ms) */
331 if (names_waitfor_name(CON_NAMES_STR, &con_l4id, 5000) == 0) {
332 fprintf(stderr, "PANIC: %s not registered at names", CON_NAMES_STR);
335 INFO("Found my console through names, it's at "l4util_idfmt".\n",
336 l4util_idstr(con_l4id));
338 PRINT("Screenshot'ing, please smile... ;-)\n");
340 if (con_if_screenshot_call(&con_l4id, get_vc, &ds,
341 &xres, &yres, &bpp, &env)) {
342 fprintf(stderr, "Could not get screenshot\n");
345 INFO("Got screenshot: res: %dx%d, bpp: %d\n", xres, yres, bpp);
347 if (l4dm_mem_size(&ds, &fb_size)) {
348 fprintf(stderr, "Couldn't get size of data space\n");
351 INFO("Size of data space: %d\n", fb_size);
353 if ((fb_mem = malloc(fb_size)) == NULL) {
354 fprintf(stderr, "Couldn't malloc %d Bytes of memory!\n", fb_size);
357 raw_pic_size = xres*yres*3;
358 if ((raw_pic_mem = malloc(raw_pic_size)) == NULL) {
359 fprintf(stderr, "Couldn't malloc %d bytes of memory!\n", raw_pic_size);
363 pages = fb_size / L4_PAGESIZE; // size is always a multiple of L4_PAGESIZE?
364 for (i = 0; i < pages; i++) {
366 l4_fpage_unmap(l4_fpage((l4_umword_t)map_page, L4_LOG2_PAGESIZE,
367 L4_FPAGE_RW, L4_MAP_ITEM_MAP),
368 L4_FP_FLUSH_PAGE|L4_FP_ALL_SPACES);
370 /* page in L4 page */
371 if ((error = l4dm_map_pages(&ds, i*L4_PAGESIZE, L4_PAGESIZE,
372 (l4_addr_t)map_page, L4_LOG2_PAGESIZE,
373 0, L4DM_RO, &fpage_addr,&fpage_size)) < 0) {
374 fprintf(stderr, "Error %d requesting ds %d at ds_manager "
376 error, ds.id, l4util_idstr(ds.manager));
381 memcpy(fb_mem + i*L4_PAGESIZE, map_page, L4_PAGESIZE);
384 if (l4dm_close(&ds)) {
385 fprintf(stderr, "Error on closing dataspace, expect memory leakage...\n");
389 static void convert_fb_to_raw(void)
395 /* color distribution: r:5 g:5 b:5 + 1 empty bit */
398 for (i=0; i < xres*yres; i++) {
399 memcpy(&col, fb_mem + i*2, 2);
400 col15_to_raw(&col, &raw);
401 memcpy(raw_pic_mem + i*3, &raw, 3);
406 /* color distribution: r:5 g:6 b:5 */
409 for (i=0; i < xres*yres; i++) {
410 memcpy(&col, fb_mem + i*2, 2);
411 col16_to_raw(&col, &raw);
412 memcpy(raw_pic_mem + i*3, &raw, 3);
417 /* color distribution: r:8 g:8 b:8 */
420 for (i=0; i < xres*yres; i++) {
421 memcpy(&col, fb_mem + i*3, 3);
422 col24_to_raw(&col, &raw);
423 memcpy(raw_pic_mem + i*3, &raw, 3);
428 /* color distribution: r:8 g:8 b:8 + an empty byte */
431 for (i=0; i < xres*yres; i++) {
432 memcpy(&col, fb_mem + i*4, 3);
433 col32_to_raw(&col, &raw);
434 memcpy(raw_pic_mem + i*3, &raw, 3);
439 fprintf(stderr, "Unknown bits_per_pixel value %d, giving up.\n", bpp);
444 int main(int argc, char **argv)
449 nr_opts = process_args(argc, argv);
451 if (argc - nr_opts == 0) {
452 /* no filename given -> invent one */
453 char my_hostname[100];
454 gethostname(my_hostname, 100);
455 if (strlen(file_ext) == 0)
456 strcpy(file_ext, STD_EXT);
457 sprintf(filename, "%s.%s.%d%s",
458 PROGNAME, my_hostname, (int)time(NULL), file_ext);
460 if (strlen(argv[nr_opts]) > FILENAME_LEN - strlen(RAW_EXT)
461 - strlen(file_ext)) {
462 fprintf(stderr, "Error: given filename too long\n");
465 strcpy(filename, argv[nr_opts]);
466 strcat(filename, file_ext);
468 strcpy(raw_filename, filename);
469 strcat(raw_filename, RAW_EXT);
470 strcpy(fb_filename, filename);
471 strcat(fb_filename, FB_EXT);
473 if (!opt_process_raw_input_only) {
477 write_fb(fb_mem, fb_size);
481 INFO("Writing raw picture data to %s\n", raw_filename);
482 write_raw(raw_pic_mem, raw_pic_size);
486 convert_raw_to_pic(filename, raw_filename, xres, yres);
489 if (unlink(raw_filename) == -1)
490 perror(raw_filename);