From patchwork Thu Jun 24 04:06:42 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Deborah Brouwer X-Patchwork-Id: 12340861 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-15.7 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id F195AC48BDF for ; Thu, 24 Jun 2021 04:06:58 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id DD30A613C5 for ; Thu, 24 Jun 2021 04:06:58 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229465AbhFXEJQ (ORCPT ); Thu, 24 Jun 2021 00:09:16 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:44802 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229379AbhFXEJQ (ORCPT ); Thu, 24 Jun 2021 00:09:16 -0400 Received: from mail-pf1-x442.google.com (mail-pf1-x442.google.com [IPv6:2607:f8b0:4864:20::442]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id BB90EC061574 for ; Wed, 23 Jun 2021 21:06:56 -0700 (PDT) Received: by mail-pf1-x442.google.com with SMTP id 21so4078867pfp.3 for ; Wed, 23 Jun 2021 21:06:56 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=lITQes0iBLiJqo64kQcf6MfY2419xehwB0F4UXUdPlU=; b=oqFIf53xHvvw+aq8FdBenGq0UrvBDmjlHXnR+VBf61qjTg2ksYfQFRFJ4aMB7CkFqd X9h1ZC5p242hlmvh5JzjIMiEqMxoDZkEyHsOH7+giJAnWqOb5EzRj9X7/8bdlCIOelC8 vc51NAm6GVF3Pdx7b+xmvK0yZZeg9nqO0TvG/gy9+urEIEz8ekzOdUoxUVdqhNbg/EoS cXxuMWDimMAywYVGDXqdmfEJCjDHm+QW8cWaNctnvUC0C08iXgyx3ajGUhQwUIIRG5/6 GzKXGjMfv4sqGG4V6Yj67UiHyD7a3ET4KBypHpbgzoUyQsRSfR4zftdXyRsHap8Ad89Z G4jg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=lITQes0iBLiJqo64kQcf6MfY2419xehwB0F4UXUdPlU=; b=Y2aloRiWIYCgH+V9DljKRjD6DGhTqbOLxaPNZ2Y+cCezgbekRkWxed1B7gRF4I5jUe LFDsC/YkhfzYUYakutPtFHTxYSmGEfS15wfb7Cr1MLGCCLY5ipwv/53ue1g0RnTBw7ww DAc+QA0/q5YSwvuRPaKItPcs84MCvqlWxyTEocS1bMXvIBUjcf+oCJd1fa/5JuJGw1So jrPMmD5ucUMuB6ELtAWdw2dZ+obSj98rI9007MRosZlKQdGXvtFy89T4VVgcN37mDqce 26DmwXEstyvDl7X7K/RRiPrr2OuRc9IK5CsPsIprnblcggsO8HiJX+vZl7lR/8y4cgHb EA/w== X-Gm-Message-State: AOAM533DKgIMVthhvumicJnGeEQDkfSZAKafFlz65ViroCmWAa2+a5M0 Wcpeb3UmjatD1RXhb5X8SlGpr6W/N1NF4w== X-Google-Smtp-Source: ABdhPJyaw/jdFel4WjbI+Zr3y0M8jtLG6BIW8LurfwbjqCSncuObr5t8rxrZ841K/X4XshmUXL92CQ== X-Received: by 2002:a63:eb4f:: with SMTP id b15mr2948128pgk.2.1624507616333; Wed, 23 Jun 2021 21:06:56 -0700 (PDT) Received: from ada-comp.hitronhub.home (S0106ac202ecb0523.gv.shawcable.net. [70.67.120.89]) by smtp.gmail.com with ESMTPSA id s20sm7094320pjn.23.2021.06.23.21.06.55 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 23 Jun 2021 21:06:56 -0700 (PDT) From: Deborah Brouwer To: linux-media@vger.kernel.org Cc: hverkuil@xs4all.nl, jaffe1@gmail.com, Deborah Brouwer Subject: [PATCH v4 1/3] cec-follower: use log_addr_type to get local device type Date: Wed, 23 Jun 2021 21:06:42 -0700 Message-Id: <59c23b55c0335521cad505907d1d0e704e034359.1624506445.git.deborahbrouwer3563@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: References: MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-media@vger.kernel.org A device may use a Backup logical address (aka Reserved in CEC Version < 2.0) if the logical addresses that the device would normally used are unavailable. Since a Backup logical address is not unique to any device type, it cannot be used to determine the device type of the follower. Instead use the more accurate log_addr_type as returned by CEC_ADAP_G_LOG_ADDRS to find the device type. Signed-off-by: Deborah Brouwer --- utils/cec-follower/cec-follower.h | 2 +- utils/cec-follower/cec-processing.cpp | 7 ++++--- utils/cec-follower/cec-tuner.cpp | 2 +- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/utils/cec-follower/cec-follower.h b/utils/cec-follower/cec-follower.h index 3fa95417..343ae998 100644 --- a/utils/cec-follower/cec-follower.h +++ b/utils/cec-follower/cec-follower.h @@ -222,7 +222,7 @@ void sad_encode(const struct short_audio_desc *sad, __u32 *descriptor); // cec-tuner.cpp void tuner_dev_info_init(struct state *state); -void process_tuner_record_timer_msgs(struct node *node, struct cec_msg &msg, unsigned me); +void process_tuner_record_timer_msgs(struct node *node, struct cec_msg &msg, unsigned me, __u8 type); // CEC processing void reply_feature_abort(struct node *node, struct cec_msg *msg, diff --git a/utils/cec-follower/cec-processing.cpp b/utils/cec-follower/cec-processing.cpp index 41bb990c..b1c8f3d9 100644 --- a/utils/cec-follower/cec-processing.cpp +++ b/utils/cec-follower/cec-processing.cpp @@ -271,7 +271,7 @@ static void update_deck_state(struct node *node, unsigned me, __u8 deck_state_ne } } -static void processMsg(struct node *node, struct cec_msg &msg, unsigned me) +static void processMsg(struct node *node, struct cec_msg &msg, unsigned me, __u8 type) { __u8 to = cec_msg_destination(&msg); __u8 from = cec_msg_initiator(&msg); @@ -672,7 +672,7 @@ static void processMsg(struct node *node, struct cec_msg &msg, unsigned me) case CEC_MSG_SET_TIMER_PROGRAM_TITLE: case CEC_MSG_TIMER_CLEARED_STATUS: case CEC_MSG_TIMER_STATUS: - process_tuner_record_timer_msgs(node, msg, me); + process_tuner_record_timer_msgs(node, msg, me, type); return; /* Dynamic Auto Lipsync */ @@ -1009,6 +1009,7 @@ void testProcessing(struct node *node, bool wallclock) doioctl(node, CEC_S_MODE, &mode); doioctl(node, CEC_ADAP_G_LOG_ADDRS, &laddrs); me = laddrs.log_addr[0]; + __u8 type = laddrs.log_addr_type[0]; poll_remote_devs(node, me); @@ -1088,7 +1089,7 @@ void testProcessing(struct node *node, bool wallclock) msg.sequence, ts2s(msg.rx_ts, wallclock).c_str()); } if (node->adap_la_mask) - processMsg(node, msg, me); + processMsg(node, msg, me, type); } __u8 pwr_state = current_power_state(node); diff --git a/utils/cec-follower/cec-tuner.cpp b/utils/cec-follower/cec-tuner.cpp index b9c21684..d1718986 100644 --- a/utils/cec-follower/cec-tuner.cpp +++ b/utils/cec-follower/cec-tuner.cpp @@ -482,7 +482,7 @@ static bool analog_set_tuner_dev_info(struct node *node, struct cec_msg *msg) return false; } -void process_tuner_record_timer_msgs(struct node *node, struct cec_msg &msg, unsigned me) +void process_tuner_record_timer_msgs(struct node *node, struct cec_msg &msg, unsigned me, __u8 type) { bool is_bcast = cec_msg_is_broadcast(&msg); From patchwork Thu Jun 24 04:06:43 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Deborah Brouwer X-Patchwork-Id: 12340863 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-12.9 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,UNWANTED_LANGUAGE_BODY, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 56783C49EA5 for ; Thu, 24 Jun 2021 04:07:01 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 3A3F8613C5 for ; Thu, 24 Jun 2021 04:07:01 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229772AbhFXEJS (ORCPT ); Thu, 24 Jun 2021 00:09:18 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:44812 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229379AbhFXEJS (ORCPT ); Thu, 24 Jun 2021 00:09:18 -0400 Received: from mail-pj1-x1044.google.com (mail-pj1-x1044.google.com [IPv6:2607:f8b0:4864:20::1044]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 5D57CC061574 for ; Wed, 23 Jun 2021 21:06:59 -0700 (PDT) Received: by mail-pj1-x1044.google.com with SMTP id m15-20020a17090a5a4fb029016f385ffad0so2682275pji.0 for ; Wed, 23 Jun 2021 21:06:59 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=N0EgdZC0HZLg72h1xV3U2l7/aTfX5ujBJgUfX6rTvKs=; b=bfuWn/iihMf/QglYuZ7UhVQVBEP507vT1SHgtnadBxw180aC3rYTa6sX2gnHAB5Ca9 DZqHf6g4kUnhG5IWpg9yMdxRhNeP/9ZW0okVgdctr1vqXa8aS3PhBo55pTPcZORRVOpC RmASks/ldUwU89+zlTo4n8fXUNP1bkOR5DYW1kjkVxF0Zyrhv+eiG0RIgqCjXxA+YQIq U2O2MuPDJ9zZPRzXkUvGaj12wUNUTDY1CGeU93WuHwY3cWswGxCaNIYX9rDj+X2BQoEf 2GwPZxwpTSB+9YcAsMJz7xT106d94O1Pyuqx6X1fsaVOWC6KiTlunwq4zV42ALZEKd8S r7wg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=N0EgdZC0HZLg72h1xV3U2l7/aTfX5ujBJgUfX6rTvKs=; b=fcl8/5JBj2+SNAQWV5117vbunc85hp02n/dH4r1DoUAX87/WjERdRLAT07UyCBEVdY he+fcMdEB2W7wwp4BKS5CIxu1lTWz/wuReDQR4XLobhkTRzPVm7T2NSBYmtX2fGjgmTH QwkILSRVtngliAWCatRHeQKuXrKGw8Kl/y5p2OMEYwNtztfSlT8oVrUtUPH7hdvhIkkC DnK2ncB1+1+OrUjanXEv/3Tp+dSq0YAsnodtW07zMQRr+M6Yc++WJSVKYXXj4Rl1NP5a LQGJD6T2DDGjNVYLCot2aUC9r7QXyJ8rw72bDJTTOY0OyHUVg6lJIhcaTg9MsKL5bRa5 trdw== X-Gm-Message-State: AOAM530QbgGQ6U9Et/CBD3pnQtX7/VhNM/XFBiEjv3/zVGjgSUhjhnFY dSb6VGmktN/C0mbcPfgHWJF4GRBIGrslSw== X-Google-Smtp-Source: ABdhPJzkBUjiJM6GCLLqyr9KVvdvx6oZCxAcpBkoHua4xHM1PEYd14pZefGNLa6vVdJNY9qCI6zizQ== X-Received: by 2002:a17:90a:2e87:: with SMTP id r7mr13033768pjd.232.1624507618656; Wed, 23 Jun 2021 21:06:58 -0700 (PDT) Received: from ada-comp.hitronhub.home (S0106ac202ecb0523.gv.shawcable.net. [70.67.120.89]) by smtp.gmail.com with ESMTPSA id s20sm7094320pjn.23.2021.06.23.21.06.57 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 23 Jun 2021 21:06:58 -0700 (PDT) From: Deborah Brouwer To: linux-media@vger.kernel.org Cc: hverkuil@xs4all.nl, jaffe1@gmail.com, Deborah Brouwer Subject: [PATCH v4 2/3] cec: expand One Touch Record tests Date: Wed, 23 Jun 2021 21:06:43 -0700 Message-Id: X-Mailer: git-send-email 2.25.1 In-Reply-To: References: MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-media@vger.kernel.org Expand the One Touch Record tests so that the follower and initiator know their local and remote device types and respond accordingly. Send Record TV Screen and check that Record On source replies are valid. Send Record On source messages and check that Record Status replies are valid. Send Record Off and check that the recording terminates. Signed-off-by: Deborah Brouwer --- utils/cec-compliance/cec-compliance.cpp | 1 + utils/cec-compliance/cec-compliance.h | 1 + utils/cec-compliance/cec-test.cpp | 366 ++++++++++++++++++++++-- utils/cec-follower/cec-follower.cpp | 1 + utils/cec-follower/cec-follower.h | 3 +- utils/cec-follower/cec-processing.cpp | 4 +- utils/cec-follower/cec-tuner.cpp | 222 ++++++++++++-- 7 files changed, 549 insertions(+), 49 deletions(-) diff --git a/utils/cec-compliance/cec-compliance.cpp b/utils/cec-compliance/cec-compliance.cpp index c04904c2..d4b12298 100644 --- a/utils/cec-compliance/cec-compliance.cpp +++ b/utils/cec-compliance/cec-compliance.cpp @@ -1236,6 +1236,7 @@ int main(int argc, char **argv) node.num_log_addrs = laddrs.num_log_addrs; memcpy(node.log_addr, laddrs.log_addr, laddrs.num_log_addrs); node.adap_la_mask = laddrs.log_addr_mask; + node.prim_devtype = laddrs.primary_device_type[0]; printf("Find remote devices:\n"); printf("\tPolling: %s\n", ok(poll_remote_devs(&node))); diff --git a/utils/cec-compliance/cec-compliance.h b/utils/cec-compliance/cec-compliance.h index 818181ab..41e2d63d 100644 --- a/utils/cec-compliance/cec-compliance.h +++ b/utils/cec-compliance/cec-compliance.h @@ -166,6 +166,7 @@ struct node { struct remote remote[16]; __u16 phys_addr; bool in_standby; + __u8 prim_devtype; }; struct remote_subtest { diff --git a/utils/cec-compliance/cec-test.cpp b/utils/cec-compliance/cec-test.cpp index 40d8369d..864ab83c 100644 --- a/utils/cec-compliance/cec-test.cpp +++ b/utils/cec-compliance/cec-test.cpp @@ -48,6 +48,69 @@ 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); + 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 and 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; + } +} + /* System Information */ int system_info_polling(struct node *node, unsigned me, unsigned la, bool interactive) @@ -1141,24 +1204,14 @@ static const vec_remote_subtests tuner_ctl_subtests{ /* One Touch Record */ -/* - TODO: These are very rudimentary tests which should be expanded. - - - The HDMI CEC 1.4b spec details that Standby shall not be acted upon while the - device is recording, but it should remember that it received Standby. - */ - static int one_touch_rec_tv_screen(struct node *node, unsigned me, unsigned la, bool interactive) { - /* - TODO: - - Page 36 in HDMI CEC 1.4b spec lists additional behaviors that should be - checked for. - - The TV should ignore this message when received from other LA than Recording or - Reserved. - */ struct cec_msg msg; + cec_msg_init(&msg, me, la); + cec_msg_report_physical_addr(&msg, node->phys_addr, node->prim_devtype); + fail_on_test(!transmit_timeout(node, &msg)); + cec_msg_init(&msg, me, la); cec_msg_record_tv_screen(&msg, true); fail_on_test(!transmit_timeout(node, &msg)); @@ -1172,45 +1225,283 @@ static int one_touch_rec_tv_screen(struct node *node, unsigned me, unsigned la, 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)); - return 0; + struct cec_op_record_src rec_src = {}; + + cec_ops_record_on(&msg, &rec_src); + + if (rec_src.type < CEC_OP_RECORD_SRC_OWN || rec_src.type > CEC_OP_RECORD_SRC_EXT_PHYS_ADDR) + return fail("Invalid source.\n"); + + if (rec_src.type == CEC_OP_RECORD_SRC_DIGITAL && + rec_src.digital.service_id_method == CEC_OP_SERVICE_ID_METHOD_BY_DIG_ID) { + 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.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) { - /* - TODO: Page 36 in HDMI CEC 1.4b spec lists additional behaviors that should be - checked for. - */ 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); - fail_on_test(!transmit_timeout(node, &msg)); + /* 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)); - fail_on_test(cec_has_record(1 << la) && unrecognized_op(&msg)); - if (unrecognized_op(&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; - return 0; + __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)); + + 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 = 1046; + rec_src.digital.arib.service_id = 30505; + 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_DIG_ID; + rec_src.digital.dig_bcast_system = CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ATSC_T; + rec_src.digital.atsc.transport_id = 1675; + rec_src.digital.atsc.program_number = 3; + 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_S2; + rec_src.digital.dvb.transport_id = 61; + rec_src.digital.dvb.service_id = 7193; + rec_src.digital.dvb.orig_network_id = 70; + 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_ARIB_T; + rec_src.digital.channel.channel_number_fmt = 1; + rec_src.digital.channel.major = 0; + rec_src.digital.channel.minor = 51992; + 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_SAT; + rec_src.digital.channel.channel_number_fmt = 2; + rec_src.digital.channel.major = 3; + rec_src.digital.channel.minor = 55295; + 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_DVB_T; + rec_src.digital.channel.channel_number_fmt = 1; + rec_src.digital.channel.major = 0; + rec_src.digital.channel.minor = 21; + 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_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_off(struct node *node, unsigned me, unsigned la, bool interactive) +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_off(&msg, false); + cec_msg_record_on_own(&msg); + msg.msg[2] = 0; /* Invalid source operand */ fail_on_test(!transmit_timeout(node, &msg)); - fail_on_test(cec_has_record(1 << la) && unrecognized_op(&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 */ + rec_src.digital.channel.channel_number_fmt = 1; + 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)); + + 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_ATSC_SAT; + rec_src.digital.atsc.transport_id = 0; /* Invalid transport id */ + rec_src.digital.atsc.program_number = 50316; + 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_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 = 0; /* Invalid service id */ + rec_src.digital.dvb.orig_network_id = 8945; + 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_TERRESTRIAL; + rec_src.analog.ana_freq = 0; /* Invalid analog 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 analog 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_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_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); + fail_on_test(!transmit_timeout(node, &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)) @@ -1218,13 +1509,30 @@ static int one_touch_rec_off(struct node *node, unsigned me, unsigned la, bool i if (timed_out(&msg)) return OK_PRESUMED; - return 0; + __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, one_touch_rec_on }, - { "Record Off", CEC_LOG_ADDR_MASK_RECORD, one_touch_rec_off }, + { + "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 */ diff --git a/utils/cec-follower/cec-follower.cpp b/utils/cec-follower/cec-follower.cpp index ff47d698..482192e7 100644 --- a/utils/cec-follower/cec-follower.cpp +++ b/utils/cec-follower/cec-follower.cpp @@ -317,6 +317,7 @@ void state_init(struct node &node) node.state.deck_report_changes_to = 0; node.state.deck_state = CEC_OP_DECK_INFO_STOP; node.state.deck_skip_start = 0; + node.state.one_touch_record_on = false; tuner_dev_info_init(&node.state); node.state.last_aud_rate_rx_ts = 0; } diff --git a/utils/cec-follower/cec-follower.h b/utils/cec-follower/cec-follower.h index 343ae998..589ea6bf 100644 --- a/utils/cec-follower/cec-follower.h +++ b/utils/cec-follower/cec-follower.h @@ -53,6 +53,7 @@ struct state { __u8 deck_report_changes_to; __u8 deck_state; __u64 deck_skip_start; + bool one_touch_record_on; time_t toggle_power_status; __u64 last_aud_rate_rx_ts; }; @@ -62,6 +63,7 @@ struct node { const char *device; unsigned caps; unsigned available_log_addrs; + __u8 remote_prim_devtype; unsigned adap_la_mask; unsigned remote_la_mask; __u16 remote_phys_addr[15]; @@ -74,7 +76,6 @@ struct node { bool has_deck_ctl; bool has_rec_tv; bool has_osd_string; - bool ignore_la[16]; unsigned short ignore_opcode[256]; }; diff --git a/utils/cec-follower/cec-processing.cpp b/utils/cec-follower/cec-processing.cpp index b1c8f3d9..f985a841 100644 --- a/utils/cec-follower/cec-processing.cpp +++ b/utils/cec-follower/cec-processing.cpp @@ -396,8 +396,10 @@ static void processMsg(struct node *node, struct cec_msg &msg, unsigned me, __u8 __u8 prim_dev_type; cec_ops_report_physical_addr(&msg, &phys_addr, &prim_dev_type); - if (from < 15) + if (from < 15) { node->remote_phys_addr[from] = phys_addr; + node->remote_prim_devtype = prim_dev_type; + } return; } diff --git a/utils/cec-follower/cec-tuner.cpp b/utils/cec-follower/cec-tuner.cpp index d1718986..4ecb62a6 100644 --- a/utils/cec-follower/cec-tuner.cpp +++ b/utils/cec-follower/cec-tuner.cpp @@ -482,6 +482,155 @@ static bool analog_set_tuner_dev_info(struct node *node, struct cec_msg *msg) return false; } +static bool digital_service_info_valid(const struct cec_op_record_src &rec_src) +{ + switch (rec_src.digital.dig_bcast_system) { + case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ARIB_GEN: + case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ARIB_CS: + case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ATSC_GEN: + case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ATSC_CABLE: + case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_DVB_GEN: + case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_DVB_C: + case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_DVB_S: + return true; + case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ARIB_BS: + if (rec_src.digital.service_id_method == CEC_OP_SERVICE_ID_METHOD_BY_DIG_ID) { + for (unsigned i = 0; i < NUM_DIGITAL_CHANS; i++) { + + if (rec_src.digital.arib.transport_id == digital_arib_data[0][i].tsid && + rec_src.digital.arib.service_id == digital_arib_data[0][i].sid && + rec_src.digital.arib.orig_network_id == digital_arib_data[0][i].onid) + return true; + } + } else { + for (unsigned i = 0; i < NUM_DIGITAL_CHANS; i++) { + + if (rec_src.digital.channel.channel_number_fmt == digital_arib_data[0][i].fmt && + rec_src.digital.channel.major == digital_arib_data[0][i].major && + rec_src.digital.channel.minor == digital_arib_data[0][i].minor) + return true; + } + } + return false; + case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ARIB_T: + if (rec_src.digital.service_id_method == CEC_OP_SERVICE_ID_METHOD_BY_DIG_ID) { + for (unsigned i = 0; i < NUM_DIGITAL_CHANS; i++) { + + if (rec_src.digital.arib.transport_id == digital_arib_data[1][i].tsid && + rec_src.digital.arib.service_id == digital_arib_data[1][i].sid && + rec_src.digital.arib.orig_network_id == digital_arib_data[1][i].onid) + return true; + } + } else { + for (unsigned i = 0; i < NUM_DIGITAL_CHANS; i++) { + + if (rec_src.digital.channel.channel_number_fmt == digital_arib_data[1][i].fmt && + rec_src.digital.channel.major == digital_arib_data[1][i].major && + rec_src.digital.channel.minor == digital_arib_data[1][i].minor) + return true; + } + } + return false; + case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ATSC_SAT: + if (rec_src.digital.service_id_method == CEC_OP_SERVICE_ID_METHOD_BY_DIG_ID) { + + for (unsigned i = 0; i < NUM_DIGITAL_CHANS; i++) { + + if (rec_src.digital.atsc.transport_id == digital_atsc_data[0][i].tsid && + rec_src.digital.atsc.program_number == digital_atsc_data[0][i].sid) + return true; + } + } else { + for (unsigned i = 0; i < NUM_DIGITAL_CHANS; i++) { + + if (rec_src.digital.channel.channel_number_fmt == digital_atsc_data[0][i].fmt && + rec_src.digital.channel.major == digital_atsc_data[0][i].major && + rec_src.digital.channel.minor == digital_atsc_data[0][i].minor) + return true; + } + } + return false; + case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ATSC_T: + if (rec_src.digital.service_id_method == CEC_OP_SERVICE_ID_METHOD_BY_DIG_ID) { + for (unsigned i = 0; i < NUM_DIGITAL_CHANS; i++) { + + if (rec_src.digital.atsc.transport_id == digital_atsc_data[1][i].tsid && + rec_src.digital.atsc.program_number == digital_atsc_data[1][i].sid) + return true; + } + } else { + for (unsigned i = 0; i < NUM_DIGITAL_CHANS; i++) { + + if (rec_src.digital.channel.channel_number_fmt == digital_atsc_data[1][i].fmt && + rec_src.digital.channel.major == digital_atsc_data[1][i].major && + rec_src.digital.channel.minor == digital_atsc_data[1][i].minor) + return true; + } + } + return false; + case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_DVB_S2: + if (rec_src.digital.service_id_method == CEC_OP_SERVICE_ID_METHOD_BY_DIG_ID) { + for (unsigned i = 0; i < NUM_DIGITAL_CHANS; i++) { + if (rec_src.digital.dvb.transport_id == digital_dvb_data[0][i].tsid && + rec_src.digital.dvb.service_id == digital_dvb_data[0][i].sid && + rec_src.digital.dvb.orig_network_id == digital_dvb_data[0][i].onid) + return true; + } + } else { + for (unsigned i = 0; i < NUM_DIGITAL_CHANS; i++) { + + if (rec_src.digital.channel.channel_number_fmt == digital_dvb_data[0][i].fmt && + rec_src.digital.channel.major == digital_dvb_data[0][i].major && + rec_src.digital.channel.minor == digital_dvb_data[0][i].minor) + return true; + } + } + return false; + case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_DVB_T: + if (rec_src.digital.service_id_method == CEC_OP_SERVICE_ID_METHOD_BY_DIG_ID) { + for (unsigned i = 0; i < NUM_DIGITAL_CHANS; i++) { + + if (rec_src.digital.dvb.transport_id == digital_dvb_data[1][i].tsid && + rec_src.digital.dvb.service_id == digital_dvb_data[1][i].sid && + rec_src.digital.dvb.orig_network_id == digital_dvb_data[1][i].onid) + return true; + } + } else { + for (unsigned i = 0; i < NUM_DIGITAL_CHANS; i++) { + + if (rec_src.digital.channel.channel_number_fmt == digital_dvb_data[1][i].fmt && + rec_src.digital.channel.major == digital_dvb_data[1][i].major && + rec_src.digital.channel.minor == digital_dvb_data[1][i].minor) + return true; + } + } + return false; + default: + return false; + } +} + +static bool analog_service_info_valid(const cec_op_record_src &rec_src) +{ + __u8 bcast_type = rec_src.analog.ana_bcast_type; + unsigned freq = (rec_src.analog.ana_freq * 625) / 10; + __u8 bcast_system = rec_src.analog.bcast_system; + + if (bcast_type > CEC_OP_ANA_BCAST_TYPE_TERRESTRIAL) + return false; + + if (bcast_system > CEC_OP_BCAST_SYSTEM_PAL_DK && bcast_system != CEC_OP_BCAST_SYSTEM_OTHER) + return false; + + for (unsigned i = 0; i < NUM_ANALOG_FREQS; i++) { + + if (freq == analog_freqs_khz[bcast_type][bcast_system][i]) + return true; + } + + return false; +} + void process_tuner_record_timer_msgs(struct node *node, struct cec_msg &msg, unsigned me, __u8 type) { bool is_bcast = cec_msg_is_broadcast(&msg); @@ -577,23 +726,16 @@ void process_tuner_record_timer_msgs(struct node *node, struct cec_msg &msg, uns return; } - /* - One Touch Record - - This is only a basic implementation. - - TODO: - - If we are a TV, we should only send Record On if the - remote end is a Recording device or Reserved. Otherwise ignore. - - - Device state should reflect whether we are recording, etc. In - recording mode we should ignore Standby messages. - */ + /* One Touch Record */ case CEC_MSG_RECORD_TV_SCREEN: { if (!node->has_rec_tv) break; + /* Ignore if initiator is not a recording device */ + if (node->remote_prim_devtype != CEC_OP_PRIM_DEVTYPE_RECORD) + return; + struct cec_op_record_src rec_src = {}; rec_src.type = CEC_OP_RECORD_SRC_OWN; @@ -602,24 +744,68 @@ void process_tuner_record_timer_msgs(struct node *node, struct cec_msg &msg, uns transmit(node, &msg); return; } - case CEC_MSG_RECORD_ON: - if (!cec_has_record(1 << me)) + case CEC_MSG_RECORD_ON: { + if (type != CEC_LOG_ADDR_TYPE_RECORD) + break; + + __u8 rec_status; + bool feature_abort = false; + struct cec_op_record_src rec_src = {}; + + cec_ops_record_on(&msg, &rec_src); + switch (rec_src.type) { + case CEC_OP_RECORD_SRC_OWN: + rec_status = CEC_OP_RECORD_STATUS_CUR_SRC; + break; + case CEC_OP_RECORD_SRC_DIGITAL: + if (digital_service_info_valid(rec_src)) + rec_status = CEC_OP_RECORD_STATUS_DIG_SERVICE; + else + feature_abort = true; + break; + case CEC_OP_RECORD_SRC_ANALOG: + if (analog_service_info_valid(rec_src)) + rec_status = CEC_OP_RECORD_STATUS_ANA_SERVICE; + else + feature_abort = true; + break; + case CEC_OP_RECORD_SRC_EXT_PLUG: + /* Plug number range is 1-255 in spec, but a realistic range of connectors is 6. */ + if (rec_src.ext_plug.plug < 1 || rec_src.ext_plug.plug > 6) + feature_abort = true; + else + rec_status = CEC_OP_RECORD_STATUS_EXT_INPUT; + break; + case CEC_OP_RECORD_SRC_EXT_PHYS_ADDR: + rec_status = CEC_OP_RECORD_STATUS_INVALID_EXT_PHYS_ADDR; break; + default: + feature_abort = true; + break; + } + if (feature_abort) { + reply_feature_abort(node, &msg, CEC_OP_ABORT_INVALID_OP); + return; + } + if (node->state.one_touch_record_on) + rec_status = CEC_OP_RECORD_STATUS_ALREADY_RECORDING; cec_msg_set_reply_to(&msg, &msg); - cec_msg_record_status(&msg, CEC_OP_RECORD_STATUS_CUR_SRC); + cec_msg_record_status(&msg, rec_status); transmit(node, &msg); + node->state.one_touch_record_on = true; return; + } case CEC_MSG_RECORD_OFF: - if (!cec_has_record(1 << me)) + if (type != CEC_LOG_ADDR_TYPE_RECORD) break; + cec_msg_set_reply_to(&msg, &msg); cec_msg_record_status(&msg, CEC_OP_RECORD_STATUS_TERMINATED_OK); transmit(node, &msg); + node->state.one_touch_record_on = false; return; case CEC_MSG_RECORD_STATUS: return; - - /* Timer Programming From patchwork Thu Jun 24 04:06:44 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Deborah Brouwer X-Patchwork-Id: 12340865 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-15.7 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id BBC6DC49EA6 for ; Thu, 24 Jun 2021 04:07:03 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 56F4D613CE for ; Thu, 24 Jun 2021 04:07:03 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229813AbhFXEJU (ORCPT ); Thu, 24 Jun 2021 00:09:20 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:44822 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229379AbhFXEJU (ORCPT ); Thu, 24 Jun 2021 00:09:20 -0400 Received: from mail-pj1-x1043.google.com (mail-pj1-x1043.google.com [IPv6:2607:f8b0:4864:20::1043]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 4BB31C061574 for ; Wed, 23 Jun 2021 21:07:01 -0700 (PDT) Received: by mail-pj1-x1043.google.com with SMTP id bv7-20020a17090af187b029016fb18e04cfso4759125pjb.0 for ; Wed, 23 Jun 2021 21:07:01 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=7vtdCUa4AD/+GDlxyb03WUltkgIs0LCS0MSGBTT2s1c=; b=ARJVGKxOBJ39Orf4wf+kAPxzSvGub/WOX/ApaCMhr+kmM9w/wOeozfvn4lI2nZnQqO uRHWSVbZdyrRHGaz3joPzbFoq+9RkQ+Ac9mPip+qZEnGRfKDvt+7Lz4IiyY9dWyNiaAu fPC7JCDcDZfAQXCEr2O0GR+gqBAOSF7Qfl9ddEz2jAFnOemV+wg/V+5wUiUADzoC8Mho Mv2QMgRR8mkc6KfpWlU18RLNySB1mjHZlIKv7oscvZlkFLKdq9/7U7ap+tlb3y30Je6M g8N5qWQdtAkq+BvUTOD5pKPhNfgHj4jmn7gV/DoaOPgajkNKraQlkWbOSNy9aKHqw/AR IBkA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=7vtdCUa4AD/+GDlxyb03WUltkgIs0LCS0MSGBTT2s1c=; b=Rs3WyoRaT2ejeUh6E6m8p4ZWTLOvoCVbfp6r2Z+6hpQJjR03YRQ4/Azt0sJxG4gOFO gPxGGgNcJV1tnLmE5phhUaXDAyrk4w4lfoBvfGfY8oajgiRcYexZW8jHcZ/aSeCEKtc1 uqpvy0nzuFS6+xdttN3VxAHud9CRHzi6JbnGlUbPA/56B06lK+8Ls9wYb3YSy0tqoNSK c8M6J1l5hFEsoNcfM1RaM7H3EcXL1NNu50nWbsRF8lVUcgrDPLAJaayVizkExTB/m65B YlqZWTdoUaHUqZcGz6t52UN5mHjaVxahgHaTGKUUBk/xOTVqqBSQ8FERy/kaEe1WnEHw fRQg== X-Gm-Message-State: AOAM532ZFk652gd1aWDt6J0ufAIt29GVf+/HhCrZ3D2Qu9sFIfI2WZoQ NdY9yAAn19itSV+rPsUSsH/5geZiAHAU6Q== X-Google-Smtp-Source: ABdhPJzjcelTPww6uLxH2HRjC21B3COBEsDT3Y4xfGUchD19YVinPs9DAwS4Pe23e8+99D9OmvsCVQ== X-Received: by 2002:a17:90a:bb89:: with SMTP id v9mr12902140pjr.0.1624507620779; Wed, 23 Jun 2021 21:07:00 -0700 (PDT) Received: from ada-comp.hitronhub.home (S0106ac202ecb0523.gv.shawcable.net. [70.67.120.89]) by smtp.gmail.com with ESMTPSA id s20sm7094320pjn.23.2021.06.23.21.06.59 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 23 Jun 2021 21:07:00 -0700 (PDT) From: Deborah Brouwer To: linux-media@vger.kernel.org Cc: hverkuil@xs4all.nl, jaffe1@gmail.com, Deborah Brouwer Subject: [PATCH v4 3/3] cec: add One Touch Record Standby tests Date: Wed, 23 Jun 2021 21:06:44 -0700 Message-Id: <97f889b42fe38417fd5a7cdc2c00cdf848361508.1624506446.git.deborahbrouwer3563@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: References: MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-media@vger.kernel.org Check that the recording device ignores a Standby message while it is recording. When the recording is finished, check that the recording device enters standby unless the recording device is the active source. Signed-off-by: Deborah Brouwer --- utils/cec-compliance/cec-test-power.cpp | 63 +++++++++++++++++++++++++ utils/cec-follower/cec-follower.h | 2 + utils/cec-follower/cec-processing.cpp | 8 +++- utils/cec-follower/cec-tuner.cpp | 9 ++++ 4 files changed, 80 insertions(+), 2 deletions(-) diff --git a/utils/cec-compliance/cec-test-power.cpp b/utils/cec-compliance/cec-test-power.cpp index b675bfc4..c6bf7093 100644 --- a/utils/cec-compliance/cec-test-power.cpp +++ b/utils/cec-compliance/cec-test-power.cpp @@ -677,6 +677,67 @@ static int standby_resume_wakeup_deck_play(struct node *node, unsigned me, unsig return standby_resume_wakeup_deck(node, me, la, interactive, CEC_OP_PLAY_MODE_PLAY_FWD); } +static int standby_record(struct node *node, unsigned me, unsigned la, bool interactive, __u8 opcode) +{ + struct cec_msg msg; + __u8 rec_status; + + cec_msg_init(&msg, me, la); + cec_msg_record_on_own(&msg); + msg.reply = CEC_MSG_RECORD_STATUS; + fail_on_test(!transmit_timeout(node, &msg, 10000)); + if (timed_out_or_abort(&msg)) + return OK_NOT_SUPPORTED; + cec_ops_record_status(&msg, &rec_status); + fail_on_test(rec_status != CEC_OP_RECORD_STATUS_CUR_SRC && + rec_status != CEC_OP_RECORD_STATUS_ALREADY_RECORDING); + + cec_msg_init(&msg, me, la); + cec_msg_standby(&msg); + fail_on_test(!transmit_timeout(node, &msg)); + /* Standby should not interrupt the recording. */ + fail_on_test(!cec_msg_status_is_abort(&msg)); + + /* When the recording stops, the recorder should standby unless the recorder is the active source */ + cec_msg_init(&msg, me, la); + if (opcode == CEC_MSG_ACTIVE_SOURCE) + cec_msg_active_source(&msg, node->remote[la].phys_addr); + else + cec_msg_active_source(&msg, node->remote[la].phys_addr + 1); + fail_on_test(!transmit_timeout(node, &msg)); + + cec_msg_init(&msg, me, la); + cec_msg_record_off(&msg, false); + fail_on_test(!transmit_timeout(node, &msg)); + + unsigned unresponsive_time = 0; + + if (opcode == CEC_MSG_ACTIVE_SOURCE) { + fail_on_test(!poll_stable_power_status(node, me, la, CEC_OP_POWER_STATUS_ON, unresponsive_time)); + } else { + fail_on_test(!poll_stable_power_status(node, me, la, CEC_OP_POWER_STATUS_STANDBY, unresponsive_time)); + fail_on_test(interactive && !question("Is the device in standby?")); + node->remote[la].in_standby = true; + + int ret = standby_resume_wakeup(node, me, la, interactive); + if (ret) + return ret; + node->remote[la].in_standby = false; + } + + return OK; +} + +static int standby_record_active_source(struct node *node, unsigned me, unsigned la, bool interactive) +{ + return standby_record(node, me, la, interactive, CEC_MSG_ACTIVE_SOURCE); +} + +static int standby_record_inactive_source(struct node *node, unsigned me, unsigned la, bool interactive) +{ + return standby_record(node, me, la, interactive, CEC_MSG_INACTIVE_SOURCE); +} + const vec_remote_subtests standby_resume_subtests{ { "Standby", CEC_LOG_ADDR_MASK_ALL, standby_resume_standby }, { "Repeated Standby message does not wake up", CEC_LOG_ADDR_MASK_ALL, standby_resume_standby_toggle }, @@ -697,4 +758,6 @@ const vec_remote_subtests standby_resume_subtests{ { "Power State Transitions", CEC_LOG_ADDR_MASK_TV, power_state_transitions, false, true }, { "Deck Eject Standby Resume", CEC_LOG_ADDR_MASK_PLAYBACK | CEC_LOG_ADDR_MASK_RECORD, standby_resume_wakeup_deck_eject }, { "Deck Play Standby Resume", CEC_LOG_ADDR_MASK_PLAYBACK | CEC_LOG_ADDR_MASK_RECORD, standby_resume_wakeup_deck_play }, + { "Record Standby Active Source", CEC_LOG_ADDR_MASK_RECORD | CEC_LOG_ADDR_MASK_BACKUP, standby_record_active_source }, + { "Record Standby Inactive Source", CEC_LOG_ADDR_MASK_RECORD | CEC_LOG_ADDR_MASK_BACKUP, standby_record_inactive_source }, }; diff --git a/utils/cec-follower/cec-follower.h b/utils/cec-follower/cec-follower.h index 589ea6bf..b4d7563f 100644 --- a/utils/cec-follower/cec-follower.h +++ b/utils/cec-follower/cec-follower.h @@ -54,6 +54,7 @@ struct state { __u8 deck_state; __u64 deck_skip_start; bool one_touch_record_on; + bool one_touch_record_standby; time_t toggle_power_status; __u64 last_aud_rate_rx_ts; }; @@ -229,5 +230,6 @@ void process_tuner_record_timer_msgs(struct node *node, struct cec_msg &msg, uns void reply_feature_abort(struct node *node, struct cec_msg *msg, __u8 reason = CEC_OP_ABORT_UNRECOGNIZED_OP); void testProcessing(struct node *node, bool wallclock); +bool enter_standby(struct node *node); #endif diff --git a/utils/cec-follower/cec-processing.cpp b/utils/cec-follower/cec-processing.cpp index f985a841..43e03878 100644 --- a/utils/cec-follower/cec-processing.cpp +++ b/utils/cec-follower/cec-processing.cpp @@ -157,7 +157,7 @@ static bool exit_standby(struct node *node) return false; } -static bool enter_standby(struct node *node) +bool enter_standby(struct node *node) { if (node->state.power_status == CEC_OP_POWER_STATUS_ON || node->state.power_status == CEC_OP_POWER_STATUS_TO_ON) { @@ -320,10 +320,14 @@ static void processMsg(struct node *node, struct cec_msg &msg, unsigned me, __u8 /* Standby */ case CEC_MSG_STANDBY: + /* Standby should not interrupt a recording in progress. */ + if (node->state.one_touch_record_on) { + node->state.one_touch_record_standby = true; + break; + } enter_standby(node); return; - /* One Touch Play and Routing Control */ case CEC_MSG_ACTIVE_SOURCE: { diff --git a/utils/cec-follower/cec-tuner.cpp b/utils/cec-follower/cec-tuner.cpp index 4ecb62a6..80b126ac 100644 --- a/utils/cec-follower/cec-tuner.cpp +++ b/utils/cec-follower/cec-tuner.cpp @@ -802,6 +802,15 @@ void process_tuner_record_timer_msgs(struct node *node, struct cec_msg &msg, uns cec_msg_set_reply_to(&msg, &msg); cec_msg_record_status(&msg, CEC_OP_RECORD_STATUS_TERMINATED_OK); transmit(node, &msg); + /* + * If standby was received during recording, enter standby when the recording is finished + * unless the recording device is the currently the active source. + */ + if (node->state.one_touch_record_standby) { + if (node->phys_addr != node->state.active_source_pa) + enter_standby(node); + node->state.one_touch_record_standby = false; + } node->state.one_touch_record_on = false; return; case CEC_MSG_RECORD_STATUS: