上一篇文章《红外技术及Android手机红外遥控器开发》中简单介绍了红外遥控技术和Android 手机红外遥控开发操控中的点击事件,只需要按照编码协议规则对键值等进行编码解析,最后转化成数组形式表示的电平信号,调用Android红外技术API发送电平信号数组即可。
但是在实际开发过程中,不仅需要实现点击按键模拟遥控器短按,也需要模拟遥控器的长按操作。那遥控器的长按操作发送的波形电平信号又是怎样的呢?仍然以NEC6121协议来说明,对重复发送的介绍如下:
解释一下:发送红外指令(引导码+用户码+数据码+数据反码+补齐108ms),然后发送重复指令(重复码+补齐108ms)。
代码如下:
- 电平信号数组构造类NecPattern.java
/**
* Created by huangr on 2019/8/8.
* ClassName : NecPattern
* Description : 构造NEC协议的pattern数组编码
*/
public class NecPattern {
private static final String TAG = "NecPattern";
//电平信号总时长
private static final int TOTAL_TIME = 108000;
//引导码
private static final int START_H = 9000;
private static final int START_L = 4500;
//结束码
private static final int END_L = 560;
private static final int END_H = 2000;
//重复码
private static final int LOOP_H = 9000;
private static final int LOOP_L = 2250;
//高电平
private static final int HIGH = 560;
//低电平0:1125
private static final int LOW_0 = 565;
//低电平1:2250
private static final int LOW_1 = 1690;
private static int[] pattern;
private static PatternList patternList = new PatternList();
/**
* 正常发码:引导码(9ms+4.5ms)+用户编码(高八位)+用户编码(低八位)+键数据码+键数据反码+结束码
*/
public static int[] buildPattern(int userCodeH, int userCodeL, int keyCode) {
//用户编码高八位00
String userH = constructBinary(userCodeH);
//用户编码低八位DF
String userL = constructBinary(userCodeL);
//数字码
String key = constructBinaryCode(keyCode);
//数字反码
String keyReverse = constructBinaryCode(~keyCode);
Log.d(TAG, " 键值 = [" + keyCode + "], 逆向编码 = [" + userH +userL+key+keyReverse+ "]");
patternList.clear();
//引导码
patternList.add(START_H);
patternList.add(START_L);
//用户编码
changeAdd(userH);
changeAdd(userL);
//键数据码
changeAdd(key);
//键数据反码
changeAdd(keyReverse);
//结束码
patternList.add(END_L);
patternList.add(END_H);
int size = patternList.size();
pattern = new int[size];
Log.d(TAG, " 键值 = [" + keyCode + "], 脉冲信号编码 = " + patternList.toString());
for (int i = 0; i < size; i++) {
pattern[i] = patternList.get(i);
}
return pattern;
}
/**
* 连续发码:引导码(9ms+4.5ms)+用户编码(高八位)+用户编码(低八位)+键数据码+键数据反码+延时码+重复码
*/
public static int[] buildPattern(int userCodeH, int userCodeL, int keyCode, boolean longPress) {
//用户编码高八位00
String userH = constructBinary(userCodeH);
//用户编码低八位DF
String userL = constructBinary(userCodeL);
//数字码
String key = constructBinaryCode(keyCode);
//数字反码
String keyReverse = constructBinaryCode(~keyCode);
Log.d(TAG, " 键值 = [" + keyCode + "], 逆向编码 = [" + userH +userL+key+keyReverse+ "]");
patternList.clear();
//引导码
patternList.add(START_H);
patternList.add(START_L);
//用户编码
changeAdd(userH);
changeAdd(userL);
//键数据码
changeAdd(key);
//键数据反码
changeAdd(keyReverse);
//延时码
patternList.add(HIGH);
int gapTime = TOTAL_TIME - HIGH - START_H - START_L - patternList.getTotalTime();//108000-9000-4500-32位command-560
patternList.add(gapTime);
//重复码
patternList.add(LOOP_H);
patternList.add(LOOP_L);
if(longPress){
//如果长按则添加重复码,重复码需要3次以上设备才能响应
for (int i = 0; i < 6; i++) {
//延时码
patternList.add(HIGH);
patternList.add(TOTAL_TIME-HIGH-LOOP_H-LOOP_L);//108000-560-9000-2250
//重复码
patternList.add(LOOP_H);
patternList.add(LOOP_L);
}
}
int size = patternList.size();
pattern = new int[size];
Log.d(TAG, " 键值 = [" + keyCode + "], 长按脉冲信号编码 = " + patternList.toString());
for (int i = 0; i < size; i++) {
pattern[i] = patternList.get(i);
}
return pattern;
}
/**
* 十六进制键值转化为二进制串,并逆转编码
* @param keyCode
* @return
*/
private static String constructBinary(int keyCode) {
String binaryStr = convertToBinary(keyCode);
char[] chars = binaryStr.toCharArray();
StringBuffer sb = new StringBuffer();
for (int i = 7; i >= 4; i--) {
sb.append(chars[i]);
}
for (int i = 3; i >= 0; i--) {
sb.append(chars[i]);
}
return sb.toString();
}
/**
* 十六进制键值转化为二进制串,并逆转编码
* @param keyCode
* @return
*/
private static String constructBinaryCode(int keyCode) {
String binaryStr = convertToBinary(keyCode);
Log.d(TAG, " 键值 = [" + keyCode + "], 数据码 = [" + binaryStr + "]");
char[] chars = binaryStr.toCharArray();
StringBuffer sb = new StringBuffer();
for (int i = 7; i >= 4; i--) {
sb.append(chars[i]);
}
for (int i = 3; i >= 0; i--) {
sb.append(chars[i]);
}
return sb.toString();
}
/**
* 数字转换为长度为8位的二进制字符串
* @return
*/
private static String convertToBinary(int num) {
String binary = Integer.toBinaryString(num);
StringBuffer sb8 = new StringBuffer();
//每个元素长度为8位,不够前面补充0
if (binary.length() < 8) {
for (int i = 0; i < 8 - binary.length(); i++) {
sb8.append("0");
}
String binaryStr8 = sb8.append(binary).toString();
return binaryStr8;
}else{
String binaryStr8 = binary.substring(binary.length() - 8);
return binaryStr8;
}
}
/**
* 二进制转成电平信号
*
* @param code
*/
public static void changeAdd(String code) {
int len = code.length();
String part;
for (int i = 0; i < len; i++) {
patternList.add(HIGH);
part = code.substring(i, i + 1);
if (part.equals("0"))
patternList.add(LOW_0);
else
patternList.add(LOW_1);
}
}
}
- 辅助类PatternList.java
import java.util.ArrayList;
import java.util.List;
/**
* Created by huangr on 2019/8/29.
* ClassName : PatternList
* Description : 封装list和totalTime,方便统计和获取list元素中数据之和
*/
public class PatternList {
private List<Integer> list;
private int totalTime;
public PatternList() {
list = new ArrayList<>();
totalTime = 0;
}
public List<Integer> getList() {
return list;
}
public void setList(List<Integer> list) {
this.list = list;
}
public int getTotalTime() {
return totalTime;
}
public void setTotalTime(int totalTime) {
this.totalTime = totalTime;
}
public void clear(){
list.clear();
totalTime = 0;
}
public void add(Integer Integer) {
list.add(Integer);
totalTime += Integer;
}
public Integer get(int index) {
return list.get(index);
}
public int size(){
return list.size();
}
public String toString(){
return "" + list;
}
}
- 封装的红外遥控管理类ConsumerIrManagerApi.java
import android.annotation.TargetApi;
import android.content.Context;
import android.os.Build;
@TargetApi(Build.VERSION_CODES.KITKAT)
public class ConsumerIrManagerApi {
private static ConsumerIrManagerApi instance;
private static android.hardware.ConsumerIrManager service;
private ConsumerIrManagerApi(Context context) {
//Android4.4才开始支持红外功能
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT){
// 获取系统的红外遥控服务
service = (android.hardware.ConsumerIrManager) context.getApplicationContext().getSystemService(Context.CONSUMER_IR_SERVICE);
}
}
public static ConsumerIrManagerApi getConsumerIrManager(Context context){
if(instance == null){
instance = new ConsumerIrManagerApi(context);
}
return instance;
}
/**
* 手机是否有红外功能
* @return
*/
public static boolean hasIrEmitter() {
//android4.4及以上版本&有红外功能
if(service!=null){
return service.hasIrEmitter();
}
//android4.4以下及4.4以上没红外功能
return false;
}
/**
* 发射红外信号
* @param carrierFrequency 红外频率
* @param pattern
*/
public static void transmit(int carrierFrequency, int[] pattern) {
if(service!=null){
service.transmit(carrierFrequency, pattern);
}
}
/**
* 获取可支持的红外信号频率
* @return
*/
public static android.hardware.ConsumerIrManager.CarrierFrequencyRange[] getCarrierFrequencies() {
if(service!=null){
return service.getCarrierFrequencies();
}
return null;
}
}
- 调用方法
private void sendKeyEvent(String keyCodeStr, boolean longPress) {
Log.e("TAG", "发送红外信号:");
ConsumerIrManagerApi.getIrManager(reactContext).sendKeyEvent(type,keyCodeStr,longPress);
}