当前位置: 嘉峪关在线首页 > 资讯 > 正文

手机APP万能遥控器的具体方案和编程实现

手机APP万能遥控器的具体方案和编程实现

实际上怀疑红外线可能被淘汰,用蓝牙、WIFI等替代。比如说空调,配一个WIFI或蓝牙模块,那么就可以用手机进行控制了。

之前认为NFC可能逐步淘汰,现在想想红外线是否如此?实际上怀疑红外线可能被淘汰,用蓝牙、WIFI等替代。比如说空调,配一个WIFI或蓝牙模块,那么就可以用手机进行控制了。WIFI模块可能要输入密码,这个是有点麻烦,但可以想办法配置。现在手机越来越贵,红外线的成本可能就不是问题,也许会逐步加上。

TYPE-C接口。这个接口好用,也推出很久了,现在很多新机还是MicroUSB接口。NFC,比如刷公交,非常方便。红外线说是用来遥控。

Android红外遥控器移植

1.编译hal层代码

红外的hal代码路径

hardware/libhardware/modules/consumerir/

最终生成consumerir.default.so,但system文件系统中并没有该库,选择安装该库即可。

在device文件下的mk文件中加入

PRODUCT_PACKAGES += \
consumerir.default

在Andoird8.0以后的版本,libhardware中有部分代码集成在hardware/interfaces/ir,可以单独编译文件夹,将相应的库进行安装,如

PRODUCT_PACKAGES += android.hardware.ir@1.0-service \
android.hardware.ir@1.0-impl 、
consumerir.default


android.hardware.ir
hwbinder
1.0

IIr
default


如果ir的hal层打开失败,会报如下错误。

04-15 10:08:47.061 2089 2089 I SystemServer: StartConsumerIrService
04-15 10:08:47.062 242 242 W hwservicemanager: getTransport: Cannot find entry android.hardware.ir@1.0::IConsumerIr/default in either framework or device manifest.
04-15 10:08:47.063 2089 2089 E System : ******************************************
04-15 10:08:47.064 2089 2089 E System : ************ Failure starting core service
04-15 10:08:47.064 2089 2089 E System : java.lang.RuntimeException: FEATURE_CONSUMER_IR present, but no IR HAL loaded!
04-15 10:08:47.064 2089 2089 E System : at com.android.server.ConsumerIrService.(ConsumerIrService.java:51)
04-15 10:08:47.064 2089 2089 E System : at com.android.server.SystemServer.startOtherServices(SystemServer.java:874)
04-15 10:08:47.064 2089 2089 E System : at com.android.server.SystemServer.run(SystemServer.java:446)
04-15 10:08:47.064 2089 2089 E System : at com.android.server.SystemServer.main(SystemServer.java:309)
04-15 10:08:47.064 2089 2089 E System : at java.lang.reflect.Method.invoke(Native Method)
04-15 10:08:47.064 2089 2089 E System : at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:504)

2.让系统支持红外功能

PRODUCT_COPY_FILES += \
frameworks/native/data/etc/android.hardware.consumerir.xml:system/etc/permissions/android.hardware.consumerir.xml

或者

PRODUCT_COPY_FILES += \
frameworks/native/data/etc/android.hardware.consumerir.xml:vendor/etc/permission/android.hardware.consumerir.xml

应用在打开红外设备的时候会申请红外权限,这个就是红外权限的文件,没有应用会出错。选择合适的红外芯片,并移植好驱动后,就可以通过第三方的应用控制电器了。另外有些红外芯片支持学习功能,但Android并没有相应的接口,可以改Android代码,然后将应源码放在Android源码下编译。如果要做android-studio下编译(android-api不能直接访问新方法),可采用getDeclaredMethod这个方法来获取Android系统新添加的方法。

红外framework层代码路径

frameworks/base/services/core/java/com/android/server/ConsumerIrService.java
frameworks/base/core/java/android/hardware/IConsumerIrService.aidl
frameworks/base/services/core/jni/com_android_server_ConsumerIrService.cpp

3.红外驱动移植

手机红外硬件方案介绍https://blog.csdn.net/mike8825/article/details/80955992

手机红外方案

