]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/l4con/examples/dropsshot/main.c
Inital import
[l4.git] / l4 / pkg / l4con / examples / dropsshot / main.c
1 /*
2  * Linux program to take screenshot from the DROPS console
3  */
4
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <string.h>
8 #include <sys/stat.h>
9 #include <fcntl.h>
10 #include <unistd.h>
11 #include <time.h>
12 #define _GNU_SOURCE
13 #include <getopt.h>
14
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>
22
23 #define MY_SBUF_SIZE 65536
24
25 /* global vars */
26 l4_threadid_t con_l4id;         /* con at names */
27 l4_threadid_t vc_l4id;          /* partner VC */
28
29 char opt_verbose                = 0;
30 char opt_quiet                  = 0;
31 char opt_write_fb               = 0;
32 char opt_convert                = 1;
33 char opt_delete_raw             = 1;
34 char opt_process_raw_input_only = 0;
35
36 char get_vc = 0; /* 0 ... current foreground VC */
37
38 #define INFO(format, args...) { if (opt_verbose) printf(format, ## args); \
39                               } while (0);
40
41 #define PRINT(format, args...) { if (!opt_quiet) printf(format, ## args); \
42                                } while (0);
43
44 #define FILENAME_LEN 196
45 #define FILEEXT_LEN 10
46 #define RAW_EXT ".raw"
47 #define FB_EXT ".fb"
48 #define STD_EXT ".png"
49 #define PROGNAME "dropsshot"
50
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;
56 int raw_pic_size;
57 l4_size_t fb_size;
58 char *fb_mem, *raw_pic_mem;
59
60 typedef char l4_page_t[L4_PAGESIZE];
61 static l4_page_t map_page __attribute__ ((aligned(L4_PAGESIZE)));
62
63 typedef struct bpp_15 {
64   unsigned short blue:5;
65   unsigned short green:5;
66   unsigned short red:5;
67   unsigned short reserved:1;
68 } __attribute__((packed)) bpp_15_t;
69
70 typedef struct bpp_16 {
71   unsigned short blue:5;
72   unsigned short green:6;
73   unsigned short red:5;
74 } __attribute__((packed)) bpp_16_t;
75
76 typedef struct bpp_24 {
77   unsigned char blue, green, red;
78 } bpp_24_t;
79
80 typedef struct bpp_32 {
81   unsigned char blue, green, red;
82   unsigned char pad; /* so that this struct is 4 bytes... */
83 } bpp_32_t;
84
85 typedef struct raw {
86   unsigned char red, green, blue;
87 } raw_t;
88
89 /* pseudo short options for long options */
90 enum {
91   OPTION_GETRAWFB = 256,
92 };
93 static struct option long_options[] = {
94   {"verbose",     0, 0, 'v'},
95   {"quiet",       0, 0, 'q'},
96   {"ext",         1, 0, 'e'},
97   {"keep-raw",    0, 0, 'r'},
98   {"noconvert",   0, 0, 'n'},
99   {"help",        0, 0, 'h'},
100   {"processraw",  0, 0, 'p'},
101   {"size",        1, 0, 's'},
102   {"vc",          1, 0, 'i'},
103   {"get-fb",      0, 0, OPTION_GETRAWFB},
104   {0, 0, 0, 0}
105 };
106
107 void static usage(void)
108 {
109   printf("Usage: %s [options] [picname.ext]\n"
110          "\n"
111          "Options:\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"
115          "                                 Default: png\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"
126          "\n"
127          , PROGNAME);
128 }
129
130 static void decode_size(char *size_str)
131 {
132   int i = 0;
133   char *s = size_str;
134   char xx[10], yy[10];
135   char *t;
136   
137   t = xx;
138   while (*s) {
139     if (*s == 'x') {
140       i = 0;
141       s++;
142       *t = 0;
143       t = yy;
144     }
145     *t = *s;
146     s++;
147     i++;
148     t++;
149     if (i == 10) {
150       fprintf(stderr, "size string is wrong.\n");
151       exit(1);
152     }
153   }
154   *t = 0;
155
156   xres = strtol(xx, &t, 10);
157   if (t != NULL && *t) {
158     fprintf(stderr, "x part of size is wrong.\n");
159     exit(1);
160   }
161   yres = strtol(yy, &t, 10);
162   if (t != NULL && *t) {
163     fprintf(stderr, "y part of size is wrong.\n");
164     exit(1);
165   }
166
167 }
168
169 static int process_args(int argc, char **argv)
170 {
171   int c;
172   int option_index = 0;
173
174   while ((c = getopt_long(argc, argv, "vqe:nrhps:i:",
175                   long_options, &option_index)) != -1) {
176
177     switch (c) {
178       case 'v':
179         opt_verbose = 1;
180         break;
181       case 'q':
182         opt_quiet = 1;
183         break;
184       case 'e':
185         strcpy(file_ext, ".");
186         strncat(file_ext, optarg, FILEEXT_LEN-1);
187         break;
188       case OPTION_GETRAWFB:
189         opt_write_fb = 1;
190         break;
191       case 'n':
192         opt_convert = 0;
193         opt_delete_raw = 0;
194         break;
195       case 'r':
196         opt_delete_raw = 0;
197         break;
198       case 'p':
199         opt_process_raw_input_only = 1;
200         opt_delete_raw = 0;
201         break;
202       case 's':
203         decode_size(optarg);
204         break;
205       case 'i':
206         get_vc = atol(optarg);
207         break;
208       case 'h':
209         usage();
210         exit(0);
211       default:
212         printf("Unknown option.\n");
213         usage();
214         exit(1);
215     }
216   }
217
218   return optind;
219 }
220
221 void static inline col15_to_raw(bpp_15_t *c, raw_t *r)
222 {
223   r->red   = c->red   << 3;
224   r->green = c->green << 3;
225   r->blue  = c->blue  << 3;
226 }
227 void static inline col16_to_raw(bpp_16_t *c, raw_t *r)
228 {
229   r->red   = (unsigned char)c->red   << 3;
230   r->green = (unsigned char)c->green << 2;
231   r->blue  = (unsigned char)c->blue  << 3;
232 }
233
234 void static inline col24_to_raw(bpp_24_t *c, raw_t *r)
235 {
236   r->red   = c->red;
237   r->green = c->green;
238   r->blue  = c->blue;
239 }
240
241 void static inline col32_to_raw(bpp_32_t *c, raw_t *r)
242 {
243   r->red   = c->red;
244   r->green = c->green;
245   r->blue  = c->blue;
246 }
247
248 static void convert_raw_to_pic(char *filename, char *raw_filename,
249                                int xres, int yres)
250 {
251   char exec_str[260];
252   int len;
253
254   if (xres == 0 || yres == 0) {
255     fprintf(stderr, "Width or height seems to be wrong.\n");
256     exit(1);
257   }
258
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!");
264     exit(1);
265   }
266   INFO("Exec string: %s\n", exec_str);
267
268   PRINT("Converting raw data to picture... ");
269   if (system(exec_str)) {
270     fprintf(stderr, "Error while converting.\n");
271   } else {
272     PRINT("done.\n");
273     INFO("Pictures converted, result in %s\n", filename);
274   }
275 }
276
277 static void write_fb(char *fb_mem, int size)
278 {
279   int fb_fd;
280
281   if ((fb_fd = open(fb_filename, O_RDWR|O_CREAT, 0666)) == -1) {
282     perror(fb_filename);
283     exit(1);
284   }
285
286   if (write(fb_fd, fb_mem, size) != size) {
287     fprintf(stderr, "Error writing fb file (%s)\n", fb_filename);
288   }
289
290   if (close(fb_fd) == -1) {
291     perror("close");
292     exit(1);
293   }
294 }
295
296 static void write_raw(char *raw_pic_mem, int raw_pic_size)
297 {
298   int raw_fd;
299
300   if ((raw_fd = open(raw_filename, O_RDWR|O_CREAT, 0666)) == -1) {
301     perror(raw_filename);
302     exit(1);
303   }
304
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);
307   }
308
309   if (close(raw_fd) == -1) {
310     perror("close");
311     exit(1);
312   }
313 }
314
315 static void get_fb(void)
316 {
317   l4_addr_t fpage_addr;
318   l4_size_t fpage_size;
319   l4dm_dataspace_t ds;
320   CORBA_Environment env = dice_default_environment;
321   int i, pages, error;
322   struct stat st;
323
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");
327     exit(1);
328   }
329
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);
333     exit(1);
334   }
335   INFO("Found my console through names, it's at "l4util_idfmt".\n",
336        l4util_idstr(con_l4id));
337
338   PRINT("Screenshot'ing, please smile... ;-)\n");
339   /* get screenshot */
340   if (con_if_screenshot_call(&con_l4id, get_vc, &ds, 
341                         &xres, &yres, &bpp, &env)) {
342     fprintf(stderr, "Could not get screenshot\n");
343     exit(1);
344   }
345   INFO("Got screenshot: res: %dx%d, bpp: %d\n", xres, yres, bpp);
346
347   if (l4dm_mem_size(&ds, &fb_size)) {
348     fprintf(stderr, "Couldn't get size of data space\n");
349     exit(1);
350   }
351   INFO("Size of data space: %d\n", fb_size);
352
353   if ((fb_mem = malloc(fb_size)) == NULL) {
354     fprintf(stderr, "Couldn't malloc %d Bytes of memory!\n", fb_size);
355     exit(1);
356   }
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);
360     exit(1);
361   }
362   
363   pages = fb_size / L4_PAGESIZE; // size is always a multiple of L4_PAGESIZE?
364   for (i = 0; i < pages; i++) {
365     /* unmap memory */
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);
369
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 "
375               l4util_idfmt"\n",
376           error, ds.id, l4util_idstr(ds.manager));
377       l4dm_close(&ds);
378       exit(error);
379     }
380
381     memcpy(fb_mem + i*L4_PAGESIZE, map_page, L4_PAGESIZE);
382   }
383
384   if (l4dm_close(&ds)) {
385     fprintf(stderr, "Error on closing dataspace, expect memory leakage...\n");
386   }
387 }
388
389 static void convert_fb_to_raw(void)
390 {
391   int i;
392
393   switch (bpp) {
394     case 15: {
395                /* color distribution: r:5 g:5 b:5 + 1 empty bit */
396                bpp_15_t col;
397                raw_t    raw;
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);
402                }
403                break;
404              }
405     case 16: {
406                /* color distribution: r:5 g:6 b:5 */
407                bpp_16_t col;
408                raw_t    raw;
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);
413                }
414                break;
415              }
416     case 24: {
417                /* color distribution: r:8 g:8 b:8 */
418                bpp_24_t col;
419                raw_t    raw;
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);
424                }
425                break;
426              }
427     case 32: {
428                /* color distribution: r:8 g:8 b:8 + an empty byte */
429                bpp_32_t col;
430                raw_t    raw;
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);
435                }
436                break;
437              }
438     default:
439       fprintf(stderr, "Unknown bits_per_pixel value %d, giving up.\n", bpp);
440       exit(1);
441   }
442 }
443
444 int main(int argc, char **argv)
445 {
446   int nr_opts;
447
448
449   nr_opts = process_args(argc, argv);
450
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);
459   } else {
460     if (strlen(argv[nr_opts]) > FILENAME_LEN - strlen(RAW_EXT)
461                                 - strlen(file_ext)) {
462       fprintf(stderr, "Error: given filename too long\n");
463       exit(1);
464     }
465     strcpy(filename, argv[nr_opts]);
466     strcat(filename, file_ext);
467   }
468   strcpy(raw_filename, filename);
469   strcat(raw_filename, RAW_EXT);
470   strcpy(fb_filename, filename);
471   strcat(fb_filename, FB_EXT);
472
473   if (!opt_process_raw_input_only) {
474     get_fb();
475
476     if (opt_write_fb)
477       write_fb(fb_mem, fb_size);
478
479     convert_fb_to_raw();
480
481     INFO("Writing raw picture data to %s\n", raw_filename);
482     write_raw(raw_pic_mem, raw_pic_size);
483   }
484
485   if (opt_convert)
486     convert_raw_to_pic(filename, raw_filename, xres, yres);
487
488   if (opt_delete_raw)
489     if (unlink(raw_filename) == -1)
490       perror(raw_filename);
491   
492   return 0;
493 }