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