1 /* 2 * Copyright (C) 2020 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 android.hdmicec.cts; 18 19 import static com.google.common.truth.Truth.assertThat; 20 21 import java.util.regex.Matcher; 22 import java.util.regex.Pattern; 23 24 public class CecMessage { 25 26 private static final int HEXADECIMAL_RADIX = 16; 27 buildCecMessage( LogicalAddress source, LogicalAddress destination, CecOperand operand, int params)28 public static String buildCecMessage( 29 LogicalAddress source, LogicalAddress destination, CecOperand operand, int params) { 30 return "" + source + destination + ":" + operand + formatParams(params); 31 } 32 formatParams(String rawParams)33 public static String formatParams(String rawParams) { 34 StringBuilder params = new StringBuilder(""); 35 int position = 0; 36 int endPosition = 2; 37 38 do { 39 params.append(":" + rawParams.substring(position, endPosition)); 40 position = endPosition; 41 endPosition += 2; 42 } while (endPosition <= rawParams.length()); 43 return params.toString(); 44 } 45 formatParams(long rawParam)46 public static String formatParams(long rawParam) { 47 StringBuilder params = new StringBuilder(""); 48 49 do { 50 params.insert(0, ":" + String.format("%02x", rawParam % 256)); 51 rawParam >>= 8; 52 } while (rawParam > 0); 53 54 return params.toString(); 55 } 56 57 /** 58 * Formats the rawParam into CEC message parameters. The parameters will be at least 59 * minimumNibbles long. 60 */ formatParams(long rawParam, int minimumNibbles)61 public static String formatParams(long rawParam, int minimumNibbles) { 62 StringBuilder params = new StringBuilder(""); 63 64 do { 65 params.insert(0, ":" + String.format("%02x", rawParam % 256)); 66 rawParam >>= 8; 67 minimumNibbles -= 2; 68 } while (rawParam > 0 || minimumNibbles > 0); 69 70 return params.toString(); 71 } 72 hexStringToInt(String message)73 public static int hexStringToInt(String message) { 74 return Integer.parseInt(message, HEXADECIMAL_RADIX); 75 } 76 getAsciiString(String message)77 public static String getAsciiString(String message) { 78 String params = getNibbles(message).substring(4); 79 StringBuilder builder = new StringBuilder(); 80 81 for (int i = 2; i <= params.length(); i += 2) { 82 builder.append((char) hexStringToInt(params.substring(i - 2, i))); 83 } 84 85 return builder.toString(); 86 } 87 getParamsAsString(String message)88 public static String getParamsAsString(String message) { 89 return getNibbles(message).substring(4); 90 } 91 92 /** Gets the params from a CEC message. */ getParams(String message)93 public static int getParams(String message) { 94 return hexStringToInt(getNibbles(message).substring(4)); 95 } 96 97 /** Gets the first 'numNibbles' number of param nibbles from a CEC message. */ getParams(String message, int numNibbles)98 public static int getParams(String message, int numNibbles) { 99 int paramStart = 4; 100 int end = numNibbles + paramStart; 101 return hexStringToInt(getNibbles(message).substring(paramStart, end)); 102 } 103 104 /** 105 * From the params of a CEC message, gets the nibbles from position start to position end. 106 * The start and end are relative to the beginning of the params. For example, in the following 107 * message - 4F:82:10:00:04, getParams(message, 0, 4) will return 0x1000 and 108 * getParams(message, 4, 6) will return 0x04. 109 */ getParams(String message, int start, int end)110 public static int getParams(String message, int start, int end) { 111 return hexStringToInt(getNibbles(message).substring(4).substring(start, end)); 112 } 113 114 /** 115 * Gets the source logical address from a CEC message. 116 */ getSource(String message)117 public static LogicalAddress getSource(String message) { 118 String param = getNibbles(message).substring(0, 1); 119 return LogicalAddress.getLogicalAddress(hexStringToInt(param)); 120 } 121 122 /** Gets the destination logical address from a CEC message. */ getDestination(String message)123 public static LogicalAddress getDestination(String message) { 124 String param = getNibbles(message).substring(1, 2); 125 return LogicalAddress.getLogicalAddress(hexStringToInt(param)); 126 } 127 128 /** Gets the operand from a CEC message. */ getOperand(String message)129 public static CecOperand getOperand(String message) { 130 String param = getNibbles(message).substring(2, 4); 131 return CecOperand.getOperand(hexStringToInt(param)); 132 } 133 134 /** 135 * Converts ascii characters to hexadecimal numbers that can be appended to a CEC message as 136 * params. For example, "spa" will be converted to ":73:70:61" 137 */ convertStringToHexParams(String rawParams)138 public static String convertStringToHexParams(String rawParams) { 139 StringBuilder params = new StringBuilder(""); 140 for (int i = 0; i < rawParams.length(); i++) { 141 params.append(String.format(":%02x", (int) rawParams.charAt(i))); 142 } 143 return params.toString(); 144 } 145 146 /** 147 * Assert for the DUT's physical address with the value passed from command line argument. 148 * Assert for the source's physical address in a <Routing Change> message. 149 */ assertPhysicalAddressValid(String message, int expectedPhysicalAddress)150 public static void assertPhysicalAddressValid(String message, int expectedPhysicalAddress) { 151 int physicalAddress = getParams(message, HdmiCecConstants.PHYSICAL_ADDRESS_LENGTH); 152 assertThat(physicalAddress).isEqualTo(expectedPhysicalAddress); 153 } 154 155 /** Assert for the target's physical address in a <Routing Change> message. */ assertTargetPhysicalAddressValid(String message, int expectedTargetPhysicalAddress)156 public static void assertTargetPhysicalAddressValid(String message, int expectedTargetPhysicalAddress) { 157 int targetPhysicalAddress = getParams(message, 4, 8); 158 assertThat(targetPhysicalAddress).isEqualTo(expectedTargetPhysicalAddress); 159 } 160 getNibbles(String message)161 private static String getNibbles(String message) { 162 final String tag1 = "group1"; 163 final String tag2 = "group2"; 164 String paramsPattern = "(?:.*[>>|<<].*?)" + 165 "(?<" + tag1 + ">[\\p{XDigit}{2}:]+)" + 166 "(?<" + tag2 + ">\\p{XDigit}{2})" + 167 "(?:.*?)"; 168 String nibbles = ""; 169 170 Pattern p = Pattern.compile(paramsPattern); 171 Matcher m = p.matcher(message); 172 if (m.matches()) { 173 nibbles = m.group(tag1).replace(":", "") + m.group(tag2); 174 } 175 return nibbles; 176 } 177 } 178