This is an automatic generated email to let you know that the following patch were queued at the http://git.linuxtv.org/cgit.cgi/v4l-utils.git tree:
Subject: cec-ctl: add --test-power-cycle option Author: Hans Verkuil <hverkuil-ci...@xs4all.nl> Date: Thu Jun 20 14:22:33 2019 +0200 Add the new --test-power-cycle option: this will test how well a display supports the Standby and Image View On messages. This is the first version, and it is likely to be improved going forward. Also improved the --stress-test-power-cycle option: it is now possible to provide a max-sleep suboption to have the test sleep for a random time from 0 to max-sleep seconds before transmitting Standby or Image View On. This will randomize the timings. Signed-off-by: Hans Verkuil <hverkuil-ci...@xs4all.nl> utils/cec-ctl/cec-ctl.1.in | 9 +- utils/cec-ctl/cec-ctl.cpp | 205 ++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 192 insertions(+), 22 deletions(-) --- http://git.linuxtv.org/cgit.cgi/v4l-utils.git/commit/?id=070a4d421778c313f79d840bf400a7d60dfe7dc9 diff --git a/utils/cec-ctl/cec-ctl.1.in b/utils/cec-ctl/cec-ctl.1.in index 22cad7bf8b38..e44ae6829dd5 100644 --- a/utils/cec-ctl/cec-ctl.1.in +++ b/utils/cec-ctl/cec-ctl.1.in @@ -244,9 +244,14 @@ via the \fB\-\-analyze\-pin\fR option. Use \- to write to stdout instead of to a Read and analyze the CEC pin events from the given file. Use \- to read from stdin instead of from a file. .TP -\fB\-\-stress\-test\-power\-cycle\fR \fI<count>\fR -This option performs a stress test for a display: it powercycles the display \fI<count>\fR +\fB\-\-test\-power\-cycle\fR +This option tests the power cycle behavior of the display. +.TP +\fB\-\-stress\-test\-power\-cycle\fR \fIcnt\fR=\fI<count>\fR \fImax-sleep\fR=\fI<secs>\fR +This option performs a stress test for a display: it power cycles the display \fI<count>\fR times using the CEC Standby and Image View On commands. If \fI<count>\fR is 0, then never stop. +If \fI<secs>\fR is non-zero (0 is the default), then sleep for a random number of seconds +between 0 and \fI<secs>\fR before each Standby or Image View On message. .TP \fB\-\-help\-all\fR Prints the help message for all options. diff --git a/utils/cec-ctl/cec-ctl.cpp b/utils/cec-ctl/cec-ctl.cpp index c15605ef240f..0b262409e99d 100644 --- a/utils/cec-ctl/cec-ctl.cpp +++ b/utils/cec-ctl/cec-ctl.cpp @@ -646,6 +646,7 @@ enum Option { OptFeatSinkHasARCTx, OptFeatSourceHasARCRx, OptStressTestPowerCycle, + OptTestPowerCycle, OptVendorCommand = 508, OptVendorCommandWithID, OptVendorRemoteButtonDown, @@ -748,6 +749,7 @@ static struct option long_options[] = { { "vendor-command", required_argument, 0, OptVendorCommand }, \ { "custom-command", required_argument, 0, OptCustomCommand }, \ + { "test-power-cycle", no_argument, 0, OptTestPowerCycle }, \ { "stress-test-power-cycle", required_argument, 0, OptStressTestPowerCycle }, \ { 0, 0, 0, 0 } @@ -830,8 +832,12 @@ static void usage(void) " Use - for stdout.\n" " --analyze-pin <from> Analyze the low-level CEC pin changes from the file <from>.\n" " Use - for stdin.\n" - " --stress-test-power-cycle <count>\n" - " Powercycle display <count> times. If 0, then never stop.\n" + " --test-power-cycle Test power cycle behavior of the display.\n" + " --stress-test-power-cycle cnt=<count>[,max-sleep=<secs>]\n" + " Power cycle display <count> times. If 0, then never stop.\n" + " If <secs> is non-zero (0 is the default), then sleep for\n" + " a random number of seconds between 0 and <secs> before\n" + " each Standby or Image View On message.\n" "\n" CEC_USAGE "\n" @@ -1620,7 +1626,7 @@ err: exit(1); } -static bool wait_for_pwr_state(struct node &node, unsigned from, bool on) +static bool wait_for_pwr_state(struct node &node, unsigned from, bool on, unsigned &no_reply) { struct cec_msg msg; __u8 pwr; @@ -1639,26 +1645,147 @@ static bool wait_for_pwr_state(struct node &node, unsigned from, bool on) if (msg.rx_status & CEC_RX_STATUS_OK) { cec_ops_report_power_status(&msg, &pwr); return pwr == (on ? CEC_OP_POWER_STATUS_ON : CEC_OP_POWER_STATUS_STANDBY); + } else { + no_reply++; } return !on; } -static void stress_test_power_cycle(struct node &node, unsigned from, unsigned cnt) +static void test_power_cycle(struct node &node, unsigned from) +{ + struct cec_msg msg; + unsigned tries; + unsigned no_reply; + __u8 wakeup_la; + int ret; + + struct cec_log_addrs laddrs = { }; + doioctl(&node, CEC_ADAP_G_LOG_ADDRS, &laddrs); + from = laddrs.log_addr[0] & 0xf; + + if (!laddrs.num_log_addrs) { + fprintf(stderr, "Adapter is unconfigured, cannot perform test\n"); + return; + } + if (!laddrs.log_addr_mask) { + printf("No Logical Addresses claimed, assume TV is in Standby\n"); + } else { + printf("Transmit Standby to TV\n"); + cec_msg_init(&msg, from, CEC_LOG_ADDR_TV); + cec_msg_standby(&msg); + ret = doioctl(&node, CEC_TRANSMIT, &msg); + if (ret) { + fprintf(stderr, "Standby Transmit failed: %s\n", strerror(ret)); + exit(1); + } + + tries = no_reply = 0; + while (!wait_for_pwr_state(node, from, false, no_reply)) { + sleep(1); + if (++tries > 60) { + fprintf(stderr, "Could not put display in standby\n"); + exit(1); + } + } + } + + for (unsigned iter = 0; iter <= 21; iter++) { + doioctl(&node, CEC_ADAP_G_LOG_ADDRS, &laddrs); + if (laddrs.num_log_addrs) + wakeup_la = from; + else + wakeup_la = CEC_LOG_ADDR_UNREGISTERED; + cec_msg_init(&msg, wakeup_la, CEC_LOG_ADDR_TV); + cec_msg_image_view_on(&msg); + ret = doioctl(&node, CEC_TRANSMIT, &msg); + if (ret) { + fprintf(stderr, "Image View On from Unregistered failed: %s\n", strerror(ret)); + exit(1); + } + tries = no_reply = 0; + while (!wait_for_pwr_state(node, from, true, no_reply)) { + sleep(1); + if (++tries > 60) + break; + } + + if (tries > 60 && wakeup_la == CEC_LOG_ADDR_UNREGISTERED) { + wakeup_la = from; + cec_msg_init(&msg, wakeup_la, CEC_LOG_ADDR_TV); + cec_msg_image_view_on(&msg); + ret = doioctl(&node, CEC_TRANSMIT, &msg); + if (ret) { + fprintf(stderr, "Image View On from %s failed: %s\n", + la2s(wakeup_la), strerror(ret)); + exit(1); + } + tries = no_reply = 0; + while (!wait_for_pwr_state(node, from, true, no_reply)) { + sleep(1); + if (++tries > 60) { + fprintf(stderr, "Unable to wake up TV\n"); + exit(1); + } + } + } + printf("Woke up TV after %d seconds using Image View On from LA %s", + tries, la2s(wakeup_la)); + if (no_reply) + printf(" (%d Give Device Power Status messages ignored", no_reply); + printf("\n"); + + doioctl(&node, CEC_ADAP_G_LOG_ADDRS, &laddrs); + from = laddrs.log_addr[0] & 0xf; + + cec_msg_init(&msg, from, CEC_LOG_ADDR_TV); + cec_msg_standby(&msg); + ret = doioctl(&node, CEC_TRANSMIT, &msg); + if (ret) { + fprintf(stderr, "Standby Transmit failed: %s\n", strerror(ret)); + exit(1); + } + + tries = no_reply = 0; + while (!wait_for_pwr_state(node, from, false, no_reply)) { + sleep(1); + if (++tries > 60) { + fprintf(stderr, "Could not put display in standby\n"); + exit(1); + } + } + printf("Put TV in Standby after %d seconds from LA %s", + tries, la2s(from)); + if (no_reply) + printf(" (%d Give Device Power Status messages ignored", no_reply); + printf("\n"); + unsigned secs = iter <= 10 ? iter : 10 + 10 * (iter - 10); + printf("Sleep %d seconds\n", secs); + sleep(secs); + } +} + +static void stress_test_power_cycle(struct node &node, unsigned from, + unsigned cnt, unsigned max_sleep) { struct cec_msg msg; unsigned tries = 0; unsigned iter = 0; + unsigned no_reply = 0; + unsigned mod_usleep = 0; int ret; + if (max_sleep) + mod_usleep = 1000000 * max_sleep + 1; + if (from == CEC_LOG_ADDR_UNREGISTERED) from = CEC_LOG_ADDR_PLAYBACK_1; - while (!wait_for_pwr_state(node, from, true)) { - if (++tries > 10) { + while (!wait_for_pwr_state(node, from, true, no_reply)) { + if (++tries > 50) { fprintf(stderr, "Could not wake up display\n"); exit(1); } - sleep(5); + sleep(1); cec_msg_init(&msg, from, CEC_LOG_ADDR_TV); cec_msg_image_view_on(&msg); ret = doioctl(&node, CEC_TRANSMIT, &msg); @@ -1673,9 +1800,19 @@ static void stress_test_power_cycle(struct node &node, unsigned from, unsigned c from = laddrs.log_addr[0] & 0xf; for (;;) { + unsigned usecs1 = mod_usleep ? random() % mod_usleep : 0; + unsigned usecs2 = mod_usleep ? random() % mod_usleep : 0; + iter++; - printf("Transmit Standby (iteration %u)\n", iter); + if (mod_usleep) + printf("Sleep %.2fs, then transmit Standby ", usecs1 / 1000000.0); + else + printf("Transmit Standby "); + printf("(iteration %u)\n", iter); + + usleep(usecs1); + cec_msg_init(&msg, from, CEC_LOG_ADDR_BROADCAST); cec_msg_standby(&msg); ret = doioctl(&node, CEC_TRANSMIT, &msg); @@ -1684,23 +1821,29 @@ static void stress_test_power_cycle(struct node &node, unsigned from, unsigned c exit(1); } - tries = 0; - while (!wait_for_pwr_state(node, from, false)) { - sleep(5); - if (++tries > 10) { + tries = no_reply = 0; + while (!wait_for_pwr_state(node, from, false, no_reply)) { + sleep(1); + if (++tries > 50) { fprintf(stderr, "Could not put display in standby\n"); exit(1); } } + usleep(usecs2); + + if (mod_usleep) + printf("Sleep %.2fs, then transmit Image View On ", usecs2 / 1000000.0); + else + printf("Transmit Image View On "); + printf("(iteration %u)\n", iter); - printf("Transmit Image View On (iteration %u)\n", iter); - tries = 0; - while (!wait_for_pwr_state(node, from, true)) { - if (++tries > 10) { + tries = no_reply = 0; + while (!wait_for_pwr_state(node, from, true, no_reply)) { + if (++tries > 50) { fprintf(stderr, "Display is stuck in standby\n"); exit(1); } - sleep(5); + sleep(1); cec_msg_init(&msg, from, CEC_LOG_ADDR_TV); cec_msg_image_view_on(&msg); ret = doioctl(&node, CEC_TRANSMIT, &msg); @@ -1824,6 +1967,7 @@ int main(int argc, char **argv) __u32 monitor_time = 0; __u32 vendor_id = 0x000c03; /* HDMI LLC vendor ID */ unsigned int pwr_cycle_cnt = 0; + unsigned int max_sleep = 0; __u16 phys_addr; __u8 from = 0, to = 0, first_to = 0xff; __u8 dev_features = 0; @@ -2194,9 +2338,28 @@ int main(int argc, char **argv) list_devices(); break; - case OptStressTestPowerCycle: - pwr_cycle_cnt = strtoul(optarg, NULL, 0); + case OptStressTestPowerCycle: { + static const char *arg_names[] = { + "cnt", + "max-sleep", + NULL + }; + char *value, *subs = optarg; + + while (*subs != '\0') { + switch (parse_subopt(&subs, arg_names, &value)) { + case 0: + pwr_cycle_cnt = strtoul(value, 0L, 0); + break; + case 1: + max_sleep = strtoul(value, 0L, 0); + break; + default: + exit(1); + } + } break; + } default: if (ch >= OptHelpAll) { @@ -2536,8 +2699,10 @@ int main(int argc, char **argv) if (options[OptNonBlocking]) fcntl(node.fd, F_SETFL, fcntl(node.fd, F_GETFL) & ~O_NONBLOCK); + if (options[OptTestPowerCycle]) + test_power_cycle(node, from); if (options[OptStressTestPowerCycle]) - stress_test_power_cycle(node, from, pwr_cycle_cnt); + stress_test_power_cycle(node, from, pwr_cycle_cnt, max_sleep); skip_la: if (options[OptMonitor] || options[OptMonitorAll] || options[OptMonitorPin] || options[OptStorePin]) _______________________________________________ linuxtv-commits mailing list linuxtv-commits@linuxtv.org https://www.linuxtv.org/cgi-bin/mailman/listinfo/linuxtv-commits