红外知识介绍的网站(https://www.sbprojects.net/knowledge/ir/index.php),包含各种红外协议,其中常见是是nec协议。

手机APP万能遥控器的具体方案和编程实现

手机APP万能遥控器的具体方案和编程实现

手机APP万能遥控器的具体方案和编程实现

手机APP万能遥控器的具体方案和编程实现

图1是红外的发射电路,图2是红外的接收电路,图3和图4是nec协议

9毫秒脉冲+4.5毫秒低电平+8位地址码+8位地址反码+8位命令码+8位命令反码

比如地址码是0xff,相当于8个逻辑1,按图4进行发送即可。

所谓的码库就是时间信息(单位是us),由于对称性,nec发一次码的时间为(9+4.5+(2.15+1.12)×32),大约118ms

脉冲经过图2的电路处理后,就变成了一个简单的波形,如图5橙色部分(或反相),只要判断脉冲的长度(ktime_sub&&ktime_get),便可将需要的红外码解析出来了,内核已集成相关的代码gpio-ir-recv.c,编译相应的协议文件即可。

1.io/pwm/spi-do控制红外灯发射红外线(成本低,不支持学习功能,小米手机采用这种方案)

2.芯片方案

下面三种芯片都是支持学习型的芯片

 abov(MC96FR116C 硬件i2c) http://www.abov.co.kr/en/
ETEK(et4007 模拟i2c) http://www.etek.com.cn/
宏芯达(hxd019d 模拟i2c) http://www.hxdkj88.com/

3.红外码库(这部分一般需要购买)

	酷控 遥控精灵 宏芯达等

拿小米的开源代码来分析下,使用过gpio,pwm,spi-do来控制红外的发射。

如Redmi 4X(gpio方式),电路类似下图

手机APP万能遥控器的具体方案和编程实现

https://github.com/MiCode/Xiaomi_Kernel_OpenSource/blob/santoni-n-oss/arch/arm/boot/dts/qcom/msm8917-pmi8937-qrd-sku5_S88503.dtsi

gpio-leds {
compatible = "gpio-leds";
status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&gpio_led_off>;
infred {
gpios = <&tlmm 45 0>;
label = "infrared";
linux,default-trigger = "infra-red";
default-state = "off";
retain-state-suspended;
};
};
驱动https://github.com/MiCode/Xiaomi_Kernel_OpenSource/blob/santoni-n-oss/drivers/leds/leds-gpio.c
Redmi Note 4X Standard(pwm方式)
https://github.com/MiCode/Xiaomi_Kernel_OpenSource/blob/mido-n-oss/arch/arm/boot/dts/qcom/msm8953-qrd.dtsi
pwm_ir {
compatible = "pwm-ir";
pwms = <&pmi8950_pwm 0 0>;
reg-id = "vdd";
vdd-supply = <&pm8953_l8>;
};
驱动https://github.com/MiCode/Xiaomi_Kernel_OpenSource/blob/mido-n-oss/drivers/media/rc/pwm-ir.c
Xiaomi5X, Redmi 5Plus(spi-do方式,即使用spi的一个口来发射,因为spi有参考时钟,能用来做延时,同时spi要开启dma模式,保证传输过程中不受cpu影响,保证时序稳定)
https://github.com/MiCode/Xiaomi_Kernel_OpenSource/blob/tiffany-n-oss/arch/arm/boot/dts/qcom/msm8953-qrd.dtsi
&spi_6 {
status = "ok";
peel_ir@0 {
compatible = "peel_ir";
reg = <0x0>;
spi-max-frequency = <19200000>;
vdd-supply = <&pm8953_l8>;
peel_ir,reg-id = "vdd";
peel_ir,lr-gpio = <73>;
peel_ir,lr-gpio-valid = <0>;
peel_ir,spi-bpw = <32>;
peel_ir,spi-clk-speed = <960000>;
peel_ir,spi-mode = <0>;
peel_ir,peel-field = <2345>;
status = "ok";
};
};

驱动https://github.com/MiCode/Xiaomi_Kernel_OpenSource/blob/tiffany-n-oss/drivers/media/rc/peelir.c

最新的内核https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/drivers/media/rc?h=v4.19.6

已集成这三种方式ir-spi.c,pwm-ir-tx.c,gpio-ir-tx.c

SmartConfig

1.一定要了解802.11帧格式的原理,了解各ADDR字段的含义

2.编码长度是相对值,获取同步头的过程中需要计算编码基准长度

2.数据一定要顺序解耦,即任何一个数据的解析不能依赖于它与其他数据的相对顺序,一个较好的方式是使用多个组播地址,对配网包的各字节数据进行分离

3.同步头和数据部分的比例要合适,因为配网分为两个阶段即数据源定位和配网数据获取,比例失调会导致某一个阶段时间过长

4.信道扫描应采用多种策略对信道的信号质量进行评估,因为2.4g各信道间存在交叉覆盖,可能出现串信道情况,若在错误的信道持续监听,将大大增加监听时间

5.了解信号源是分类的,即上行和下行,两类数据包具有不同的编码基准长度,存在转换关系(上行包长度+2=对应下行包长度),且帧头中addr字段的定义也不同(见1)

6.信号的强弱是相对的,一般而言,手机的发射功率(10mW~20mW)要低于路由器(50~100mW),且距离近,信号强度高

7.802.11n有帧聚合机制,对于长度编码非常不利,使用地址编码可有效避免帧聚合(帧聚合只针对同一目标地址),不失为一个好方法

8.802.11n有功率协商机制,即接收方(AP)在ack帧会告知发送方自己接收到的信号强度,发送方(STA)会据此调整发射功率,若待配网设备的天线增益不足,可能导致收不到配网包

9.部分路由器出于安全考虑,不支持转发配网包

10.部分手机作为热点时,出于省电目的,若下属只有一台设备(发包方),则不会转发配网包

wifi模块配网方式锦集

智能家居/家电现阶段还处于普及阶段,由于家庭wifi网络的普及,目前普遍采用wifi与路由器完成连接,与手机/云端进行数据交互.

智能硬件,如智能插座,智能空调,智能空气净化器由于不具备人机交互界面,不能像电脑一样的搜索/选择指定路由器,输入连接密码的界面,所以必须先解决正确连接路由问题;

目前流行的wifi配置模式一般有以下2种:

1:智能硬件处于AP模式,手机用于station模式,手机连接到智能插座的AP后组成局域网,手机发送需要连接路由的SSID及密码至智能插座,智能硬件主动去连接指定路由后,完成连接。

在处于局域网时,

2:一键配置(smartconfig)模式:智能硬件处于混杂模式(可以抓取空中所有的802.11帧)下,监听网络中的所有报文;手机APP将SSID和密码编码到UDP报文中,通过广播包或组播报发送,智能硬件接收到UDP报文后解码,得到正确的SSID和密码,然后主动连接指定SSID的路由,完成连接

以上两种方式都可以达到让智能硬件连接至指定路由的效果,但是AP模式需要手动切换手机wifi连接的网络,先连接智能硬件的AP网络,配置完成后再恢复连接正常wifi网络.有一定的复杂性,耗时较长;

但是smartconfig由于路由器品牌及手机品牌众多,存在一定的兼容性问题,所以目前一般厂家仍保留AP模式,作为smartconfig失败后的备用配网方案;

1、AP接入

AP是(wireless)Access Point的缩写,即(无线)访问接入点。简单来讲就是像无线路由器一样,设备一打开后进入AP模式,在手机的网络列表中可以找到类似TPLINK_XXX的名字的(SSID).

手机APP万能遥控器的具体方案和编程实现

2、解析一键配置,其大体工作原理如下:

1、设备进入初始化状态,开始收听附近的WIFI数据包;

2、手机/平板APP设置WiFi名字和密码后,发送UDP广播(组播)包;----智能设备的WIFI芯片可以收到该UDP包,只要知道UDP的组织形式,就可以通过收到的UDP包解密出WIFI的SSID和密码;

3、设备通过UDP包(长度)获取配置信息,切换网络模式,连接上WIFI,配置完成。

如下图所示

手机APP万能遥控器的具体方案和编程实现

所谓智能配网:即使用WIFI设备本身自带的WIFI信号,在MAC层将SSID和密码按照一定的协议格式填充在MAC包中不加密的包头部分,采用广播和抓包的方式,从手机等设备将SSID和密码分段多次传递给WIFI模块。

下面重点讲解一下一键配置模式原理及应用;当前主流IOT的wifi方案有:

手机APP万能遥控器的具体方案和编程实现

这个功能最早是TI提出并应用于CC3200上;不过从原理上讲,只要芯片驱动支持开启混杂模式(WiFi Promiscuous),就可以支持一键配网功能,只是各个厂家叫法及实现编码方式不同而已;

手机编码发送采用有UDP组播或广播,不同的发送方式和编码,对应的解码过程也不一样。当前测试发现,微信是通过UDP广播包实现的;TI是通过往一固定IP地址发送udp包;其他芯片厂家提供的一般为UDP组播方式;

由于无线数据传播必定是广播的,所以必然可以被监听到;如果AP没有加密的话,UDP直接可以把相关的信息发送出来.但是路由器AP一般都是加密的,而且加密方式不固定.wifi模块在无法直接解析出数据包

我们通过分析802.11的MAC帧格式,可以知道,链路层载荷数据(即网络层的头部及网络层数)在数据帧中是清晰可见的,只要接到到802.11帧就可以立刻提取出载荷数据.

常见两种数据帧格式:


手机APP万能遥控器的具体方案和编程实现

Station to AP

手机APP万能遥控器的具体方案和编程实现

AP to Station

手机APP万能遥控器的具体方案和编程实现

DA:目标MAC地址
SA:源MAC地址
LENGTH:表示后面数据的长度
LLC:表示LLC头
SNAP:表示3byte的厂商代码和2byte的协议类型表示
DATA:载荷数据
FCS:帧检验序列

发送端:可以采用2种不同的编码发送方式——UDP广播和组播;

一:UDP广播:

小规模测试后,发现当前只有微信的AirKiss采用了全网广播模式,为啥微信会采用广播模式,原因未知;TI采用的是固定IP地址的UDP数据包,原理和微信基本一致;

从802.11帧格式分析中获知,从无线信号监听方的角度来说,不管无线信道有没有加密,DA、SA、LENGTH 、LLC、SNAP、FCS字段总是暴露的,因此信号监听方可以从这6个字段获取有效信息.

从发送方讲,由于操作系统的限制,如果采用广播,则只剩下LENGTH这一字段发送方可通过改变其所需要发送数据包的长度进行控制,所以只要指定出一套利用长度编码的通讯协议,就可利用广播数据包的Lenght字段进行数据传递;

手机APP万能遥控器的具体方案和编程实现

二:UDP组播:

组播地址是保留的D类地址从224.0.0.0-239.255.255.255 映射到MAC地址为:01:00:5e:xx:xx:xx (低23bit 直接映射);因此目的IP地址与MAC地址映射关系为:将MAC地址的前25位设定为01.00.5e,而MAC地址的后23位对应IP地址的位;

故发送端可以将数据编码在组播ip的后23bit中,通过组播包发送,接收端进行解码即可;

手机APP万能遥控器的具体方案和编程实现

接收端进入一键配置功能后,wifi 模块首先处于混杂模式,一种就是在13个信道,等时切换,如200ms 切换一下,轮询13个信道(一种是1,6,11 加大权重,大多数路由器会在1,6,11 不重叠信道;还有一种方式,先扫描所有路由器,看看那些信道有路由器,就在那些信道切换,具体切换信道时间,与wifi模块抓包性能有关),当wifi 在某一信道收到手机发的包(组播或广播),就锁定该信道,在该信道收包,解析出完整的数据

从信道1开始监听路由上的数据,如当前监听信道有符合规则的数据包,就停止信道切换,停留在当前信道接收完全部数据.否则就依次切换至信道2.3.4....直到信道14后又从信道1开始继续监听依次循环;

当然,wifi智能硬件可以在开启混杂模式之前,先行扫描当前环境下存在的AP获取所有当前AP的信道,然后只对当前扫描到的信道进行依次监听,如当前环境下只存在2个路由,分别在1.6信道,只需轮流扫描channel1和channel6,这样可以提高配置效率

可以采用如下编码方式:由于数据一次只能发送23bit,所以我们需要保证数据有序,23bit 里面需要包含index ,所以可以这样设计:01:00:5e:index(7bit),data[index]:data[index+1]

如:data[0] 为长度, data[1] 为校验,data[2]-data[n] 为具体数据, APP 按顺序发包,wifi 可以无序收包解析,拿到SSID 和PASSWD

还有一个值得注意的方面:随着无线路由器双频WIFI(即可以有两个WIFI名字,其中一个5G,一个2.4G)的越来越多,也许下一次智能硬件升级更换WIFI方案,要考虑支持5G。

格力空调遥控器红外编码透析(长码)

格力空调遥控器(YB0F2)红外码组成如下,按解码顺序排列

起始码(S)+35位数据码+连接码(C)+32位数据码

1、各种编码的电平宽度:

数据码由“0”“1”组成:

0的电平宽度为:600us低电平+600us高电平,

1的电平宽度为:600us低电平+1600us高电平

起始码S电平宽度为:9000us低电平+4500us高电平

连接码C电平宽度为:600us低电平+20000us高电平

2、数据码的形成机制

前35位数据码形成如下图所示:

手机APP万能遥控器的具体方案和编程实现

后32位数据码形成如下图所示:

手机APP万能遥控器的具体方案和编程实现

上表中,大于两位的数据都是逆序递增的,各数据的意义如下:

手机APP万能遥控器的具体方案和编程实现

校验码形成:

校验码 = (模式 – 1) + (温度– 16) + 5 + 左右扫风 + 换气 + 节能 - 开关

之后取二进制后四位,再逆序;

下面是Python语言拼码程序,Python版本为2.7.11

[python] view plain copy print?
#coding=utf-8
#说明:格力空调红外拼码Python脚本程序
#对应的码库为格力9,inst值:100032

startLevel = (9000,4500) #起始码
linkLevel = (550,20000) #连接码
lowLevel = (550,550) #低电平
highLevel = (550,1660) #高电平

#模式标志
modeFlag = 4
def modeCodeFunc(m):
global modeFlag
modeCode = (lowLevel+lowLevel+lowLevel, #自动
highLevel+lowLevel+lowLevel, #制冷
lowLevel+highLevel+lowLevel, #加湿
highLevel+highLevel+lowLevel,#送风
lowLevel+lowLevel+highLevel) #制热
if m > modeCode.__len__()-1:
print "模式参数必须小于" +str(modeCode.__len__())
return modeCode[0]
modeFlag = m
return modeCode[m]

#开关
keyFlag = 0
def keyCodeFunc(k):
global keyFlag
keyCode = (lowLevel, #关
highLevel) #开
keyFlag = k
return keyCode[k]

#风速
fanSpeedFlag =0
def fanSpeedCodeFunc(f):
global fanSpeedFlag
fanSpeedCode = (lowLevel+lowLevel, #自动
highLevel+lowLevel, #一档
lowLevel+highLevel, #二档
highLevel+highLevel) #三档
if f>fanSpeedCode.__len__()-1:
print "风速参数必须小于"+str(fanSpeedCode.__len__())
return fanSpeedCode[0]
fanSpeedFlag = f
return fanSpeedCode[f]

#扫风
#fanScanFlag = 0
def fanScanCodeFunc(f):

fanScanCode = (lowLevel,highLevel)
fanScanFlag = f
if f>fanScanCode.__len__()-1:
print "扫风参数必须小于"+str(fanScanCode.__len__())
return fanScanCode[0]
return fanScanCode[f]

def getSleepCode(s):
sleepCode = (lowLevel,highLevel)
if s>sleepCode.__len__()-1:
print "睡眠参数必须小于"+str(sleepCode.__len__())
return sleepCode[0]
return sleepCode[s]

tempFlag = 16
def tempertureCodeFunc(t):
global tempFlag
tempFlag = t
tempCode = ()# lowLevel+lowLevel+lowLevel+lowLevel

dat = t - 16
#print dat
print bin(dat)
for i in range(0, 4, 1):
x = dat & 1
#print x,
if x == 1:
tempCode += highLevel
elif x == 0:
tempCode += lowLevel
dat = dat >> 1

return tempCode

#定时数据
def getTimerCode():
timerCode = lowLevel+lowLevel+lowLevel+lowLevel+\
lowLevel+lowLevel+lowLevel+lowLevel
return timerCode

#超强、灯光、健康、干燥、换气
def getOtherCode(strong, light, health, dry, breath):
otherFuncCode = ()
if True==strong:
otherFuncCode = highLevel
else:
otherFuncCode = lowLevel

if True==light:
otherFuncCode += highLevel
else:
otherFuncCode += lowLevel

if True==health:
otherFuncCode += highLevel
else:
otherFuncCode += lowLevel

if True==dry:
otherFuncCode += highLevel
else:
otherFuncCode += lowLevel

if True==breath:
otherFuncCode += highLevel
else:
otherFuncCode += lowLevel

return otherFuncCode


#前35位结束码后七位结束码
#所有按键都是
#000 1010
def getFirstCodeEnd():
firstCodeEnd = lowLevel+lowLevel+lowLevel+highLevel+lowLevel+highLevel+lowLevel
return firstCodeEnd

#连接码
def getLinkCode():
linkCode = lowLevel+highLevel+lowLevel+linkLevel
return linkCode


#上下扫风
fanUpAndDownFlag = 1;
fanLeftAndRightFlag = 1;
def fanUpAndDownCodeFunc(f):
global fanUpAndDownFlag
fanUpAndDownCode = (lowLevel+lowLevel+lowLevel+lowLevel,
highLevel+lowLevel+lowLevel+lowLevel)
fanUpAndDownFlag = f
fanScanCodeFunc(fanUpAndDownFlag or fanLeftAndRightFlag)
return fanUpAndDownCode[f]

#左右扫风

def fanLeftAndRightCodeFunc(f):
global fanLeftAndRightFlag
fanLeftAndRightCode =(lowLevel+lowLevel+lowLevel+lowLevel,
highLevel+lowLevel+lowLevel+lowLevel)
fanLeftAndRightFlag = f
fanScanCodeFunc(fanUpAndDownFlag or fanLeftAndRightFlag)
return fanLeftAndRightCode[f]

#0000
#0100
#0000
#0000
#0000
def getOtherFunc2():
otherFunc2 = lowLevel+lowLevel+lowLevel+lowLevel
otherFunc2 += lowLevel+highLevel+lowLevel+lowLevel
otherFunc2+= lowLevel+lowLevel+lowLevel+lowLevel+\
lowLevel+lowLevel+lowLevel+lowLevel+\
lowLevel+lowLevel+lowLevel+lowLevel
return otherFunc2

def getCheckoutCode():
#校验码 = (模式 – 1) + (温度 – 16) + 5 + 左右扫风 + 换气 + 节能 - 开关
# 取二进制后四位,再逆序
dat = (modeFlag - 1) + (tempFlag - 16) + 5 + fanLeftAndRightFlag + 0 + 0 - keyFlag
print(dat)
code = ()
for i in range(0, 4, 1):
x = dat & 1
if 1 == x:
code += highLevel
elif 0 == x:
code += lowLevel
dat = dat >> 1

#print code
return code

def getSecondCodeEnd():
secondCodeEnd = (550,40000)
return secondCodeEnd

if __name__ == "__main__":
print("格力空调遥控器红外编码-长码")
print("100032-格力9")
code = startLevel #起始码
code += modeCodeFunc(1) #模式:0自动,1制冷,2加湿,3送风,4加热
code += keyCodeFunc(1) #开关:0关,1开
code += fanSpeedCodeFunc(0) #风速:0自动,1一档,2二档,3三档
code += fanScanCodeFunc(0) #扫风:0关,1开-设置上下扫风和左右扫风的时候会自动设置为1
code += getSleepCode(0) #睡眠
code += tempertureCodeFunc(16) #温度
code += getTimerCode() #定时
code += getOtherCode(False,True,False,False,False) #其他-超强、灯光、健康、干燥、换气
code += getFirstCodeEnd() #剩余的编码
code += getLinkCode() #连接码
code += fanUpAndDownCodeFunc(0) #上下扫风
code += fanLeftAndRightCodeFunc(1) #左右扫风
code += getOtherFunc2() #固定码
code += getCheckoutCode() #校验码
code += getSecondCodeEnd() #结束码
print "电平码:"
print code

格力空调红外协议解析

uint8_t GREE1[35]={0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0, 
0x00,0x80,0x40,0xc0,0x20,0xa0,0x60,0xe0,0x10,0x90,0x50,0xd0,0x30,0xB0,0x70
};
uint8_t GREE2[35]={0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,
0x0c,0x02,0x0a,0x06,0x0e,0x01,0x09,0x05,0x0d,0x03,0x0b,0x07,0x0f,0x00,0x08 //校验码1
};
uint8_t GREE3[35]={0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,
0x06,0x0e,0x01,0x09,0x05,0x0d,0x03,0x0b,0x07,0x0f,0x00,0x08,0x04,0x0c,0x02 //校验码2
};
void GREE_temperature(uint8_t temp )
{
Pir_Start();
Pir_SendData(0x9c);
Pir_SendData(GREE1[temp]); //
Pir_SendData(0x04);
Pir_SendData(0x0a);
Pir_Send3bit(0x40);

Pir_Connect();
Pir_SendData(0x00);
Pir_SendData(0x00);
Pir_SendData(0x00);
Pir_SendData(GREE2[temp]);//26°
Pir_Stop();

Pir_Start();
Pir_SendData(0x9c);
Pir_SendData(GREE1[temp]);
Pir_SendData(0x04);
Pir_SendData(0x0e);
Pir_Send3bit(0x40);

Pir_Connect();
Pir_SendData(0x00);
Pir_SendData(0x00);
Pir_SendData(0x0c);
Pir_SendData(GREE3[temp]);//26°
Pir_Stop();
}

手机遥控器代码

任何红外线的信号都是可以由一串二进制编码翻译表达出来的,手机通过外设或内部遥控模块电压信号都可以传递出一串含有二进制编码信息,转化为红外遥控器的红外线发射出来。本课题旨在通过智能手机的软件支持,配合一个外接硬件红外发射模块内转化为红外线输出,达到各种电器遥控器合为一体的目的,力求为使用者带来方便。

遥控软件部分所实现的功能是:

1)遥控器面板的选择以及绘制。

