aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHans Verkuil <hverkuil-cisco@xs4all.nl>2021-07-13 10:04:15 +0200
committerHans Verkuil <hverkuil-cisco@xs4all.nl>2021-07-13 10:04:15 +0200
commita4f2e3a6f306f0bef6664451b44d5a7a18b26803 (patch)
treef000cec5383ff017ec035dcc6aeb10f3258bd718
parent08bfcfc894ceba4c1f574c7eda59a74a1fb5b822 (diff)
downloadv4l-utils-a4f2e3a6f306f0bef6664451b44d5a7a18b26803.tar.gz
cec-compliance: add cec-test-tuner-record-timer.cpp
Split off the tuner, record and timer tests into a separate source since cec-test.cpp became a bit too big. Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
-rw-r--r--utils/cec-compliance/Makefile.am2
-rw-r--r--utils/cec-compliance/cec-compliance.h5
-rw-r--r--utils/cec-compliance/cec-test-tuner-record-timer.cpp1088
-rw-r--r--utils/cec-compliance/cec-test.cpp1071
4 files changed, 1094 insertions, 1072 deletions
diff --git a/utils/cec-compliance/Makefile.am b/utils/cec-compliance/Makefile.am
index 93c1b568..81a68370 100644
--- a/utils/cec-compliance/Makefile.am
+++ b/utils/cec-compliance/Makefile.am
@@ -1,7 +1,7 @@
bin_PROGRAMS = cec-compliance
man_MANS = cec-compliance.1
-cec_compliance_SOURCES = cec-compliance.cpp cec-compliance.h cec-test.cpp cec-test-adapter.cpp cec-test-audio.cpp cec-test-power.cpp cec-test-fuzzing.cpp
+cec_compliance_SOURCES = cec-compliance.cpp cec-compliance.h cec-test.cpp cec-test-adapter.cpp cec-test-audio.cpp cec-test-power.cpp cec-test-fuzzing.cpp cec-test-tuner-record-timer.cpp
cec_compliance_CPPFLAGS = -I$(top_srcdir)/utils/libcecutil $(GIT_SHA) $(GIT_COMMIT_CNT) $(GIT_COMMIT_DATE)
cec_compliance_LDADD = -lrt ../libcecutil/libcecutil.la
diff --git a/utils/cec-compliance/cec-compliance.h b/utils/cec-compliance/cec-compliance.h
index efc828ce..08365e07 100644
--- a/utils/cec-compliance/cec-compliance.h
+++ b/utils/cec-compliance/cec-compliance.h
@@ -457,6 +457,11 @@ int setExpectedResult(char *optarg, bool no_warnings);
void testRemote(struct node *node, unsigned me, unsigned la, unsigned test_tags,
bool interactive);
+// cec-test-tuner-record-timer.cpp
+extern const vec_remote_subtests tuner_ctl_subtests;
+extern const vec_remote_subtests one_touch_rec_subtests;
+extern const vec_remote_subtests timer_prog_subtests;
+
// cec-test-audio.cpp
extern const vec_remote_subtests sac_subtests;
extern const vec_remote_subtests dal_subtests;
diff --git a/utils/cec-compliance/cec-test-tuner-record-timer.cpp b/utils/cec-compliance/cec-test-tuner-record-timer.cpp
new file mode 100644
index 00000000..1ba5a135
--- /dev/null
+++ b/utils/cec-compliance/cec-test-tuner-record-timer.cpp
@@ -0,0 +1,1088 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright 2016 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ */
+
+#include <cstring>
+#include <map>
+#include <sstream>
+#include <vector>
+
+#include <sys/ioctl.h>
+#include <unistd.h>
+
+#include "cec-compliance.h"
+
+enum Months { Jan = 1, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec };
+
+/* Tuner Control */
+
+static const char *bcast_type2s(__u8 bcast_type)
+{
+ switch (bcast_type) {
+ case CEC_OP_ANA_BCAST_TYPE_CABLE:
+ return "Cable";
+ case CEC_OP_ANA_BCAST_TYPE_SATELLITE:
+ return "Satellite";
+ case CEC_OP_ANA_BCAST_TYPE_TERRESTRIAL:
+ return "Terrestrial";
+ default:
+ return "Future use";
+ }
+}
+
+static int log_tuner_service(const struct cec_op_tuner_device_info &info,
+ const char *prefix = "")
+{
+ printf("\t\t%s", prefix);
+
+ if (info.is_analog) {
+ double freq_mhz = (info.analog.ana_freq * 625) / 10000.0;
+
+ printf("Analog Channel %.2f MHz (%s, %s)\n", freq_mhz,
+ bcast_system2s(info.analog.bcast_system),
+ bcast_type2s(info.analog.ana_bcast_type));
+
+ switch (info.analog.bcast_system) {
+ case CEC_OP_BCAST_SYSTEM_PAL_BG:
+ case CEC_OP_BCAST_SYSTEM_SECAM_LQ:
+ case CEC_OP_BCAST_SYSTEM_PAL_M:
+ case CEC_OP_BCAST_SYSTEM_NTSC_M:
+ case CEC_OP_BCAST_SYSTEM_PAL_I:
+ case CEC_OP_BCAST_SYSTEM_SECAM_DK:
+ case CEC_OP_BCAST_SYSTEM_SECAM_BG:
+ case CEC_OP_BCAST_SYSTEM_SECAM_L:
+ case CEC_OP_BCAST_SYSTEM_PAL_DK:
+ break;
+ default:
+ return fail("invalid analog bcast_system %u", info.analog.bcast_system);
+ }
+ if (info.analog.ana_bcast_type > CEC_OP_ANA_BCAST_TYPE_TERRESTRIAL)
+ return fail("invalid analog bcast_type %u\n", info.analog.ana_bcast_type);
+ fail_on_test(!info.analog.ana_freq);
+ return 0;
+ }
+
+ __u8 system = info.digital.dig_bcast_system;
+
+ printf("%s Channel ", dig_bcast_system2s(system));
+ if (info.digital.service_id_method) {
+ __u16 major = info.digital.channel.major;
+ __u16 minor = info.digital.channel.minor;
+
+ switch (info.digital.channel.channel_number_fmt) {
+ case CEC_OP_CHANNEL_NUMBER_FMT_2_PART:
+ printf("%u.%u\n", major, minor);
+ break;
+ case CEC_OP_CHANNEL_NUMBER_FMT_1_PART:
+ printf("%u\n", minor);
+ break;
+ default:
+ printf("%u.%u\n", major, minor);
+ return fail("invalid service ID method\n");
+ }
+ return 0;
+ }
+
+
+ switch (system) {
+ case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ARIB_GEN:
+ case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ARIB_BS:
+ case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ARIB_CS:
+ case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ARIB_T: {
+ __u16 tsid = info.digital.arib.transport_id;
+ __u16 sid = info.digital.arib.service_id;
+ __u16 onid = info.digital.arib.orig_network_id;
+
+ printf("TSID: %u, SID: %u, ONID: %u\n", tsid, sid, onid);
+ break;
+ }
+ case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ATSC_GEN:
+ case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ATSC_SAT:
+ case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ATSC_CABLE:
+ case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ATSC_T: {
+ __u16 tsid = info.digital.atsc.transport_id;
+ __u16 pn = info.digital.atsc.program_number;
+
+ printf("TSID: %u, Program Number: %u\n", tsid, pn);
+ break;
+ }
+ case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_DVB_GEN:
+ case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_DVB_S:
+ case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_DVB_S2:
+ case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_DVB_C:
+ case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_DVB_T: {
+ __u16 tsid = info.digital.dvb.transport_id;
+ __u16 sid = info.digital.dvb.service_id;
+ __u16 onid = info.digital.dvb.orig_network_id;
+
+ printf("TSID: %u, SID: %u, ONID: %u\n", tsid, sid, onid);
+ break;
+ }
+ default:
+ break;
+ }
+
+ switch (system) {
+ case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ARIB_GEN:
+ case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ATSC_GEN:
+ case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_DVB_GEN:
+ warn_once("generic digital broadcast systems should not be used");
+ break;
+ case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ARIB_BS:
+ case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ARIB_CS:
+ case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ARIB_T:
+ case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ATSC_CABLE:
+ case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ATSC_SAT:
+ case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ATSC_T:
+ case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_DVB_C:
+ case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_DVB_S:
+ case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_DVB_S2:
+ case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_DVB_T:
+ break;
+ default:
+ return fail("invalid digital broadcast system %u", system);
+ }
+
+ if (info.digital.service_id_method > CEC_OP_SERVICE_ID_METHOD_BY_CHANNEL)
+ return fail("invalid service ID method %u\n", info.digital.service_id_method);
+
+ return 0;
+}
+
+static int tuner_ctl_test(struct node *node, unsigned me, unsigned la, bool interactive)
+{
+ struct cec_msg msg;
+ struct cec_op_tuner_device_info info = {};
+ std::vector<struct cec_op_tuner_device_info> info_vec;
+ bool has_tuner = (1 << la) & (CEC_LOG_ADDR_MASK_TV | CEC_LOG_ADDR_MASK_TUNER);
+ int ret;
+
+ cec_msg_init(&msg, me, la);
+ cec_msg_give_tuner_device_status(&msg, true, CEC_OP_STATUS_REQ_ONCE);
+ fail_on_test(!transmit_timeout(node, &msg));
+ fail_on_test(!has_tuner && !timed_out_or_abort(&msg));
+ if (!has_tuner)
+ return OK_NOT_SUPPORTED;
+ if (timed_out(&msg) || unrecognized_op(&msg))
+ return OK_NOT_SUPPORTED;
+ if (cec_msg_status_is_abort(&msg))
+ return OK_REFUSED;
+
+ printf("\t Start Channel Scan\n");
+ cec_ops_tuner_device_status(&msg, &info);
+ info_vec.push_back(info);
+ ret = log_tuner_service(info);
+ if (ret)
+ return ret;
+
+ while (true) {
+ cec_msg_init(&msg, me, la);
+ cec_msg_tuner_step_increment(&msg);
+ fail_on_test(!transmit(node, &msg));
+ fail_on_test(cec_msg_status_is_abort(&msg));
+ if (cec_msg_status_is_abort(&msg)) {
+ fail_on_test(abort_reason(&msg) == CEC_OP_ABORT_UNRECOGNIZED_OP);
+ if (abort_reason(&msg) == CEC_OP_ABORT_REFUSED) {
+ warn("Tuner step increment does not wrap.\n");
+ break;
+ }
+
+ warn("Tuner at end of service list did not receive feature abort refused.\n");
+ break;
+ }
+ cec_msg_init(&msg, me, la);
+ cec_msg_give_tuner_device_status(&msg, true, CEC_OP_STATUS_REQ_ONCE);
+ fail_on_test(!transmit_timeout(node, &msg));
+ fail_on_test(timed_out_or_abort(&msg));
+ memset(&info, 0, sizeof(info));
+ cec_ops_tuner_device_status(&msg, &info);
+ if (!memcmp(&info, &info_vec[0], sizeof(info)))
+ break;
+ ret = log_tuner_service(info);
+ if (ret)
+ return ret;
+ info_vec.push_back(info);
+ }
+ printf("\t Finished Channel Scan\n");
+
+ printf("\t Start Channel Test\n");
+ for (const auto &iter : info_vec) {
+ cec_msg_init(&msg, me, la);
+ log_tuner_service(iter, "Select ");
+ if (iter.is_analog)
+ cec_msg_select_analogue_service(&msg, iter.analog.ana_bcast_type,
+ iter.analog.ana_freq, iter.analog.bcast_system);
+ else
+ cec_msg_select_digital_service(&msg, &iter.digital);
+ fail_on_test(!transmit(node, &msg));
+ fail_on_test(cec_msg_status_is_abort(&msg));
+ cec_msg_init(&msg, me, la);
+ cec_msg_give_tuner_device_status(&msg, true, CEC_OP_STATUS_REQ_ONCE);
+ fail_on_test(!transmit_timeout(node, &msg));
+ fail_on_test(timed_out_or_abort(&msg));
+ memset(&info, 0, sizeof(info));
+ cec_ops_tuner_device_status(&msg, &info);
+ if (memcmp(&info, &iter, sizeof(info))) {
+ log_tuner_service(info);
+ log_tuner_service(iter);
+ }
+ fail_on_test(memcmp(&info, &iter, sizeof(info)));
+ }
+ printf("\t Finished Channel Test\n");
+
+ cec_msg_init(&msg, me, la);
+ cec_msg_select_analogue_service(&msg, 3, 16000, 9);
+ printf("\t\tSelect invalid analog channel\n");
+ fail_on_test(!transmit_timeout(node, &msg));
+ fail_on_test(!cec_msg_status_is_abort(&msg));
+ fail_on_test(abort_reason(&msg) != CEC_OP_ABORT_INVALID_OP);
+ cec_msg_init(&msg, me, la);
+ info.digital.service_id_method = CEC_OP_SERVICE_ID_METHOD_BY_DIG_ID;
+ info.digital.dig_bcast_system = CEC_OP_DIG_SERVICE_BCAST_SYSTEM_DVB_S2;
+ info.digital.dvb.transport_id = 0;
+ info.digital.dvb.service_id = 0;
+ info.digital.dvb.orig_network_id = 0;
+ cec_msg_select_digital_service(&msg, &info.digital);
+ printf("\t\tSelect invalid digital channel\n");
+ fail_on_test(!transmit_timeout(node, &msg));
+ fail_on_test(!cec_msg_status_is_abort(&msg));
+ fail_on_test(abort_reason(&msg) != CEC_OP_ABORT_INVALID_OP);
+
+ return 0;
+}
+
+const vec_remote_subtests tuner_ctl_subtests{
+ { "Tuner Control", CEC_LOG_ADDR_MASK_TUNER | CEC_LOG_ADDR_MASK_TV, tuner_ctl_test },
+};
+
+/* One Touch Record */
+
+static int one_touch_rec_on_send(struct node *node, unsigned me, unsigned la,
+ const struct cec_op_record_src &rec_src, __u8 &rec_status)
+{
+ struct cec_msg msg;
+
+ cec_msg_init(&msg, me, la);
+ cec_msg_record_off(&msg, false);
+ fail_on_test(!transmit_timeout(node, &msg));
+
+ cec_msg_init(&msg, me, la);
+ cec_msg_record_on(&msg, true, &rec_src);
+ /* Allow 10s for reply because the spec says it may take several seconds to accurately respond. */
+ fail_on_test(!transmit_timeout(node, &msg, 10000));
+ fail_on_test(timed_out_or_abort(&msg));
+ cec_ops_record_status(&msg, &rec_status);
+
+ return OK;
+}
+
+static int one_touch_rec_on_send_invalid(struct node *node, unsigned me, unsigned la,
+ const struct cec_op_record_src &rec_src)
+{
+ struct cec_msg msg;
+
+ cec_msg_init(&msg, me, la);
+ cec_msg_record_on(&msg, true, &rec_src);
+ fail_on_test(!transmit_timeout(node, &msg));
+ fail_on_test(!cec_msg_status_is_abort(&msg));
+ fail_on_test(abort_reason(&msg) != CEC_OP_ABORT_INVALID_OP);
+
+ return OK;
+}
+
+/*
+ * Returns true if the Record Status is an error indicating that the
+ * request to start recording has failed.
+ */
+static bool rec_status_is_a_valid_error_status(__u8 rec_status)
+{
+ switch (rec_status) {
+ case CEC_OP_RECORD_STATUS_NO_DIG_SERVICE:
+ case CEC_OP_RECORD_STATUS_NO_ANA_SERVICE:
+ case CEC_OP_RECORD_STATUS_NO_SERVICE:
+ case CEC_OP_RECORD_STATUS_INVALID_EXT_PLUG:
+ case CEC_OP_RECORD_STATUS_INVALID_EXT_PHYS_ADDR:
+ case CEC_OP_RECORD_STATUS_UNSUP_CA:
+ case CEC_OP_RECORD_STATUS_NO_CA_ENTITLEMENTS:
+ case CEC_OP_RECORD_STATUS_CANT_COPY_SRC:
+ case CEC_OP_RECORD_STATUS_NO_MORE_COPIES:
+ case CEC_OP_RECORD_STATUS_NO_MEDIA:
+ case CEC_OP_RECORD_STATUS_PLAYING:
+ case CEC_OP_RECORD_STATUS_ALREADY_RECORDING:
+ case CEC_OP_RECORD_STATUS_MEDIA_PROT:
+ case CEC_OP_RECORD_STATUS_NO_SIGNAL:
+ case CEC_OP_RECORD_STATUS_MEDIA_PROBLEM:
+ case CEC_OP_RECORD_STATUS_NO_SPACE:
+ case CEC_OP_RECORD_STATUS_PARENTAL_LOCK:
+ case CEC_OP_RECORD_STATUS_OTHER:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static int one_touch_rec_tv_screen(struct node *node, unsigned me, unsigned la, bool interactive)
+{
+ struct cec_msg msg;
+
+ cec_msg_init(&msg, me, la);
+ cec_msg_record_tv_screen(&msg, true);
+ fail_on_test(!transmit_timeout(node, &msg));
+ fail_on_test_v2(node->remote[la].cec_version,
+ node->remote[la].has_rec_tv && unrecognized_op(&msg));
+ fail_on_test_v2(node->remote[la].cec_version,
+ !node->remote[la].has_rec_tv && !unrecognized_op(&msg));
+ if (unrecognized_op(&msg))
+ return OK_NOT_SUPPORTED;
+ if (refused(&msg))
+ return OK_REFUSED;
+ if (cec_msg_status_is_abort(&msg))
+ return OK_PRESUMED;
+ /* Follower should ignore this message if it is not sent by a recording device */
+ if (node->prim_devtype != CEC_OP_PRIM_DEVTYPE_RECORD) {
+ fail_on_test(!timed_out(&msg));
+ return OK;
+ }
+ fail_on_test(timed_out(&msg));
+
+ struct cec_op_record_src rec_src = {};
+
+ cec_ops_record_on(&msg, &rec_src);
+
+ fail_on_test(rec_src.type < CEC_OP_RECORD_SRC_OWN ||
+ rec_src.type > CEC_OP_RECORD_SRC_EXT_PHYS_ADDR);
+
+ if (rec_src.type == CEC_OP_RECORD_SRC_DIGITAL) {
+ switch (rec_src.digital.dig_bcast_system) {
+ case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ARIB_GEN:
+ case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ATSC_GEN:
+ case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_DVB_GEN:
+ case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ARIB_BS:
+ case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ARIB_CS:
+ case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ARIB_T:
+ case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ATSC_CABLE:
+ case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ATSC_SAT:
+ case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ATSC_T:
+ case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_DVB_C:
+ case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_DVB_S:
+ case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_DVB_S2:
+ case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_DVB_T:
+ break;
+ default:
+ return fail("Invalid digital service broadcast system operand.\n");
+ }
+
+ if (rec_src.digital.service_id_method == CEC_OP_SERVICE_ID_METHOD_BY_CHANNEL)
+ fail_on_test(rec_src.digital.channel.channel_number_fmt < CEC_OP_CHANNEL_NUMBER_FMT_1_PART ||
+ rec_src.digital.channel.channel_number_fmt > CEC_OP_CHANNEL_NUMBER_FMT_2_PART);
+ }
+
+ if (rec_src.type == CEC_OP_RECORD_SRC_ANALOG) {
+ fail_on_test(rec_src.analog.ana_bcast_type > CEC_OP_ANA_BCAST_TYPE_TERRESTRIAL);
+ fail_on_test(rec_src.analog.bcast_system > CEC_OP_BCAST_SYSTEM_PAL_DK &&
+ rec_src.analog.bcast_system != CEC_OP_BCAST_SYSTEM_OTHER);
+ fail_on_test(rec_src.analog.ana_freq == 0 || rec_src.analog.ana_freq == 0xffff);
+ }
+
+ if (rec_src.type == CEC_OP_RECORD_SRC_EXT_PLUG)
+ fail_on_test(rec_src.ext_plug.plug == 0);
+
+ return OK;
+}
+
+static int one_touch_rec_on(struct node *node, unsigned me, unsigned la, bool interactive)
+{
+ struct cec_msg msg;
+ struct cec_op_record_src rec_src = {};
+
+ rec_src.type = CEC_OP_RECORD_SRC_OWN;
+ cec_msg_init(&msg, me, la);
+ cec_msg_record_on(&msg, true, &rec_src);
+ /* Allow 10s for reply because the spec says it may take several seconds to accurately respond. */
+ fail_on_test(!transmit_timeout(node, &msg, 10000));
+ fail_on_test(timed_out(&msg));
+ if (unrecognized_op(&msg)) {
+ fail_on_test(node->remote[la].prim_type == CEC_OP_PRIM_DEVTYPE_RECORD);
+ return OK_NOT_SUPPORTED;
+ }
+ if (refused(&msg))
+ return OK_REFUSED;
+ if (cec_msg_status_is_abort(&msg))
+ return OK_PRESUMED;
+
+ __u8 rec_status;
+
+ cec_ops_record_status(&msg, &rec_status);
+ if (rec_status != CEC_OP_RECORD_STATUS_CUR_SRC)
+ fail_on_test(!rec_status_is_a_valid_error_status(rec_status));
+
+ /* In the following tests, these digital services are taken from the cec-follower tuner emulation. */
+ memset(&rec_src, 0, sizeof(rec_src));
+ rec_src.type = CEC_OP_RECORD_SRC_DIGITAL;
+ rec_src.digital.service_id_method = CEC_OP_SERVICE_ID_METHOD_BY_DIG_ID;
+ rec_src.digital.dig_bcast_system = CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ARIB_BS;
+ rec_src.digital.arib.transport_id = 1032;
+ rec_src.digital.arib.service_id = 30203;
+ rec_src.digital.arib.orig_network_id = 1;
+ fail_on_test(one_touch_rec_on_send(node, me, la, rec_src, rec_status));
+ if (rec_status != CEC_OP_RECORD_STATUS_DIG_SERVICE)
+ fail_on_test(!rec_status_is_a_valid_error_status(rec_status));
+
+ memset(&rec_src, 0, sizeof(rec_src));
+ rec_src.type = CEC_OP_RECORD_SRC_DIGITAL;
+ rec_src.digital.service_id_method = CEC_OP_SERVICE_ID_METHOD_BY_CHANNEL;
+ rec_src.digital.dig_bcast_system = CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ATSC_T;
+ rec_src.digital.channel.channel_number_fmt = CEC_OP_CHANNEL_NUMBER_FMT_2_PART;
+ rec_src.digital.channel.major = 4;
+ rec_src.digital.channel.minor = 1;
+ fail_on_test(one_touch_rec_on_send(node, me, la, rec_src, rec_status));
+ if (rec_status != CEC_OP_RECORD_STATUS_DIG_SERVICE)
+ fail_on_test(!rec_status_is_a_valid_error_status(rec_status));
+
+ memset(&rec_src, 0, sizeof(rec_src));
+ rec_src.type = CEC_OP_RECORD_SRC_DIGITAL;
+ rec_src.digital.service_id_method = CEC_OP_SERVICE_ID_METHOD_BY_DIG_ID;
+ rec_src.digital.dig_bcast_system = CEC_OP_DIG_SERVICE_BCAST_SYSTEM_DVB_T;
+ rec_src.digital.dvb.transport_id = 1004;
+ rec_src.digital.dvb.service_id = 1040;
+ rec_src.digital.dvb.orig_network_id = 8945;
+ fail_on_test(one_touch_rec_on_send(node, me, la, rec_src, rec_status));
+ if (rec_status != CEC_OP_RECORD_STATUS_DIG_SERVICE)
+ fail_on_test(!rec_status_is_a_valid_error_status(rec_status));
+
+ /* In the following tests, these channels taken from the cec-follower tuner emulation. */
+ memset(&rec_src, 0, sizeof(rec_src));
+ rec_src.type = CEC_OP_RECORD_STATUS_ANA_SERVICE;
+ rec_src.analog.ana_bcast_type = CEC_OP_ANA_BCAST_TYPE_CABLE;
+ rec_src.analog.ana_freq = (471250 * 10) / 625;
+ rec_src.analog.bcast_system = CEC_OP_BCAST_SYSTEM_PAL_BG;
+ fail_on_test(one_touch_rec_on_send(node, me, la, rec_src, rec_status));
+ if (rec_status != CEC_OP_RECORD_STATUS_ANA_SERVICE)
+ fail_on_test(!rec_status_is_a_valid_error_status(rec_status));
+
+ memset(&rec_src, 0, sizeof(rec_src));
+ rec_src.type = CEC_OP_RECORD_STATUS_ANA_SERVICE;
+ rec_src.analog.ana_bcast_type = CEC_OP_ANA_BCAST_TYPE_SATELLITE;
+ rec_src.analog.ana_freq = (551250 * 10) / 625;
+ rec_src.analog.bcast_system = CEC_OP_BCAST_SYSTEM_SECAM_BG;
+ fail_on_test(one_touch_rec_on_send(node, me, la, rec_src, rec_status));
+ if (rec_status != CEC_OP_RECORD_STATUS_ANA_SERVICE)
+ fail_on_test(!rec_status_is_a_valid_error_status(rec_status));
+
+ memset(&rec_src, 0, sizeof(rec_src));
+ rec_src.type = CEC_OP_RECORD_STATUS_ANA_SERVICE;
+ rec_src.analog.ana_bcast_type = CEC_OP_ANA_BCAST_TYPE_TERRESTRIAL;
+ rec_src.analog.ana_freq = (185250 * 10) / 625;
+ rec_src.analog.bcast_system = CEC_OP_BCAST_SYSTEM_PAL_DK;
+ fail_on_test(one_touch_rec_on_send(node, me, la, rec_src, rec_status));
+ if (rec_status != CEC_OP_RECORD_STATUS_ANA_SERVICE)
+ fail_on_test(!rec_status_is_a_valid_error_status(rec_status));
+
+ memset(&rec_src, 0, sizeof(rec_src));
+ rec_src.type = CEC_OP_RECORD_SRC_EXT_PLUG;
+ rec_src.ext_plug.plug = 1;
+ fail_on_test(one_touch_rec_on_send(node, me, la, rec_src, rec_status));
+ if (rec_status != CEC_OP_RECORD_STATUS_EXT_INPUT)
+ fail_on_test(!rec_status_is_a_valid_error_status(rec_status));
+
+ memset(&rec_src, 0, sizeof(rec_src));
+ rec_src.type = CEC_OP_RECORD_SRC_EXT_PHYS_ADDR;
+ fail_on_test(one_touch_rec_on_send(node, me, la, rec_src, rec_status));
+ if (rec_status != CEC_OP_RECORD_STATUS_EXT_INPUT)
+ fail_on_test(!rec_status_is_a_valid_error_status(rec_status));
+
+ return OK;
+}
+
+static int one_touch_rec_on_invalid(struct node *node, unsigned me, unsigned la, bool interactive)
+{
+ struct cec_msg msg;
+
+ cec_msg_init(&msg, me, la);
+ cec_msg_record_on_own(&msg);
+ msg.msg[2] = 0; /* Invalid source operand */
+ fail_on_test(!transmit_timeout(node, &msg));
+ if (unrecognized_op(&msg))
+ return OK_NOT_SUPPORTED;
+ fail_on_test(!cec_msg_status_is_abort(&msg));
+ fail_on_test(abort_reason(&msg) != CEC_OP_ABORT_INVALID_OP);
+
+ cec_msg_init(&msg, me, la);
+ cec_msg_record_on_own(&msg);
+ msg.msg[2] = 6; /* Invalid source operand */
+ fail_on_test(!transmit_timeout(node, &msg));
+ fail_on_test(!cec_msg_status_is_abort(&msg));
+ fail_on_test(abort_reason(&msg) != CEC_OP_ABORT_INVALID_OP);
+
+ struct cec_op_record_src rec_src = {};
+
+ rec_src.type = CEC_OP_RECORD_SRC_DIGITAL;
+ rec_src.digital.service_id_method = CEC_OP_SERVICE_ID_METHOD_BY_CHANNEL;
+ rec_src.digital.dig_bcast_system = 0x7f; /* Invalid digital service broadcast system operand */
+ rec_src.digital.channel.channel_number_fmt = CEC_OP_CHANNEL_NUMBER_FMT_1_PART;
+ rec_src.digital.channel.major = 0;
+ rec_src.digital.channel.minor = 30203;
+ fail_on_test(one_touch_rec_on_send_invalid(node, me, la, rec_src));
+
+ rec_src.type = CEC_OP_RECORD_SRC_DIGITAL;
+ rec_src.digital.service_id_method = CEC_OP_SERVICE_ID_METHOD_BY_CHANNEL;
+ rec_src.digital.dig_bcast_system = CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ARIB_BS;
+ rec_src.digital.channel.channel_number_fmt = 0; /* Invalid channel number format operand */
+ rec_src.digital.channel.major = 0;
+ rec_src.digital.channel.minor = 30609;
+ fail_on_test(one_touch_rec_on_send_invalid(node, me, la, rec_src));
+
+ memset(&rec_src, 0, sizeof(rec_src));
+ rec_src.type = CEC_OP_RECORD_SRC_ANALOG;
+ rec_src.analog.ana_bcast_type = 0xff; /* Invalid analog broadcast type */
+ rec_src.analog.ana_freq = (519250 * 10) / 625;
+ rec_src.analog.bcast_system = CEC_OP_BCAST_SYSTEM_PAL_BG;
+ fail_on_test(one_touch_rec_on_send_invalid(node, me, la, rec_src));
+
+ memset(&rec_src, 0, sizeof(rec_src));
+ rec_src.type = CEC_OP_RECORD_SRC_ANALOG;
+ rec_src.analog.ana_bcast_type = CEC_OP_ANA_BCAST_TYPE_SATELLITE;
+ rec_src.analog.ana_freq = (703250 * 10) / 625;
+ rec_src.analog.bcast_system = 0xff; /* Invalid analog broadcast system */
+ fail_on_test(one_touch_rec_on_send_invalid(node, me, la, rec_src));
+
+ memset(&rec_src, 0, sizeof(rec_src));
+ rec_src.type = CEC_OP_RECORD_SRC_ANALOG;
+ rec_src.analog.ana_bcast_type = CEC_OP_ANA_BCAST_TYPE_TERRESTRIAL;
+ rec_src.analog.ana_freq = 0; /* Invalid frequency */
+ rec_src.analog.bcast_system = CEC_OP_BCAST_SYSTEM_NTSC_M;
+ fail_on_test(one_touch_rec_on_send_invalid(node, me, la, rec_src));
+
+ memset(&rec_src, 0, sizeof(rec_src));
+ rec_src.type = CEC_OP_RECORD_SRC_ANALOG;
+ rec_src.analog.ana_bcast_type = CEC_OP_ANA_BCAST_TYPE_CABLE;
+ rec_src.analog.ana_freq = 0xffff; /* Invalid frequency */
+ rec_src.analog.bcast_system = CEC_OP_BCAST_SYSTEM_SECAM_L;
+ fail_on_test(one_touch_rec_on_send_invalid(node, me, la, rec_src));
+
+ memset(&rec_src, 0, sizeof(rec_src));
+ rec_src.type = CEC_OP_RECORD_SRC_EXT_PLUG;
+ rec_src.ext_plug.plug = 0; /* Invalid plug */
+ fail_on_test(one_touch_rec_on_send_invalid(node, me, la, rec_src));
+
+ return OK;
+}
+
+static int one_touch_rec_off(struct node *node, unsigned me, unsigned la, bool interactive)
+{
+ struct cec_msg msg;
+
+ cec_msg_init(&msg, me, la);
+ cec_msg_record_off(&msg, true);
+ /* Allow 10s for reply because the spec says it may take several seconds to accurately respond. */
+ fail_on_test(!transmit_timeout(node, &msg, 10000));
+ if (unrecognized_op(&msg)) {
+ fail_on_test(node->remote[la].prim_type == CEC_OP_PRIM_DEVTYPE_RECORD);
+ return OK_NOT_SUPPORTED;
+ }
+ if (refused(&msg))
+ return OK_REFUSED;
+ if (cec_msg_status_is_abort(&msg))
+ return OK_PRESUMED;
+ if (timed_out(&msg))
+ return OK_PRESUMED;
+
+ __u8 rec_status;
+
+ cec_ops_record_status(&msg, &rec_status);
+
+ fail_on_test(rec_status != CEC_OP_RECORD_STATUS_TERMINATED_OK &&
+ rec_status != CEC_OP_RECORD_STATUS_ALREADY_TERM);
+
+ return OK;
+}
+
+const vec_remote_subtests one_touch_rec_subtests{
+ { "Record TV Screen", CEC_LOG_ADDR_MASK_TV, one_touch_rec_tv_screen },
+ {
+ "Record On",
+ CEC_LOG_ADDR_MASK_RECORD | CEC_LOG_ADDR_MASK_BACKUP,
+ one_touch_rec_on,
+ },
+ {
+ "Record On Invalid Operand",
+ CEC_LOG_ADDR_MASK_RECORD | CEC_LOG_ADDR_MASK_BACKUP,
+ one_touch_rec_on_invalid,
+ },
+ { "Record Off", CEC_LOG_ADDR_MASK_RECORD | CEC_LOG_ADDR_MASK_BACKUP, one_touch_rec_off },
+
+};
+
+/* Timer Programming */
+
+static int timer_status_is_valid(const struct cec_msg &msg)
+{
+ __u8 timer_overlap_warning;
+ __u8 media_info;
+ __u8 prog_info;
+ __u8 prog_error;
+ __u8 duration_hr;
+ __u8 duration_min;
+
+ cec_ops_timer_status(&msg, &timer_overlap_warning, &media_info, &prog_info,
+ &prog_error, &duration_hr, &duration_min);
+ fail_on_test(media_info > CEC_OP_MEDIA_INFO_NO_MEDIA);
+ if (prog_info)
+ fail_on_test(prog_info < CEC_OP_PROG_INFO_ENOUGH_SPACE ||
+ prog_info > CEC_OP_PROG_INFO_MIGHT_NOT_BE_ENOUGH_SPACE);
+ else
+ fail_on_test(prog_error < CEC_OP_PROG_ERROR_NO_FREE_TIMER ||
+ (prog_error > CEC_OP_PROG_ERROR_CLOCK_FAILURE &&
+ prog_error != CEC_OP_PROG_ERROR_DUPLICATE));
+
+ return OK;
+}
+
+static int timer_cleared_status_is_valid(const struct cec_msg &msg)
+{
+ __u8 timer_cleared_status;
+
+ cec_ops_timer_cleared_status(&msg, &timer_cleared_status);
+ fail_on_test(timer_cleared_status != CEC_OP_TIMER_CLR_STAT_RECORDING &&
+ timer_cleared_status != CEC_OP_TIMER_CLR_STAT_NO_MATCHING &&
+ timer_cleared_status != CEC_OP_TIMER_CLR_STAT_NO_INFO &&
+ timer_cleared_status != CEC_OP_TIMER_CLR_STAT_CLEARED);
+
+ return OK;
+}
+
+static bool timer_has_error(const struct cec_msg &msg)
+{
+ __u8 timer_overlap_warning;
+ __u8 media_info;
+ __u8 prog_info;
+ __u8 prog_error;
+ __u8 duration_hr;
+ __u8 duration_min;
+
+ cec_ops_timer_status(&msg, &timer_overlap_warning, &media_info, &prog_info,
+ &prog_error, &duration_hr, &duration_min);
+ if (prog_error)
+ return true;
+
+ return false;
+}
+
+static int send_timer_error(struct node *node, unsigned me, unsigned la, __u8 day, __u8 month,
+ __u8 start_hr, __u8 start_min, __u8 dur_hr, __u8 dur_min, __u8 rec_seq)
+{
+ struct cec_msg msg;
+ cec_msg_init(&msg, me, la);
+ cec_msg_set_analogue_timer(&msg, true, day, month, start_hr, start_min, dur_hr, dur_min,
+ rec_seq, CEC_OP_ANA_BCAST_TYPE_CABLE, 7668, // 479.25 MHz
+ node->remote[la].bcast_sys);
+ fail_on_test(!transmit_timeout(node, &msg, 10000));
+ fail_on_test(timed_out(&msg));
+ if (cec_msg_status_is_abort(&msg))
+ fail_on_test(abort_reason(&msg) != CEC_OP_ABORT_INVALID_OP);
+ else
+ fail_on_test(!timer_has_error(msg));
+
+ return OK;
+}
+
+static bool timer_overlap_warning_is_set(const struct cec_msg &msg)
+{
+ __u8 timer_overlap_warning;
+ __u8 media_info;
+ __u8 prog_info;
+ __u8 prog_error;
+ __u8 duration_hr;
+ __u8 duration_min;
+
+ cec_ops_timer_status(&msg, &timer_overlap_warning, &media_info, &prog_info,
+ &prog_error, &duration_hr, &duration_min);
+
+ if (timer_overlap_warning)
+ return true;
+
+ return false;
+}
+
+static int send_timer_overlap(struct node *node, unsigned me, unsigned la, __u8 day, __u8 month,
+ __u8 start_hr, __u8 start_min, __u8 dur_hr, __u8 dur_min, __u8 rec_seq)
+{
+ struct cec_msg msg;
+
+ cec_msg_init(&msg, me, la);
+ cec_msg_set_analogue_timer(&msg, true, day, month, start_hr, start_min, dur_hr, dur_min,
+ rec_seq, CEC_OP_ANA_BCAST_TYPE_CABLE, 7668, // 479.25 MHz
+ node->remote[la].bcast_sys);
+ fail_on_test(!transmit_timeout(node, &msg, 10000));
+ fail_on_test(timed_out_or_abort(&msg));
+ fail_on_test(timer_has_error(msg));
+ fail_on_test(!timer_overlap_warning_is_set(msg));
+
+ return OK;
+}
+
+static int clear_timer(struct node *node, unsigned me, unsigned la, __u8 day, __u8 month,
+ __u8 start_hr, __u8 start_min, __u8 dur_hr, __u8 dur_min, __u8 rec_seq)
+{
+ struct cec_msg msg;
+
+ cec_msg_init(&msg, me, la);
+ cec_msg_clear_analogue_timer(&msg, true, day, month, start_hr, start_min, dur_hr, dur_min,
+ rec_seq, CEC_OP_ANA_BCAST_TYPE_CABLE, 7668, // 479.25 MHz
+ node->remote[la].bcast_sys);
+ fail_on_test(!transmit_timeout(node, &msg, 10000));
+ fail_on_test(timed_out_or_abort(&msg));
+ fail_on_test(timer_has_error(msg));
+ fail_on_test(timer_cleared_status_is_valid(msg));
+
+ return OK;
+}
+
+static int timer_prog_set_analog_timer(struct node *node, unsigned me, unsigned la, bool interactive)
+{
+ struct cec_msg msg;
+
+ cec_msg_init(&msg, me, la);
+ /* Set timer to start tomorrow, at current time, for 2 hr, 30 min. */
+ time_t tomorrow = node->current_time + (24 * 60 * 60);
+ struct tm *t = localtime(&tomorrow);
+ cec_msg_set_analogue_timer(&msg, true, t->tm_mday, t->tm_mon + 1, t->tm_hour, t->tm_min, 2, 30,
+ 0x7f, CEC_OP_ANA_BCAST_TYPE_CABLE, 7668, // 479.25 MHz
+ node->remote[la].bcast_sys);
+ fail_on_test(!transmit_timeout(node, &msg, 10000));
+ fail_on_test(timed_out(&msg));
+ if (unrecognized_op(&msg))
+ return OK_NOT_SUPPORTED;
+ if (refused(&msg))
+ return OK_REFUSED;
+ if (cec_msg_status_is_abort(&msg))
+ return OK_PRESUMED;
+ fail_on_test(timer_status_is_valid(msg));
+
+ return OK;
+}
+
+static int timer_prog_set_digital_timer(struct node *node, unsigned me, unsigned la, bool interactive)
+{
+ struct cec_msg msg;
+ struct cec_op_digital_service_id digital_service_id = {};
+
+ digital_service_id.service_id_method = CEC_OP_SERVICE_ID_METHOD_BY_CHANNEL;
+ digital_service_id.channel.channel_number_fmt = CEC_OP_CHANNEL_NUMBER_FMT_1_PART;
+ digital_service_id.channel.minor = 1;
+ digital_service_id.dig_bcast_system = node->remote[la].dig_bcast_sys;
+ cec_msg_init(&msg, me, la);
+ /* Set timer to start 2 days from now, at current time, for 4 hr, 30 min. */
+ time_t two_days_ahead = node->current_time + (2 * 24 * 60 * 60);
+ struct tm *t = localtime(&two_days_ahead);
+ cec_msg_set_digital_timer(&msg, true, t->tm_mday, t->tm_mon + 1, t->tm_hour,
+ t->tm_min, 4, 30, CEC_OP_REC_SEQ_ONCE_ONLY, &digital_service_id);
+ fail_on_test(!transmit_timeout(node, &msg, 10000));
+ fail_on_test(timed_out(&msg));
+ if (unrecognized_op(&msg))
+ return OK_NOT_SUPPORTED;
+ if (refused(&msg))
+ return OK_REFUSED;
+ if (cec_msg_status_is_abort(&msg))
+ return OK_PRESUMED;
+ fail_on_test(timer_status_is_valid(msg));
+
+ return 0;
+}
+
+static int timer_prog_set_ext_timer(struct node *node, unsigned me, unsigned la, bool interactive)
+{
+ struct cec_msg msg;
+
+ cec_msg_init(&msg, me, la);
+ /* Set timer to start 3 days from now, at current time, for 6 hr, 30 min. */
+ time_t three_days_ahead = node->current_time + (3 * 24 * 60 * 60);
+ struct tm *t = localtime(&three_days_ahead);
+ cec_msg_set_ext_timer(&msg, true, t->tm_mday, t->tm_mon + 1, t->tm_hour, t->tm_min, 6, 30,
+ CEC_OP_REC_SEQ_ONCE_ONLY, CEC_OP_EXT_SRC_PHYS_ADDR, 0, node->phys_addr);
+ fail_on_test(!transmit_timeout(node, &msg, 10000));
+ fail_on_test(timed_out(&msg));
+ if (unrecognized_op(&msg))
+ return OK_NOT_SUPPORTED;
+ if (refused(&msg))
+ return OK_REFUSED;
+ if (cec_msg_status_is_abort(&msg))
+ return OK_PRESUMED;
+ fail_on_test(timer_status_is_valid(msg));
+
+ return 0;
+}
+
+static int timer_prog_clear_analog_timer(struct node *node, unsigned me, unsigned la, bool interactive)
+{
+ struct cec_msg msg;
+
+ cec_msg_init(&msg, me, la);
+ /* Clear timer set to start tomorrow, at current time, for 2 hr, 30 min. */
+ time_t tomorrow = node->current_time + (24 * 60 * 60);
+ struct tm *t = localtime(&tomorrow);
+ cec_msg_clear_analogue_timer(&msg, true, t->tm_mday, t->tm_mon + 1, t->tm_hour, t->tm_min, 2, 30,
+ 0x7f, CEC_OP_ANA_BCAST_TYPE_CABLE,7668, // 479.25 MHz
+ node->remote[la].bcast_sys);
+ fail_on_test(!transmit_timeout(node, &msg, 10000));
+ fail_on_test(timed_out(&msg));
+ if (unrecognized_op(&msg))
+ return OK_NOT_SUPPORTED;
+ if (refused(&msg))
+ return OK_REFUSED;
+ if (cec_msg_status_is_abort(&msg))
+ return OK_PRESUMED;
+ fail_on_test(timer_cleared_status_is_valid(msg));
+
+ return 0;
+}
+
+static int timer_prog_clear_digital_timer(struct node *node, unsigned me, unsigned la, bool interactive)
+{
+ struct cec_msg msg;
+ struct cec_op_digital_service_id digital_service_id = {};
+
+ digital_service_id.service_id_method = CEC_OP_SERVICE_ID_METHOD_BY_CHANNEL;
+ digital_service_id.channel.channel_number_fmt = CEC_OP_CHANNEL_NUMBER_FMT_1_PART;
+ digital_service_id.channel.minor = 1;
+ digital_service_id.dig_bcast_system = node->remote[la].dig_bcast_sys;
+ cec_msg_init(&msg, me, la);
+ /* Clear timer set to start 2 days from now, at current time, for 4 hr, 30 min. */
+ time_t two_days_ahead = node->current_time + (2 * 24 * 60 * 60);
+ struct tm *t = localtime(&two_days_ahead);
+ cec_msg_clear_digital_timer(&msg, true, t->tm_mday, t->tm_mon + 1, t->tm_hour,
+ t->tm_min, 4, 30, CEC_OP_REC_SEQ_ONCE_ONLY, &digital_service_id);
+ fail_on_test(!transmit_timeout(node, &msg, 10000));
+ fail_on_test(timed_out(&msg));
+ if (unrecognized_op(&msg))
+ return OK_NOT_SUPPORTED;
+ if (refused(&msg))
+ return OK_REFUSED;
+ if (cec_msg_status_is_abort(&msg))
+ return OK_PRESUMED;
+ fail_on_test(timer_cleared_status_is_valid(msg));
+
+ return 0;
+}
+
+static int timer_prog_clear_ext_timer(struct node *node, unsigned me, unsigned la, bool interactive)
+{
+ struct cec_msg msg;
+
+ cec_msg_init(&msg, me, la);
+ /* Clear timer set to start 3 days from now, at current time, for 6 hr, 30 min. */
+ time_t three_days_ahead = node->current_time + (3 * 24 * 60 * 60);
+ struct tm *t = localtime(&three_days_ahead);
+ cec_msg_clear_ext_timer(&msg, true, t->tm_mday, t->tm_mon + 1, t->tm_hour, t->tm_min, 6, 30,
+ CEC_OP_REC_SEQ_ONCE_ONLY, CEC_OP_EXT_SRC_PHYS_ADDR, 0, node->phys_addr);
+ fail_on_test(!transmit_timeout(node, &msg, 10000));
+ fail_on_test(timed_out(&msg));
+ if (unrecognized_op(&msg))
+ return OK_NOT_SUPPORTED;
+ if (refused(&msg))
+ return OK_REFUSED;
+ if (cec_msg_status_is_abort(&msg))
+ return OK_PRESUMED;
+ fail_on_test(timer_cleared_status_is_valid(msg));
+
+ return 0;
+}
+
+static int timer_prog_set_prog_title(struct node *node, unsigned me, unsigned la, bool interactive)
+{
+ struct cec_msg msg;
+
+ cec_msg_init(&msg, me, la);
+ cec_msg_set_timer_program_title(&msg, "Super-Hans II");
+ fail_on_test(!transmit_timeout(node, &msg));
+ if (unrecognized_op(&msg))
+ return OK_NOT_SUPPORTED;
+ if (refused(&msg))
+ return OK_REFUSED;
+
+ return OK_PRESUMED;
+}
+
+static int timer_errors(struct node *node, unsigned me, unsigned la, bool interactive)
+{
+ struct cec_msg msg;
+
+ /* Day error: November 31, at 6:00 am, for 1 hr. */
+ fail_on_test(send_timer_error(node, me, la, 31, Nov, 6, 0, 1, 0, CEC_OP_REC_SEQ_ONCE_ONLY));
+
+ /* Day error: December 32, at 6:00 am, for 1 hr. */
+ fail_on_test(send_timer_error(node, me, la, 32, Dec, 6, 0, 1, 0, CEC_OP_REC_SEQ_ONCE_ONLY));
+
+ /* Day error: 0, in January, at 6:00 am, for 1 hr. Day range begins at 1. */
+ fail_on_test(send_timer_error(node, me, la, 0, Jan, 6, 0, 1, 0, CEC_OP_REC_SEQ_ONCE_ONLY));
+
+ /* Month error: 0, on day 5, at 6:00 am, for 1 hr. CEC month range is 1-12. */
+ fail_on_test(send_timer_error(node, me, la, 5, 0, 6, 0, 1, 0, CEC_OP_REC_SEQ_ONCE_ONLY));
+
+ /* Month error: 13, on day 5, at 6:00 am, for 1 hr. */
+ fail_on_test(send_timer_error(node, me, la, 5, 13, 6, 0, 1, 0, CEC_OP_REC_SEQ_ONCE_ONLY));
+
+ /* Start hour error: 24 hr, on August 5, for 1 hr. Start hour range is 0-23. */
+ fail_on_test(send_timer_error(node, me, la, 5, Aug, 24, 0, 1, 0, CEC_OP_REC_SEQ_ONCE_ONLY));
+
+ /* Start min error: 60 min, on August 5, for 1 hr. Start min range is 0-59. */
+ fail_on_test(send_timer_error(node, me, la, 5, Aug, 0, 60, 1, 0, CEC_OP_REC_SEQ_ONCE_ONLY));
+
+ /* Recording duration error: 0 hr, 0 min on August 5, at 6:00am. */
+ fail_on_test(send_timer_error(node, me, la, 5, Aug, 6, 0, 0, 0, CEC_OP_REC_SEQ_ONCE_ONLY));
+
+ /* Duplicate timer error: start 2 hrs from now, for 1 hr. */
+ time_t two_hours_ahead = node->current_time + (2 * 60 * 60);
+ struct tm *t = localtime(&two_hours_ahead);
+ cec_msg_init(&msg, me, la);
+ cec_msg_set_analogue_timer(&msg, true, t->tm_mday, t->tm_mon + 1, t->tm_hour, t->tm_min, 1, 0,
+ CEC_OP_REC_SEQ_ONCE_ONLY,CEC_OP_ANA_BCAST_TYPE_CABLE,
+ 7668, // 479.25 MHz
+ node->remote[la].bcast_sys);
+ fail_on_test(!transmit_timeout(node, &msg, 10000));
+ fail_on_test(timed_out_or_abort(&msg));
+ fail_on_test(timer_has_error(msg)); /* The first timer should be set. */
+ fail_on_test(send_timer_error(node, me, la, t->tm_mday, t->tm_mon + 1, t->tm_hour,
+ t->tm_min, 1, 0, CEC_OP_REC_SEQ_ONCE_ONLY));
+
+ /* Clear the timer that was set to test duplicate timers. */
+ fail_on_test(clear_timer(node, me, la, t->tm_mday, t->tm_mon + 1, t->tm_hour, t->tm_min, 1, 0,
+ CEC_OP_REC_SEQ_ONCE_ONLY));
+
+ /* Recording sequence error: 0xff, on August 5, at 6:00 am, for 1 hr. */
+ fail_on_test(send_timer_error(node, me, la, 5, Aug, 6, 0, 1, 0, 0xff));
+
+ /* Error in last day of February, at 6:00 am, for 1 hr. */
+ time_t current_time = node->current_time;
+ t = localtime(&current_time);
+ if ((t->tm_mon + 1) > Feb)
+ t->tm_year++; /* The timer will be for next year. */
+ if (!(t->tm_year % 4) && ((t->tm_year % 100) || !(t->tm_year % 400)))
+ fail_on_test(send_timer_error(node, me, la, 30, Feb, 6, 0, 1, 0, CEC_OP_REC_SEQ_ONCE_ONLY));
+ else
+ fail_on_test(send_timer_error(node, me, la, 29, Feb, 6, 0, 1, 0, CEC_OP_REC_SEQ_ONCE_ONLY));
+
+ return OK;
+}
+
+static int timer_overlap_warning(struct node *node, unsigned me, unsigned la, bool interactive)
+{
+ struct cec_msg msg;
+
+ time_t tomorrow = node->current_time + (24 * 60 * 60);
+ struct tm *t = localtime(&tomorrow);
+
+ /* No overlap: set timer for tomorrow at 8:00 am for 2 hr. */
+ cec_msg_init(&msg, me, la);
+ cec_msg_set_analogue_timer(&msg, true, t->tm_mday, t->tm_mon + 1, 8, 0, 2, 0,
+ CEC_OP_REC_SEQ_ONCE_ONLY, CEC_OP_ANA_BCAST_TYPE_CABLE,
+ 7668, // 479.25 MHz
+ node->remote[la].bcast_sys);
+ fail_on_test(!transmit_timeout(node, &msg, 10000));
+ if (unrecognized_op(&msg))
+ return OK_NOT_SUPPORTED;
+ fail_on_test(timed_out_or_abort(&msg));
+ fail_on_test(timer_has_error(msg));
+ fail_on_test(timer_overlap_warning_is_set(msg));
+
+ /* No overlap, just adjacent: set timer for tomorrow at 10:00 am for 15 min. */
+ cec_msg_init(&msg, me, la);
+ cec_msg_set_analogue_timer(&msg, true, t->tm_mday, t->tm_mon + 1, 10, 0, 0, 15,
+ CEC_OP_REC_SEQ_ONCE_ONLY, CEC_OP_ANA_BCAST_TYPE_CABLE,
+ 7668, // 479.25 MHz
+ node->remote[la].bcast_sys);
+ fail_on_test(!transmit_timeout(node, &msg, 10000));
+ fail_on_test(timed_out_or_abort(&msg));
+ fail_on_test(timer_has_error(msg));
+ fail_on_test(timer_overlap_warning_is_set(msg));
+
+ /* No overlap, just adjacent: set timer for tomorrow at 7:45 am for 15 min. */
+ cec_msg_init(&msg, me, la);
+ cec_msg_set_analogue_timer(&msg, true, t->tm_mday, t->tm_mon + 1, 7, 45, 0, 15,
+ CEC_OP_REC_SEQ_ONCE_ONLY, CEC_OP_ANA_BCAST_TYPE_CABLE,
+ 7668, // 479.25 MHz
+ node->remote[la].bcast_sys);
+ fail_on_test(!transmit_timeout(node, &msg, 10000));
+ fail_on_test(timed_out_or_abort(&msg));
+ fail_on_test(timer_has_error(msg));
+ fail_on_test(timer_overlap_warning_is_set(msg));
+
+ /* Overlap tail end: set timer for tomorrow at 9:00 am for 2 hr, repeats on Sun. */
+ fail_on_test(send_timer_overlap(node, me, la, t->tm_mday, t->tm_mon + 1, 9, 0, 2, 0, 0x1));
+
+ /* Overlap front end: set timer for tomorrow at 7:00 am for 1 hr, 30 min. */
+ fail_on_test(send_timer_overlap(node, me, la, t->tm_mday, t->tm_mon + 1, 7, 0, 1, 30, 0x1));
+
+ /* Overlap same start time: set timer for tomorrow at 8:00 am for 30 min. */
+ fail_on_test(send_timer_overlap(node, me, la, t->tm_mday, t->tm_mon + 1, 8, 0, 0, 30, 0x1));
+
+ /* Overlap same end time: set timer for tomorrow at 9:30 am for 30 min. */
+ fail_on_test(send_timer_overlap(node, me, la, t->tm_mday, t->tm_mon + 1, 9, 30, 0, 30, 0x1));
+
+ /* Overlap all timers: set timer for tomorrow at 6:00 am for 6 hr. */
+ fail_on_test(send_timer_overlap(node, me, la, t->tm_mday, t->tm_mon + 1, 6, 0, 6, 0, 0x1));
+
+ /* Clear all the timers. */
+ fail_on_test(clear_timer(node, me, la, t->tm_mday, t->tm_mon + 1, 8, 0, 2, 0,
+ CEC_OP_REC_SEQ_ONCE_ONLY));
+ fail_on_test(clear_timer(node, me, la, t->tm_mday, t->tm_mon + 1, 10, 0, 0, 15,
+ CEC_OP_REC_SEQ_ONCE_ONLY));
+ fail_on_test(clear_timer(node, me, la, t->tm_mday, t->tm_mon + 1, 7, 45, 0, 15,
+ CEC_OP_REC_SEQ_ONCE_ONLY));
+ fail_on_test(clear_timer(node, me, la, t->tm_mday, t->tm_mon + 1, 9, 0, 2, 0, 0x1));
+ fail_on_test(clear_timer(node, me, la, t->tm_mday, t->tm_mon + 1, 7, 0, 1, 30, 0x1));
+ fail_on_test(clear_timer(node, me, la, t->tm_mday, t->tm_mon + 1, 8, 0, 0, 30, 0x1));
+ fail_on_test(clear_timer(node, me, la, t->tm_mday, t->tm_mon + 1, 9, 30, 0, 30, 0x1));
+ fail_on_test(clear_timer(node, me, la, t->tm_mday, t->tm_mon + 1, 6, 0, 6, 0, 0x1));
+
+ return OK;
+}
+
+const vec_remote_subtests timer_prog_subtests{
+ {
+ "Set Analogue Timer",
+ CEC_LOG_ADDR_MASK_RECORD | CEC_LOG_ADDR_MASK_BACKUP,
+ timer_prog_set_analog_timer,
+ },
+ {
+ "Set Digital Timer",
+ CEC_LOG_ADDR_MASK_RECORD | CEC_LOG_ADDR_MASK_BACKUP,
+ timer_prog_set_digital_timer,
+ },
+ {
+ "Set Timer Program Title",
+ CEC_LOG_ADDR_MASK_RECORD | CEC_LOG_ADDR_MASK_BACKUP,
+ timer_prog_set_prog_title,
+ },
+ {
+ "Set External Timer",
+ CEC_LOG_ADDR_MASK_RECORD | CEC_LOG_ADDR_MASK_BACKUP,
+ timer_prog_set_ext_timer,
+ },
+ {
+ "Clear Analogue Timer",
+ CEC_LOG_ADDR_MASK_RECORD | CEC_LOG_ADDR_MASK_BACKUP,
+ timer_prog_clear_analog_timer,
+ },
+ {
+ "Clear Digital Timer",
+ CEC_LOG_ADDR_MASK_RECORD | CEC_LOG_ADDR_MASK_BACKUP,
+ timer_prog_clear_digital_timer,
+ },
+ {
+ "Clear External Timer",
+ CEC_LOG_ADDR_MASK_RECORD | CEC_LOG_ADDR_MASK_BACKUP,
+ timer_prog_clear_ext_timer,
+ },
+ {
+ "Set Timers with Errors",
+ CEC_LOG_ADDR_MASK_RECORD | CEC_LOG_ADDR_MASK_BACKUP,
+ timer_errors,
+ },
+ {
+ "Set Overlapping Timers",
+ CEC_LOG_ADDR_MASK_RECORD | CEC_LOG_ADDR_MASK_BACKUP,
+ timer_overlap_warning,
+ },
+};
diff --git a/utils/cec-compliance/cec-test.cpp b/utils/cec-compliance/cec-test.cpp
index e123bf08..fae6c304 100644
--- a/utils/cec-compliance/cec-test.cpp
+++ b/utils/cec-compliance/cec-test.cpp
@@ -50,192 +50,6 @@ static int test_play_mode(struct node *node, unsigned me, unsigned la, __u8 play
return OK;
}
-static int one_touch_rec_on_send(struct node *node, unsigned me, unsigned la,
- const struct cec_op_record_src &rec_src, __u8 &rec_status)
-{
- struct cec_msg msg;
-
- cec_msg_init(&msg, me, la);
- cec_msg_record_off(&msg, false);
- fail_on_test(!transmit_timeout(node, &msg));
-
- cec_msg_init(&msg, me, la);
- cec_msg_record_on(&msg, true, &rec_src);
- /* Allow 10s for reply because the spec says it may take several seconds to accurately respond. */
- fail_on_test(!transmit_timeout(node, &msg, 10000));
- fail_on_test(timed_out_or_abort(&msg));
- cec_ops_record_status(&msg, &rec_status);
-
- return OK;
-}
-
-static int one_touch_rec_on_send_invalid(struct node *node, unsigned me, unsigned la,
- const struct cec_op_record_src &rec_src)
-{
- struct cec_msg msg;
-
- cec_msg_init(&msg, me, la);
- cec_msg_record_on(&msg, true, &rec_src);
- fail_on_test(!transmit_timeout(node, &msg));
- fail_on_test(!cec_msg_status_is_abort(&msg));
- fail_on_test(abort_reason(&msg) != CEC_OP_ABORT_INVALID_OP);
-
- return OK;
-}
-
-/*
- * Returns true if the Record Status is an error indicating that the
- * request to start recording has failed.
- */
-static bool rec_status_is_a_valid_error_status(__u8 rec_status)
-{
- switch (rec_status) {
- case CEC_OP_RECORD_STATUS_NO_DIG_SERVICE:
- case CEC_OP_RECORD_STATUS_NO_ANA_SERVICE:
- case CEC_OP_RECORD_STATUS_NO_SERVICE:
- case CEC_OP_RECORD_STATUS_INVALID_EXT_PLUG:
- case CEC_OP_RECORD_STATUS_INVALID_EXT_PHYS_ADDR:
- case CEC_OP_RECORD_STATUS_UNSUP_CA:
- case CEC_OP_RECORD_STATUS_NO_CA_ENTITLEMENTS:
- case CEC_OP_RECORD_STATUS_CANT_COPY_SRC:
- case CEC_OP_RECORD_STATUS_NO_MORE_COPIES:
- case CEC_OP_RECORD_STATUS_NO_MEDIA:
- case CEC_OP_RECORD_STATUS_PLAYING:
- case CEC_OP_RECORD_STATUS_ALREADY_RECORDING:
- case CEC_OP_RECORD_STATUS_MEDIA_PROT:
- case CEC_OP_RECORD_STATUS_NO_SIGNAL:
- case CEC_OP_RECORD_STATUS_MEDIA_PROBLEM:
- case CEC_OP_RECORD_STATUS_NO_SPACE:
- case CEC_OP_RECORD_STATUS_PARENTAL_LOCK:
- case CEC_OP_RECORD_STATUS_OTHER:
- return true;
- default:
- return false;
- }
-}
-
-static int timer_status_is_valid(const struct cec_msg &msg)
-{
- __u8 timer_overlap_warning;
- __u8 media_info;
- __u8 prog_info;
- __u8 prog_error;
- __u8 duration_hr;
- __u8 duration_min;
-
- cec_ops_timer_status(&msg, &timer_overlap_warning, &media_info, &prog_info,
- &prog_error, &duration_hr, &duration_min);
- fail_on_test(media_info > CEC_OP_MEDIA_INFO_NO_MEDIA);
- if (prog_info)
- fail_on_test(prog_info < CEC_OP_PROG_INFO_ENOUGH_SPACE ||
- prog_info > CEC_OP_PROG_INFO_MIGHT_NOT_BE_ENOUGH_SPACE);
- else
- fail_on_test(prog_error < CEC_OP_PROG_ERROR_NO_FREE_TIMER ||
- (prog_error > CEC_OP_PROG_ERROR_CLOCK_FAILURE &&
- prog_error != CEC_OP_PROG_ERROR_DUPLICATE));
-
- return OK;
-}
-
-static int timer_cleared_status_is_valid(const struct cec_msg &msg)
-{
- __u8 timer_cleared_status;
-
- cec_ops_timer_cleared_status(&msg, &timer_cleared_status);
- fail_on_test(timer_cleared_status != CEC_OP_TIMER_CLR_STAT_RECORDING &&
- timer_cleared_status != CEC_OP_TIMER_CLR_STAT_NO_MATCHING &&
- timer_cleared_status != CEC_OP_TIMER_CLR_STAT_NO_INFO &&
- timer_cleared_status != CEC_OP_TIMER_CLR_STAT_CLEARED);
-
- return OK;
-}
-
-static bool timer_has_error(const struct cec_msg &msg)
-{
- __u8 timer_overlap_warning;
- __u8 media_info;
- __u8 prog_info;
- __u8 prog_error;
- __u8 duration_hr;
- __u8 duration_min;
-
- cec_ops_timer_status(&msg, &timer_overlap_warning, &media_info, &prog_info,
- &prog_error, &duration_hr, &duration_min);
- if (prog_error)
- return true;
-
- return false;
-}
-
-static int send_timer_error(struct node *node, unsigned me, unsigned la, __u8 day, __u8 month,
- __u8 start_hr, __u8 start_min, __u8 dur_hr, __u8 dur_min, __u8 rec_seq)
-{
- struct cec_msg msg;
- cec_msg_init(&msg, me, la);
- cec_msg_set_analogue_timer(&msg, true, day, month, start_hr, start_min, dur_hr, dur_min,
- rec_seq, CEC_OP_ANA_BCAST_TYPE_CABLE, 7668, // 479.25 MHz
- node->remote[la].bcast_sys);
- fail_on_test(!transmit_timeout(node, &msg, 10000));
- fail_on_test(timed_out(&msg));
- if (cec_msg_status_is_abort(&msg))
- fail_on_test(abort_reason(&msg) != CEC_OP_ABORT_INVALID_OP);
- else
- fail_on_test(!timer_has_error(msg));
-
- return OK;
-}
-
-static bool timer_overlap_warning_is_set(const struct cec_msg &msg)
-{
- __u8 timer_overlap_warning;
- __u8 media_info;
- __u8 prog_info;
- __u8 prog_error;
- __u8 duration_hr;
- __u8 duration_min;
-
- cec_ops_timer_status(&msg, &timer_overlap_warning, &media_info, &prog_info,
- &prog_error, &duration_hr, &duration_min);
-
- if (timer_overlap_warning)
- return true;
-
- return false;
-}
-
-static int send_timer_overlap(struct node *node, unsigned me, unsigned la, __u8 day, __u8 month,
- __u8 start_hr, __u8 start_min, __u8 dur_hr, __u8 dur_min, __u8 rec_seq)
-{
- struct cec_msg msg;
-
- cec_msg_init(&msg, me, la);
- cec_msg_set_analogue_timer(&msg, true, day, month, start_hr, start_min, dur_hr, dur_min,
- rec_seq, CEC_OP_ANA_BCAST_TYPE_CABLE, 7668, // 479.25 MHz
- node->remote[la].bcast_sys);
- fail_on_test(!transmit_timeout(node, &msg, 10000));
- fail_on_test(timed_out_or_abort(&msg));
- fail_on_test(timer_has_error(msg));
- fail_on_test(!timer_overlap_warning_is_set(msg));
-
- return OK;
-}
-
-static int clear_timer(struct node *node, unsigned me, unsigned la, __u8 day, __u8 month,
- __u8 start_hr, __u8 start_min, __u8 dur_hr, __u8 dur_min, __u8 rec_seq)
-{
- struct cec_msg msg;
-
- cec_msg_init(&msg, me, la);
- cec_msg_clear_analogue_timer(&msg, true, day, month, start_hr, start_min, dur_hr, dur_min,
- rec_seq, CEC_OP_ANA_BCAST_TYPE_CABLE, 7668, // 479.25 MHz
- node->remote[la].bcast_sys);
- fail_on_test(!transmit_timeout(node, &msg, 10000));
- fail_on_test(timed_out_or_abort(&msg));
- fail_on_test(timer_has_error(msg));
- fail_on_test(timer_cleared_status_is_valid(msg));
-
- return OK;
-}
/* System Information */
@@ -1087,891 +901,6 @@ static const vec_remote_subtests deck_ctl_subtests{
},
};
-/* Tuner Control */
-
-static const char *bcast_type2s(__u8 bcast_type)
-{
- switch (bcast_type) {
- case CEC_OP_ANA_BCAST_TYPE_CABLE:
- return "Cable";
- case CEC_OP_ANA_BCAST_TYPE_SATELLITE:
- return "Satellite";
- case CEC_OP_ANA_BCAST_TYPE_TERRESTRIAL:
- return "Terrestrial";
- default:
- return "Future use";
- }
-}
-
-static int log_tuner_service(const struct cec_op_tuner_device_info &info,
- const char *prefix = "")
-{
- printf("\t\t%s", prefix);
-
- if (info.is_analog) {
- double freq_mhz = (info.analog.ana_freq * 625) / 10000.0;
-
- printf("Analog Channel %.2f MHz (%s, %s)\n", freq_mhz,
- bcast_system2s(info.analog.bcast_system),
- bcast_type2s(info.analog.ana_bcast_type));
-
- switch (info.analog.bcast_system) {
- case CEC_OP_BCAST_SYSTEM_PAL_BG:
- case CEC_OP_BCAST_SYSTEM_SECAM_LQ:
- case CEC_OP_BCAST_SYSTEM_PAL_M:
- case CEC_OP_BCAST_SYSTEM_NTSC_M:
- case CEC_OP_BCAST_SYSTEM_PAL_I:
- case CEC_OP_BCAST_SYSTEM_SECAM_DK:
- case CEC_OP_BCAST_SYSTEM_SECAM_BG:
- case CEC_OP_BCAST_SYSTEM_SECAM_L:
- case CEC_OP_BCAST_SYSTEM_PAL_DK:
- break;
- default:
- return fail("invalid analog bcast_system %u", info.analog.bcast_system);
- }
- if (info.analog.ana_bcast_type > CEC_OP_ANA_BCAST_TYPE_TERRESTRIAL)
- return fail("invalid analog bcast_type %u\n", info.analog.ana_bcast_type);
- fail_on_test(!info.analog.ana_freq);
- return 0;
- }
-
- __u8 system = info.digital.dig_bcast_system;
-
- printf("%s Channel ", dig_bcast_system2s(system));
- if (info.digital.service_id_method) {
- __u16 major = info.digital.channel.major;
- __u16 minor = info.digital.channel.minor;
-
- switch (info.digital.channel.channel_number_fmt) {
- case CEC_OP_CHANNEL_NUMBER_FMT_2_PART:
- printf("%u.%u\n", major, minor);
- break;
- case CEC_OP_CHANNEL_NUMBER_FMT_1_PART:
- printf("%u\n", minor);
- break;
- default:
- printf("%u.%u\n", major, minor);
- return fail("invalid service ID method\n");
- }
- return 0;
- }
-
-
- switch (system) {
- case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ARIB_GEN:
- case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ARIB_BS:
- case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ARIB_CS:
- case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ARIB_T: {
- __u16 tsid = info.digital.arib.transport_id;
- __u16 sid = info.digital.arib.service_id;
- __u16 onid = info.digital.arib.orig_network_id;
-
- printf("TSID: %u, SID: %u, ONID: %u\n", tsid, sid, onid);
- break;
- }
- case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ATSC_GEN:
- case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ATSC_SAT:
- case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ATSC_CABLE:
- case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ATSC_T: {
- __u16 tsid = info.digital.atsc.transport_id;
- __u16 pn = info.digital.atsc.program_number;
-
- printf("TSID: %u, Program Number: %u\n", tsid, pn);
- break;
- }
- case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_DVB_GEN:
- case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_DVB_S:
- case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_DVB_S2:
- case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_DVB_C:
- case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_DVB_T: {
- __u16 tsid = info.digital.dvb.transport_id;
- __u16 sid = info.digital.dvb.service_id;
- __u16 onid = info.digital.dvb.orig_network_id;
-
- printf("TSID: %u, SID: %u, ONID: %u\n", tsid, sid, onid);
- break;
- }
- default:
- break;
- }
-
- switch (system) {
- case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ARIB_GEN:
- case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ATSC_GEN:
- case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_DVB_GEN:
- warn_once("generic digital broadcast systems should not be used");
- break;
- case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ARIB_BS:
- case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ARIB_CS:
- case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ARIB_T:
- case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ATSC_CABLE:
- case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ATSC_SAT:
- case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ATSC_T:
- case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_DVB_C:
- case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_DVB_S:
- case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_DVB_S2:
- case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_DVB_T:
- break;
- default:
- return fail("invalid digital broadcast system %u", system);
- }
-
- if (info.digital.service_id_method > CEC_OP_SERVICE_ID_METHOD_BY_CHANNEL)
- return fail("invalid service ID method %u\n", info.digital.service_id_method);
-
- return 0;
-}
-
-static int tuner_ctl_test(struct node *node, unsigned me, unsigned la, bool interactive)
-{
- struct cec_msg msg;
- struct cec_op_tuner_device_info info = {};
- std::vector<struct cec_op_tuner_device_info> info_vec;
- bool has_tuner = (1 << la) & (CEC_LOG_ADDR_MASK_TV | CEC_LOG_ADDR_MASK_TUNER);
- int ret;
-
- cec_msg_init(&msg, me, la);
- cec_msg_give_tuner_device_status(&msg, true, CEC_OP_STATUS_REQ_ONCE);
- fail_on_test(!transmit_timeout(node, &msg));
- fail_on_test(!has_tuner && !timed_out_or_abort(&msg));
- if (!has_tuner)
- return OK_NOT_SUPPORTED;
- if (timed_out(&msg) || unrecognized_op(&msg))
- return OK_NOT_SUPPORTED;
- if (cec_msg_status_is_abort(&msg))
- return OK_REFUSED;
-
- printf("\t Start Channel Scan\n");
- cec_ops_tuner_device_status(&msg, &info);
- info_vec.push_back(info);
- ret = log_tuner_service(info);
- if (ret)
- return ret;
-
- while (true) {
- cec_msg_init(&msg, me, la);
- cec_msg_tuner_step_increment(&msg);
- fail_on_test(!transmit(node, &msg));
- fail_on_test(cec_msg_status_is_abort(&msg));
- if (cec_msg_status_is_abort(&msg)) {
- fail_on_test(abort_reason(&msg) == CEC_OP_ABORT_UNRECOGNIZED_OP);
- if (abort_reason(&msg) == CEC_OP_ABORT_REFUSED) {
- warn("Tuner step increment does not wrap.\n");
- break;
- }
-
- warn("Tuner at end of service list did not receive feature abort refused.\n");
- break;
- }
- cec_msg_init(&msg, me, la);
- cec_msg_give_tuner_device_status(&msg, true, CEC_OP_STATUS_REQ_ONCE);
- fail_on_test(!transmit_timeout(node, &msg));
- fail_on_test(timed_out_or_abort(&msg));
- memset(&info, 0, sizeof(info));
- cec_ops_tuner_device_status(&msg, &info);
- if (!memcmp(&info, &info_vec[0], sizeof(info)))
- break;
- ret = log_tuner_service(info);
- if (ret)
- return ret;
- info_vec.push_back(info);
- }
- printf("\t Finished Channel Scan\n");
-
- printf("\t Start Channel Test\n");
- for (const auto &iter : info_vec) {
- cec_msg_init(&msg, me, la);
- log_tuner_service(iter, "Select ");
- if (iter.is_analog)
- cec_msg_select_analogue_service(&msg, iter.analog.ana_bcast_type,
- iter.analog.ana_freq, iter.analog.bcast_system);
- else
- cec_msg_select_digital_service(&msg, &iter.digital);
- fail_on_test(!transmit(node, &msg));
- fail_on_test(cec_msg_status_is_abort(&msg));
- cec_msg_init(&msg, me, la);
- cec_msg_give_tuner_device_status(&msg, true, CEC_OP_STATUS_REQ_ONCE);
- fail_on_test(!transmit_timeout(node, &msg));
- fail_on_test(timed_out_or_abort(&msg));
- memset(&info, 0, sizeof(info));
- cec_ops_tuner_device_status(&msg, &info);
- if (memcmp(&info, &iter, sizeof(info))) {
- log_tuner_service(info);
- log_tuner_service(iter);
- }
- fail_on_test(memcmp(&info, &iter, sizeof(info)));
- }
- printf("\t Finished Channel Test\n");
-
- cec_msg_init(&msg, me, la);
- cec_msg_select_analogue_service(&msg, 3, 16000, 9);
- printf("\t\tSelect invalid analog channel\n");
- fail_on_test(!transmit_timeout(node, &msg));
- fail_on_test(!cec_msg_status_is_abort(&msg));
- fail_on_test(abort_reason(&msg) != CEC_OP_ABORT_INVALID_OP);
- cec_msg_init(&msg, me, la);
- info.digital.service_id_method = CEC_OP_SERVICE_ID_METHOD_BY_DIG_ID;
- info.digital.dig_bcast_system = CEC_OP_DIG_SERVICE_BCAST_SYSTEM_DVB_S2;
- info.digital.dvb.transport_id = 0;
- info.digital.dvb.service_id = 0;
- info.digital.dvb.orig_network_id = 0;
- cec_msg_select_digital_service(&msg, &info.digital);
- printf("\t\tSelect invalid digital channel\n");
- fail_on_test(!transmit_timeout(node, &msg));
- fail_on_test(!cec_msg_status_is_abort(&msg));
- fail_on_test(abort_reason(&msg) != CEC_OP_ABORT_INVALID_OP);
-
- return 0;
-}
-
-static const vec_remote_subtests tuner_ctl_subtests{
- { "Tuner Control", CEC_LOG_ADDR_MASK_TUNER | CEC_LOG_ADDR_MASK_TV, tuner_ctl_test },
-};
-
-/* One Touch Record */
-
-static int one_touch_rec_tv_screen(struct node *node, unsigned me, unsigned la, bool interactive)
-{
- struct cec_msg msg;
-
- cec_msg_init(&msg, me, la);
- cec_msg_record_tv_screen(&msg, true);
- fail_on_test(!transmit_timeout(node, &msg));
- fail_on_test_v2(node->remote[la].cec_version,
- node->remote[la].has_rec_tv && unrecognized_op(&msg));
- fail_on_test_v2(node->remote[la].cec_version,
- !node->remote[la].has_rec_tv && !unrecognized_op(&msg));
- if (unrecognized_op(&msg))
- return OK_NOT_SUPPORTED;
- if (refused(&msg))
- return OK_REFUSED;
- if (cec_msg_status_is_abort(&msg))
- return OK_PRESUMED;
- /* Follower should ignore this message if it is not sent by a recording device */
- if (node->prim_devtype != CEC_OP_PRIM_DEVTYPE_RECORD) {
- fail_on_test(!timed_out(&msg));
- return OK;
- }
- fail_on_test(timed_out(&msg));
-
- struct cec_op_record_src rec_src = {};
-
- cec_ops_record_on(&msg, &rec_src);
-
- fail_on_test(rec_src.type < CEC_OP_RECORD_SRC_OWN ||
- rec_src.type > CEC_OP_RECORD_SRC_EXT_PHYS_ADDR);
-
- if (rec_src.type == CEC_OP_RECORD_SRC_DIGITAL) {
- switch (rec_src.digital.dig_bcast_system) {
- case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ARIB_GEN:
- case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ATSC_GEN:
- case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_DVB_GEN:
- case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ARIB_BS:
- case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ARIB_CS:
- case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ARIB_T:
- case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ATSC_CABLE:
- case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ATSC_SAT:
- case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ATSC_T:
- case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_DVB_C:
- case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_DVB_S:
- case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_DVB_S2:
- case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_DVB_T:
- break;
- default:
- return fail("Invalid digital service broadcast system operand.\n");
- }
-
- if (rec_src.digital.service_id_method == CEC_OP_SERVICE_ID_METHOD_BY_CHANNEL)
- fail_on_test(rec_src.digital.channel.channel_number_fmt < CEC_OP_CHANNEL_NUMBER_FMT_1_PART ||
- rec_src.digital.channel.channel_number_fmt > CEC_OP_CHANNEL_NUMBER_FMT_2_PART);
- }
-
- if (rec_src.type == CEC_OP_RECORD_SRC_ANALOG) {
- fail_on_test(rec_src.analog.ana_bcast_type > CEC_OP_ANA_BCAST_TYPE_TERRESTRIAL);
- fail_on_test(rec_src.analog.bcast_system > CEC_OP_BCAST_SYSTEM_PAL_DK &&
- rec_src.analog.bcast_system != CEC_OP_BCAST_SYSTEM_OTHER);
- fail_on_test(rec_src.analog.ana_freq == 0 || rec_src.analog.ana_freq == 0xffff);
- }
-
- if (rec_src.type == CEC_OP_RECORD_SRC_EXT_PLUG)
- fail_on_test(rec_src.ext_plug.plug == 0);
-
- return OK;
-}
-
-static int one_touch_rec_on(struct node *node, unsigned me, unsigned la, bool interactive)
-{
- struct cec_msg msg;
- struct cec_op_record_src rec_src = {};
-
- rec_src.type = CEC_OP_RECORD_SRC_OWN;
- cec_msg_init(&msg, me, la);
- cec_msg_record_on(&msg, true, &rec_src);
- /* Allow 10s for reply because the spec says it may take several seconds to accurately respond. */
- fail_on_test(!transmit_timeout(node, &msg, 10000));
- fail_on_test(timed_out(&msg));
- if (unrecognized_op(&msg)) {
- fail_on_test(node->remote[la].prim_type == CEC_OP_PRIM_DEVTYPE_RECORD);
- return OK_NOT_SUPPORTED;
- }
- if (refused(&msg))
- return OK_REFUSED;
- if (cec_msg_status_is_abort(&msg))
- return OK_PRESUMED;
-
- __u8 rec_status;
-
- cec_ops_record_status(&msg, &rec_status);
- if (rec_status != CEC_OP_RECORD_STATUS_CUR_SRC)
- fail_on_test(!rec_status_is_a_valid_error_status(rec_status));
-
- /* In the following tests, these digital services are taken from the cec-follower tuner emulation. */
- memset(&rec_src, 0, sizeof(rec_src));
- rec_src.type = CEC_OP_RECORD_SRC_DIGITAL;
- rec_src.digital.service_id_method = CEC_OP_SERVICE_ID_METHOD_BY_DIG_ID;
- rec_src.digital.dig_bcast_system = CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ARIB_BS;
- rec_src.digital.arib.transport_id = 1032;
- rec_src.digital.arib.service_id = 30203;
- rec_src.digital.arib.orig_network_id = 1;
- fail_on_test(one_touch_rec_on_send(node, me, la, rec_src, rec_status));
- if (rec_status != CEC_OP_RECORD_STATUS_DIG_SERVICE)
- fail_on_test(!rec_status_is_a_valid_error_status(rec_status));
-
- memset(&rec_src, 0, sizeof(rec_src));
- rec_src.type = CEC_OP_RECORD_SRC_DIGITAL;
- rec_src.digital.service_id_method = CEC_OP_SERVICE_ID_METHOD_BY_CHANNEL;
- rec_src.digital.dig_bcast_system = CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ATSC_T;
- rec_src.digital.channel.channel_number_fmt = CEC_OP_CHANNEL_NUMBER_FMT_2_PART;
- rec_src.digital.channel.major = 4;
- rec_src.digital.channel.minor = 1;
- fail_on_test(one_touch_rec_on_send(node, me, la, rec_src, rec_status));
- if (rec_status != CEC_OP_RECORD_STATUS_DIG_SERVICE)
- fail_on_test(!rec_status_is_a_valid_error_status(rec_status));
-
- memset(&rec_src, 0, sizeof(rec_src));
- rec_src.type = CEC_OP_RECORD_SRC_DIGITAL;
- rec_src.digital.service_id_method = CEC_OP_SERVICE_ID_METHOD_BY_DIG_ID;
- rec_src.digital.dig_bcast_system = CEC_OP_DIG_SERVICE_BCAST_SYSTEM_DVB_T;
- rec_src.digital.dvb.transport_id = 1004;
- rec_src.digital.dvb.service_id = 1040;
- rec_src.digital.dvb.orig_network_id = 8945;
- fail_on_test(one_touch_rec_on_send(node, me, la, rec_src, rec_status));
- if (rec_status != CEC_OP_RECORD_STATUS_DIG_SERVICE)
- fail_on_test(!rec_status_is_a_valid_error_status(rec_status));
-
- /* In the following tests, these channels taken from the cec-follower tuner emulation. */
- memset(&rec_src, 0, sizeof(rec_src));
- rec_src.type = CEC_OP_RECORD_STATUS_ANA_SERVICE;
- rec_src.analog.ana_bcast_type = CEC_OP_ANA_BCAST_TYPE_CABLE;
- rec_src.analog.ana_freq = (471250 * 10) / 625;
- rec_src.analog.bcast_system = CEC_OP_BCAST_SYSTEM_PAL_BG;
- fail_on_test(one_touch_rec_on_send(node, me, la, rec_src, rec_status));
- if (rec_status != CEC_OP_RECORD_STATUS_ANA_SERVICE)
- fail_on_test(!rec_status_is_a_valid_error_status(rec_status));
-
- memset(&rec_src, 0, sizeof(rec_src));
- rec_src.type = CEC_OP_RECORD_STATUS_ANA_SERVICE;
- rec_src.analog.ana_bcast_type = CEC_OP_ANA_BCAST_TYPE_SATELLITE;
- rec_src.analog.ana_freq = (551250 * 10) / 625;
- rec_src.analog.bcast_system = CEC_OP_BCAST_SYSTEM_SECAM_BG;
- fail_on_test(one_touch_rec_on_send(node, me, la, rec_src, rec_status));
- if (rec_status != CEC_OP_RECORD_STATUS_ANA_SERVICE)
- fail_on_test(!rec_status_is_a_valid_error_status(rec_status));
-
- memset(&rec_src, 0, sizeof(rec_src));
- rec_src.type = CEC_OP_RECORD_STATUS_ANA_SERVICE;
- rec_src.analog.ana_bcast_type = CEC_OP_ANA_BCAST_TYPE_TERRESTRIAL;
- rec_src.analog.ana_freq = (185250 * 10) / 625;
- rec_src.analog.bcast_system = CEC_OP_BCAST_SYSTEM_PAL_DK;
- fail_on_test(one_touch_rec_on_send(node, me, la, rec_src, rec_status));
- if (rec_status != CEC_OP_RECORD_STATUS_ANA_SERVICE)
- fail_on_test(!rec_status_is_a_valid_error_status(rec_status));
-
- memset(&rec_src, 0, sizeof(rec_src));
- rec_src.type = CEC_OP_RECORD_SRC_EXT_PLUG;
- rec_src.ext_plug.plug = 1;
- fail_on_test(one_touch_rec_on_send(node, me, la, rec_src, rec_status));
- if (rec_status != CEC_OP_RECORD_STATUS_EXT_INPUT)
- fail_on_test(!rec_status_is_a_valid_error_status(rec_status));
-
- memset(&rec_src, 0, sizeof(rec_src));
- rec_src.type = CEC_OP_RECORD_SRC_EXT_PHYS_ADDR;
- fail_on_test(one_touch_rec_on_send(node, me, la, rec_src, rec_status));
- if (rec_status != CEC_OP_RECORD_STATUS_EXT_INPUT)
- fail_on_test(!rec_status_is_a_valid_error_status(rec_status));
-
- return OK;
-}
-
-static int one_touch_rec_on_invalid(struct node *node, unsigned me, unsigned la, bool interactive)
-{
- struct cec_msg msg;
-
- cec_msg_init(&msg, me, la);
- cec_msg_record_on_own(&msg);
- msg.msg[2] = 0; /* Invalid source operand */
- fail_on_test(!transmit_timeout(node, &msg));
- if (unrecognized_op(&msg))
- return OK_NOT_SUPPORTED;
- fail_on_test(!cec_msg_status_is_abort(&msg));
- fail_on_test(abort_reason(&msg) != CEC_OP_ABORT_INVALID_OP);
-
- cec_msg_init(&msg, me, la);
- cec_msg_record_on_own(&msg);
- msg.msg[2] = 6; /* Invalid source operand */
- fail_on_test(!transmit_timeout(node, &msg));
- fail_on_test(!cec_msg_status_is_abort(&msg));
- fail_on_test(abort_reason(&msg) != CEC_OP_ABORT_INVALID_OP);
-
- struct cec_op_record_src rec_src = {};
-
- rec_src.type = CEC_OP_RECORD_SRC_DIGITAL;
- rec_src.digital.service_id_method = CEC_OP_SERVICE_ID_METHOD_BY_CHANNEL;
- rec_src.digital.dig_bcast_system = 0x7f; /* Invalid digital service broadcast system operand */
- rec_src.digital.channel.channel_number_fmt = CEC_OP_CHANNEL_NUMBER_FMT_1_PART;
- rec_src.digital.channel.major = 0;
- rec_src.digital.channel.minor = 30203;
- fail_on_test(one_touch_rec_on_send_invalid(node, me, la, rec_src));
-
- rec_src.type = CEC_OP_RECORD_SRC_DIGITAL;
- rec_src.digital.service_id_method = CEC_OP_SERVICE_ID_METHOD_BY_CHANNEL;
- rec_src.digital.dig_bcast_system = CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ARIB_BS;
- rec_src.digital.channel.channel_number_fmt = 0; /* Invalid channel number format operand */
- rec_src.digital.channel.major = 0;
- rec_src.digital.channel.minor = 30609;
- fail_on_test(one_touch_rec_on_send_invalid(node, me, la, rec_src));
-
- memset(&rec_src, 0, sizeof(rec_src));
- rec_src.type = CEC_OP_RECORD_SRC_ANALOG;
- rec_src.analog.ana_bcast_type = 0xff; /* Invalid analog broadcast type */
- rec_src.analog.ana_freq = (519250 * 10) / 625;
- rec_src.analog.bcast_system = CEC_OP_BCAST_SYSTEM_PAL_BG;
- fail_on_test(one_touch_rec_on_send_invalid(node, me, la, rec_src));
-
- memset(&rec_src, 0, sizeof(rec_src));
- rec_src.type = CEC_OP_RECORD_SRC_ANALOG;
- rec_src.analog.ana_bcast_type = CEC_OP_ANA_BCAST_TYPE_SATELLITE;
- rec_src.analog.ana_freq = (703250 * 10) / 625;
- rec_src.analog.bcast_system = 0xff; /* Invalid analog broadcast system */
- fail_on_test(one_touch_rec_on_send_invalid(node, me, la, rec_src));
-
- memset(&rec_src, 0, sizeof(rec_src));
- rec_src.type = CEC_OP_RECORD_SRC_ANALOG;
- rec_src.analog.ana_bcast_type = CEC_OP_ANA_BCAST_TYPE_TERRESTRIAL;
- rec_src.analog.ana_freq = 0; /* Invalid frequency */
- rec_src.analog.bcast_system = CEC_OP_BCAST_SYSTEM_NTSC_M;
- fail_on_test(one_touch_rec_on_send_invalid(node, me, la, rec_src));
-
- memset(&rec_src, 0, sizeof(rec_src));
- rec_src.type = CEC_OP_RECORD_SRC_ANALOG;
- rec_src.analog.ana_bcast_type = CEC_OP_ANA_BCAST_TYPE_CABLE;
- rec_src.analog.ana_freq = 0xffff; /* Invalid frequency */
- rec_src.analog.bcast_system = CEC_OP_BCAST_SYSTEM_SECAM_L;
- fail_on_test(one_touch_rec_on_send_invalid(node, me, la, rec_src));
-
- memset(&rec_src, 0, sizeof(rec_src));
- rec_src.type = CEC_OP_RECORD_SRC_EXT_PLUG;
- rec_src.ext_plug.plug = 0; /* Invalid plug */
- fail_on_test(one_touch_rec_on_send_invalid(node, me, la, rec_src));
-
- return OK;
-}
-
-static int one_touch_rec_off(struct node *node, unsigned me, unsigned la, bool interactive)
-{
- struct cec_msg msg;
-
- cec_msg_init(&msg, me, la);
- cec_msg_record_off(&msg, true);
- /* Allow 10s for reply because the spec says it may take several seconds to accurately respond. */
- fail_on_test(!transmit_timeout(node, &msg, 10000));
- if (unrecognized_op(&msg)) {
- fail_on_test(node->remote[la].prim_type == CEC_OP_PRIM_DEVTYPE_RECORD);
- return OK_NOT_SUPPORTED;
- }
- if (refused(&msg))
- return OK_REFUSED;
- if (cec_msg_status_is_abort(&msg))
- return OK_PRESUMED;
- if (timed_out(&msg))
- return OK_PRESUMED;
-
- __u8 rec_status;
-
- cec_ops_record_status(&msg, &rec_status);
-
- fail_on_test(rec_status != CEC_OP_RECORD_STATUS_TERMINATED_OK &&
- rec_status != CEC_OP_RECORD_STATUS_ALREADY_TERM);
-
- return OK;
-}
-
-static const vec_remote_subtests one_touch_rec_subtests{
- { "Record TV Screen", CEC_LOG_ADDR_MASK_TV, one_touch_rec_tv_screen },
- {
- "Record On",
- CEC_LOG_ADDR_MASK_RECORD | CEC_LOG_ADDR_MASK_BACKUP,
- one_touch_rec_on,
- },
- {
- "Record On Invalid Operand",
- CEC_LOG_ADDR_MASK_RECORD | CEC_LOG_ADDR_MASK_BACKUP,
- one_touch_rec_on_invalid,
- },
- { "Record Off", CEC_LOG_ADDR_MASK_RECORD | CEC_LOG_ADDR_MASK_BACKUP, one_touch_rec_off },
-
-};
-
-/* Timer Programming */
-
-static int timer_prog_set_analog_timer(struct node *node, unsigned me, unsigned la, bool interactive)
-{
- struct cec_msg msg;
-
- cec_msg_init(&msg, me, la);
- /* Set timer to start tomorrow, at current time, for 2 hr, 30 min. */
- time_t tomorrow = node->current_time + (24 * 60 * 60);
- struct tm *t = localtime(&tomorrow);
- cec_msg_set_analogue_timer(&msg, true, t->tm_mday, t->tm_mon + 1, t->tm_hour, t->tm_min, 2, 30,
- 0x7f, CEC_OP_ANA_BCAST_TYPE_CABLE, 7668, // 479.25 MHz
- node->remote[la].bcast_sys);
- fail_on_test(!transmit_timeout(node, &msg, 10000));
- fail_on_test(timed_out(&msg));
- if (unrecognized_op(&msg))
- return OK_NOT_SUPPORTED;
- if (refused(&msg))
- return OK_REFUSED;
- if (cec_msg_status_is_abort(&msg))
- return OK_PRESUMED;
- fail_on_test(timer_status_is_valid(msg));
-
- return OK;
-}
-
-static int timer_prog_set_digital_timer(struct node *node, unsigned me, unsigned la, bool interactive)
-{
- struct cec_msg msg;
- struct cec_op_digital_service_id digital_service_id = {};
-
- digital_service_id.service_id_method = CEC_OP_SERVICE_ID_METHOD_BY_CHANNEL;
- digital_service_id.channel.channel_number_fmt = CEC_OP_CHANNEL_NUMBER_FMT_1_PART;
- digital_service_id.channel.minor = 1;
- digital_service_id.dig_bcast_system = node->remote[la].dig_bcast_sys;
- cec_msg_init(&msg, me, la);
- /* Set timer to start 2 days from now, at current time, for 4 hr, 30 min. */
- time_t two_days_ahead = node->current_time + (2 * 24 * 60 * 60);
- struct tm *t = localtime(&two_days_ahead);
- cec_msg_set_digital_timer(&msg, true, t->tm_mday, t->tm_mon + 1, t->tm_hour,
- t->tm_min, 4, 30, CEC_OP_REC_SEQ_ONCE_ONLY, &digital_service_id);
- fail_on_test(!transmit_timeout(node, &msg, 10000));
- fail_on_test(timed_out(&msg));
- if (unrecognized_op(&msg))
- return OK_NOT_SUPPORTED;
- if (refused(&msg))
- return OK_REFUSED;
- if (cec_msg_status_is_abort(&msg))
- return OK_PRESUMED;
- fail_on_test(timer_status_is_valid(msg));
-
- return 0;
-}
-
-static int timer_prog_set_ext_timer(struct node *node, unsigned me, unsigned la, bool interactive)
-{
- struct cec_msg msg;
-
- cec_msg_init(&msg, me, la);
- /* Set timer to start 3 days from now, at current time, for 6 hr, 30 min. */
- time_t three_days_ahead = node->current_time + (3 * 24 * 60 * 60);
- struct tm *t = localtime(&three_days_ahead);
- cec_msg_set_ext_timer(&msg, true, t->tm_mday, t->tm_mon + 1, t->tm_hour, t->tm_min, 6, 30,
- CEC_OP_REC_SEQ_ONCE_ONLY, CEC_OP_EXT_SRC_PHYS_ADDR, 0, node->phys_addr);
- fail_on_test(!transmit_timeout(node, &msg, 10000));
- fail_on_test(timed_out(&msg));
- if (unrecognized_op(&msg))
- return OK_NOT_SUPPORTED;
- if (refused(&msg))
- return OK_REFUSED;
- if (cec_msg_status_is_abort(&msg))
- return OK_PRESUMED;
- fail_on_test(timer_status_is_valid(msg));
-
- return 0;
-}
-
-static int timer_prog_clear_analog_timer(struct node *node, unsigned me, unsigned la, bool interactive)
-{
- struct cec_msg msg;
-
- cec_msg_init(&msg, me, la);
- /* Clear timer set to start tomorrow, at current time, for 2 hr, 30 min. */
- time_t tomorrow = node->current_time + (24 * 60 * 60);
- struct tm *t = localtime(&tomorrow);
- cec_msg_clear_analogue_timer(&msg, true, t->tm_mday, t->tm_mon + 1, t->tm_hour, t->tm_min, 2, 30,
- 0x7f, CEC_OP_ANA_BCAST_TYPE_CABLE,7668, // 479.25 MHz
- node->remote[la].bcast_sys);
- fail_on_test(!transmit_timeout(node, &msg, 10000));
- fail_on_test(timed_out(&msg));
- if (unrecognized_op(&msg))
- return OK_NOT_SUPPORTED;
- if (refused(&msg))
- return OK_REFUSED;
- if (cec_msg_status_is_abort(&msg))
- return OK_PRESUMED;
- fail_on_test(timer_cleared_status_is_valid(msg));
-
- return 0;
-}
-
-static int timer_prog_clear_digital_timer(struct node *node, unsigned me, unsigned la, bool interactive)
-{
- struct cec_msg msg;
- struct cec_op_digital_service_id digital_service_id = {};
-
- digital_service_id.service_id_method = CEC_OP_SERVICE_ID_METHOD_BY_CHANNEL;
- digital_service_id.channel.channel_number_fmt = CEC_OP_CHANNEL_NUMBER_FMT_1_PART;
- digital_service_id.channel.minor = 1;
- digital_service_id.dig_bcast_system = node->remote[la].dig_bcast_sys;
- cec_msg_init(&msg, me, la);
- /* Clear timer set to start 2 days from now, at current time, for 4 hr, 30 min. */
- time_t two_days_ahead = node->current_time + (2 * 24 * 60 * 60);
- struct tm *t = localtime(&two_days_ahead);
- cec_msg_clear_digital_timer(&msg, true, t->tm_mday, t->tm_mon + 1, t->tm_hour,
- t->tm_min, 4, 30, CEC_OP_REC_SEQ_ONCE_ONLY, &digital_service_id);
- fail_on_test(!transmit_timeout(node, &msg, 10000));
- fail_on_test(timed_out(&msg));
- if (unrecognized_op(&msg))
- return OK_NOT_SUPPORTED;
- if (refused(&msg))
- return OK_REFUSED;
- if (cec_msg_status_is_abort(&msg))
- return OK_PRESUMED;
- fail_on_test(timer_cleared_status_is_valid(msg));
-
- return 0;
-}
-
-static int timer_prog_clear_ext_timer(struct node *node, unsigned me, unsigned la, bool interactive)
-{
- struct cec_msg msg;
-
- cec_msg_init(&msg, me, la);
- /* Clear timer set to start 3 days from now, at current time, for 6 hr, 30 min. */
- time_t three_days_ahead = node->current_time + (3 * 24 * 60 * 60);
- struct tm *t = localtime(&three_days_ahead);
- cec_msg_clear_ext_timer(&msg, true, t->tm_mday, t->tm_mon + 1, t->tm_hour, t->tm_min, 6, 30,
- CEC_OP_REC_SEQ_ONCE_ONLY, CEC_OP_EXT_SRC_PHYS_ADDR, 0, node->phys_addr);
- fail_on_test(!transmit_timeout(node, &msg, 10000));
- fail_on_test(timed_out(&msg));
- if (unrecognized_op(&msg))
- return OK_NOT_SUPPORTED;
- if (refused(&msg))
- return OK_REFUSED;
- if (cec_msg_status_is_abort(&msg))
- return OK_PRESUMED;
- fail_on_test(timer_cleared_status_is_valid(msg));
-
- return 0;
-}
-
-static int timer_prog_set_prog_title(struct node *node, unsigned me, unsigned la, bool interactive)
-{
- struct cec_msg msg;
-
- cec_msg_init(&msg, me, la);
- cec_msg_set_timer_program_title(&msg, "Super-Hans II");
- fail_on_test(!transmit_timeout(node, &msg));
- if (unrecognized_op(&msg))
- return OK_NOT_SUPPORTED;
- if (refused(&msg))
- return OK_REFUSED;
-
- return OK_PRESUMED;
-}
-
-static int timer_errors(struct node *node, unsigned me, unsigned la, bool interactive)
-{
- struct cec_msg msg;
-
- /* Day error: November 31, at 6:00 am, for 1 hr. */
- fail_on_test(send_timer_error(node, me, la, 31, Nov, 6, 0, 1, 0, CEC_OP_REC_SEQ_ONCE_ONLY));
-
- /* Day error: December 32, at 6:00 am, for 1 hr. */
- fail_on_test(send_timer_error(node, me, la, 32, Dec, 6, 0, 1, 0, CEC_OP_REC_SEQ_ONCE_ONLY));
-
- /* Day error: 0, in January, at 6:00 am, for 1 hr. Day range begins at 1. */
- fail_on_test(send_timer_error(node, me, la, 0, Jan, 6, 0, 1, 0, CEC_OP_REC_SEQ_ONCE_ONLY));
-
- /* Month error: 0, on day 5, at 6:00 am, for 1 hr. CEC month range is 1-12. */
- fail_on_test(send_timer_error(node, me, la, 5, 0, 6, 0, 1, 0, CEC_OP_REC_SEQ_ONCE_ONLY));
-
- /* Month error: 13, on day 5, at 6:00 am, for 1 hr. */
- fail_on_test(send_timer_error(node, me, la, 5, 13, 6, 0, 1, 0, CEC_OP_REC_SEQ_ONCE_ONLY));
-
- /* Start hour error: 24 hr, on August 5, for 1 hr. Start hour range is 0-23. */
- fail_on_test(send_timer_error(node, me, la, 5, Aug, 24, 0, 1, 0, CEC_OP_REC_SEQ_ONCE_ONLY));
-
- /* Start min error: 60 min, on August 5, for 1 hr. Start min range is 0-59. */
- fail_on_test(send_timer_error(node, me, la, 5, Aug, 0, 60, 1, 0, CEC_OP_REC_SEQ_ONCE_ONLY));
-
- /* Recording duration error: 0 hr, 0 min on August 5, at 6:00am. */
- fail_on_test(send_timer_error(node, me, la, 5, Aug, 6, 0, 0, 0, CEC_OP_REC_SEQ_ONCE_ONLY));
-
- /* Duplicate timer error: start 2 hrs from now, for 1 hr. */
- time_t two_hours_ahead = node->current_time + (2 * 60 * 60);
- struct tm *t = localtime(&two_hours_ahead);
- cec_msg_init(&msg, me, la);
- cec_msg_set_analogue_timer(&msg, true, t->tm_mday, t->tm_mon + 1, t->tm_hour, t->tm_min, 1, 0,
- CEC_OP_REC_SEQ_ONCE_ONLY,CEC_OP_ANA_BCAST_TYPE_CABLE,
- 7668, // 479.25 MHz
- node->remote[la].bcast_sys);
- fail_on_test(!transmit_timeout(node, &msg, 10000));
- fail_on_test(timed_out_or_abort(&msg));
- fail_on_test(timer_has_error(msg)); /* The first timer should be set. */
- fail_on_test(send_timer_error(node, me, la, t->tm_mday, t->tm_mon + 1, t->tm_hour,
- t->tm_min, 1, 0, CEC_OP_REC_SEQ_ONCE_ONLY));
-
- /* Clear the timer that was set to test duplicate timers. */
- fail_on_test(clear_timer(node, me, la, t->tm_mday, t->tm_mon + 1, t->tm_hour, t->tm_min, 1, 0,
- CEC_OP_REC_SEQ_ONCE_ONLY));
-
- /* Recording sequence error: 0xff, on August 5, at 6:00 am, for 1 hr. */
- fail_on_test(send_timer_error(node, me, la, 5, Aug, 6, 0, 1, 0, 0xff));
-
- /* Error in last day of February, at 6:00 am, for 1 hr. */
- time_t current_time = node->current_time;
- t = localtime(&current_time);
- if ((t->tm_mon + 1) > Feb)
- t->tm_year++; /* The timer will be for next year. */
- if (!(t->tm_year % 4) && ((t->tm_year % 100) || !(t->tm_year % 400)))
- fail_on_test(send_timer_error(node, me, la, 30, Feb, 6, 0, 1, 0, CEC_OP_REC_SEQ_ONCE_ONLY));
- else
- fail_on_test(send_timer_error(node, me, la, 29, Feb, 6, 0, 1, 0, CEC_OP_REC_SEQ_ONCE_ONLY));
-
- return OK;
-}
-
-static int timer_overlap_warning(struct node *node, unsigned me, unsigned la, bool interactive)
-{
- struct cec_msg msg;
-
- time_t tomorrow = node->current_time + (24 * 60 * 60);
- struct tm *t = localtime(&tomorrow);
-
- /* No overlap: set timer for tomorrow at 8:00 am for 2 hr. */
- cec_msg_init(&msg, me, la);
- cec_msg_set_analogue_timer(&msg, true, t->tm_mday, t->tm_mon + 1, 8, 0, 2, 0,
- CEC_OP_REC_SEQ_ONCE_ONLY, CEC_OP_ANA_BCAST_TYPE_CABLE,
- 7668, // 479.25 MHz
- node->remote[la].bcast_sys);
- fail_on_test(!transmit_timeout(node, &msg, 10000));
- if (unrecognized_op(&msg))
- return OK_NOT_SUPPORTED;
- fail_on_test(timed_out_or_abort(&msg));
- fail_on_test(timer_has_error(msg));
- fail_on_test(timer_overlap_warning_is_set(msg));
-
- /* No overlap, just adjacent: set timer for tomorrow at 10:00 am for 15 min. */
- cec_msg_init(&msg, me, la);
- cec_msg_set_analogue_timer(&msg, true, t->tm_mday, t->tm_mon + 1, 10, 0, 0, 15,
- CEC_OP_REC_SEQ_ONCE_ONLY, CEC_OP_ANA_BCAST_TYPE_CABLE,
- 7668, // 479.25 MHz
- node->remote[la].bcast_sys);
- fail_on_test(!transmit_timeout(node, &msg, 10000));
- fail_on_test(timed_out_or_abort(&msg));
- fail_on_test(timer_has_error(msg));
- fail_on_test(timer_overlap_warning_is_set(msg));
-
- /* No overlap, just adjacent: set timer for tomorrow at 7:45 am for 15 min. */
- cec_msg_init(&msg, me, la);
- cec_msg_set_analogue_timer(&msg, true, t->tm_mday, t->tm_mon + 1, 7, 45, 0, 15,
- CEC_OP_REC_SEQ_ONCE_ONLY, CEC_OP_ANA_BCAST_TYPE_CABLE,
- 7668, // 479.25 MHz
- node->remote[la].bcast_sys);
- fail_on_test(!transmit_timeout(node, &msg, 10000));
- fail_on_test(timed_out_or_abort(&msg));
- fail_on_test(timer_has_error(msg));
- fail_on_test(timer_overlap_warning_is_set(msg));
-
- /* Overlap tail end: set timer for tomorrow at 9:00 am for 2 hr, repeats on Sun. */
- fail_on_test(send_timer_overlap(node, me, la, t->tm_mday, t->tm_mon + 1, 9, 0, 2, 0, 0x1));
-
- /* Overlap front end: set timer for tomorrow at 7:00 am for 1 hr, 30 min. */
- fail_on_test(send_timer_overlap(node, me, la, t->tm_mday, t->tm_mon + 1, 7, 0, 1, 30, 0x1));
-
- /* Overlap same start time: set timer for tomorrow at 8:00 am for 30 min. */
- fail_on_test(send_timer_overlap(node, me, la, t->tm_mday, t->tm_mon + 1, 8, 0, 0, 30, 0x1));
-
- /* Overlap same end time: set timer for tomorrow at 9:30 am for 30 min. */
- fail_on_test(send_timer_overlap(node, me, la, t->tm_mday, t->tm_mon + 1, 9, 30, 0, 30, 0x1));
-
- /* Overlap all timers: set timer for tomorrow at 6:00 am for 6 hr. */
- fail_on_test(send_timer_overlap(node, me, la, t->tm_mday, t->tm_mon + 1, 6, 0, 6, 0, 0x1));
-
- /* Clear all the timers. */
- fail_on_test(clear_timer(node, me, la, t->tm_mday, t->tm_mon + 1, 8, 0, 2, 0,
- CEC_OP_REC_SEQ_ONCE_ONLY));
- fail_on_test(clear_timer(node, me, la, t->tm_mday, t->tm_mon + 1, 10, 0, 0, 15,
- CEC_OP_REC_SEQ_ONCE_ONLY));
- fail_on_test(clear_timer(node, me, la, t->tm_mday, t->tm_mon + 1, 7, 45, 0, 15,
- CEC_OP_REC_SEQ_ONCE_ONLY));
- fail_on_test(clear_timer(node, me, la, t->tm_mday, t->tm_mon + 1, 9, 0, 2, 0, 0x1));
- fail_on_test(clear_timer(node, me, la, t->tm_mday, t->tm_mon + 1, 7, 0, 1, 30, 0x1));
- fail_on_test(clear_timer(node, me, la, t->tm_mday, t->tm_mon + 1, 8, 0, 0, 30, 0x1));
- fail_on_test(clear_timer(node, me, la, t->tm_mday, t->tm_mon + 1, 9, 30, 0, 30, 0x1));
- fail_on_test(clear_timer(node, me, la, t->tm_mday, t->tm_mon + 1, 6, 0, 6, 0, 0x1));
-
- return OK;
-}
-
-static const vec_remote_subtests timer_prog_subtests{
- {
- "Set Analogue Timer",
- CEC_LOG_ADDR_MASK_RECORD | CEC_LOG_ADDR_MASK_BACKUP,
- timer_prog_set_analog_timer,
- },
- {
- "Set Digital Timer",
- CEC_LOG_ADDR_MASK_RECORD | CEC_LOG_ADDR_MASK_BACKUP,
- timer_prog_set_digital_timer,
- },
- {
- "Set Timer Program Title",
- CEC_LOG_ADDR_MASK_RECORD | CEC_LOG_ADDR_MASK_BACKUP,
- timer_prog_set_prog_title,
- },
- {
- "Set External Timer",
- CEC_LOG_ADDR_MASK_RECORD | CEC_LOG_ADDR_MASK_BACKUP,
- timer_prog_set_ext_timer,
- },
- {
- "Clear Analogue Timer",
- CEC_LOG_ADDR_MASK_RECORD | CEC_LOG_ADDR_MASK_BACKUP,
- timer_prog_clear_analog_timer,
- },
- {
- "Clear Digital Timer",
- CEC_LOG_ADDR_MASK_RECORD | CEC_LOG_ADDR_MASK_BACKUP,
- timer_prog_clear_digital_timer,
- },
- {
- "Clear External Timer",
- CEC_LOG_ADDR_MASK_RECORD | CEC_LOG_ADDR_MASK_BACKUP,
- timer_prog_clear_ext_timer,
- },
- {
- "Set Timers with Errors",
- CEC_LOG_ADDR_MASK_RECORD | CEC_LOG_ADDR_MASK_BACKUP,
- timer_errors,
- },
- {
- "Set Overlapping Timers",
- CEC_LOG_ADDR_MASK_RECORD | CEC_LOG_ADDR_MASK_BACKUP,
- timer_overlap_warning,
- },
-};
-
static const char *hec_func_state2s(__u8 hfs)
{
switch (hfs) {