1 | /* |
2 | Copyright (c) 2013, Broadcom Europe Ltd |
3 | All rights reserved. |
4 | |
5 | Redistribution and use in source and binary forms, with or without |
6 | modification, 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 | |
16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND |
17 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
18 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
19 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY |
20 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
21 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
22 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
23 | ON 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 |
25 | SOFTWARE, 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 | |
49 | struct 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 | |
58 | static int do_commands(int argc, const char **argv); |
59 | static int do_version(int argc, const char **argv); |
60 | static int do_stats(int argc, const char **argv); |
61 | static int do_usage(int argc, const char **argv); |
62 | static int do_create(int argc, const char **argv); |
63 | static int do_eventlog(int argc, const char **argv); |
64 | static int do_components(int argc, const char **argv); |
65 | static int do_mmal_stats(int argc, const char **argv); |
66 | static int do_imageconv_stats(int argc, const char **argv); |
67 | static int do_compact(int argc, const char **argv); |
68 | static int do_autosusptest(int argc, const char **argv); |
69 | static int do_camerainfo(int argc, const char **argv); |
70 | static int do_host_log(int argc, const char **argv); |
71 | static int do_host_log_write(int argc, const char **argv); |
72 | |
73 | static 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 | |
92 | static 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 | |
104 | int 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 | |
134 | static 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 | |
146 | static 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 | |
165 | static 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 | |
184 | static 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 | |
215 | static 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 | |
240 | static 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 | |
254 | struct event_handler |
255 | { |
256 | MMAL_DBG_EVENT_TYPE_T type; |
257 | void (*handler)(MMAL_DBG_ENTRY_T *entry, char *, size_t); |
258 | }; |
259 | |
260 | static 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 | |
271 | static 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 | |
285 | static 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 | |
293 | static 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 | |
301 | static 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 | }; |
309 | static int n_handlers = sizeof(handlers)/sizeof(handlers[0]); |
310 | |
311 | static 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 | |
343 | static 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; |
401 | fail: |
402 | CloseVideoCoreMemory(vc); |
403 | return -1; |
404 | |
405 | } |
406 | |
407 | static 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; |
441 | fail: |
442 | return -1; |
443 | } |
444 | |
445 | static 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 | |
494 | fail: |
495 | CloseVideoCoreMemory(vc); |
496 | return -1; |
497 | } |
498 | |
499 | static 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 | |
583 | static 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; |
659 | fail: |
660 | CloseVideoCoreMemory(vc); |
661 | return -1; |
662 | |
663 | } |
664 | |
665 | static 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 | |
704 | static int autosusp_signal; |
705 | |
706 | static 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 | |
713 | static 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 | |
770 | static 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 | |
830 | static 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 | |
870 | fail: |
871 | CloseVideoCoreMemory(vc); |
872 | return -1; |
873 | } |
874 | |
875 | static 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 | |