2)遥控器面板上的按键与对应要发出的红外遥控信号所对应的控制音频信号之间的触发关系对应选择遥控码库。

3)通过手机外设接口的发射红外线遥控代码。

能的不多部分型号三星GALAXY S4诺基亚很多老手机不过目前很多新出的手机会考虑加红外功能。

不同品牌的手机遥控器代码:

长虹
000. 008. 009. 091. 092. 093. 010. 011. 014. 016 .026. 028. 033. 051. 088.100.157.158.159. 160. 161. 180 .181. 185 .186 .191. 192 .210. 211. 212. 229. 230 .231 .232
康佳
011 .017 .029 .032 .034. 054 .067 .069 .071 .075 .076 .077 .078 .079 .080 .081 107 113 117. 173 .174. 175. 176. 189. 201. 202. 203. 217 .218. 220. 226 .267.236
创维 011. 025.033.045.046.060 .070. 017 .072. 073. 074. 079. 083.010 .107. 108 .109 162 163 .164 .165 .166 .167. 168. 169. 177. 224.225. 235. 246
海信
000. 006 .007. 008. 010 .014 .015. 025. 045. 046 .103. 105. 107 .115 .116 .128. 129.130.131.138 .139.150 .151 .152 .153 .154 .155 .156 .182 .183 .184 .193 .194 .213 .228
金星
007. 008. 011 .013. 024. 025. 032. 033 .039 .051 .065 .071 .073. 079 .091 .097 .138
福日
007 .011 .015 .023.024. 028. 033. 034. 040. 043. 053. 056. 060 .061 .065 .079
百乐
BAILE 016. 025. 012 .019. 026. 027.028. 029 .030. 031. 042
宝声
BAOSHENG 011. 025. 016
长城
011 .016 .017. 023 .024 .025.033. 040 .043 .053. 056 .001 .012. 029 .027 .026.028 .029.030
海虹HAIHONG
016 .025 .026 .027. 028 .029 .030
昆仑KUNLUN
001.011.021.022.033.025.012.042.040.039
凯歌KAIGE
011.016.023.024.025.033.040.043.053.056.079
康力KANGLI
027.012.019.025.026.028.030.031.033.120
康虹KANGHONG
009.058.057
康立KANGLI
016.023024.025.040.043.011.026.029.042.005

