最近在做有智能表具通讯的时候,想通过手机的红外向表具发送指令,但找了网上的说明,对于android红外的通讯示例非常少,大多数是讲的遥控器的通讯,去国外网站上扒了一下,还真有这方面内容,大致的通讯过程,后面有时间再分析,需要根据具体的波特率进行调整,我们的设备是2400 停止位1 偶校验,如果是无校验或者奇校验,代码需要调整。
java
package com.example.ifrareddemo;
import android.util.Log;
import java.io.Console;
import java.util.ArrayList;
import java.util.List;
public class MahouCode {
private static final int[] CRC_TABLE = {
0x00, 0x5E, 0xBC, 0xE2, 0x61, 0x3F, 0xDD, 0x83,
0xC2, 0x9C, 0x7E, 0x20, 0xA3, 0xFD, 0x1F, 0x41,
0x9D, 0xC3, 0x21, 0x7F, 0xFC, 0xA2, 0x40, 0x1E,
0x5F, 0x01, 0xE3, 0xBD, 0x3E, 0x60, 0x82, 0xDC,
0x23, 0x7D, 0x9F, 0xC1, 0x42, 0x1C, 0xFE, 0xA0,
0xE1, 0xBF, 0x5D, 0x03, 0x80, 0xDE, 0x3C, 0x62,
0xBE, 0xE0, 0x02, 0x5C, 0xDF, 0x81, 0x63, 0x3D,
0x7C, 0x22, 0xC0, 0x9E, 0x1D, 0x43, 0xA1, 0xFF,
0x46, 0x18, 0xFA, 0xA4, 0x27, 0x79, 0x9B, 0xC5,
0x84, 0xDA, 0x38, 0x66, 0xE5, 0xBB, 0x59, 0x07,
0xDB, 0x85, 0x67, 0x39, 0xBA, 0xE4, 0x06, 0x58,
0x19, 0x47, 0xA5, 0xFB, 0x78, 0x26, 0xC4, 0x9A,
0x65, 0x3B, 0xD9, 0x87, 0x04, 0x5A, 0xB8, 0xE6,
0xA7, 0xF9, 0x1B, 0x45, 0xC6, 0x98, 0x7A, 0x24,
0xF8, 0xA6, 0x44, 0x1A, 0x99, 0xC7, 0x25, 0x7B,
0x3A, 0x64, 0x86, 0xD8, 0x5B, 0x05, 0xE7, 0xB9,
0x8C, 0xD2, 0x30, 0x6E, 0xED, 0xB3, 0x51, 0x0F,
0x4E, 0x10, 0xF2, 0xAC, 0x2F, 0x71, 0x93, 0xCD,
0x11, 0x4F, 0xAD, 0xF3, 0x70, 0x2E, 0xCC, 0x92,
0xD3, 0x8D, 0x6F, 0x31, 0xB2, 0xEC, 0x0E, 0x50,
0xAF, 0xF1, 0x13, 0x4D, 0xCE, 0x90, 0x72, 0x2C,
0x6D, 0x33, 0xD1, 0x8F, 0x0C, 0x52, 0xB0, 0xEE,
0x32, 0x6C, 0x8E, 0xD0, 0x53, 0x0D, 0xEF, 0xB1,
0xF0, 0xAE, 0x4C, 0x12, 0x91, 0xCF, 0x2D, 0x73,
0xCA, 0x94, 0x76, 0x28, 0xAB, 0xF5, 0x17, 0x49,
0x08, 0x56, 0xB4, 0xEA, 0x69, 0x37, 0xD5, 0x8B,
0x57, 0x09, 0xEB, 0xB5, 0x36, 0x68, 0x8A, 0xD4,
0x95, 0xCB, 0x29, 0x77, 0xF4, 0xAA, 0x48, 0x16,
0xE9, 0xB7, 0x55, 0x0B, 0x88, 0xD6, 0x34, 0x6A,
0x2B, 0x75, 0x97, 0xC9, 0x4A, 0x14, 0xF6, 0xA8,
0x74, 0x2A, 0xC8, 0x96, 0x15, 0x4B, 0xA9, 0xF7,
0xB6, 0xE8, 0x0A, 0x54, 0xD7, 0x89, 0x6B, 0x35
};
private static final float CARRIER_FREQUENCY = 38400f; // The IR carrier frequency in hertz.
private final float BAUD_RATE = 2400f;
private final float MICROSEC_PER_SEC = 1000000f;
private final int START_BIT = 0;
private final int STOP_BIT = 1;
private final int[] pattern; // The toggle pattern in microseconds to transmit.
private int[] oldApiPattern; // The toggle pattern in pulses to transmit.
private final String hexCode; // The MwM hex code
/**
* Creates an MahouCode with the given MwM hex code.
*
* @param code the hex code.
*/
public MahouCode(String code) {
List<Integer> hexList = parseByteValues(code);
hexCode = codeListToString(hexList);
List<Integer> patternList;
patternList = generatePattern(hexCode, true);
pattern = convertIntegers(patternList);
}
/**
* Converts a list of integers to a hex string.
*/
private static String codeListToString(List<Integer> hexList) {
StringBuilder sb = new StringBuilder();
for (int item : hexList) {
sb.append(String.format("%02X", item));
sb.append(' ');
}
return sb.toString().trim();
}
/**
* Parses the byte values from the hex code string and returns it as a list of integers.
*
* @param hexCode The hex code string. Spaces are ignored.
* @return List of values of each hex byte.
*/
private static List<Integer> parseByteValues(String hexCode) {
List<Integer> result = new ArrayList<>();
String codeString = hexCode.replace(" ", "").trim();
int size = codeString.length();
if (size % 2 == 0) {
for (String s : getParts(codeString, 2)) {
result.add(Integer.parseInt(s, 16));
}
}
return result;
}
/**
* Split a string into parts by partition size.
*
* @param string String to be partitioned
* @param partitionSize length of parts
* @return list of parts
*/
private static List<String> getParts(String string, int partitionSize) {
List<String> parts = new ArrayList<>();
int len = string.length();
for (int i = 0; i < len; i += partitionSize) {
parts.add(string.substring(i, Math.min(len, i + partitionSize)));
}
return parts;
}
/**
* Automatically convert the given code to a 9x code. Do not include CRC.
*
* @param code9x string without the starting 9X and ending CRC.
* @return the full code with the starting 9X and ending CRC.
*/
public static String parse9x(String code9x) {
List<Integer> integers = parseByteValues(code9x);
integers.add(0, 0x90 - 1 + integers.size());
integers.add(calcCrc(integers));
return codeListToString(integers);
}
/**
* Calculates the CRC for the given list of integers.
*
* @param data The list of integers that represents the hex code
* @return The calculated CRC value.
*/
private static int calcCrc(List<Integer> data) {
int crc = 0;
for (int i = 0; i < data.size(); i++) {
crc = CRC_TABLE[crc ^ data.get(i)];
}
return crc;
}
/**
* Gets the carrier frequency.
*
* @return the carrier frequency.
*/
public static int getCarrierFrequency() {
return (int) CARRIER_FREQUENCY;
}
/**
* Gets the hex code.
*
* @return the hex code.
*/
public String getCode() {
return hexCode;
}
/**
* Gets the toggle pattern.
*
* @return the toggle pattern.
*/
public int[] getPattern() {
return pattern;
}
/**
* Gets the old API toggle pattern.
*
* @return the old API toggle pattern.
*/
public int[] getOldApiPattern() {
if (oldApiPattern == null) {
oldApiPattern = convertIntegers(generatePattern(hexCode, false));
}
return oldApiPattern;
}
/**
* Convert list of integers to primitive array.
*
* @param integers list of integers.
* @return array of int.
*/
private int[] convertIntegers(List<Integer> integers) {
int[] ret = new int[integers.size()];
for (int i = 0; i < ret.length; i++) {
ret[i] = integers.get(i);
}
return ret;
}
/**
* Generates the toggle pattern in terms of microseconds if isNew is true; otherwise, in
* terms of pulse.
*
* @param code the hex code string.
* @param isNew the flag to indicate if generating for Android 4.4.3 or newer.
* @return the toggle pattern in terms based on isNew.
*/
private List<Integer> generatePattern(String code, boolean isNew) {
// If API is new (>= 4.4.3), calculate microseconds per bit, else calculate pulse per bit.
float multiplier = (isNew) ? (MICROSEC_PER_SEC / BAUD_RATE) : (CARRIER_FREQUENCY / BAUD_RATE);
List<Integer> patternList = new ArrayList<>();
List<Integer> buffer = parseByteValues(code);
buffer = toTogglePattern(buffer);
for (int num = 0; num < buffer.size(); num++) {
patternList.add(Math.round(buffer.get(num) * multiplier));
}
return patternList;
}
/**
* Transforms the list of code values to toggle pattern.
*
* @param codeValues the list of integer values of the hex codes.
* @return the alternating toggle pattern in terms of bits.
*/
private List<Integer> toTogglePattern(List<Integer> codeValues) {
StringBuilder myStr = new StringBuilder();
for (int value : codeValues) {
// Convert byte value to binary
StringBuilder binaryString = new StringBuilder(String.format("%8s", Integer.toString(value, 2)).replace(' ', '0'));
myStr.append(START_BIT) //起始位
.append(binaryString.reverse()) // Reverse to send least significant bit first
.append(GetCheck(binaryString)) //偶校验
.append(STOP_BIT); //停止位
}
String fullString = myStr.toString();
Log.d("IR",fullString);
List<Integer> togglePattern = new ArrayList<>();
// Count the occurrence of the same consecutive bits and add them to the pattern list
char c = fullString.charAt(0);
int count = 1;
for (int i = 1; i < fullString.length(); i++) {
if (c == fullString.charAt(i)) {
count++;
} else {
togglePattern.add(count);
c = fullString.charAt(i);
count = 1;
}
}
togglePattern.add(count);
return togglePattern;
}
public String GetCheck(StringBuilder sb)
{
String str=sb.toString();
return str.replace("0","").length()%2==0?"0":"1";
}
}
上面的是帮助类,调用也比较简单
java
public ConsumerIrManager mCIR;
public TextView txtResult;
public Button btnSend;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
txtResult=findViewById(R.id.txtResult);
btnSend=findViewById(R.id.btnSend);
mCIR = (ConsumerIrManager) getSystemService(Context.CONSUMER_IR_SERVICE);/* 获取系统的红外遥控服务 */
if (!mCIR.hasIrEmitter()) { /* 检查是否有红外发射器 */
txtResult.setText("不支持红外");
} else {
/* Find IR!! */
txtResult.setText("支持红外");
}
btnSend.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String str="FEFEFEFEFEFE680000AAAAAAAAAAAAAA01C111F01000D294EDD417EE63EB3AC786BEA46C7CCBF716";
MahouCode mahouCode=new MahouCode(str);
mCIR.transmit(38400,mahouCode.getPattern());
}
});
handPermission();
}
public void handPermission() {
// 定位权限组
String[] mPermissionGroup = new String[]{
Manifest.permission.TRANSMIT_IR};
// 过滤已持有的权限
List<String> mRequestList = new ArrayList<>();
for (String permission : mPermissionGroup) {
if ((ContextCompat.checkSelfPermission(this, permission)
!= PackageManager.PERMISSION_GRANTED)) {
mRequestList.add(permission);
}
}
// 申请未持有的权限
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && !mRequestList.isEmpty()) {
ActivityCompat.requestPermissions(this, mRequestList.toArray(
new String[mRequestList.size()]), 100);
}
}