1/*
2Copyright (c) 2013, Broadcom Europe Ltd
3All rights reserved.
4
5Redistribution and use in source and binary forms, with or without
6modification, are permitted provided that the following conditions are met:
7 * Redistributions of source code must retain the above copyright
8 notice, this list of conditions and the following disclaimer.
9 * Redistributions in binary form must reproduce the above copyright
10 notice, this list of conditions and the following disclaimer in the
11 documentation and/or other materials provided with the distribution.
12 * Neither the name of the copyright holder nor the
13 names of its contributors may be used to endorse or promote products
14 derived from this software without specific prior written permission.
15
16THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
20DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26*/
27
28#include "interface/mmal/mmal.h"
29#include "interface/mmal/util/mmal_util.h"
30#include "mmal_vc_api.h"
31#include <stdio.h>
32#include <stddef.h>
33#include <sys/time.h>
34#include <limits.h>
35#ifdef __ANDROID__
36#include <android/log.h>
37#endif
38#include "host_applications/linux/libs/debug_sym/debug_sym.h"
39#include "mmal_vc_msgnames.h"
40#include "mmal_vc_dbglog.h"
41#include "vchiq.h"
42#include "interface/vmcs_host/vc_imageconv_defs.h"
43
44/** Command-line diagnostics at the VC MMAL API level.
45 *
46 * @fixme: how does this work with multiple videocores?
47 */
48
49struct cmd {
50 const char *name;
51 int (*pfn)(int argc, const char **argv);
52 const char *descr;
53 int flags;
54};
55
56#define CONNECT 1
57
58static int do_commands(int argc, const char **argv);
59static int do_version(int argc, const char **argv);
60static int do_stats(int argc, const char **argv);
61static int do_usage(int argc, const char **argv);
62static int do_create(int argc, const char **argv);
63static int do_eventlog(int argc, const char **argv);
64static int do_components(int argc, const char **argv);
65static int do_mmal_stats(int argc, const char **argv);
66static int do_imageconv_stats(int argc, const char **argv);
67static int do_compact(int argc, const char **argv);
68static int do_autosusptest(int argc, const char **argv);
69static int do_camerainfo(int argc, const char **argv);
70static int do_host_log(int argc, const char **argv);
71static int do_host_log_write(int argc, const char **argv);
72
73static struct cmd cmds[] = {
74 { "help", do_usage, "give this help", 0 },
75 { "version", do_version, "report VC MMAL server version number", CONNECT },
76 { "stats", do_stats, "report VC MMAL statistics", CONNECT },
77 { "reset", do_stats, "reset VC MMAL statistics", CONNECT },
78 { "commands", do_commands, "list available commands", CONNECT },
79 { "create", do_create, "create a component", CONNECT },
80 { "eventlog", do_eventlog, "display event log", 0 },
81 { "components", do_components, "[update] list components", 0 },
82 { "mmal-stats", do_mmal_stats, "list mmal core stats", CONNECT },
83 { "ic-stats", do_imageconv_stats, "[reset] list imageconv stats", CONNECT },
84 { "compact", do_compact, "trigger memory compaction", CONNECT },
85 { "autosusp", do_autosusptest, "test out auto-suspend/resume", CONNECT },
86 { "camerainfo", do_camerainfo, "get camera info", CONNECT },
87 { "host_log", do_host_log, "dumps the MMAL VC log", CONNECT },
88 { "host_log_write", do_host_log_write, "appends a message to the MMAL VC log of host messages", CONNECT },
89 { NULL, NULL, NULL, 0},
90};
91
92static void do_connect(void)
93{
94 /* this command needs a vchiq connection */
95 MMAL_STATUS_T st;
96 if ((st = mmal_vc_init()) != MMAL_SUCCESS)
97 {
98 fprintf(stderr, "failed to initialize mmal vc library (%i:%s)\n",
99 st, mmal_status_to_string(st));
100 exit(1);
101 }
102}
103
104int main(int argc, const char **argv)
105{
106 int i;
107
108 if (argc < 2)
109 {
110 do_usage(argc, argv);
111 exit(1);
112 }
113
114 for (i = 0; cmds[i].name; i++)
115 {
116 if (strcasecmp(cmds[i].name, argv[1]) == 0)
117 {
118 int rc;
119 if (cmds[i].flags & CONNECT)
120 {
121 do_connect();
122 }
123 rc = cmds[i].pfn(argc, argv);
124
125 if (cmds[i].flags & CONNECT)
126 mmal_vc_deinit();
127 return rc;
128 }
129 }
130 fprintf(stderr,"unknown command %s\n", argv[1]);
131 return -1;
132}
133
134static int do_commands(int argc, const char **argv)
135{
136 int i = 0;
137 (void)argc; (void)argv;
138 while (cmds[i].name)
139 {
140 printf("%-20s %s\n", cmds[i].name, cmds[i].descr);
141 i++;
142 }
143 return 0;
144}
145
146static int do_create(int argc, const char **argv)
147{
148 MMAL_COMPONENT_T *comp;
149 MMAL_STATUS_T st;
150 if (argc != 3)
151 {
152 printf("usage: mmal-vc-diag create <name>\n");
153 printf(" e.g. vc.camera\n");
154 exit(1);
155 }
156 st = mmal_component_create(argv[2], &comp);
157 if (comp)
158 printf("Created component\n");
159 else
160 printf("Failed to create %s: %d\n", argv[2], st);
161
162 return 0;
163}
164
165static int do_version(int argc, const char **argv)
166{
167 uint32_t maj = UINT_MAX, min = UINT_MAX, minimum;
168 MMAL_STATUS_T st = mmal_vc_get_version(&maj, &min, &minimum);
169 (void)argc; (void)argv;
170 if (st == MMAL_SUCCESS)
171 {
172 printf("version %d.%02d (min %d)\n", maj, min, minimum);
173 return 0;
174 }
175 else
176 {
177 fprintf(stderr, "error getting version (%i:%s)\n", st, mmal_status_to_string(st));
178 return -1;
179 }
180}
181
182#define STATS_FIELD(x) { #x, offsetof(MMAL_VC_STATS_T, x) }
183
184static struct {
185 const char *name;
186 unsigned offset;
187} stats_fields [] = {
188 STATS_FIELD(buffers.rx),
189 STATS_FIELD(buffers.rx_zero_copy),
190 STATS_FIELD(buffers.rx_empty),
191 STATS_FIELD(buffers.rx_fails),
192 STATS_FIELD(buffers.tx),
193 STATS_FIELD(buffers.tx_zero_copy),
194 STATS_FIELD(buffers.tx_empty),
195 STATS_FIELD(buffers.tx_fails),
196 STATS_FIELD(buffers.tx_short_msg),
197 STATS_FIELD(buffers.rx_short_msg),
198 STATS_FIELD(service.created),
199 STATS_FIELD(service.pending_destroy),
200 STATS_FIELD(service.destroyed),
201 STATS_FIELD(service.failures),
202 STATS_FIELD(commands.bad_messages),
203 STATS_FIELD(commands.executed),
204 STATS_FIELD(commands.failed),
205 STATS_FIELD(commands.replies),
206 STATS_FIELD(commands.reply_fails),
207 STATS_FIELD(events.tx),
208 STATS_FIELD(events.tx_fails),
209 STATS_FIELD(worker.enqueued_messages),
210 STATS_FIELD(worker.dequeued_messages),
211 STATS_FIELD(worker.max_parameter_set_delay),
212 STATS_FIELD(worker.max_messages_waiting)
213};
214
215static int do_stats(int argc, const char **argv)
216{
217 MMAL_VC_STATS_T stats;
218 int reset_stats = strcasecmp(argv[1], "reset") == 0;
219 MMAL_STATUS_T st = mmal_vc_get_stats(&stats, reset_stats);
220 int ret;
221 (void)argc; (void)argv;
222 if (st != MMAL_SUCCESS)
223 {
224 fprintf(stderr, "error getting status (%i,%s)\n", st, mmal_status_to_string(st));
225 ret = -1;
226 }
227 else
228 {
229 unsigned i;
230 uint32_t *ptr = (uint32_t*)&stats;
231 for (i=0; i<vcos_countof(stats_fields); i++)
232 {
233 printf("%-32s: %u\n", stats_fields[i].name, ptr[stats_fields[i].offset/sizeof(uint32_t)]);
234 }
235 ret = 0;
236 }
237 return ret;
238}
239
240static int do_usage(int argc, const char **argv)
241{
242 const char *last_slash = strrchr(argv[0], '/');
243 const char *progname = last_slash ? last_slash+1:argv[0];
244 (void)argc;
245 printf("usage: %s [command [args]]\n", progname);
246 printf(" %s commands - list available commands\n", progname);
247 return 0;
248}
249
250/*
251 * Print out the event log
252 */
253
254struct event_handler
255{
256 MMAL_DBG_EVENT_TYPE_T type;
257 void (*handler)(MMAL_DBG_ENTRY_T *entry, char *, size_t);
258};
259
260static void on_openclose(MMAL_DBG_ENTRY_T *entry,
261 char *buf,
262 size_t buflen)
263{
264 switch (entry->event_type) {
265 case MMAL_DBG_OPENED: snprintf(buf,buflen,"opened"); break;
266 case MMAL_DBG_CLOSED: snprintf(buf,buflen,"closed"); break;
267 default: break;
268 }
269}
270
271static void on_bulk_ack(MMAL_DBG_ENTRY_T *entry,
272 char *buf,
273 size_t buflen)
274{
275 switch (entry->u.uint)
276 {
277 case VCHIQ_BULK_RECEIVE_ABORTED: snprintf(buf,buflen,"vchiq bulk rx abort"); break;
278 case VCHIQ_BULK_TRANSMIT_ABORTED: snprintf(buf,buflen,"vchiq bulk tx abort"); break;
279 case VCHIQ_BULK_TRANSMIT_DONE: snprintf(buf,buflen,"vchiq bulk tx done"); break;
280 case VCHIQ_BULK_RECEIVE_DONE: snprintf(buf,buflen,"vchiq bulk rx done"); break;
281 default: snprintf(buf,buflen,"vchiq unknown reason %d", entry->u.uint); break;
282 }
283}
284
285static void on_msg(MMAL_DBG_ENTRY_T *entry,
286 char *buf,
287 size_t buflen)
288{
289 uint32_t id = entry->u.msg.header.msgid;
290 snprintf(buf,buflen,"msgid %d (%s)", id, mmal_msgname(id));
291}
292
293static void on_bulk(MMAL_DBG_ENTRY_T *entry,
294 char *buf,
295 size_t buflen)
296{
297 const char *name = entry->event_type == MMAL_DBG_BULK_TX ? "tx" : "rx";
298 snprintf(buf,buflen,"bulk %s len %d", name, entry->u.bulk.len);
299}
300
301static struct event_handler handlers[] = {
302 { MMAL_DBG_OPENED, on_openclose },
303 { MMAL_DBG_CLOSED, on_openclose },
304 { MMAL_DBG_BULK_ACK, on_bulk_ack },
305 { MMAL_DBG_MSG, on_msg },
306 { MMAL_DBG_BULK_TX, on_bulk },
307 { MMAL_DBG_BULK_RX, on_bulk },
308};
309static int n_handlers = sizeof(handlers)/sizeof(handlers[0]);
310
311static void print_mmal_event_log(VC_MEM_ACCESS_HANDLE_T vc, MMAL_DBG_LOG_T *log)
312{
313 uint32_t i;
314 uint32_t n = vcos_min(log->num_entries, log->index);
315 uint32_t mask = log->num_entries-1;
316 uint32_t start = log->index < log->num_entries ?
317 0 : log->index & mask;
318 uint32_t last_t = 0;
319 (void)vc;
320
321 for (i=0; i<n; i++)
322 {
323 MMAL_DBG_ENTRY_T *e = &log->entries[(start+i) & mask];
324 char buf[256];
325 int j;
326 uint32_t t = e->time;
327 printf("[%08u]: ", t-last_t);
328 last_t = t;
329 for (j=0; j<n_handlers; j++)
330 {
331 if (handlers[j].type == e->event_type)
332 {
333 handlers[j].handler(e, buf, sizeof(buf));
334 printf("%s\n", buf);
335 break;
336 }
337 }
338 if (j == n_handlers )
339 printf("Unknown event type %d\n", e->event_type);
340 }
341}
342
343static int do_eventlog(int argc, const char **argv)
344{
345 VC_MEM_ACCESS_HANDLE_T vc;
346 VC_MEM_ADDR_T addr; /** The address of the pointer to the log */
347 size_t size;
348 VC_MEM_ADDR_T logaddr; /** The address of the log itself */
349 MMAL_DBG_LOG_T log;
350
351 (void)argc; (void)argv;
352 int rc;
353 if ((rc = OpenVideoCoreMemory(&vc)) < 0)
354 {
355 fprintf(stderr,"Unable to open videocore memory: %d\n", rc);
356 return -1;
357 }
358 if (!LookupVideoCoreSymbol(vc, "mmal_dbg_log", &addr, &size))
359 {
360 fprintf(stderr,"Could not get MMAL log address\n");
361 goto fail;
362 }
363 if (!ReadVideoCoreUInt32(vc, &logaddr, addr))
364 {
365 fprintf(stderr,"Could not read MMAL log pointer at address 0x%x\n",
366 addr);
367 goto fail;
368 }
369 if (!ReadVideoCoreMemory(vc, &log, logaddr, sizeof(log)))
370 {
371 fprintf(stderr,"Could not read MMAL log at address 0x%x\n",
372 logaddr);
373 goto fail;
374 }
375 if (log.magic != MMAL_MAGIC)
376 {
377 fprintf(stderr,"Bad magic 0x%08x in log at 0x%x\n", log.magic, logaddr);
378 goto fail;
379 }
380 if (log.size != sizeof(log))
381 {
382 fprintf(stderr,"MMAL Log size mismatch (got %d, expected %zu)\n",
383 log.size, sizeof(log));
384 goto fail;
385 }
386 if (log.elemsize != sizeof(MMAL_DBG_ENTRY_T))
387 {
388 fprintf(stderr,"MMAL log element size mismatch (got %d, expected %zu)\n",
389 log.elemsize, sizeof(MMAL_DBG_ENTRY_T));
390 goto fail;
391 }
392
393 printf("reading MMAL log at 0x%x version %d magic %x\n",
394 logaddr, log.version, log.magic);
395 printf("%d events, %d entries each size %d\n", log.index, log.num_entries,
396 log.elemsize);
397 print_mmal_event_log(vc, &log);
398
399 CloseVideoCoreMemory(vc);
400 return 0;
401fail:
402 CloseVideoCoreMemory(vc);
403 return -1;
404
405}
406
407static int print_component_stats(const MMAL_VC_STATS_T *stats)
408{
409 size_t i;
410 if (stats->components.list_size > 64)
411 {
412 fprintf(stderr,"component array looks corrupt (list size %d\n",
413 stats->components.list_size);
414 goto fail;
415 }
416 printf("%d created, %d destroyed (%d destroying), %d create failures\n",
417 stats->components.created,
418 stats->components.destroyed,
419 stats->components.destroying,
420 stats->components.failed);
421
422 for (i=0; i < stats->components.list_size; i++)
423 {
424 const struct MMAL_VC_COMP_STATS_T *cs = stats->components.component_list+i;
425 const char *state;
426 /* coverity[overrun-local] */
427 if (cs->state != MMAL_STATS_COMP_IDLE)
428 {
429 switch (cs->state)
430 {
431 case MMAL_STATS_COMP_CREATED: state = "created"; break;
432 case MMAL_STATS_COMP_DESTROYING: state = "destroying"; break;
433 case MMAL_STATS_COMP_DESTROYED: state = "destroyed"; break;
434 default: state = "corrupt"; break;
435 }
436 printf("%-32s: %s: pid %d address %p pool mem alloc size %d\n",
437 cs->name, state, cs->pid, cs->comp, cs->pool_mem_alloc_size);
438 }
439 }
440 return 0;
441fail:
442 return -1;
443}
444
445static int do_components(int argc, const char **argv)
446{
447 VC_MEM_ACCESS_HANDLE_T vc;
448 VC_MEM_ADDR_T addr, statsaddr;
449 size_t size;
450 MMAL_VC_STATS_T stats;
451 int rc;
452
453
454 if (argc > 2 && (strcasecmp(argv[2], "update") == 0))
455 {
456 MMAL_STATUS_T status;
457 do_connect();
458 status = mmal_vc_get_stats(&stats, 0);
459 if (status != MMAL_SUCCESS)
460 {
461 fprintf(stderr, "Failed to update MMAL stats. error %s",
462 mmal_status_to_string(status));
463 return -1;
464 }
465 }
466 else
467 {
468 if ((rc = OpenVideoCoreMemory(&vc)) < 0)
469 {
470 fprintf(stderr,"Unable to open videocore memory: %d\n", rc);
471 return -1;
472 }
473 if (!LookupVideoCoreSymbol(vc, "mmal_vc_stats", &addr, &size))
474 {
475 fprintf(stderr,"Could not get MMAL stats address\n");
476 goto fail;
477 }
478 if (!ReadVideoCoreUInt32(vc, &statsaddr, addr))
479 {
480 fprintf(stderr,"Could not read MMAL stats pointer at address 0x%x\n",
481 addr);
482 goto fail;
483 }
484 if (!ReadVideoCoreMemory(vc, &stats, statsaddr, sizeof(stats)))
485 {
486 fprintf(stderr,"Could not read MMAL stats at address 0x%x\n", addr);
487 goto fail;
488 }
489 CloseVideoCoreMemory(vc);
490 }
491 rc = print_component_stats(&stats);
492 return rc;
493
494fail:
495 CloseVideoCoreMemory(vc);
496 return -1;
497}
498
499static int do_mmal_stats(int argc, const char **argv)
500{
501 unsigned comp_index = 0;
502 MMAL_BOOL_T more_ports = MMAL_TRUE, reset = MMAL_FALSE;
503 unsigned port_index = 0;
504 MMAL_PORT_TYPE_T type = MMAL_PORT_TYPE_INPUT;
505
506 if (argc >= 3)
507 reset = strcasecmp(argv[2], "reset") == 0;
508
509 printf("component\t\tport\t\tbuffers\t\tfps\tdelay\n");
510 while (more_ports)
511 {
512 int dir;
513 const char *dirnames[] = {"rx","tx"};
514 MMAL_STATS_RESULT_T result;
515
516 for (dir = MMAL_CORE_STATS_RX; dir <= MMAL_CORE_STATS_TX; dir++)
517 {
518 double framerate;
519 MMAL_CORE_STATISTICS_T stats;
520 char name[32];
521 MMAL_STATUS_T status = mmal_vc_get_core_stats(&stats,
522 &result,
523 name, sizeof(name),
524 type,
525 comp_index,
526 port_index,
527 dir,
528 reset);
529 if (status != MMAL_SUCCESS)
530 {
531 fprintf(stderr, "could not get core stats: %s\n",
532 mmal_status_to_string(status));
533 exit(1);
534 }
535
536 if (result == MMAL_STATS_FOUND)
537 {
538 if (stats.first_buffer_time == stats.last_buffer_time)
539 framerate = 0;
540 else
541 framerate = 1.0e6*(1+stats.buffer_count)/(stats.last_buffer_time-stats.first_buffer_time);
542
543 printf("%-20s\t%d [%s]%2s\t%-10d\t%4.1f\t%d\n",
544 name, port_index,
545 type == MMAL_PORT_TYPE_INPUT ? "in " : "out",
546 dirnames[dir],
547 stats.buffer_count, framerate, stats.max_delay);
548
549 }
550 }
551
552 switch (result)
553 {
554 case MMAL_STATS_FOUND:
555 port_index++;
556 break;
557
558 case MMAL_STATS_COMPONENT_NOT_FOUND:
559 more_ports = MMAL_FALSE;
560 break;
561
562 case MMAL_STATS_PORT_NOT_FOUND:
563 port_index = 0;
564 if (type == MMAL_PORT_TYPE_INPUT)
565 {
566 type = MMAL_PORT_TYPE_OUTPUT;
567 }
568 else
569 {
570 type = MMAL_PORT_TYPE_INPUT;
571 comp_index++;
572 }
573 break;
574 default:
575 fprintf(stderr, "bad result from query: %d\n", result);
576 vcos_assert(0);
577 exit(1);
578 }
579 }
580 return 0;
581}
582
583static int do_imageconv_stats(int argc, const char **argv)
584{
585 VC_MEM_ACCESS_HANDLE_T vc;
586 VC_MEM_ADDR_T addr, statsaddr;
587 size_t size;
588 IMAGECONV_STATS_T stats;
589 long convert_time;
590 double frame_rate;
591 int rc;
592 int reset_stats = 0;
593
594 if (argc > 2)
595 reset_stats = strcasecmp(argv[2], "reset") == 0;
596
597 if ((rc = OpenVideoCoreMemory(&vc)) < 0)
598 {
599 fprintf(stderr,"Unable to open videocore memory: %d\n", rc);
600 return -1;
601 }
602 if (!LookupVideoCoreSymbol(vc, "imageconv_stats", &addr, &size))
603 {
604 fprintf(stderr,"Could not get imageconv stats address\n");
605 goto fail;
606 }
607 if (!ReadVideoCoreUInt32(vc, &statsaddr, addr))
608 {
609 fprintf(stderr, "Could not read imageconv stats address\n");
610 goto fail;
611 }
612
613 if (reset_stats)
614 {
615 memset(&stats, 0, sizeof(stats));
616 stats.magic = IMAGECONV_STATS_MAGIC;
617 if (!WriteVideoCoreMemory(vc, &stats, statsaddr, sizeof(stats)))
618 {
619 fprintf(stderr, "Could not write stats at 0x%x\n", statsaddr);
620 goto fail;
621 }
622 }
623
624 if (!ReadVideoCoreMemory(vc, &stats, statsaddr, sizeof(stats)))
625 {
626 fprintf(stderr, "Could not read stats at 0x%x\n", statsaddr);
627 goto fail;
628 }
629
630 if (stats.magic != IMAGECONV_STATS_MAGIC)
631 {
632 fprintf(stderr, "Bad magic 0x%x\n", stats.magic);
633 goto fail;
634 }
635
636 if (stats.conversions)
637 convert_time = stats.time_spent / stats.conversions;
638 else
639 convert_time = 0;
640
641 if (stats.conversions)
642 frame_rate = 1000000.0 * stats.conversions /
643 (stats.last_image_ts - stats.first_image_ts);
644 else
645 frame_rate = 0;
646
647 printf("%-25s:\t%d\n", "conversions", stats.conversions);
648 printf("%-25s:\t%d\n", "size requests", stats.size_requests);
649 printf("%-25s:\t%d\n", "max vrf delay", stats.max_vrf_delay);
650 printf("%-25s:\t%d\n", "vrf wait time", stats.vrf_wait_time);
651 printf("%-25s:\t%d\n", "duplicate conversions", stats.duplicate_conversions);
652 printf("%-25s:\t%d\n", "failures", stats.failures);
653 printf("%-25s:\t%ld\n", "convert time / image (us)", convert_time);
654 printf("%-25s:\t%.1f\n", "client frame_rate", frame_rate);
655 printf("%-25s:\t%d us\n", "max delay to consume", stats.max_delay);
656
657 CloseVideoCoreMemory(vc);
658 return 0;
659fail:
660 CloseVideoCoreMemory(vc);
661 return -1;
662
663}
664
665static int do_compact(int argc, const char **argv)
666{
667 uint32_t duration;
668
669 if (argc > 2)
670 {
671 if (strcmp(argv[2], "a") == 0)
672 {
673 mmal_vc_compact(MMAL_VC_COMPACT_AGGRESSIVE, &duration);
674 printf("Triggered aggressive compaction on VC - duration %u us.\n", duration);
675 }
676 else if (strcmp(argv[2], "d") == 0)
677 {
678 mmal_vc_compact(MMAL_VC_COMPACT_DISCARD, &duration);
679 printf("Triggered discard compaction on VC - duration %u us.\n", duration);
680 }
681 else if (strcmp(argv[2], "n") == 0)
682 {
683 mmal_vc_compact(MMAL_VC_COMPACT_NORMAL, &duration);
684 printf("Triggered normal compaction on VC - duration %u us.\n", duration);
685 }
686 else
687 {
688 printf("Invalid memory compaction option %s\n.", argv[2]);
689 exit(1);
690 }
691 }
692 else
693 {
694 printf("Invalid memory compaction arguments. Need to specify 'a', 'n' or 't'.\n");
695 exit(1);
696 }
697 return 0;
698}
699
700/* Autosuspend test. Create a component, but kill process
701 * shortly after startup.
702 */
703
704static int autosusp_signal;
705
706static void autosusp_timeout_handler(int cause, siginfo_t *how, void *ucontext)
707{
708 (void)how; (void)ucontext; (void)cause;
709 printf("Sending signal %d\n", autosusp_signal);
710 kill(getpid(), autosusp_signal);
711}
712
713static int do_autosusptest(int argc, const char **argv)
714{
715 long timeout;
716 struct timeval interval;
717 MMAL_STATUS_T status;
718
719 if (argc != 4)
720 {
721 printf("usage: %s autosusp <timeout-ms> <signal>\n",
722 argv[0]);
723 printf(" e.g. 650 9\n");
724 exit(1);
725 }
726 timeout = 1000 * atoi(argv[2]);
727 autosusp_signal = atoi(argv[3]);
728
729 if ((status=mmal_vc_use()) != MMAL_SUCCESS)
730 {
731 fprintf(stderr,"mmal_vc_use failed: %d\n", status);
732 exit(1);
733 }
734
735 /* install a signal handler for the alarm */
736 struct sigaction sa;
737 memset(&sa, 0, sizeof(struct sigaction));
738 sa.sa_sigaction = autosusp_timeout_handler;
739 sigemptyset(&sa.sa_mask);
740 sa.sa_flags = SA_SIGINFO;
741 if (sigaction(SIGALRM, &sa, 0))
742 {
743 perror("sigaction");
744 exit(1);
745 }
746
747 /* when to expire */
748 interval.tv_sec = timeout / 1000000;
749 interval.tv_usec = timeout % 1000000;
750
751 struct itimerval alarm_spec = {
752 .it_interval = {0,0},
753 .it_value = interval
754 };
755
756 int rc = setitimer(ITIMER_REAL, &alarm_spec, NULL);
757 if (rc < 0)
758 {
759 perror("setitimer failed");
760 exit(1);
761 }
762
763 usleep(timeout + 1000000);
764 printf("%s: not killed by timer\n", argv[0]);
765 mmal_vc_release();
766
767 return 0;
768}
769
770static int do_camerainfo(int argc, const char **argv)
771{
772 MMAL_COMPONENT_T *comp;
773 MMAL_STATUS_T st;
774 MMAL_PARAMETER_CAMERA_INFO_T mmal_camera_config_info;
775 unsigned i;
776 (void)argc;
777 (void)argv;
778
779 st = mmal_component_create("vc.camera_info", &comp);
780 if (st != MMAL_SUCCESS)
781 {
782 fprintf(stderr, "Failed to create camera_info: %d\n", st);
783 exit(1);
784 }
785
786 mmal_camera_config_info.hdr.id = MMAL_PARAMETER_CAMERA_INFO;
787 mmal_camera_config_info.hdr.size = sizeof(mmal_camera_config_info);
788 st = mmal_port_parameter_get(comp->control, &mmal_camera_config_info.hdr);
789 if (st != MMAL_SUCCESS)
790 {
791 fprintf(stderr, "%s: get param failed:%d", __FUNCTION__, st);
792 exit(1);
793 }
794
795 printf("cameras : %d\n", mmal_camera_config_info.num_cameras);
796 printf("flashes : %d\n", mmal_camera_config_info.num_flashes);
797
798 for (i=0; i<mmal_camera_config_info.num_cameras; i++)
799 {
800 printf("camera %u : port %u: %u x %u lens %s\n",
801 i,
802 mmal_camera_config_info.cameras[i].port_id,
803 mmal_camera_config_info.cameras[i].max_width,
804 mmal_camera_config_info.cameras[i].max_height,
805 mmal_camera_config_info.cameras[i].lens_present ? "present" : "absent");
806 }
807 for (i=0; i<mmal_camera_config_info.num_flashes; i++)
808 {
809 const char *flash_type;
810 switch (mmal_camera_config_info.flashes[i].flash_type)
811 {
812 case MMAL_PARAMETER_CAMERA_INFO_FLASH_TYPE_XENON:
813 flash_type = "Xenon";
814 break;
815 case MMAL_PARAMETER_CAMERA_INFO_FLASH_TYPE_LED:
816 flash_type = "LED";
817 break;
818 case MMAL_PARAMETER_CAMERA_INFO_FLASH_TYPE_OTHER:
819 flash_type = "Other";
820 break;
821 default:
822 flash_type = "invalid";
823 }
824 printf("flash %u : flash type %s\n", i, flash_type);
825 }
826 mmal_component_destroy(comp);
827 return 0;
828}
829
830static int do_host_log(int argc, const char **argv)
831{
832 VC_MEM_ACCESS_HANDLE_T vc;
833 VC_MEM_ADDR_T log_addr;
834 MMAL_VC_HOST_LOG_T log;
835 const char *msg = &log.buffer[0];
836 const char *log_end = &log.buffer[sizeof(log.buffer)];
837 int rc;
838
839 (void) argc;
840 (void) argv;
841
842 if ((rc = OpenVideoCoreMemory(&vc)) < 0)
843 {
844 fprintf(stderr,"Unable to open videocore memory: %d\n", rc);
845 return -1;
846 }
847 if (!ReadVideoCoreUInt32BySymbol(vc, "mmal_host_log", &log_addr))
848 {
849 fprintf(stderr, "Could not read mmal_host_log address\n");
850 goto fail;
851 }
852 if (!ReadVideoCoreMemory(vc, &log, log_addr, sizeof(log)))
853 {
854 fprintf(stderr, "Could not read log at 0x%x\n", log_addr);
855 goto fail;
856 }
857
858 while (msg < log_end)
859 {
860 if (*msg)
861 msg += printf("%s", msg);
862
863 /* Skip multiple null characters */
864 while (msg < log_end && *msg == 0) ++msg;
865 }
866
867 CloseVideoCoreMemory(vc);
868 return 0;
869
870fail:
871 CloseVideoCoreMemory(vc);
872 return -1;
873}
874
875static int do_host_log_write(int argc, const char **argv)
876{
877 if (argc > 2)
878 mmal_vc_host_log(argv[2]);
879 return 0;
880}
881