每一个代码对应的品牌和遥控器型号都是不同的,例如说:

科朗手机遥控器代码对应的型号:
遥控器型号 对应编码
HYDFSR-0102 305
HYDFSR-0123 307
HYDFSR-0134 304
LCD20001EU 309
HTR-022 118
HTR-001 175
HTR-044 272
HYDFSR-0077/0079 116

输入特定的代码之后,我们的手机遥控器就变成了万能遥控器,无论什么样的电器都可以轻松使用,不仅如此,手机遥控器最大的特点就是可以远程控制!只要我们拥有家用电器专属的代码,就可以搭配手机使用了,将您的手机换身为遥控器,这个可比万能遥控器好用的多,当然,家用电器里自带的遥控器也再也不用害怕丢失,只要有手机遥控器代码就可以轻松完成呢。

安卓手机上那些遥控app是怎么实现的

现在手机搭载了红外后,下个遥控精灵什么的,基本上都能作为遥控器使用,而且是遥控器的合体版,好强大。这种遥控app是怎么实现的,除了红外,我看到wifi和蓝牙也是可以控制的。

手机与电器连接可能通过以下方式:

1. 手机发射音频(可以是高频人耳不能分辨,也可以是语音),需对应的电器模块有解析音频的能力

2. 手机通过蓝牙与对应电器蓝牙模块连接

