Test that a valid Deck Status message is received in response to Give Deck Status and that Give Deck Status automatic reporting can be turned on and off. Test that the follower returns Feature Abort for an invalid Give Deck Status operand. Signed-off-by: Deborah Brouwer <deborahbrouwer3563@xxxxxxxxx> --- utils/cec-compliance/cec-test.cpp | 72 ++++++++++++++++++++++----- utils/cec-follower/cec-follower.cpp | 2 + utils/cec-follower/cec-follower.h | 1 + utils/cec-follower/cec-processing.cpp | 41 +++++++-------- 4 files changed, 81 insertions(+), 35 deletions(-) diff --git a/utils/cec-compliance/cec-test.cpp b/utils/cec-compliance/cec-test.cpp index fb57d10b..4578dd13 100644 --- a/utils/cec-compliance/cec-test.cpp +++ b/utils/cec-compliance/cec-test.cpp @@ -601,10 +601,6 @@ static const vec_remote_subtests dev_menu_ctl_subtests{ /* Deck Control */ -/* - TODO: These are very rudimentary tests which should be expanded. - */ - static int deck_ctl_give_status(struct node *node, unsigned me, unsigned la, bool interactive) { struct cec_msg msg = {}; @@ -613,12 +609,11 @@ static int deck_ctl_give_status(struct node *node, unsigned me, unsigned la, boo cec_msg_give_deck_status(&msg, true, CEC_OP_STATUS_REQ_ONCE); fail_on_test(!transmit_timeout(node, &msg)); fail_on_test(timed_out(&msg)); - if (is_playback_or_rec(la)) { - fail_on_test_v2(node->remote[la].cec_version, - node->remote[la].has_deck_ctl && cec_msg_status_is_abort(&msg)); - fail_on_test_v2(node->remote[la].cec_version, - !node->remote[la].has_deck_ctl && !unrecognized_op(&msg)); - } + + fail_on_test_v2(node->remote[la].cec_version, + node->remote[la].has_deck_ctl && cec_msg_status_is_abort(&msg)); + fail_on_test_v2(node->remote[la].cec_version, + !node->remote[la].has_deck_ctl && !unrecognized_op(&msg)); if (unrecognized_op(&msg)) return OK_NOT_SUPPORTED; if (refused(&msg)) @@ -626,7 +621,51 @@ static int deck_ctl_give_status(struct node *node, unsigned me, unsigned la, boo if (cec_msg_status_is_abort(&msg)) return OK_PRESUMED; - return 0; + __u8 deck_info; + + cec_ops_deck_status(&msg, &deck_info); + fail_on_test(deck_info < CEC_OP_DECK_INFO_PLAY || deck_info > CEC_OP_DECK_INFO_OTHER); + + cec_msg_init(&msg, me, la); + cec_msg_give_deck_status(&msg, true, CEC_OP_STATUS_REQ_ON); + fail_on_test(!transmit_timeout(node, &msg)); + fail_on_test(timed_out(&msg)); + cec_ops_deck_status(&msg, &deck_info); + fail_on_test(deck_info < CEC_OP_DECK_INFO_PLAY || deck_info > CEC_OP_DECK_INFO_OTHER); + + cec_msg_init(&msg, me, la); + cec_msg_give_deck_status(&msg, true, CEC_OP_STATUS_REQ_OFF); + /* + * Reply would not normally be expected for CEC_OP_STATUS_REQ_OFF. + * If a reply is received, then the follower failed to turn off + * status reporting as required. + */ + msg.reply = CEC_MSG_DECK_STATUS; + fail_on_test(!transmit_timeout(node, &msg)); + fail_on_test(!timed_out(&msg)); + + return OK; +} + +static int deck_ctl_give_status_invalid(struct node *node, unsigned me, unsigned la, bool interactive) +{ + struct cec_msg msg = {}; + + cec_msg_init(&msg, me, la); + cec_msg_give_deck_status(&msg, true, 0); /* Invalid 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_give_deck_status(&msg, true, 4); /* Invalid 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); + + return OK; } static int deck_ctl_deck_status(struct node *node, unsigned me, unsigned la, bool interactive) @@ -693,7 +732,16 @@ static int deck_ctl_play(struct node *node, unsigned me, unsigned la, bool inter } static const vec_remote_subtests deck_ctl_subtests{ - { "Give Deck Status", CEC_LOG_ADDR_MASK_PLAYBACK | CEC_LOG_ADDR_MASK_RECORD, deck_ctl_give_status }, + { + "Give Deck Status", + CEC_LOG_ADDR_MASK_PLAYBACK | CEC_LOG_ADDR_MASK_RECORD, + deck_ctl_give_status, + }, + { + "Give Deck Status Invalid Operand", + CEC_LOG_ADDR_MASK_PLAYBACK | CEC_LOG_ADDR_MASK_RECORD, + deck_ctl_give_status_invalid, + }, { "Deck Status", CEC_LOG_ADDR_MASK_ALL, deck_ctl_deck_status }, { "Deck Control", CEC_LOG_ADDR_MASK_PLAYBACK | CEC_LOG_ADDR_MASK_RECORD, deck_ctl_deck_ctl }, { "Play", CEC_LOG_ADDR_MASK_PLAYBACK | CEC_LOG_ADDR_MASK_RECORD, deck_ctl_play }, diff --git a/utils/cec-follower/cec-follower.cpp b/utils/cec-follower/cec-follower.cpp index 1f598fdf..047d7a04 100644 --- a/utils/cec-follower/cec-follower.cpp +++ b/utils/cec-follower/cec-follower.cpp @@ -313,6 +313,8 @@ void state_init(struct node &node) node.state.sac_active = false; node.state.volume = 50; node.state.mute = false; + node.state.deck_report_changes = false; + node.state.deck_state = CEC_OP_DECK_INFO_STOP; 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 391b9ab4..0492faa9 100644 --- a/utils/cec-follower/cec-follower.h +++ b/utils/cec-follower/cec-follower.h @@ -50,6 +50,7 @@ struct state { bool service_by_dig_id; bool tuner_report_changes; bool deck_report_changes; + __u8 deck_state; unsigned toggle_power_status; __u64 last_aud_rate_rx_ts; }; diff --git a/utils/cec-follower/cec-processing.cpp b/utils/cec-follower/cec-processing.cpp index 5b9db19f..3d2e4a2c 100644 --- a/utils/cec-follower/cec-processing.cpp +++ b/utils/cec-follower/cec-processing.cpp @@ -505,36 +505,31 @@ static void processMsg(struct node *node, struct cec_msg &msg, unsigned me) break; - /* - Deck Control - - This is only a basic implementation. - - TODO: Device state should reflect whether we are playing, - fast forwarding, etc. - */ + /* Deck Control */ case CEC_MSG_GIVE_DECK_STATUS: - if (node->has_deck_ctl) { - __u8 status_req; + if (!node->has_deck_ctl) + break; - cec_ops_give_deck_status(&msg, &status_req); - if (status_req < CEC_OP_STATUS_REQ_ON || - status_req > CEC_OP_STATUS_REQ_ONCE) { - reply_feature_abort(node, &msg, CEC_OP_ABORT_INVALID_OP); - return; - } - if (status_req != CEC_OP_STATUS_REQ_ONCE) - node->state.deck_report_changes = - status_req == CEC_OP_STATUS_REQ_ON; - if (status_req == CEC_OP_STATUS_REQ_OFF) - return; + __u8 status_req; + cec_ops_give_deck_status(&msg, &status_req); + + switch (status_req) { + case CEC_OP_STATUS_REQ_ON: + node->state.deck_report_changes = true; + fallthrough; + case CEC_OP_STATUS_REQ_ONCE: cec_msg_set_reply_to(&msg, &msg); - cec_msg_deck_status(&msg, CEC_OP_DECK_INFO_STOP); + cec_msg_deck_status(&msg, node->state.deck_state); transmit(node, &msg); return; + case CEC_OP_STATUS_REQ_OFF: + node->state.deck_report_changes = false; + return; + default: + reply_feature_abort(node, &msg, CEC_OP_ABORT_INVALID_OP); + return; } - break; case CEC_MSG_PLAY: if (node->has_deck_ctl) return; -- 2.17.1