上一篇文章《紅外技術及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);
}