3. 手机通过网络与对应电器网络模块连接,该方式应该是智能家居的主流方法。

4. 手机通过红外与对应电器红外模块连接。如果手机不具备红外模块,市面上也有音频转红外模块、蓝牙转红外模块出售。

解决通信的问题后,需要了解各种电器的通信协议,协议编码,协议规则。不同电器的生产厂家对外红遥控制器的编码进行了规范,各编码各不相同,从而形成不同的编码方式,目前红外遥控协议有数十种,比如:RC5、SIRCS、SONy、RECS80、Denon、NEC、Motorola、SAMSWNG和Daewoo等。我国家用电器的红外遥控协议用得较多的是NEC协议或其变种。但是国内厂商基本上也不会公开自己使用的协议和编码格式,而且为了不同品牌之前的遥控没有干扰,也会自己定义编码内容。所以要实现你说的那些功能不是一件简单的事。

某果是android上的一个遥控器,它这些协议配置文件就有100多个,遥控编码配置文件有1000多个!由此可见,这个工作量非常大。这些协议配置文件应该是这些遥控器app之间的核心竞争力吧,毕竟能解析的协议越多,可以适配的电器就越多。所以这些协议也不会轻易公开。

手机: 什么是红外接口

红外接口英文简称为IrDA,是Infrared Data Association(红外线数据标准协会)的英文缩写,IrDA红外接口是一种红外线无线传输协议以及基于该协议的无线传输接口。支持IrDA接口的掌上电脑,可以无线地向支持IrDA的设备无线连接来实现信息资源的共享。

