android串口权限
1. 如何开放android的串口权限
要调用串口,肯定是要用到JNI的,而且要有打开对应串口设备的权限
至于是不是通过USB转的,没啥关系,因为USB转串口的驱动已经把USB的特征封装了,就当它是一个纯串口操作就行
android-serialport-api也是用的JNI,要想知道能不能用,装它的DEMO代码试试就知道了
不然重新写一个JNI的库,用android-serialport-api的也行,不然网上也好多现成的代码,基本不用重写
2. Android开发之串口通信:AndroidSerialPort
Android 串口通信,基于 谷歌官方android-serialport-api 编译
项目github地址: https://github.com/AIlll/AndroidSerialPort
读取数据时很可能会遇到分包的情况,即不能一次性读取正确的完整的数据
解决办法:可以在读取到数据时,让读取数据的线程sleep一段时间,等待数据全部接收完,再一次性读取出来。这样应该可以避免大部分的分包情况
只接收一条数据的情况下,以上方法可以应对数据分包,数据量多的情况下需要考虑是否会因为sleep导致接收多条数据,可以根据通信协议核对包头包尾等参数。
打开串口时,会检测读写权限,当没有权限时,会尝试对其进行提权
3. Android UART 串口通信
最近有项目需要实现windows机器和Android开发版进行UART串口通信,经过3天查找尝试,特记录一下最终方案,希望之后的同行少走弯路,最后在git上回开源我最终的方案希望大家支持。
Android 3.0.1
Gradle 4.1
ARM开发版 : RK3399
PC机器:Win10
开发机器:MAC 10.13.3
先上图
由于 android-serialport-api 项目中的so使用较old的ndk编译,所以在对于Android 6.0 以上版本兼容的时候会报错 dlopen failed: "has text relocations" 。且使用的mk进行编译,特升级为用cmake编译。
升级 android-serialport-api
项目结构:
app对应原项目中的各个Activity, androidserial 是mole 对应编译之前的so,还有API的封装。可以直接引用androidserial,调用方法参考app目录下的activity。
注意 关于权限!
当接入开发板后如果发现 Error You do not have read/write permission to the serial port 需要root 权限 ,在开发者模式中开启root 权限 adb和应用
使用一下命令开启Android对串口的读写权限
setenforce 0 : 关闭防火墙,有人说关键是这,但是我的环境不用关闭,只要给权限就可以
注意 关于ttyS1 - 6 ttyS1 - 6 对应的是 UART 串口1-6 一般都是一一对应的。这个具体要看一下开发板的说明。
记录的比较糙,还请见谅,如有问题请留言,我看到后肯定回复。项目主要看结构,剩下的都是复制黏贴的事。 git地址:https://github.com/braincs/AndroidSerialLibrary
4. Android串口通讯
1.打开串口。
2.串口处于监听状态
3.想串口写入数胡锋据,串口接收到数据返回数据
SerialPort类所嫌迟在的包一定要和上图包名一直,因为串口通讯需要使用jni中裤者晌的函数。
package android_serialport_api;
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import com.fx.serialporttest.L;
public class SerialPort {
/*
* Do not remove or rename the field mFd: it is used by native method
* close();
*/
private FileDescriptor mFd;
private FileInputStream mFileInputStream;
private FileOutputStream mFileOutputStream;
/**
* 构造方法
* @param device 串口地址
* @param baurate 波特率
* @param flags
* @throws IOException
* @throws InterruptedException
*/
public SerialPort(File device,int baudrate,int flags) {
/*
* 检测是否有访问权限
*/
if(!device.canRead()||!device.canWrite()){
//如果没有读写权限,尝试chmod命令这个文件
L.tag("没有读写权限");
Process su;
try {
su = Runtime.getRuntime().exec("/system/bin/su");//获取root读写权限
String cmd = "chmod 777"+device.getAbsolutePath()+"\n"+"exit\n";
su.getOutputStream().write(cmd.getBytes()); //向此路径文件写入命令
if((su.waitFor()!=0||!device.canRead()||!device.canWrite())){
throw new SecurityException();
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
mFd = open(device.getAbsolutePath(),baudrate,flags);
if(mFd==null){
mFd = open(device.getAbsolutePath(),baudrate,flags);
L.tag("native open return null");
}
mFileInputStream = new FileInputStream(mFd);
mFileOutputStream = new FileOutputStream(mFd);
}
public FileInputStream getmFileInputStream() {
return mFileInputStream;
}
public void setmFileInputStream(FileInputStream mFileInputStream) {
this.mFileInputStream = mFileInputStream;
}
public FileOutputStream getmFileOutputStream() {
return mFileOutputStream;
}
public void setmFileOutputStream(FileOutputStream mFileOutputStream) {
this.mFileOutputStream = mFileOutputStream;
}
//JNI
private native static FileDescriptor open(String path,int baudrate,int flags);
public native void close();
static {
System.loadLibrary("serial_port");
}
}
package android_serialport_api;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import com.fx.serialporttest.L;
public class SerialPortFinger {
private static ReadThread readThread;
private static FileInputStream mFileInputStream;
private static FileOutputStream mFileOutputStream;
static String path = "/dev/ttyS0";//设备主板的串口地址,地址有所不同
public void startListener(){
SerialPort serialPort = new SerialPort(new File(path), 9600, 0);//9600是波特率,这个也是有所不同,具体要看设备
mFileInputStream = serialPort.getmFileInputStream();
mFileOutputStream = serialPort.getmFileOutputStream();//获取串口写入流
readThread = new ReadThread();
readThread.start();//开启监听
}
/**
* 发送指令到串口
*
* @param cmd
* @return
*/
public boolean sendCmds(String cmd) {
boolean result = true;
byte[] mBuffer = (cmd+"\r\n").getBytes();
try {
if (mFileOutputStream != null) {
mFileOutputStream.write(mBuffer);
} else {
result = false;
}
} catch (IOException e) {
e.printStackTrace();
result = false;
}
return result;
}
static class ReadThread extends Thread{
@Override
public void run() {
// TODO Auto-generated method stub
super.run();
int len;
StringBuffer sb = new StringBuffer("");
while(true){ //循环监听串口,读取返回的数据
byte[] buffer = new byte[1024];
if(mFileInputStream==null){
return;
}
try {
len = mFileInputStream.read(buffer);
if(len>0){
sb.append(new String(buffer, 0, len));
}
if(!sb.toString().equals(""))
{
L.tag(sb.toString());//收到串口的返回数据,在日志中打印出来
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
L.tag("接受完成");
}
}
}
}
5. android虚拟机串口通信
工具:Virtual Serial Port Driver.
用这个工具虚拟出一对串口。
下载地址
2.用串口调试助手,测试串口通信。
3.用这个命令启动虚拟机:emulator @2.2 -scale auto -qemu -serial COM3 &
说明:
2.2:是虚拟机的名称。
COM3是你要选择的串口。
ps:在cmd中使用这个命令有两种方式:1)将安卓的sdk的tools文件夹加入到path环境变量中,2)在安卓的sdk的tools文件夹下打开cmd。
4.虚拟机中测试串口通信用谷歌的一个开源项目:android_serialport_api
5.在虚拟机中运行项目。
说明:运行前要获取设备的权限
1)在cmd中用adb shell命令,进入虚拟机命令行环境。
2)打开dev文件夹:cd dev
3)获取权限:chmod 777 ttyS2
6.谷歌的开源项目不能导入进eclipse,我整理了一下,调通了。
6. Android平台到底能不能通过串口发送AT指令呢,急!!!
AT命令(Attention)在手机中,用于对modem(也就是移动模块)通过串口命令进行操作,处理与语音电话、短信和数据。
关于AT命令:
Android系统与AT命令
对于智能手机,AP和BP分离的情况,在AP上的系统通过串口和BP通信是个不错方式。在Android的源码中有一个内部包com.android.internal.telephony中有对AT命令的封装和解析,但这种internal的包开发者不能调用的SDK部分,可以用来封装ROM。这说明Android对AT command的方式是支持的。
对于Android如何调用AT command
用root登录命令行,直接对串口进行操作,如echo -e "AT " > /dev/smd0
具体的串口,不同设备会有不同,甚至不一定会提供。这种方式,开发者是可以调用的,通过Runtime.exec直接执行命令行命令,但要求是root,例如echo -e "ATD123456789; " > /dev/smd0,拨打123456789的号码。
目前最新的AT命令标准发布与2014.6.27,似乎还活得挺滋润的。但是给出的keywords是UMTS, GSM, command, terminal, LTE这说明CDMA确实很可能不是采用AT命令的方式。
7. android 串口为什么不能正常读写
串口通让游信枝滑拦数据丢失很大一部分原因是:mscomm的inputlen设置设置有问题;
解决方案:
mscomm的inputlen设置为0吧(读取整个缓冲区),读完一次,清空一次缓冲区试试;
参考如下:
猛胡窗体初始化事件中建议将mscomm的这几个属性做如下设置:
mscomm.inbuffersize=8 '接收缓冲区大小
mscomm.rthreshold=4 '促发oncomm事件的字符数
mscomm.inputlen=0 '默认读取整个缓冲区
mscomm.inputmode=cominputmodetext '以文本方式接收
mscomm.inbuffercount=0 '清空缓冲区
oncomm事件中,建议处理完接收数据后用mscomm.inbuffercount=0清空缓冲区
8. android串口消息
android串口消息连接的方法为:
1.模拟器可以使用PC的串口。
启动模拟器并加载PC串口 命令如下。
运行 emulator @模拟器名称 -qmu -serial COM1。
2.查看串口是否被加载。
启动后使用 adb shell 命令打开命令行
cd dev 查看会发现ttyS0 ttyS1 ttyS2,其他ttyS2 就是我们加载上来的串口COM1
3.修改权限
chmod 777 ttyS2
现在我们可以开发串口程序了。
4.串口程序实例
下载libserial_port.so ,放入libs/armeabi 目录,可以自己创建此目录
libserial_port.so 下载地址:
http://code.google.com/p/android-serialport-api/
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import android.util.Log;
public class SerialPort {
private static final String TAG = "SerialPort";
private FileDescriptor mFd;
private FileInputStream mFileInputStream;
private FileOutputStream mFileOutputStream;
public SerialPort(File device, int baudrate) throws SecurityException, IOException {
if (!device.canRead() || !device.canWrite()) {
try {
Process su;
su = Runtime.getRuntime().exec("/system/bin/su");
String cmd = "chmod 666 " + device.getAbsolutePath() + "n"
+ "exitn";
su.getOutputStream().write(cmd.getBytes());
if ((su.waitFor() != 0) || !device.canRead()
|| !device.canWrite()) {
throw new SecurityException();
}
} catch (Exception e) {
e.printStackTrace();
throw new SecurityException();
}
}
mFd = open(device.getAbsolutePath(), baudrate);
if (mFd == null) {
Log.e(TAG, "native open returns null");
throw new IOException();
}
mFileInputStream = new FileInputStream(mFd);
mFileOutputStream = new FileOutputStream(mFd);
}
public InputStream getInputStream() {
return mFileInputStream;
}
public OutputStream getOutputStream() {
return mFileOutputStream;
}
//JNI
private native static FileDescriptor open(String path, int baudrate);
public native void close();
static {
System.loadLibrary("serial_port");
}
}
####################################
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
public class PrintClass {
//输入流
private static InputStream in;
//输出流
private static OutputStream out;
private static final String PORT = "/dev/ttyS2";//串口
private SerialPort serialPort;
private void Connect()
{
try {
serialPort = new SerialPort(new File(PORT), 38400);
in = serialPort.getInputStream();
out = serialPort.getOutputStream();
} catch (SecurityException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
public void CloseSerialPort()
{
try {
out.close();
in.close();
serialPort.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}