@@ -33,6 +33,20 @@ static int deck_status_get(struct node *node, unsigned me, unsigned la, __u8 &de
return OK;
}
+static int test_play_mode(struct node *node, unsigned me, unsigned la, __u8 play_mode, __u8 expected)
+{
+ struct cec_msg msg = {};
+ __u8 deck_status;
+
+ cec_msg_init(&msg, me, la);
+ cec_msg_play(&msg, play_mode);
+ fail_on_test(!transmit_timeout(node, &msg));
+ fail_on_test(cec_msg_status_is_abort(&msg)); /* Assumes deck has media. */
+ fail_on_test(deck_status_get(node, me, la, deck_status));
+ fail_on_test(deck_status != expected);
+
+ return OK;
+}
/* System Information */
@@ -794,24 +808,78 @@ static int deck_ctl_deck_ctl_invalid(struct node *node, unsigned me, unsigned la
static int deck_ctl_play(struct node *node, unsigned me, unsigned la, bool interactive)
{
struct cec_msg msg = {};
+ __u8 deck_status;
cec_msg_init(&msg, me, la);
- cec_msg_play(&msg, CEC_OP_PLAY_MODE_PLAY_STILL);
+ cec_msg_play(&msg, CEC_OP_PLAY_MODE_PLAY_FWD);
fail_on_test(!transmit_timeout(node, &msg));
- if (is_playback_or_rec(la)) {
- 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 && !unrecognized_op(&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 && !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;
+ fail_on_test(deck_status_get(node, me, la, deck_status));
+ if (cec_msg_status_is_abort(&msg)) {
+ if (!incorrect_mode(&msg))
+ return FAIL;
+ if (deck_status == CEC_OP_DECK_INFO_NO_MEDIA)
+ info("Play Still: no media.\n");
+ else
+ warn("Deck has media but returned Feature Abort with Incorrect Mode.");
+ return OK;
+ }
+ fail_on_test(deck_status != CEC_OP_DECK_INFO_PLAY);
- return OK_PRESUMED;
+ fail_on_test(test_play_mode(node, me, la, CEC_OP_PLAY_MODE_PLAY_STILL, CEC_OP_DECK_INFO_STILL));
+ fail_on_test(test_play_mode(node, me, la, CEC_OP_PLAY_MODE_PLAY_REV, CEC_OP_DECK_INFO_PLAY_REV));
+ fail_on_test(test_play_mode(node, me, la, CEC_OP_PLAY_MODE_PLAY_FAST_FWD_MIN, CEC_OP_DECK_INFO_FAST_FWD));
+ fail_on_test(test_play_mode(node, me, la, CEC_OP_PLAY_MODE_PLAY_FAST_REV_MIN, CEC_OP_DECK_INFO_FAST_REV));
+ fail_on_test(test_play_mode(node, me, la, CEC_OP_PLAY_MODE_PLAY_FAST_FWD_MED, CEC_OP_DECK_INFO_FAST_FWD));
+ fail_on_test(test_play_mode(node, me, la, CEC_OP_PLAY_MODE_PLAY_FAST_REV_MED, CEC_OP_DECK_INFO_FAST_REV));
+ fail_on_test(test_play_mode(node, me, la, CEC_OP_PLAY_MODE_PLAY_FAST_FWD_MAX, CEC_OP_DECK_INFO_FAST_FWD));
+ fail_on_test(test_play_mode(node, me, la, CEC_OP_PLAY_MODE_PLAY_FAST_REV_MAX, CEC_OP_DECK_INFO_FAST_REV));
+ fail_on_test(test_play_mode(node, me, la, CEC_OP_PLAY_MODE_PLAY_SLOW_FWD_MIN, CEC_OP_DECK_INFO_SLOW));
+ fail_on_test(test_play_mode(node, me, la, CEC_OP_PLAY_MODE_PLAY_SLOW_REV_MIN, CEC_OP_DECK_INFO_SLOW_REV));
+ fail_on_test(test_play_mode(node, me, la, CEC_OP_PLAY_MODE_PLAY_SLOW_FWD_MED, CEC_OP_DECK_INFO_SLOW));
+ fail_on_test(test_play_mode(node, me, la, CEC_OP_PLAY_MODE_PLAY_SLOW_REV_MED, CEC_OP_DECK_INFO_SLOW_REV));
+ fail_on_test(test_play_mode(node, me, la, CEC_OP_PLAY_MODE_PLAY_SLOW_FWD_MAX, CEC_OP_DECK_INFO_SLOW));
+ fail_on_test(test_play_mode(node, me, la, CEC_OP_PLAY_MODE_PLAY_SLOW_REV_MAX, CEC_OP_DECK_INFO_SLOW_REV));
+
+ cec_msg_init(&msg, me, la);
+ cec_msg_deck_control(&msg, CEC_OP_DECK_CTL_MODE_STOP);
+ fail_on_test(!transmit_timeout(node, &msg));
+
+ return OK;
+}
+
+static int deck_ctl_play_invalid(struct node *node, unsigned me, unsigned la, bool interactive)
+{
+ struct cec_msg msg = {};
+
+ cec_msg_init(&msg, me, la);
+ cec_msg_play(&msg, 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_play(&msg, 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);
+
+ cec_msg_init(&msg, me, la);
+ cec_msg_play(&msg, 0x26); /* 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 const vec_remote_subtests deck_ctl_subtests{
@@ -826,7 +894,6 @@ static const vec_remote_subtests deck_ctl_subtests{
deck_ctl_give_status_invalid,
},
{ "Deck Status", CEC_LOG_ADDR_MASK_ALL, deck_ctl_deck_status },
- { "Play", CEC_LOG_ADDR_MASK_PLAYBACK | CEC_LOG_ADDR_MASK_RECORD, deck_ctl_play },
{
"Deck Control",
CEC_LOG_ADDR_MASK_PLAYBACK | CEC_LOG_ADDR_MASK_RECORD,
@@ -837,6 +904,16 @@ static const vec_remote_subtests deck_ctl_subtests{
CEC_LOG_ADDR_MASK_PLAYBACK | CEC_LOG_ADDR_MASK_RECORD,
deck_ctl_deck_ctl_invalid,
},
+ {
+ "Play",
+ CEC_LOG_ADDR_MASK_PLAYBACK | CEC_LOG_ADDR_MASK_RECORD,
+ deck_ctl_play,
+ },
+ {
+ "Play Invalid Operand",
+ CEC_LOG_ADDR_MASK_PLAYBACK | CEC_LOG_ADDR_MASK_RECORD,
+ deck_ctl_play_invalid,
+ },
};
/* Tuner Control */
@@ -551,14 +551,63 @@ static void processMsg(struct node *node, struct cec_msg &msg, unsigned me)
return;
}
case CEC_MSG_PLAY:
- if (node->has_deck_ctl)
+ if (!node->has_deck_ctl)
+ break;
+
+ __u8 deck_state;
+ __u8 play_mode;
+
+ cec_ops_play(&msg, &play_mode);
+
+ switch (play_mode) {
+ case CEC_OP_PLAY_MODE_PLAY_FWD:
+ deck_state = CEC_OP_DECK_INFO_PLAY;
+ break;
+ case CEC_OP_PLAY_MODE_PLAY_REV:
+ deck_state = CEC_OP_DECK_INFO_PLAY_REV;
+ break;
+ case CEC_OP_PLAY_MODE_PLAY_STILL:
+ deck_state = CEC_OP_DECK_INFO_STILL;
+ break;
+ case CEC_OP_PLAY_MODE_PLAY_FAST_FWD_MIN:
+ case CEC_OP_PLAY_MODE_PLAY_FAST_FWD_MED:
+ case CEC_OP_PLAY_MODE_PLAY_FAST_FWD_MAX:
+ deck_state = CEC_OP_DECK_INFO_FAST_FWD;
+ break;
+ case CEC_OP_PLAY_MODE_PLAY_FAST_REV_MIN:
+ case CEC_OP_PLAY_MODE_PLAY_FAST_REV_MED:
+ case CEC_OP_PLAY_MODE_PLAY_FAST_REV_MAX:
+ deck_state = CEC_OP_DECK_INFO_FAST_REV;
+ break;
+ case CEC_OP_PLAY_MODE_PLAY_SLOW_FWD_MIN:
+ case CEC_OP_PLAY_MODE_PLAY_SLOW_FWD_MED:
+ case CEC_OP_PLAY_MODE_PLAY_SLOW_FWD_MAX:
+ deck_state = CEC_OP_DECK_INFO_SLOW;
+ break;
+ case CEC_OP_PLAY_MODE_PLAY_SLOW_REV_MIN:
+ case CEC_OP_PLAY_MODE_PLAY_SLOW_REV_MED:
+ case CEC_OP_PLAY_MODE_PLAY_SLOW_REV_MAX:
+ deck_state = CEC_OP_DECK_INFO_SLOW_REV;
+ break;
+ default:
+ cec_msg_reply_feature_abort(&msg, CEC_OP_ABORT_INVALID_OP);
+ transmit(node, &msg);
return;
- break;
+ }
+ /* Only Play Forward and Play Still will close tray if open. */
+ if (play_mode != CEC_OP_PLAY_MODE_PLAY_FWD &&
+ play_mode != CEC_OP_PLAY_MODE_PLAY_STILL &&
+ node->state.deck_state == CEC_OP_DECK_INFO_NO_MEDIA) {
+ reply_feature_abort(node, &msg, CEC_OP_ABORT_INCORRECT_MODE);
+ return;
+ }
+ node->state.deck_skip_start = 0;
+ update_deck_state(node, me, deck_state);
+ return;
case CEC_MSG_DECK_CONTROL:
if (!node->has_deck_ctl)
break;
- __u8 deck_state;
__u8 deck_control_mode;
cec_ops_deck_control(&msg, &deck_control_mode);
Send all Deck Play commands and check that the follower implements them. Test that the follower returns Feature Abort for invalid Play operands. Signed-off-by: Deborah Brouwer <deborahbrouwer3563@gmail.com> --- utils/cec-compliance/cec-test.cpp | 99 ++++++++++++++++++++++++--- utils/cec-follower/cec-processing.cpp | 55 ++++++++++++++- 2 files changed, 140 insertions(+), 14 deletions(-)