主要应用:

设备互联、信息网关。设备互联后可完成不同设备内文件与信息的交换。信息网关负责连接信息终端和互联网。

红外通讯技术已被全球范围内的众多软硬件厂商所支持和采用,目前主流的软件和硬件平台均提供对它的支持。红外技术已被广泛应用在移动计算和移动通讯的设备中。

红外接口是新一代手机的配置标准,它支持手机与电脑以及其他数字设备进行数据交流。红外通讯有着成本低廉、连接方便、简单易用和结构紧凑的特点,因此在小型的移动设备中获得了广泛的应用。通过红外接口,各类移动设备可以自由进行数据交换。 红外线是波长在750nm至1mm之间的电磁波,它的频率高于微波而低于可见光,是一种人的眼睛看不到的光线。由于红外线的波长较短,对障碍物的衍射能力差,所以更适合应用在需要短距离无线通讯的场合,进行点对点的直线数据传输。红外数据协会(IRDA)将红外数据通讯所采用的光波波长的范围限定在850nm至900nm之内。 配备有红外接口的手机进行无线上网非常简单,不需要连接线和PC CARD,只要设置好红外连接协议就能直接上网。 红外接口是目前在世界范围内被广泛使用的一种无线连接技术,被众多的硬件和软件平台所支持;通过数据电脉冲和红外光脉冲之间的相互转换实现无线的数据收发。

红外接口的特点:用来取代点对点的线缆连接 新的通讯标准兼容早期的通讯标准 小角度(30度锥角以内),短距离,点对点直线数据传输,保密性强 传输速率较高,目前4M速率的FIR技术已被广泛使用,16M速率的VFIR技术已经发布

红外技术的主要优点: 其使手机和电脑间可以无线传输数据; 可以再同样具备红外接口的设备间进行信息交流; 同时红外接口可以省去下载或其他信息交流所发生的费用; 由于需要对接才能传输信息,安全性较强;

红外技术缺点:通讯距离短,通讯过程中不能移动,遇障碍物通讯中断; 红外通讯技术的主要目的是取代线缆连接进行无线数据传输,功能单一,扩展性差。

红外技术特征 红外线通信技术适合于低成本、跨平台、点对点高速数据连接,尤其是嵌入式系统。

红外线技术的主要应用:设备互联、信息网关。设备互联后可完成不同设备内文件与信息的交换。信息网关负责连接信息终端和互联网。 红外通讯技术已被全球范围内的众多软硬件厂商所支持和采用,目前主流的软件和硬件平台均提供对它的支持。红外技术已被广泛应用在移动计算和移动通讯的设备中。

Android 手机红外遥控器实现

经过连续几天的编制,安卓手机代码终于完成了,目前已经将我宿舍,家里,集控室的红外遥控电气设备完好的遥控了,另外还遥控了我的D7000相机,不错终于完工了。 代码分为二类: 各种电视、相机、等等遥控编码最简单,只要将按键的编码复制下来,直接变成手机发射码就可以了。(这种编码单个按键只发射单个信息) 最难的是空调编码,由于空调编码是将单个按键要发射所有控制信息,如增加一度温度,同时要将控制模式、温度、风量等等所有信息一同发射出去,还有检验码,通过长时间实验,如果像一般模仿遥控器的设备(例如万能遥控器)编码是将各种组合分别保存起来,这要就很长,也很麻烦,但用第一种方法实现起来就很容易。第二种方法主要是找规律比较麻烦,而且要再程序中变成组合再变成安卓发射码,比较麻烦。 经过摸索 格力遥控器编码规则如下(前面的资料是网上搜集来的,这里是自己总结的):

手机APP万能遥控器的具体方案和编程实现

**文件格式:开关名称 / 按键位置 / 图标名称 / 命令代码
**空调格式:格力空调YB0FB
** 0 1 2 3方式 4开5风6睡 7温度 8 10强照 干
++++/24,65,22/38000,358,179/ 100/ 0 /00/00 /0101 /0000 /0000/ 0/0/0/0 /0000 /1010 /010/ ,24,795 /0000 /0000 /1000 /0100 /0000 /0000 /0000 /++

**名称/位置/图标/位置/初始值/变化
++/空调开关/20/power/4/2
++/模式/21/mode/3/5/p1/auto/coldm/dryingm/windm/warmm
++/风量/22/velocity/5/4/t2/wind0/wind1/wind2/wind3
++/温度+/23/up/7/14/t1/16/17/18/19/20/21/22/23/24/25/26/27/28/29/30
++/温度-/28/down/7/14/t1/16/17/18/19/20/21/22/23/24/25/26/27/28/29/30
++/灯光/25/light/11/2/p3/nu/lightm
++/睡眠/26/sleep/6/2/p4/nu/sleepm

这上面是格力空调编码方案

下面是直接编码:

电视开关/0/power/38000,358,179,21,21,22,21,23,20,21,21,22,21,23,20,21,67,23,20,21,21,22,21,23,20,21,21,22,21,23,20,21,67,23,20,21,21,22,67,21,21,22,67,21,21,22,21,23,20,21,21,22,67,21,21,22,67,21,21,22,67,21,67,23,64,22,67,21,1310,358,89,22 
静音/6/mute/38000,361,176,22,21,21,21,22,21,21,22,21,21,22,21,21,67,22,21,21,22,21,21,22,21,21,22,22,20,23,20,21,67,23,20,21,67,23,65,22,65,21,67,23,20,21,22,23,19,24,19,21,22,23,19,24,19,21,22,23,64,21,67,24,64,23,64,21,1310,359,88,21
显示模式/5/screen/38000,359,178,22,21,25,18,21,21,22,21,25,18,21,21,22,67,21,21,22,21,25,18,21,21,22,21,25,18,21,21,22,67,21,21,22,67,21,21,22,21,25,63,22,67,21,21,22,21,25,18,21,21,22,67,21,67,25,18,21,21,22,67,21,67,25,63,22,1309,359,89,25
信号源/1/tvav/38000,362,175,24,20,21,21,22,21,24,20,21,21,22,21,24,64,22,21,24,20,21,21,22,21,24,20,21,21,22,21,24,64,22,21,24,64,22,21,24,20,21,21,22,21,24,20,21,67,24,20,21,21,22,67,21,67,24,64,22,67,21,67,24,20,21,67,24,1307,362,86,21

