1 /*
2  * Copyright (C) 2014 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.server.hdmi;
18 
19 import android.annotation.Nullable;
20 
21 import com.android.server.hdmi.Constants.FeatureOpcode;
22 
23 import libcore.util.EmptyArray;
24 
25 import java.util.Arrays;
26 import java.util.Objects;
27 
28 /**
29  * A class to encapsulate HDMI-CEC message used for the devices connected via
30  * HDMI cable to communicate with one another. A message is defined by its
31  * source and destination address, command (or opcode), and optional parameters.
32  */
33 public final class HdmiCecMessage {
34     public static final byte[] EMPTY_PARAM = EmptyArray.BYTE;
35 
36     private final int mSource;
37     private final int mDestination;
38 
39     private final int mOpcode;
40     private final byte[] mParams;
41 
42     /**
43      * Constructor.
44      */
HdmiCecMessage(int source, int destination, int opcode, byte[] params)45     public HdmiCecMessage(int source, int destination, int opcode, byte[] params) {
46         mSource = source;
47         mDestination = destination;
48         mOpcode = opcode & 0xFF;
49         mParams = Arrays.copyOf(params, params.length);
50     }
51 
52     @Override
equals(@ullable Object message)53     public boolean equals(@Nullable Object message) {
54         if (message instanceof HdmiCecMessage) {
55             HdmiCecMessage that = (HdmiCecMessage) message;
56             return this.mSource == that.getSource() &&
57                 this.mDestination == that.getDestination() &&
58                 this.mOpcode == that.getOpcode() &&
59                 Arrays.equals(this.mParams, that.getParams());
60         }
61         return false;
62     }
63 
64     @Override
hashCode()65     public int hashCode() {
66         return Objects.hash(
67             mSource,
68             mDestination,
69             mOpcode,
70             Arrays.hashCode(mParams));
71     }
72 
73     /**
74      * Return the source address field of the message. It is the logical address
75      * of the device which generated the message.
76      *
77      * @return source address
78      */
getSource()79     public int getSource() {
80         return mSource;
81     }
82 
83     /**
84      * Return the destination address field of the message. It is the logical address
85      * of the device to which the message is sent.
86      *
87      * @return destination address
88      */
getDestination()89     public int getDestination() {
90         return mDestination;
91     }
92 
93     /**
94      * Return the opcode field of the message. It is the type of the message that
95      * tells the destination device what to do.
96      *
97      * @return opcode
98      */
getOpcode()99     public int getOpcode() {
100         return mOpcode;
101     }
102 
103     /**
104      * Return the parameter field of the message. The contents of parameter varies
105      * from opcode to opcode, and is used together with opcode to describe
106      * the action for the destination device to take.
107      *
108      * @return parameter
109      */
getParams()110     public byte[] getParams() {
111         return mParams;
112     }
113 
114     @Override
toString()115     public String toString() {
116         StringBuilder s = new StringBuilder();
117         s.append(String.format("<%s> %X%X:%02X",
118                 opcodeToString(mOpcode), mSource, mDestination, mOpcode));
119         if (mParams.length > 0) {
120             if (filterMessageParameters(mOpcode)) {
121                 s.append(String.format(" <Redacted len=%d>", mParams.length));
122             } else {
123                 for (byte data : mParams) {
124                     s.append(String.format(":%02X", data));
125                 }
126             }
127         }
128         return s.toString();
129     }
130 
opcodeToString(@eatureOpcode int opcode)131     private static String opcodeToString(@FeatureOpcode int opcode) {
132         switch (opcode) {
133             case Constants.MESSAGE_FEATURE_ABORT:
134                 return "Feature Abort";
135             case Constants.MESSAGE_IMAGE_VIEW_ON:
136                 return "Image View On";
137             case Constants.MESSAGE_TUNER_STEP_INCREMENT:
138                 return "Tuner Step Increment";
139             case Constants.MESSAGE_TUNER_STEP_DECREMENT:
140                 return "Tuner Step Decrement";
141             case Constants.MESSAGE_TUNER_DEVICE_STATUS:
142                 return "Tuner Device Status";
143             case Constants.MESSAGE_GIVE_TUNER_DEVICE_STATUS:
144                 return "Give Tuner Device Status";
145             case Constants.MESSAGE_RECORD_ON:
146                 return "Record On";
147             case Constants.MESSAGE_RECORD_STATUS:
148                 return "Record Status";
149             case Constants.MESSAGE_RECORD_OFF:
150                 return "Record Off";
151             case Constants.MESSAGE_TEXT_VIEW_ON:
152                 return "Text View On";
153             case Constants.MESSAGE_RECORD_TV_SCREEN:
154                 return "Record Tv Screen";
155             case Constants.MESSAGE_GIVE_DECK_STATUS:
156                 return "Give Deck Status";
157             case Constants.MESSAGE_DECK_STATUS:
158                 return "Deck Status";
159             case Constants.MESSAGE_SET_MENU_LANGUAGE:
160                 return "Set Menu Language";
161             case Constants.MESSAGE_CLEAR_ANALOG_TIMER:
162                 return "Clear Analog Timer";
163             case Constants.MESSAGE_SET_ANALOG_TIMER:
164                 return "Set Analog Timer";
165             case Constants.MESSAGE_TIMER_STATUS:
166                 return "Timer Status";
167             case Constants.MESSAGE_STANDBY:
168                 return "Standby";
169             case Constants.MESSAGE_PLAY:
170                 return "Play";
171             case Constants.MESSAGE_DECK_CONTROL:
172                 return "Deck Control";
173             case Constants.MESSAGE_TIMER_CLEARED_STATUS:
174                 return "Timer Cleared Status";
175             case Constants.MESSAGE_USER_CONTROL_PRESSED:
176                 return "User Control Pressed";
177             case Constants.MESSAGE_USER_CONTROL_RELEASED:
178                 return "User Control Release";
179             case Constants.MESSAGE_GIVE_OSD_NAME:
180                 return "Give Osd Name";
181             case Constants.MESSAGE_SET_OSD_NAME:
182                 return "Set Osd Name";
183             case Constants.MESSAGE_SET_OSD_STRING:
184                 return "Set Osd String";
185             case Constants.MESSAGE_SET_TIMER_PROGRAM_TITLE:
186                 return "Set Timer Program Title";
187             case Constants.MESSAGE_SYSTEM_AUDIO_MODE_REQUEST:
188                 return "System Audio Mode Request";
189             case Constants.MESSAGE_GIVE_AUDIO_STATUS:
190                 return "Give Audio Status";
191             case Constants.MESSAGE_SET_SYSTEM_AUDIO_MODE:
192                 return "Set System Audio Mode";
193             case Constants.MESSAGE_REPORT_AUDIO_STATUS:
194                 return "Report Audio Status";
195             case Constants.MESSAGE_GIVE_SYSTEM_AUDIO_MODE_STATUS:
196                 return "Give System Audio Mode Status";
197             case Constants.MESSAGE_SYSTEM_AUDIO_MODE_STATUS:
198                 return "System Audio Mode Status";
199             case Constants.MESSAGE_ROUTING_CHANGE:
200                 return "Routing Change";
201             case Constants.MESSAGE_ROUTING_INFORMATION:
202                 return "Routing Information";
203             case Constants.MESSAGE_ACTIVE_SOURCE:
204                 return "Active Source";
205             case Constants.MESSAGE_GIVE_PHYSICAL_ADDRESS:
206                 return "Give Physical Address";
207             case Constants.MESSAGE_REPORT_PHYSICAL_ADDRESS:
208                 return "Report Physical Address";
209             case Constants.MESSAGE_REQUEST_ACTIVE_SOURCE:
210                 return "Request Active Source";
211             case Constants.MESSAGE_SET_STREAM_PATH:
212                 return "Set Stream Path";
213             case Constants.MESSAGE_DEVICE_VENDOR_ID:
214                 return "Device Vendor Id";
215             case Constants.MESSAGE_VENDOR_COMMAND:
216                 return "Vendor Command";
217             case Constants.MESSAGE_VENDOR_REMOTE_BUTTON_DOWN:
218                 return "Vendor Remote Button Down";
219             case Constants.MESSAGE_VENDOR_REMOTE_BUTTON_UP:
220                 return "Vendor Remote Button Up";
221             case Constants.MESSAGE_GIVE_DEVICE_VENDOR_ID:
222                 return "Give Device Vendor Id";
223             case Constants.MESSAGE_MENU_REQUEST:
224                 return "Menu Request";
225             case Constants.MESSAGE_MENU_STATUS:
226                 return "Menu Status";
227             case Constants.MESSAGE_GIVE_DEVICE_POWER_STATUS:
228                 return "Give Device Power Status";
229             case Constants.MESSAGE_REPORT_POWER_STATUS:
230                 return "Report Power Status";
231             case Constants.MESSAGE_GET_MENU_LANGUAGE:
232                 return "Get Menu Language";
233             case Constants.MESSAGE_SELECT_ANALOG_SERVICE:
234                 return "Select Analog Service";
235             case Constants.MESSAGE_SELECT_DIGITAL_SERVICE:
236                 return "Select Digital Service";
237             case Constants.MESSAGE_SET_DIGITAL_TIMER:
238                 return "Set Digital Timer";
239             case Constants.MESSAGE_CLEAR_DIGITAL_TIMER:
240                 return "Clear Digital Timer";
241             case Constants.MESSAGE_SET_AUDIO_RATE:
242                 return "Set Audio Rate";
243             case Constants.MESSAGE_INACTIVE_SOURCE:
244                 return "InActive Source";
245             case Constants.MESSAGE_CEC_VERSION:
246                 return "Cec Version";
247             case Constants.MESSAGE_GET_CEC_VERSION:
248                 return "Get Cec Version";
249             case Constants.MESSAGE_VENDOR_COMMAND_WITH_ID:
250                 return "Vendor Command With Id";
251             case Constants.MESSAGE_CLEAR_EXTERNAL_TIMER:
252                 return "Clear External Timer";
253             case Constants.MESSAGE_SET_EXTERNAL_TIMER:
254                 return "Set External Timer";
255             case Constants.MESSAGE_REPORT_SHORT_AUDIO_DESCRIPTOR:
256                 return "Report Short Audio Descriptor";
257             case Constants.MESSAGE_REQUEST_SHORT_AUDIO_DESCRIPTOR:
258                 return "Request Short Audio Descriptor";
259             case Constants.MESSAGE_INITIATE_ARC:
260                 return "Initiate ARC";
261             case Constants.MESSAGE_REPORT_ARC_INITIATED:
262                 return "Report ARC Initiated";
263             case Constants.MESSAGE_REPORT_ARC_TERMINATED:
264                 return "Report ARC Terminated";
265             case Constants.MESSAGE_REQUEST_ARC_INITIATION:
266                 return "Request ARC Initiation";
267             case Constants.MESSAGE_REQUEST_ARC_TERMINATION:
268                 return "Request ARC Termination";
269             case Constants.MESSAGE_GIVE_FEATURES:
270                 return "Give Features";
271             case Constants.MESSAGE_REPORT_FEATURES:
272                 return "Report Features";
273             case Constants.MESSAGE_REQUEST_CURRENT_LATENCY:
274                 return "Request Current Latency";
275             case Constants.MESSAGE_REPORT_CURRENT_LATENCY:
276                 return "Report Current Latency";
277             case Constants.MESSAGE_TERMINATE_ARC:
278                 return "Terminate ARC";
279             case Constants.MESSAGE_CDC_MESSAGE:
280                 return "Cdc Message";
281             case Constants.MESSAGE_ABORT:
282                 return "Abort";
283             default:
284                 return String.format("Opcode: %02X", opcode);
285         }
286     }
287 
filterMessageParameters(int opcode)288     private static boolean filterMessageParameters(int opcode) {
289         switch (opcode) {
290             case Constants.MESSAGE_USER_CONTROL_PRESSED:
291             case Constants.MESSAGE_USER_CONTROL_RELEASED:
292             case Constants.MESSAGE_SET_OSD_NAME:
293             case Constants.MESSAGE_SET_OSD_STRING:
294             case Constants.MESSAGE_VENDOR_COMMAND:
295             case Constants.MESSAGE_VENDOR_REMOTE_BUTTON_DOWN:
296             case Constants.MESSAGE_VENDOR_REMOTE_BUTTON_UP:
297             case Constants.MESSAGE_VENDOR_COMMAND_WITH_ID:
298                 return true;
299             default:
300                 return false;
301         }
302     }
303 }
304 
305