下面是安卓语言源代码:不喜好编程的人就不用看了:

package com.example.sumxingir;

import java.io.FileInputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import org.apache.http.util.EncodingUtils;
import android.app.Activity;
import android.content.Intent;
import android.content.res.Resources;
import android.graphics.Color;
import android.os.Bundle;
import android.os.Environment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.GridView;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;


public class room extends Activity {
String Temp;
String[] STR=new String[2];
String[] rv=new String[2];
private MyAdapter adapter = null;
private ArrayList> array;
GridView layout;
String[] Kt=new String[20]; //Kt1 整体代码
int Ktonof=0; // /Kt1 开关;
String[] base=new String[]{"","",""}; // /0电平宽度1电平宽度;高电平宽度;
int check=0 ;
String[] Ktmode=new String[10]; //空调模式
String[] Ktwendu=new String[30]; //温度变化量
String[] Ktwind=new String[10]; //风变化量
String[] Ktp3=new String[]{"","","","","",""}; //空调其它按键
String[] Ktp4=new String[]{"","","","","",""}; //空调其它按键
String[] Ktt2=new String[]{"","","","","",""}; //空调其它按键

int Count;
String[] name=new String[40] ;
int[] image=new int[40];
String[] code=new String[40];
String[] mode=new String[5];
// android.view.ViewGroup.LayoutParams lp ; //声明控件参数获取对象 LayoutParams lp;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.room);
GridView layout = (GridView) findViewById(R.id.gridview);
RelativeLayout view = (RelativeLayout) findViewById(R.id.view);
android.view.ViewGroup.LayoutParams lp ; //声明控件参数获取对象 LayoutParams lp;
lp = view.getLayoutParams(); //2、获取控件参数: lp = 控件id.getLayoutParams();
lp.height=0; view.setLayoutParams(lp);

// setContentView(layout);
Intent intent=getIntent();
Temp=intent.getStringExtra("strcode") ;
setTitle(Temp);
setTitleColor(Color.GREEN);
Temp= readFileSdcard(Temp.trim());
STR=Temp.split("\r\n"); //=============文件处理

Count=0;
for (int i=0 ;iif (STR[i].trim().length()<10 ){continue;}
if(STR[i].substring(0, 2).equals("**")){continue;}
if (STR[i].substring(0, 2).equals("++")){
if (STR[i].substring(0, 4).equals("++++")){ Kt=STR[i].trim().split("/");
lp.height=150; view.setLayoutParams(lp);
base=Kt[1].trim().split(",");
// if(Kt[Kt.length-1].trim().equals("++") ){Kt[Kt.length-1]="1111";check=1;}
} //=========空调处理
else{ // ++/空调开关/20/power/251/+1
rv=STR[i].split("/");
int s=(Integer.parseInt(rv[2])); //按键位置号
name[s]=(rv[1]).trim();
code[s]=(rv[4]+","+rv[5]); //指向代码位
// int k=Integer.parseInt(rv[4]);
if (rv[1].equals("模式")){
for(int j=4;jelse if (rv[1].equals("温度+")){ for(int j=4;jKtwendu[j-4]=rv[j].trim();}}
else if (rv[1].equals("风量")){ for(int j=4;jelse if (rv[1].equals("空调开关")){ Ktonof=Integer.parseInt(rv[4].trim()); }
else if (rv[6].equals("p3")){ for(int j=4;jelse if (rv[6].equals("p4")){ for(int j=4;jelse if (rv[6].equals("t2")){ for(int j=4;j
String m=rv[3];
if (s>Count){Count=s;}
Resources res=getResources();
image[s]= res.getIdentifier(m, "drawable", getPackageName());

}
}else{ //==================一般按键处理
rv=STR[i].split("/");
int s=(Integer.parseInt(rv[1]));
name[s]=(rv[0]);
code[s]=(rv[3]);
String m=rv[2];
if (s>Count){Count=s;}
Resources res=getResources();
image[s]= res.getIdentifier(m, "drawable", getPackageName());}

}

array = getData();
adapter = new MyAdapter();
layout.setAdapter(adapter);
layout.setOnItemClickListener(new ItemClickEvent());
if(Ktonof!=0){ show(); } //显示空调状态
}

public String readFileSdcard(String fileName) { //读取txt文件

// Temp=Environment.getExternalStorageDirectory()+"/SUMIR/code.txt";
String res = "";
try {
FileInputStream fin = new FileInputStream(
Environment.getExternalStorageDirectory()+"/SUMIR/"+fileName+".txt");
int length = fin.available();
byte[] buffer = new byte[length];
fin.read(buffer);
res = EncodingUtils.getString(buffer, "UNICODE");
fin.close();
}
catch (Exception e) { e.printStackTrace(); }
return res;
}


class MyAdapter extends ArrayAdapter> {

MyAdapter() {
super(room.this, R.layout.mygrid, array);
}

public ArrayList> getList() {
return array;
}

public View getView(int position, View convertView, ViewGroup parent) {
View row = convertView;
// String[] name1=new String[Count+1];name1=name;
if (row == null) {
LayoutInflater inflater = getLayoutInflater();
row = inflater.inflate(R.layout.mygrid, parent, false);
}
ImageView imageView = (ImageView) row.findViewById(R.id.img);
imageView.setScaleType(ImageView.ScaleType.FIT_CENTER);
imageView.setImageResource(Integer.valueOf(array.get(position)
.get("img").toString()));
TextView tv1 = (TextView) row.findViewById(R.id.txt);
tv1.setText(name[position]);
return (row); } }

private ArrayList> getData() {
ArrayList> list = new ArrayList>();

for (int i = 0; i < Count+1; i++) {
Map map = new HashMap();
map.put("img", image[i]);
list.add(map);
} return list; }
//点击处理============================================================
class ItemClickEvent implements AdapterView.OnItemClickListener {
String ircode;
RelativeLayout view = (RelativeLayout) findViewById(R.id.view);
@Override
public void onItemClick(AdapterView arg0, View arg1, int arg2,long arg3) {
// Toast.makeText(room.this, name[arg2], Toast.LENGTH_SHORT).show();
arg1.setPressed(false);
arg1.setSelected(false);
if (code[arg2]!=null) {
if (code[arg2].length()>20 ) { ircode=code[arg2];}else{
rv=code[arg2].split(",");
int k1= Integer.parseInt(rv[0]);int LimUP=Integer.parseInt(rv[1]);

if(name[arg2].substring(name[arg2].length()-1).equals("-")){
opj(k1,0,LimUP); }else{opj(k1,1,LimUP); } //Kt 位置,±,上限

ircode=readcode();
if(Kt[Kt.length-1].trim().equals("++") ){ircode+=check(ircode);}
show();

}

try {
Object localObject = getSystemService("irda");
localObject.getClass();
localObject.getClass().getMethod("write_irsend", new Class[] { String.class }).invoke(localObject, new Object[] {ircode });
return; }
catch (Exception localException) { localException.printStackTrace(); }
}}}

private void opj ( int ktsit, int bb,int Lm){ //===========+-操作 代码
Kt[ktsit]=Kt[ktsit].trim();
int L=Kt[ktsit].length();
int m=readKt(ktsit);if (bb==0){m--;}else{m++;}
if ( m>=Lm){ if (Lm>10){m=Lm;}else{m=0;}}
if (m<0){m=0;}
Temp="0000000000"+Integer.toBinaryString(m);
Temp=Temp.substring(Temp.length()-L);
Kt[ktsit]="";for(int i=0;i Kt[ktsit]+=Temp.substring(L-i-1, L-i);

}
}
private String check (String SS ){ //==========================检查校验码
String T1="";int lim=Integer.parseInt(base[0])/2+Integer.parseInt(base[1])/2;
int sum =0; int x=0; int Y=0;
rv=SS.split(",");
for (int i=4;iif(x==8){x=0;sum+=Y;Y=0; }
if(Integer.parseInt(rv[i])>lim){Y+=1<x++;
}
sum=sum%16; // T1=String.valueOf( sum);

T1=","+base[2]+"," +base[sum%2]+","+base[2]+"," +base[(sum%4)/2]+","+base[2]+","
+base[(sum%8)/4]+","+base[2]+"," +base[sum%16/8]+","+base[2] ;
return T1;
}
private void show (){ //====================================设置显示
ImageView Pv1=(ImageView) findViewById(R.id.p1);
ImageView Pv2=(ImageView) findViewById(R.id.p2);
ImageView Pv3=(ImageView) findViewById(R.id.p3);
ImageView Pv4=(ImageView) findViewById(R.id.p4);
TextView Tv1=(TextView) findViewById(R.id.t1);
TextView Tv2=(TextView) findViewById(R.id.t2);
Resources res=getResources();
if(Kt[Ktonof].trim().equals("0")){
Pv1.setVisibility(View.INVISIBLE);
Pv2.setVisibility(View.INVISIBLE);
Pv3.setVisibility(View.INVISIBLE);
Pv4.setVisibility(View.INVISIBLE);
Tv1.setVisibility(View.INVISIBLE);
Tv2.setVisibility(View.INVISIBLE);

} else{
Pv1.setVisibility(View.VISIBLE);
Pv2.setVisibility(View.VISIBLE);
Pv3.setVisibility(View.VISIBLE);
Pv4.setVisibility(View.VISIBLE);
Tv1.setVisibility(View.VISIBLE);
Tv2.setVisibility(View.VISIBLE);
int m=readKt(Integer.parseInt(Ktmode[0])); //模式显示
int Pv= res.getIdentifier(Ktmode[m+3] , "drawable", getPackageName());
Pv1.setImageResource(Pv);

m=readKt(Integer.parseInt(Ktwendu[0])); //温度显示
Tv1.setText(Ktwendu[m+3]);
if(Ktt2[0]!=""){m=readKt(Integer.parseInt(Ktt2[0])); //温度显示
Tv2.setText(Ktwendu[m+3]);}
if(Ktwind[0]!=""){m=readKt(Integer.parseInt(Ktwind[0])); //风量显示
Pv= res.getIdentifier(Ktwind[m+3] , "drawable", getPackageName());
Pv2.setImageResource(Pv); }

if(Ktp3[0]!=""){
m=readKt(Integer.parseInt(Ktp3[0])); //p3显示
Pv= res.getIdentifier(Ktp3[m+3] , "drawable", getPackageName());
Pv3.setImageResource(Pv); }
if(Ktp4[0]!=""){m=readKt(Integer.parseInt(Ktp4[0])); //p4显示
Pv= res.getIdentifier(Ktp4[m+3] , "drawable", getPackageName());
Pv4.setImageResource(Pv);}


}

}
private int readKt ( int ktsit){ //============读取 KT 指定位置 数值
byte[] b = (Kt[ktsit].trim()).getBytes();
int sum=0;
for(int i=0; i sum =sum+((b[i]-48)<}

private String readcode (){ //===================转换成发射码
String T1=Kt[2].trim();
for (int i=3;i Kt[i]=Kt[i].trim();
if (Kt[i].substring(0,1).equals(",")){ T1=T1+Kt[i]; } //直接代码
else if(Kt[i].substring(0,1).equals("-")){ //执行反码
rv=Kt[i].split("-"); Temp="";
for(int j=1;j< rv.length;j++){ Temp+=Kt[Integer.parseInt(rv[j])]; }
Temp=Temp.replace(" ", "");
for(int j=0;j< Temp.length();j++){ T1+=","+base[2]+","+base[ (Integer.parseInt(Temp.substring(j,j+1))+1)%2 ] ; }
}else if(Kt[i].substring(0,1).equals("+")){
continue;}
else{
byte[] b = (Kt[i]).getBytes();
for(int j=0;j T1+=","+base[2]+","+base[b[j]-48] ; }
} }
return T1;}
}

推荐阅读:池州在线

[责任编辑:无]