Android通过JNI操作串口
2014-07-09 10:01
295 查看
1.
本地类TtyNativeControl
package com.notioni.uart.manager;
import java.lang.ref.WeakReference;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.util.Log;
/**
*
本地方法类
*/
public
class TtyNativeControl {
private
final
static String
TAG =
"TtyNativeControl";
static{
System.loadLibrary("uart_ctl");
}
private
static
final
int
TTY_MSG_RECEIVE = 1;
private
static
final
int
TTY_CLOSE_DEVICE =
TTY_MSG_RECEIVE+1;
private
EventHandler mEventHandler;
private
ReceiveCallback mReceiveCallBack;
TtyNativeControl(){
mReceiveCallBack
= null;
Looper looper;
if((looper
= Looper.myLooper()) != null){
mEventHandler
= new EventHandler(this,
looper);
}else
if((looper = Looper.getMainLooper())
!= null){
mEventHandler
= new EventHandler(this,
looper);
}else{
mEventHandler
= null;
}
native_setup(new
WeakReference<TtyNativeControl>(this));
}
/**
*
打开驱动
*
@return
是否打开成功
*/
public
int openTty(){
return
_openTty();
}
/**
*
关闭驱动,需要一定时间,所以采用Handler机制
*/
public
int closeTty(){
// mEventHandler.obtainMessage(TTY_CLOSE_DEVICE).sendToTarget();
// return 1;
return
_closeTty();
}
/**
*
发送数据
*
@param data
*
@return
*/
public
int sendMsgToTty(byte[]
data){
return
_sendMsgToTty(data);
}
/**
*
接收数据
*
@param callback
*/
public
final
void receiveMsgFromTty(ReceiveCallback callback){
mReceiveCallBack
= callback;
_receiveMsgFromTty();
}
/**
*
设置串口数据位,校验位,速率,停止位
*
@param databits
数据位
取值
位7或8
*
@param event
校验类型
取值N ,E, O,
*
@param speed
速率
取值 2400,4800,9600,115200
*
@param stopBit
停止位
取值1
或者 2
*/
public
int configTty(int
databits,char event,int
speed,int stopBit){
return
_configTty(databits, event, speed, stopBit);
}
/**
*
@param mode
是否使用原始模式(Raw Mode)方式来通讯
取值0,1,2
说明:0=nothing,1=Raw mode,2=no raw mode
*
@param showLog
打印出串口信息Log
取值1,0
*/
public
int setMode(int
mode ,int showLog){
return
_setMode(mode, showLog);
}
/**
*
接收数据回调接口
*/
public
interface ReceiveCallback{
void
onReceiveData(byte[] data,TtyNativeControl
tty);
}
/****************************************************************
*
本地方法
*/
private
native
final
void native_setup(Object tty_this);
private
native
int _openTty();
private
native
int _closeTty();
private
native
int _sendMsgToTty(byte[]
data);
private
native
void _receiveMsgFromTty();
private
native
int _configTty(int
databits,char event,int
speed,intstopBit);
private
native
int _setMode(int
mode,int showLog);
/*
*
实现底层回调
*/
private
static
void postEventFromNative(Object tty_ref,int
what ,intarg1,int
arg2,Object obj){
Log.i(TAG,
"[postEventFromNative] what:"+what);
TtyNativeControl t = (TtyNativeControl)((WeakReference)tty_ref).get();
if(t
== null)return;
if(t.mEventHandler
!= null){
Message m = t.mEventHandler.obtainMessage(what,
arg1, arg2,obj);
t.mEventHandler.sendMessage(m);
}
}
private
class EventHandler
extends Handler{
private
TtyNativeControl mTty;
public
EventHandler(TtyNativeControl t,Looper looper){
super(looper);
mTty
= t;
}
@Override
public
void handleMessage(Message msg) {
switch(msg.what){
case
TTY_MSG_RECEIVE://底层接收数据回调上来的事件
if(mReceiveCallBack
!= null){
mReceiveCallBack.onReceiveData((byte[])msg.obj,mTty);
}
return;
case
TTY_CLOSE_DEVICE://关闭驱动
_closeTty();
break;
}
}
}
}
2.
JNI类头文件
#include
<jni.h>
#ifndef _Included_com_notioni_uart_manager_TtyNativeControl
#define _Included_com_notioni_uart_manager_TtyNativeControl
#ifdef __cplusplus
extern
"C"{
#endif
/**
* Class com_notioni_uart_TtyNativeControl
* Method
*/
JNIEXPORT
static
void
JNICALL com_notioni_uart_manager_TtyNativeControl_native_setup(JNIEnv *env,jobject clazz,jobject weak_this);
JNIEXPORT
static
int
JNICALL com_notioni_uart_manager_TtyNativeControl__openTty(JNIEnv *env,jobject clazz);
JNIEXPORT
static
int
JNICALL com_notioni_uart_manager_TtyNativeControl__closeTty(JNIEnv *env,jobject clazz);
JNIEXPORT
static
int
JNICALL com_notioni_uart_manager_TtyNativeControl__sendMsgToTty(JNIEnv *env,jobject clazz,jbyteArray data);
JNIEXPORT
static
void
JNICALL com_notioni_uart_manager_TtyNativeControl__receiveMsgFromTty(JNIEnv *env,jobject clazz);
JNIEXPORT
static
int
JNICALL com_notioni_uart_manager_TtyNativeControl__configTty(JNIEnv *env,jobject clazz,int
nBits,jchar nEvent,int
nSpeed,int
nStop);
JNIEXPORT
static
int
JNICALL com_notioni_uart_manager_TtyNativeControl__setMode(JNIEnv *env,jobject clazz,int
nMode,int
showLog);
//JNIEXPORT
int JNICALL com_notioni_uart_manager_TtyNativeControl__setSpeed(JNIEnv *env,jobjectclazz,int speed);
//JNIEXPORT
int JNICALL com_notioni_uart_manager_TtyNativeControl__setParity(JNIEnv *env,jobjectclazz,int databits,int stopbits,int parity);
#ifdef __cplusplus
}
#endif
#endif
3.
JNI实现类
#include
"JNIHelp.h"
#include
"android_runtime/AndroidRuntime.h"
#include
<utils/misc.h>
#include
<utils/Log.h>
#include
<utils/threads.h>
#include
<pthread.h>
#include
<stdio.h>
#include
<sys/types.h>
#include
<sys/stat.h>
#include
<fcntl.h>
#include
<string.h>
#include
<utils/Log.h>
#include
<sys/ioctl.h>
#include
<termios.h>
#include
"com_notioni_uart_manager_TtyNativeControl.h"
using
namespace android;
struct
fields_t{
jfieldID
tty;
jmethodID
post_event;
};
static
fields_t fields;
JavaVM* g_JavaVM;
#define TTY_DEVICE
"/dev/ttyS2"
#define LOG_TAG
"TtyNativeControl"
#define RECEIVE_DATA_INDEX
(1)
#define POST_EVENT()
static
int mTtyfd = -1;
static
int mOpen = 0;
/**
* class Listener
*/
class
JNIMyObserver{
public:
JNIMyObserver(JNIEnv* env,jobject thiz,jobject weak_thiz);
~JNIMyObserver();
void
OnEvent(const
char* buffer,int
length,int what);
private:
JNIMyObserver();
jclass
mClass;
jobject
mObject;
Mutex
mLock;
};
JNIMyObserver::JNIMyObserver(JNIEnv*
env,jobject thiz,jobject weak_thiz){
jclass clazz = env->GetObjectClass(thiz);
if(clazz
== NULL){
// jniThrowException(env,"java/lang/Exception",NULL);
LOGE("clazz is null");
return;
}
mClass
= (jclass)env->NewGlobalRef(clazz);
mObject
= env->NewGlobalRef(weak_thiz);
LOGW("mClass=%d",mClass);
LOGW("mObject=%d",mObject);
}
JNIMyObserver::~JNIMyObserver(){
JNIEnv *env = AndroidRuntime::getJNIEnv();
env->DeleteGlobalRef(mObject);
env->DeleteGlobalRef(mClass);
}
void
JNIMyObserver::OnEvent(const
char* buffer,int
length,int what){
LOGW("OnEvent");
Mutex::Autolock _l(mLock);
if(NULL
== g_JavaVM){
LOGE("JNIObserver::Event g_JavaVM is NULL");
return;
}
bool
isAttacked = false;
/*
*
创建env指针
*/
JNIEnv* env;
bool
status = (g_JavaVM->GetEnv((void**)
&env,JNI_VERSION_1_4) != JNI_OK);
if(status){
g_JavaVM->AttachCurrentThread(&env,NULL);
}
/*
*
创建JAVA byte[]数组
*/
jbyteArray obj = NULL;
if(buffer
!=NULL && buffer != 0){
const
jbyte* data = reinterpret_cast<const
jbyte*>(buffer);
obj = env->NewByteArray(length);
env->SetByteArrayRegion(obj,0,length,data);
}
env->CallStaticVoidMethod(mClass,fields.post_event,mObject,what,0,0,obj);
if(obj){
env->DeleteLocalRef(obj);
}
if(isAttacked){
g_JavaVM->DetachCurrentThread();//分离线程
}
}
/**
* class Listener end -----------------
*/
JNIMyObserver* listener;
/*
* setup
*/
static
void
JNICALL com_notioni_uart_manager_TtyNativeControl_native_setup(JNIEnv *env,jobject clazz,jobject weak_this){
LOGW("com_notioni_uart_manager_TtyNativeControl_native_setup");
env->GetJavaVM(&g_JavaVM);
if(listener
!= NULL){
delete
listener;
}
listener =
new
JNIMyObserver(env,clazz,weak_this);
}
/*
* _openTty
*/
static
int
JNICALL com_notioni_uart_manager_TtyNativeControl__openTty(JNIEnv *env,jobject clazz){
LOGW("com_notioni_uart_manager_TtyNativeControl__openTty");
mTtyfd = open(TTY_DEVICE,O_RDWR|O_NONBLOCK);//读写方式
if(mTtyfd
< 0){
LOGE("mTtyfd open failure");
return
-1;
}
if(fcntl(mTtyfd,F_SETFL,0)<0){//恢复串口为堵塞状态
LOGE("mTtyfd fcntl failure");
}
// if(isatty(STDIN_FILENO)==0){//测试是否为中断设备,非0即使终端设备
// LOGE("standard inputs is not a terminal device");
// }else{
// LOGE("isatty success");
// }
mOpen = 1;
LOGW("open device success");
return
1;
}
/*
* _closeTty
*/
static
int
JNICALL com_notioni_uart_manager_TtyNativeControl__closeTty(JNIEnv *env,jobject clazz){
LOGW("com_notioni_uart_manager_TtyNativeControl__closeTty");
if(mTtyfd
< 0){
LOGE("mTtyfd open failure ,non't close");
return
-1;
}
mOpen = 0;
sleep(2);//等待线程退出
int
c = close(mTtyfd);
if(c
< 0){
LOGE("mTtyfd close failure");
return
-1;
}
LOGW("close device success");
return
1;
}
/*
* _sendMsgToTty
*/
static
int
JNICALL com_notioni_uart_manager_TtyNativeControl__sendMsgToTty(JNIEnv *env,jobject clazz,jbyteArray data){//byte[]
LOGW("com_notioni_uart_manager_TtyNativeControl__sendMsgToTty");
//jbyte * arrayBody = env->GetByteArrayElements(data,0);
jsize theArrayLengthJ = env->GetArrayLength(data); BYTE * starter = (BYTE *)arrayBody;
if(mTtyfd
< 0){
LOGE("mTtyfd open failure ,non't write");
return
-1;
}
jbyte* arrayData = (jbyte*)env->GetByteArrayElements(data,0);
jsize arrayLength = env->GetArrayLength(data);
char*
byteData = (char*)arrayData;
int
len = (int)arrayLength;
LOGW("write data len:%d",len);
int
re = write(mTtyfd,byteData,len);
if(re
== -1){
LOGE("write device error");
}
return
re;
}
/*
*
线程Run
*/
void*
threadreadTtyData(void*
arg){
LOGW("run read data");
if(!(arg)){
return
NULL;
}
char*
buf = new
char[200];
int
result = 0,ret;
fd_set readfd;
struct
timeval timeout;
while(mOpen){
timeout.tv_sec = 2;//设定超时秒数
timeout.tv_usec = 0;//设定超时毫秒数
FD_ZERO(&readfd);//清空集合
FD_SET(mTtyfd,&readfd);///*
把要检测的句柄mTtyfd加入到集合里
*/
ret = select(mTtyfd+1,&readfd,NULL,NULL,&timeout);/*
检测我们上面设置到集合readfd里的句柄是否有可读信息
*/
switch(ret){
case
-1:/*
这说明select函数出错
*/
result = -1;
LOGE("mTtyfd read failure");
break;
case
0:/*
说明在我们设定的时间值5秒加0毫秒的时间内,mTty的状态没有发生变化
*/
break;
default:/*
说明等待时间还未到5秒加0毫秒,mTty的状态发生了变化
*/
if(FD_ISSET(mTtyfd,&readfd)){/*
先判断一下mTty这外被监视的句柄是否真的变成可读的了
*/
int
len = read(mTtyfd,buf,sizeof(buf));
/**发送数据**/
if(!(arg))break;
JNIMyObserver
*l = static_cast<JNIMyObserver
*>(arg);
l->OnEvent(buf,len,RECEIVE_DATA_INDEX);
memset(buf,0,sizeof(buf));
}
break;
}
if(result
== -1){
break;
}
}
if(buf
!= NULL){
delete
buf;
buf = NULL;
}
LOGE("stop run!");
return
NULL;
}
/*
* _receiveMsgFromTty
*/
static
void
JNICALL com_notioni_uart_manager_TtyNativeControl__receiveMsgFromTty(JNIEnv *env,jobject clazz){
LOGW("com_notioni_uart_manager_TtyNativeControl__receiveMsgFromTty");
if(mTtyfd
< 0){
LOGE("mTtyfd open failure ,non't read");
return
;
}
pthread_t id;
int
ret;
ret = pthread_create(&id,NULL,threadreadTtyData,listener);
if(ret
!= 0){
LOGE("create receiver thread failure ");
}else{
LOGW("create read data thred success");
}
}
/**
*
设置串口数据,校验位,速率,停止位
* @param nBits
类型
int数据位
取值
位7或8
* @param nEvent
类型 char
校验类型
取值N ,E, O,,S
* @param mSpeed
类型
int 速率
取值 2400,4800,9600,115200
* @param mStop
类型
int 停止位
取值1
或者 2
*/
int
set_opt(int
nBits,char nEvent,int
nSpeed,int nStop){
LOGW("set_opt:nBits=%d,nEvent=%c,nSpeed=%d,nStop=%d",nBits,nEvent,nSpeed,nStop);
struct
termios newtio,oldtio;
if(tcgetattr(mTtyfd,&oldtio)
!= 0){
LOGE("setup serial failure");
return
-1;
}
bzero(&newtio,sizeof(newtio));
//c_cflag标志可以定义CLOCAL和CREAD,这将确保该程序不被其他端口控制和信号干扰,同时串口驱动将读取进入的数据。CLOCAL和CREAD通常总是被是能的
newtio.c_cflag |=CLOCAL|CREAD;
//newtio.c_cflag &=~CSIZE;
switch(nBits){//设置数据位数
case
7:
newtio.c_cflag &=~CSIZE;
newtio.c_cflag |=CS7;
break;
case
8:
newtio.c_cflag &=~CSIZE;
newtio.c_cflag |=CS8;
break;
default:
LOGW("nBits:%d,invalid
param",nBits);
break;
}
switch(nEvent){//设置校验位
case
'O':
newtio.c_cflag |=PARENB;//enable parity checking
newtio.c_cflag |=PARODD;//奇校验位
newtio.c_iflag |=(INPCK|ISTRIP);
//options.c_iflag |= INPCK;//Disable parity
checking
break;
case
'E':
newtio.c_cflag|=PARENB;//
newtio.c_cflag&=~PARODD;//偶校验位
newtio.c_iflag|=(INPCK|ISTRIP);
//options.c_iflag |= INPCK;//Disable parity
checking
break;
case
'N':
newtio.c_cflag &=~PARENB;//清除校验位
//options.c_iflag &=~INPCK;//Enable parity
checking
break;
//case 'S':
// options.c_cflag &= ~PARENB;//清除校验位
// options.c_cflag &=~CSTOPB;
// options.c_iflag |=INPCK;//Disable parity
checking
// break;
default:
LOGW("nEvent:%c,invalid
param",nEvent);
break;
}
switch(nSpeed){//设置速率
case
2400:
LOGW("B2400:%d",B2400);
cfsetispeed(&newtio,B2400);
cfsetospeed(&newtio,B2400);
break;
case
4800:
LOGW("B4800:%d",B4800);
cfsetispeed(&newtio,B4800);
cfsetospeed(&newtio,B4800);
break;
case
9600:
LOGW("B9600:%d",B9600);
cfsetispeed(&newtio,B9600);
cfsetospeed(&newtio,B9600);
break;
case
115200:
LOGW("B115200:%d",B115200);
cfsetispeed(&newtio,B115200);
cfsetospeed(&newtio,B115200);
break;
default:
cfsetispeed(&newtio,B9600);
cfsetospeed(&newtio,B9600);
LOGW("nSpeed:%d,invalid
param",nSpeed);
break;
}
switch(nStop){//设置停止位
case
1:
newtio.c_cflag &= ~CSTOPB;
break;
case
2:
newtio.c_cflag |= CSTOPB;
break;
default:
LOGW("nStop:%d,invalid
param",nStop);
break;
}
newtio.c_cc[VTIME] = 0;//设置等待时间
newtio.c_cc[VMIN] = 0;//设置最小接收字符
tcflush(mTtyfd,TCIFLUSH);
if(tcsetattr(mTtyfd,TCSANOW,&newtio)
!= 0){
LOGE("options set error");
return
-1;
}
return
1;
}
/*
* _configTty
*/
static
int
JNICALL com_notioni_uart_manager_TtyNativeControl__configTty(JNIEnv *env,jobject clazz,int
nBits,jchar nEvent,int
nSpeed,int
nStop){
LOGW("com_notioni_uart_manager_TtyNativeControl__configTty");
return
set_opt(nBits,nEvent,nSpeed,nStop);
}
int
set_mode(int
nMode,int showLog){
LOGW("set_mode:nMode%d,nshowLog=%d",nMode,showLog);
struct
termios options;
if(tcgetattr(mTtyfd,&options)
!= 0){
LOGE("setup serial failure");
return
-1;
}
int
result = 1;
if(nMode
!= 0){
if(nMode
==1){
options.c_lflag &=~(ICANON | ECHO | ECHOE | ISIG);//input
options.c_oflag &=~OPOST;//out put
}else
if(nMode == 2){
options.c_lflag |=(ICANON | ECHO | ECHOE | ISIG);//input
options.c_oflag |=OPOST;//out put
}
if(tcsetattr(mTtyfd,TCSANOW,&options)
!= 0){
LOGE("tcsetattr device fail");
result = -1;
}
}
if(showLog
== 1){
LOGI("options c_cflag.CS7:%d,CS8:%d",options.c_cflag
& CS7,options.c_cflag & CS8);
LOGI("options c_cflag.PARENB:%d,PARODD:%d",options.c_cflag
& PARENB,options.c_cflag & PARODD);
LOGI("options c_iflag.INPCK%d,ISTRIP:%d",options.c_iflag
& INPCK,options.c_iflag & ISTRIP);
LOGI("option c_ispeed:%d,c_ospeed:%d",cfgetispeed(&options)
,cfgetospeed(&options));
LOGI("options c_cflag.CSTOPB:%d,",options.c_cflag
& CSTOPB);
LOGI("options c_cc.VTIME:%d,VMIN:%d",options.c_cc[VTIME],options.c_cc[VMIN]);
LOGI("options c_cflag.CLOCAL:%d,CREAD:%d",options.c_cflag
& CLOCAL,options.c_cflag&CREAD);
LOGI("options c_lflag.ICANON:%d,ECHO:%d,ECHOE:%d,ISIG:%d",options.c_lflag
& ICANON,options.c_lflag&ECHO,options.c_lflag&ECHOE,options.c_lflag&ISIG);
LOGI("options c_oflag.OPOST:%d,",options.c_oflag
&OPOST);
}
return
result;
}
static
int
JNICALL com_notioni_uart_manager_TtyNativeControl__setMode(JNIEnv *env,jobject clazz,int
nMode,int
showLog){
LOGW("com_notioni_uart_manager_TtyNativeControl__setMode");
return
set_mode(nMode,showLog);
}
static JNINativeMethod method_table[]
= {
{"native_setup","(Ljava/lang/Object;)V",(void*)com_notioni_uart_manager_TtyNativeControl_native_setup},
{"_openTty","()I",(void*)com_notioni_uart_manager_TtyNativeControl__openTty},
{"_closeTty","()I",(void*)com_notioni_uart_manager_TtyNativeControl__closeTty},
{"_sendMsgToTty","([B)I",(void*)com_notioni_uart_manager_TtyNativeControl__sendMsgToTty},
{"_receiveMsgFromTty","()V",(void*)com_notioni_uart_manager_TtyNativeControl__receiveMsgFromTty},
{"_configTty","(ICII)I",(void*)com_notioni_uart_manager_TtyNativeControl__configTty},
{"_setMode","(II)I",(void*)com_notioni_uart_manager_TtyNativeControl__setMode},
};
static
const
char* classPathName="com/notioni/uart/manager/TtyNativeControl";
static
int
register_com_notioni_uart_manager_TtyNativeControl(JNIEnv *env){
LOGW("register_com_notioni_uart_manager_TtyNativeControl");
jclass clazz;
clazz = env->FindClass(classPathName);
if(clazz
== NULL){
return
-1;
}
fields.post_event
= env->GetStaticMethodID(clazz,"postEventFromNative",
"(Ljava/lang/Object;IIILjava/lang/Object;)V");
if(fields.post_event
== NULL){
LOGE("Can't find
com/notioni/uart/manager.postEventFromNative");
return
-1;
}
returnAndroidRuntime::registerNativeMethods(env,classPathName,method_table,NELEM(method_table));
}
jint
JNI_OnLoad(JavaVM* vm,void*
reserved){
LOGW("JNI_OnLoad");
JNIEnv* env = NULL;
jint result = -1;
if(vm->GetEnv((void**)&env,JNI_VERSION_1_4)
!= JNI_OK){
goto
bail;
}
LOGW("register
mothod");
assert(env != NULL);
if(register_com_notioni_uart_manager_TtyNativeControl(env)
< 0){
goto
bail;
}
return
JNI_VERSION_1_4;
bail:
return
result;
}
4.
JAVA层封装本地方法
package com.notioni.uart.manager;
import com.notioni.uart.manager.TtyNativeControl.ReceiveCallback;
/*
*
单例模式
*/
public
class UARTCTLManager
{
private
TtyNativeControl mTtyControl;
private
boolean
mIsOpen =
false;
private
static UARTCTLManager
mManager;
private
UARTCTLManager(){
mTtyControl
= new TtyNativeControl();
}
public
static UARTCTLManager
getInstance(){
if(mManager
== null){
mManager
= new UARTCTLManager();
}
return
mManager;
}
/*
*
打开驱动
*/
public
int openDevice(){
int
o = mTtyControl.openTty();
o=1;
if(o
== 1){
mIsOpen
= true;
}
return
o;
}
/*
*
关闭驱动
*/
public
int closeDevice(){
int
c = mTtyControl.closeTty();
if(c
== 1){
mIsOpen
= false;
}
return
c;
}
/*
*
判断驱动是否打开
*/
public
boolean isOpenDevice(){
return
mIsOpen;
}
/*
*
发送数据
*/
public
int sendDataToDevice(byte[]
data){
return
mTtyControl.sendMsgToTty(data);
}
/*
*
注入接收数据回调方法
*/
public
void receiveDataFromDevice(ReceiveCallback
callback){
mTtyControl.receiveMsgFromTty(callback);
}
/**
*
设置串口数据位,校验位,速率,停止位
*
@param
databits 数据位
取值
位7或8
*
@param
event 校验类型
取值N ,E, O,,S
*
@param
speed 速率
取值 2400,4800,9600,115200
*
@param
stopBit 停止位
取值1
或者 2
*/
public
int configDevice(int
databits,char event,int
speed,int stopBit){
if(!mIsOpen){
return
-1;
}
int
re = mTtyControl.configTty(databits,
event, speed, stopBit);
return
re;
}
/**
*
设置串口通信模式,打印串口信息
*
@param
mode 是否使用原始模式(Raw Mode)方式来通讯
取值0,1,2
说明:0=nothing,1=Raw mode,2=no raw mode
*
@param
showLog 打印出串口信息Log
取值1,0
*
@return
*/
public
int setMode(int
mode ,int showLog){
return
mTtyControl.setMode(mode, showLog);
}
/**
*
*
接收数据回调接口,接收驱动送到的数据要实现这个回调接口
*/
public
interface ReceiveDataCallBack
extends ReceiveCallback{
}
}
5.
JAVA调用
Activity
package com.notioni.uart;
import com.notioni.uart.manager.TtyNativeControl;
import com.notioni.uart.manager.UARTCTLManager;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
public
class UARTCTLActivity
extends Activity
implements View.OnClickListener{
private
static
final String
TAG =
"UARTCTLActivity";
private
UARTCTLManager mUartctlManager;
private
Button mOpenOrCloseBtn;
private
Button mSendBtn;
private
EditText mSendText;
private
TextView mReceiveText;
private
ReceiveData mReceiveData;
/** Called when the activity is first created.
*/
@Override
public
void onCreate(Bundle
savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mUartctlManager
= UARTCTLManager.getInstance();
mReceiveData
= new ReceiveData();
mOpenOrCloseBtn
= (Button)findViewById(R.id.openOrcloseBtn);
mSendBtn
= (Button)findViewById(R.id.sendBtn);
mSendText
= (EditText)findViewById(R.id.sendMsg);
mReceiveText
= (TextView)findViewById(R.id.receiveMsg);
mOpenOrCloseBtn.setOnClickListener(this);
mSendBtn.setOnClickListener(this);
}
@Override
protected
void onResume() {
super.onResume();
}
@Override
public
void onClick(View
v) {
switch(v.getId()){
case
R.id.openOrcloseBtn://打开或关闭驱动
Log.i(TAG,
"isOpen:"+mUartctlManager.isOpenDevice());
if(mUartctlManager.isOpenDevice()){
mUartctlManager.closeDevice();
mOpenOrCloseBtn.setText(R.string.open);
}else{
int
i =mUartctlManager.openDevice();
Log.i(TAG,
"openDevice result:"+i);
mOpenOrCloseBtn.setText(R.string.close);
mUartctlManager.setMode(1,
1);//查看串口配置信息
}
break;
case
R.id.sendBtn:
openDevice();
int
re = mUartctlManager.sendDataToDevice(getSendText());
Log.i(TAG,
"send result:"+re);
break;
}
}
/*
*
打开驱动
*/
private
void openDevice(){
if(!mUartctlManager.isOpenDevice()){
mUartctlManager.openDevice();
mUartctlManager.receiveDataFromDevice(mReceiveData);
}
}
/*
*
关闭驱动
*/
public
void closeDevice(){
if(mUartctlManager.isOpenDevice()){
mUartctlManager.closeDevice();
}
}
/*
*
取出待发送的数据
*/
private
byte[] getSendText(){
String st =
mSendText.getText().toString()+"\r";
if(st
== null ||
"".equals(st)){
return
null;
}
return
st.getBytes();
}
/*
*
接收数据
*/
class
ReceiveData implements
UARTCTLManager.ReceiveDataCallBack{
@Override
public
void onReceiveData(byte[]
data, TtyNativeControl tty) {
if(mReceiveText
!= null && data !=
null){
Log.w(TAG,
"[onReceiveData] data:"+data.toString());
mReceiveText.setText(data.toString());
}
}
}
@Override
public
boolean onCreateOptionsMenu(Menu
menu) {
menu.add(1,1,0,R.string.config);
return
super.onCreateOptionsMenu(menu);
}
@Override
public
boolean onOptionsItemSelected(MenuItem
item) {
super.onOptionsItemSelected(item);
if(item.getItemId()
== 1){
Intent intent =
new Intent();
intent.setClass(this,
ConfigActivity.class);
startActivity(intent);
}
return
true;
}
@Override
protected
void onPause() {
super.onPause();
// closeDevice();
}
@Override
protected
void onDestroy() {
closeDevice();
super.onDestroy();
}
}
6.
JAVA配置串口属性
package com.notioni.uart;
import com.notioni.uart.manager.UARTCTLManager;
import android.os.Bundle;
import android.preference.ListPreference;
import android.preference.Preference;
import android.preference.PreferenceActivity;
import android.preference.PreferenceScreen;
import android.util.Log;
import android.widget.Toast;
public
class ConfigActivity
extends PreferenceActivity
implementsPreference.OnPreferenceChangeListener{
private
static
final String
TAG =
"ConfigActivity";
private
static
final String
KEY_DATABITS =
"tty_databits";
private
static
final String
KEY_EVENT =
"tty_event";
private
static
final String
KEY_SPEED =
"tty_speed";
private
static
final String
KEY_STOPBITS =
"tty_stopbits";
ListPreference
dataBitsPrefer ;
ListPreference
eventPrefer ;
ListPreference
speedPrefer ;
ListPreference
stopBitsPrefer ;
Object
dataBitsValues =
null;
Object
eventValues =
null;
Object
speedValues =
null;
Object
stopbitsValues =
null;
@Override
protected
void onCreate(Bundle
savedInstanceState) {
//
TODO Auto-generated
method stub
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.config_options);
PreferenceScreen prefSet = getPreferenceScreen();
dataBitsPrefer
= (ListPreference)prefSet.findPreference(KEY_DATABITS);
eventPrefer
= (ListPreference)prefSet.findPreference(KEY_EVENT);
speedPrefer
= (ListPreference)prefSet.findPreference(KEY_SPEED);
stopBitsPrefer
= (ListPreference)prefSet.findPreference(KEY_STOPBITS);
dataBitsPrefer.setValueIndex(0);
eventPrefer.setValueIndex(0);
speedPrefer.setValueIndex(0);
stopBitsPrefer.setValueIndex(0);
dataBitsPrefer.setOnPreferenceChangeListener(this);
eventPrefer.setOnPreferenceChangeListener(this);
speedPrefer.setOnPreferenceChangeListener(this);
stopBitsPrefer.setOnPreferenceChangeListener(this);
}
@Override
public
boolean onPreferenceChange(Preference
preference, Object newValue) {
if(preference
== dataBitsPrefer){
dataBitsValues
= newValue;
}else
if(preference ==
eventPrefer){
eventValues
= newValue;
}else
if(preference ==
speedPrefer){
speedValues
= newValue;
}else
if(preference ==
stopBitsPrefer){
stopbitsValues
= newValue;
}
Log.i(TAG,
"newValue:"+newValue);
return
false;
}
@Override
protected
void onPause() {
super.onPause();
UARTCTLManager mUartctlManager = UARTCTLManager.getInstance();
int
databits=7,speed=9600,stopbits=1;//设置默认值
char
event='N';//设置默认值
if(dataBitsValues
!= null){
databits = Integer.parseInt(dataBitsValues.toString());
}
if(eventValues
!= null){
event =
eventValues.toString().charAt(0);
}
if(speedValues
!= null){
speed = Integer.parseInt(speedValues.toString());
}
if(stopbitsValues
!= null){
stopbits = Integer.parseInt(stopbitsValues.toString());
}
if(!mUartctlManager.isOpenDevice()){
mUartctlManager.openDevice();
}
Log.e(TAG,"databit="+databits+",event="+event+",speed="+speed+",stopbits="+stopbits);
if(databits
== -1 || speed == -1 || stopbits == -1 || event=='Q'){
Toast.makeText(this,
"有参数没有设置,不去配置串口!",
Toast.LENGTH_LONG).show();
return;
}
mUartctlManager.configDevice(databits, event, speed, stopbits);
mUartctlManager.setMode(0, 1);//查看串口配置信息
// Log.e(TAG, "databit="+databits+",event="+event+",speed="+speed+",stopbits="+stopbits);
}
}
7.
config_options.xml
<?xml
version="1.0"
encoding="utf-8"?>
<PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:settings="http://schemas.android.com/apk/res/com.android.settings"
android:key="video_call_fallback_setting"
android:title="@string/tty_settings"
android:persistent="false">
<ListPreference
android:key="tty_databits"
android:title="@string/databits"
android:persistent="true"
android:entries="@array/databits_entries"
android:entryValues="@array/databits_values"
android:summary="data bits"/>
<ListPreference
android:key="tty_event"
android:title="@string/event"
android:persistent="true"
android:entries="@array/event_entries"
android:entryValues="@array/event_values"
android:summary="data bits"/>
<ListPreference
android:key="tty_speed"
android:title="@string/speed"
android:persistent="true"
android:entries="@array/speed_entries"
android:entryValues="@array/speed_values"
android:summary="data bits"/>
<ListPreference
android:key="tty_stopbits"
android:title="@string/stopbits"
android:persistent="true"
android:entries="@array/stopbits_entries"
android:entryValues="@array/stopbits_values"
android:summary="data bits"/>
</PreferenceScreen>
8.
main.xml
<?xml
version="1.0"
encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="60dip"
android:orientation="horizontal"
>
<Button
android:id="@+id/openOrcloseBtn"
android:layout_gravity="center"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/open"
/>
</LinearLayout>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="60dip"
android:orientation="horizontal"
>
<EditText
android:id="@+id/sendMsg"
android:layout_gravity="left"
android:layout_width="200dip"
android:layout_height="50dip"
/>
<Button
android:id="@+id/sendBtn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/send"
/>
</LinearLayout>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="100dip"
android:orientation="horizontal"
>
<TextView
android:id="@+id/receiveMsg"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/receiveData"
/>
</LinearLayout>
</LinearLayout>
9.
string.xml
<?xml
version="1.0"
encoding="utf-8"?>
<resources>
<string
name="hello">Hello World, UARTCTLActivity!</string>
<string
name="receiveData">Receive data show!</string>
<string
name="app_name">UARTCTL</string>
<string
name="open">Open</string>
<string
name="close">Close</string>
<string
name="send">Send</string>
<string
name="config">Config</string>
<string
name="tty_settings">Settings</string>
<string
name="databits">Data bits</string>
<string
name="event">Event</string>
<string
name="speed">Speed</string>
<string
name="stopbits">Stop bits</string>
<string-array
name="databits_entries">
<item>-1</item>
<item>7</item>
<item>8</item>
</string-array>
<string-array
name="databits_values">
<item>-1</item>
<item>7</item>
<item>8</item>
</string-array>
<string-array
name="event_entries">
<item>Settings</item>
<item>None</item>
<item>Event</item>
<item>Odd</item>
</string-array>
<string-array
name="event_values">
<item>Q</item>
<item>N</item>
<item>E</item>
<item>O</item>
</string-array>
<string-array
name="speed_entries">
<item>-1</item>
<item>B2400</item>
<item>B4800</item>
<item>B9600</item>
<item>B115200</item>
</string-array>
<string-array
name="speed_values">
<item>-1</item>
<item>2400</item>
<item>4800</item>
<item>9600</item>
<item>115200</item>
</string-array>
<string-array
name="stopbits_entries">
<item>-1</item>
<item>1</item>
<item>2</item>
</string-array>
<string-array
name="stopbits_values">
<item>-1</item>
<item>1</item>
<item>2</item>
</string-array>
</resources>
10.
Android.mk
LOCAL_PATH:=$(call
my-dir)
include
$(CLEAR_VARS)
LOCAL_MODULE_TAGS := optional
LOCAL_SRC_FILES :=
$(call all-java-files-under,src)
#LOCAL_JAVA_LIBRARIES := uart-ctl
LOCAL_JNI_SHARED_LIBRARIES := uart_ctl #so文件打包到apk中
LOCAL_PACKAGE_NAME := UARTCTL
#LOCAL_CERTIFICATE := platform
include
$(BUILD_PACKAGE)
include
$(LOCAL_PATH)/jni/Android.mk
include
$(call all-makefiles-under,$(LOCAL_PATH))
11.
jni/Android.mk
LOCAL_PATH:=$(call
my-dir)
include
$(CLEAR_VARS)
LOCAL_MODULE_TAGS := optional
LOCAL_SRC_FILES:= \
com_notioni_uart_manager_TtyNativeControl.cpp
LOCAL_C_INCLUDES := \
$(JNI_H_INCLUDE)
LOCAL_SHARED_LIBRARIES := \
libcutils \
libutils \
libui \
libandroid_runtime
LOCAL_PRELINK_MODULE := false
LOCAL_MODULE := uart_ctl
include
$(BUILD_SHARED_LIBRARY)
本地类TtyNativeControl
package com.notioni.uart.manager;
import java.lang.ref.WeakReference;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.util.Log;
/**
*
本地方法类
*/
public
class TtyNativeControl {
private
final
static String
TAG =
"TtyNativeControl";
static{
System.loadLibrary("uart_ctl");
}
private
static
final
int
TTY_MSG_RECEIVE = 1;
private
static
final
int
TTY_CLOSE_DEVICE =
TTY_MSG_RECEIVE+1;
private
EventHandler mEventHandler;
private
ReceiveCallback mReceiveCallBack;
TtyNativeControl(){
mReceiveCallBack
= null;
Looper looper;
if((looper
= Looper.myLooper()) != null){
mEventHandler
= new EventHandler(this,
looper);
}else
if((looper = Looper.getMainLooper())
!= null){
mEventHandler
= new EventHandler(this,
looper);
}else{
mEventHandler
= null;
}
native_setup(new
WeakReference<TtyNativeControl>(this));
}
/**
*
打开驱动
*
@return
是否打开成功
*/
public
int openTty(){
return
_openTty();
}
/**
*
关闭驱动,需要一定时间,所以采用Handler机制
*/
public
int closeTty(){
// mEventHandler.obtainMessage(TTY_CLOSE_DEVICE).sendToTarget();
// return 1;
return
_closeTty();
}
/**
*
发送数据
*
@param data
*
@return
*/
public
int sendMsgToTty(byte[]
data){
return
_sendMsgToTty(data);
}
/**
*
接收数据
*
@param callback
*/
public
final
void receiveMsgFromTty(ReceiveCallback callback){
mReceiveCallBack
= callback;
_receiveMsgFromTty();
}
/**
*
设置串口数据位,校验位,速率,停止位
*
@param databits
数据位
取值
位7或8
*
@param event
校验类型
取值N ,E, O,
*
@param speed
速率
取值 2400,4800,9600,115200
*
@param stopBit
停止位
取值1
或者 2
*/
public
int configTty(int
databits,char event,int
speed,int stopBit){
return
_configTty(databits, event, speed, stopBit);
}
/**
*
@param mode
是否使用原始模式(Raw Mode)方式来通讯
取值0,1,2
说明:0=nothing,1=Raw mode,2=no raw mode
*
@param showLog
打印出串口信息Log
取值1,0
*/
public
int setMode(int
mode ,int showLog){
return
_setMode(mode, showLog);
}
/**
*
接收数据回调接口
*/
public
interface ReceiveCallback{
void
onReceiveData(byte[] data,TtyNativeControl
tty);
}
/****************************************************************
*
本地方法
*/
private
native
final
void native_setup(Object tty_this);
private
native
int _openTty();
private
native
int _closeTty();
private
native
int _sendMsgToTty(byte[]
data);
private
native
void _receiveMsgFromTty();
private
native
int _configTty(int
databits,char event,int
speed,intstopBit);
private
native
int _setMode(int
mode,int showLog);
/*
*
实现底层回调
*/
private
static
void postEventFromNative(Object tty_ref,int
what ,intarg1,int
arg2,Object obj){
Log.i(TAG,
"[postEventFromNative] what:"+what);
TtyNativeControl t = (TtyNativeControl)((WeakReference)tty_ref).get();
if(t
== null)return;
if(t.mEventHandler
!= null){
Message m = t.mEventHandler.obtainMessage(what,
arg1, arg2,obj);
t.mEventHandler.sendMessage(m);
}
}
private
class EventHandler
extends Handler{
private
TtyNativeControl mTty;
public
EventHandler(TtyNativeControl t,Looper looper){
super(looper);
mTty
= t;
}
@Override
public
void handleMessage(Message msg) {
switch(msg.what){
case
TTY_MSG_RECEIVE://底层接收数据回调上来的事件
if(mReceiveCallBack
!= null){
mReceiveCallBack.onReceiveData((byte[])msg.obj,mTty);
}
return;
case
TTY_CLOSE_DEVICE://关闭驱动
_closeTty();
break;
}
}
}
}
2.
JNI类头文件
#include
<jni.h>
#ifndef _Included_com_notioni_uart_manager_TtyNativeControl
#define _Included_com_notioni_uart_manager_TtyNativeControl
#ifdef __cplusplus
extern
"C"{
#endif
/**
* Class com_notioni_uart_TtyNativeControl
* Method
*/
JNIEXPORT
static
void
JNICALL com_notioni_uart_manager_TtyNativeControl_native_setup(JNIEnv *env,jobject clazz,jobject weak_this);
JNIEXPORT
static
int
JNICALL com_notioni_uart_manager_TtyNativeControl__openTty(JNIEnv *env,jobject clazz);
JNIEXPORT
static
int
JNICALL com_notioni_uart_manager_TtyNativeControl__closeTty(JNIEnv *env,jobject clazz);
JNIEXPORT
static
int
JNICALL com_notioni_uart_manager_TtyNativeControl__sendMsgToTty(JNIEnv *env,jobject clazz,jbyteArray data);
JNIEXPORT
static
void
JNICALL com_notioni_uart_manager_TtyNativeControl__receiveMsgFromTty(JNIEnv *env,jobject clazz);
JNIEXPORT
static
int
JNICALL com_notioni_uart_manager_TtyNativeControl__configTty(JNIEnv *env,jobject clazz,int
nBits,jchar nEvent,int
nSpeed,int
nStop);
JNIEXPORT
static
int
JNICALL com_notioni_uart_manager_TtyNativeControl__setMode(JNIEnv *env,jobject clazz,int
nMode,int
showLog);
//JNIEXPORT
int JNICALL com_notioni_uart_manager_TtyNativeControl__setSpeed(JNIEnv *env,jobjectclazz,int speed);
//JNIEXPORT
int JNICALL com_notioni_uart_manager_TtyNativeControl__setParity(JNIEnv *env,jobjectclazz,int databits,int stopbits,int parity);
#ifdef __cplusplus
}
#endif
#endif
3.
JNI实现类
#include
"JNIHelp.h"
#include
"android_runtime/AndroidRuntime.h"
#include
<utils/misc.h>
#include
<utils/Log.h>
#include
<utils/threads.h>
#include
<pthread.h>
#include
<stdio.h>
#include
<sys/types.h>
#include
<sys/stat.h>
#include
<fcntl.h>
#include
<string.h>
#include
<utils/Log.h>
#include
<sys/ioctl.h>
#include
<termios.h>
#include
"com_notioni_uart_manager_TtyNativeControl.h"
using
namespace android;
struct
fields_t{
jfieldID
tty;
jmethodID
post_event;
};
static
fields_t fields;
JavaVM* g_JavaVM;
#define TTY_DEVICE
"/dev/ttyS2"
#define LOG_TAG
"TtyNativeControl"
#define RECEIVE_DATA_INDEX
(1)
#define POST_EVENT()
static
int mTtyfd = -1;
static
int mOpen = 0;
/**
* class Listener
*/
class
JNIMyObserver{
public:
JNIMyObserver(JNIEnv* env,jobject thiz,jobject weak_thiz);
~JNIMyObserver();
void
OnEvent(const
char* buffer,int
length,int what);
private:
JNIMyObserver();
jclass
mClass;
jobject
mObject;
Mutex
mLock;
};
JNIMyObserver::JNIMyObserver(JNIEnv*
env,jobject thiz,jobject weak_thiz){
jclass clazz = env->GetObjectClass(thiz);
if(clazz
== NULL){
// jniThrowException(env,"java/lang/Exception",NULL);
LOGE("clazz is null");
return;
}
mClass
= (jclass)env->NewGlobalRef(clazz);
mObject
= env->NewGlobalRef(weak_thiz);
LOGW("mClass=%d",mClass);
LOGW("mObject=%d",mObject);
}
JNIMyObserver::~JNIMyObserver(){
JNIEnv *env = AndroidRuntime::getJNIEnv();
env->DeleteGlobalRef(mObject);
env->DeleteGlobalRef(mClass);
}
void
JNIMyObserver::OnEvent(const
char* buffer,int
length,int what){
LOGW("OnEvent");
Mutex::Autolock _l(mLock);
if(NULL
== g_JavaVM){
LOGE("JNIObserver::Event g_JavaVM is NULL");
return;
}
bool
isAttacked = false;
/*
*
创建env指针
*/
JNIEnv* env;
bool
status = (g_JavaVM->GetEnv((void**)
&env,JNI_VERSION_1_4) != JNI_OK);
if(status){
g_JavaVM->AttachCurrentThread(&env,NULL);
}
/*
*
创建JAVA byte[]数组
*/
jbyteArray obj = NULL;
if(buffer
!=NULL && buffer != 0){
const
jbyte* data = reinterpret_cast<const
jbyte*>(buffer);
obj = env->NewByteArray(length);
env->SetByteArrayRegion(obj,0,length,data);
}
env->CallStaticVoidMethod(mClass,fields.post_event,mObject,what,0,0,obj);
if(obj){
env->DeleteLocalRef(obj);
}
if(isAttacked){
g_JavaVM->DetachCurrentThread();//分离线程
}
}
/**
* class Listener end -----------------
*/
JNIMyObserver* listener;
/*
* setup
*/
static
void
JNICALL com_notioni_uart_manager_TtyNativeControl_native_setup(JNIEnv *env,jobject clazz,jobject weak_this){
LOGW("com_notioni_uart_manager_TtyNativeControl_native_setup");
env->GetJavaVM(&g_JavaVM);
if(listener
!= NULL){
delete
listener;
}
listener =
new
JNIMyObserver(env,clazz,weak_this);
}
/*
* _openTty
*/
static
int
JNICALL com_notioni_uart_manager_TtyNativeControl__openTty(JNIEnv *env,jobject clazz){
LOGW("com_notioni_uart_manager_TtyNativeControl__openTty");
mTtyfd = open(TTY_DEVICE,O_RDWR|O_NONBLOCK);//读写方式
if(mTtyfd
< 0){
LOGE("mTtyfd open failure");
return
-1;
}
if(fcntl(mTtyfd,F_SETFL,0)<0){//恢复串口为堵塞状态
LOGE("mTtyfd fcntl failure");
}
// if(isatty(STDIN_FILENO)==0){//测试是否为中断设备,非0即使终端设备
// LOGE("standard inputs is not a terminal device");
// }else{
// LOGE("isatty success");
// }
mOpen = 1;
LOGW("open device success");
return
1;
}
/*
* _closeTty
*/
static
int
JNICALL com_notioni_uart_manager_TtyNativeControl__closeTty(JNIEnv *env,jobject clazz){
LOGW("com_notioni_uart_manager_TtyNativeControl__closeTty");
if(mTtyfd
< 0){
LOGE("mTtyfd open failure ,non't close");
return
-1;
}
mOpen = 0;
sleep(2);//等待线程退出
int
c = close(mTtyfd);
if(c
< 0){
LOGE("mTtyfd close failure");
return
-1;
}
LOGW("close device success");
return
1;
}
/*
* _sendMsgToTty
*/
static
int
JNICALL com_notioni_uart_manager_TtyNativeControl__sendMsgToTty(JNIEnv *env,jobject clazz,jbyteArray data){//byte[]
LOGW("com_notioni_uart_manager_TtyNativeControl__sendMsgToTty");
//jbyte * arrayBody = env->GetByteArrayElements(data,0);
jsize theArrayLengthJ = env->GetArrayLength(data); BYTE * starter = (BYTE *)arrayBody;
if(mTtyfd
< 0){
LOGE("mTtyfd open failure ,non't write");
return
-1;
}
jbyte* arrayData = (jbyte*)env->GetByteArrayElements(data,0);
jsize arrayLength = env->GetArrayLength(data);
char*
byteData = (char*)arrayData;
int
len = (int)arrayLength;
LOGW("write data len:%d",len);
int
re = write(mTtyfd,byteData,len);
if(re
== -1){
LOGE("write device error");
}
return
re;
}
/*
*
线程Run
*/
void*
threadreadTtyData(void*
arg){
LOGW("run read data");
if(!(arg)){
return
NULL;
}
char*
buf = new
char[200];
int
result = 0,ret;
fd_set readfd;
struct
timeval timeout;
while(mOpen){
timeout.tv_sec = 2;//设定超时秒数
timeout.tv_usec = 0;//设定超时毫秒数
FD_ZERO(&readfd);//清空集合
FD_SET(mTtyfd,&readfd);///*
把要检测的句柄mTtyfd加入到集合里
*/
ret = select(mTtyfd+1,&readfd,NULL,NULL,&timeout);/*
检测我们上面设置到集合readfd里的句柄是否有可读信息
*/
switch(ret){
case
-1:/*
这说明select函数出错
*/
result = -1;
LOGE("mTtyfd read failure");
break;
case
0:/*
说明在我们设定的时间值5秒加0毫秒的时间内,mTty的状态没有发生变化
*/
break;
default:/*
说明等待时间还未到5秒加0毫秒,mTty的状态发生了变化
*/
if(FD_ISSET(mTtyfd,&readfd)){/*
先判断一下mTty这外被监视的句柄是否真的变成可读的了
*/
int
len = read(mTtyfd,buf,sizeof(buf));
/**发送数据**/
if(!(arg))break;
JNIMyObserver
*l = static_cast<JNIMyObserver
*>(arg);
l->OnEvent(buf,len,RECEIVE_DATA_INDEX);
memset(buf,0,sizeof(buf));
}
break;
}
if(result
== -1){
break;
}
}
if(buf
!= NULL){
delete
buf;
buf = NULL;
}
LOGE("stop run!");
return
NULL;
}
/*
* _receiveMsgFromTty
*/
static
void
JNICALL com_notioni_uart_manager_TtyNativeControl__receiveMsgFromTty(JNIEnv *env,jobject clazz){
LOGW("com_notioni_uart_manager_TtyNativeControl__receiveMsgFromTty");
if(mTtyfd
< 0){
LOGE("mTtyfd open failure ,non't read");
return
;
}
pthread_t id;
int
ret;
ret = pthread_create(&id,NULL,threadreadTtyData,listener);
if(ret
!= 0){
LOGE("create receiver thread failure ");
}else{
LOGW("create read data thred success");
}
}
/**
*
设置串口数据,校验位,速率,停止位
* @param nBits
类型
int数据位
取值
位7或8
* @param nEvent
类型 char
校验类型
取值N ,E, O,,S
* @param mSpeed
类型
int 速率
取值 2400,4800,9600,115200
* @param mStop
类型
int 停止位
取值1
或者 2
*/
int
set_opt(int
nBits,char nEvent,int
nSpeed,int nStop){
LOGW("set_opt:nBits=%d,nEvent=%c,nSpeed=%d,nStop=%d",nBits,nEvent,nSpeed,nStop);
struct
termios newtio,oldtio;
if(tcgetattr(mTtyfd,&oldtio)
!= 0){
LOGE("setup serial failure");
return
-1;
}
bzero(&newtio,sizeof(newtio));
//c_cflag标志可以定义CLOCAL和CREAD,这将确保该程序不被其他端口控制和信号干扰,同时串口驱动将读取进入的数据。CLOCAL和CREAD通常总是被是能的
newtio.c_cflag |=CLOCAL|CREAD;
//newtio.c_cflag &=~CSIZE;
switch(nBits){//设置数据位数
case
7:
newtio.c_cflag &=~CSIZE;
newtio.c_cflag |=CS7;
break;
case
8:
newtio.c_cflag &=~CSIZE;
newtio.c_cflag |=CS8;
break;
default:
LOGW("nBits:%d,invalid
param",nBits);
break;
}
switch(nEvent){//设置校验位
case
'O':
newtio.c_cflag |=PARENB;//enable parity checking
newtio.c_cflag |=PARODD;//奇校验位
newtio.c_iflag |=(INPCK|ISTRIP);
//options.c_iflag |= INPCK;//Disable parity
checking
break;
case
'E':
newtio.c_cflag|=PARENB;//
newtio.c_cflag&=~PARODD;//偶校验位
newtio.c_iflag|=(INPCK|ISTRIP);
//options.c_iflag |= INPCK;//Disable parity
checking
break;
case
'N':
newtio.c_cflag &=~PARENB;//清除校验位
//options.c_iflag &=~INPCK;//Enable parity
checking
break;
//case 'S':
// options.c_cflag &= ~PARENB;//清除校验位
// options.c_cflag &=~CSTOPB;
// options.c_iflag |=INPCK;//Disable parity
checking
// break;
default:
LOGW("nEvent:%c,invalid
param",nEvent);
break;
}
switch(nSpeed){//设置速率
case
2400:
LOGW("B2400:%d",B2400);
cfsetispeed(&newtio,B2400);
cfsetospeed(&newtio,B2400);
break;
case
4800:
LOGW("B4800:%d",B4800);
cfsetispeed(&newtio,B4800);
cfsetospeed(&newtio,B4800);
break;
case
9600:
LOGW("B9600:%d",B9600);
cfsetispeed(&newtio,B9600);
cfsetospeed(&newtio,B9600);
break;
case
115200:
LOGW("B115200:%d",B115200);
cfsetispeed(&newtio,B115200);
cfsetospeed(&newtio,B115200);
break;
default:
cfsetispeed(&newtio,B9600);
cfsetospeed(&newtio,B9600);
LOGW("nSpeed:%d,invalid
param",nSpeed);
break;
}
switch(nStop){//设置停止位
case
1:
newtio.c_cflag &= ~CSTOPB;
break;
case
2:
newtio.c_cflag |= CSTOPB;
break;
default:
LOGW("nStop:%d,invalid
param",nStop);
break;
}
newtio.c_cc[VTIME] = 0;//设置等待时间
newtio.c_cc[VMIN] = 0;//设置最小接收字符
tcflush(mTtyfd,TCIFLUSH);
if(tcsetattr(mTtyfd,TCSANOW,&newtio)
!= 0){
LOGE("options set error");
return
-1;
}
return
1;
}
/*
* _configTty
*/
static
int
JNICALL com_notioni_uart_manager_TtyNativeControl__configTty(JNIEnv *env,jobject clazz,int
nBits,jchar nEvent,int
nSpeed,int
nStop){
LOGW("com_notioni_uart_manager_TtyNativeControl__configTty");
return
set_opt(nBits,nEvent,nSpeed,nStop);
}
int
set_mode(int
nMode,int showLog){
LOGW("set_mode:nMode%d,nshowLog=%d",nMode,showLog);
struct
termios options;
if(tcgetattr(mTtyfd,&options)
!= 0){
LOGE("setup serial failure");
return
-1;
}
int
result = 1;
if(nMode
!= 0){
if(nMode
==1){
options.c_lflag &=~(ICANON | ECHO | ECHOE | ISIG);//input
options.c_oflag &=~OPOST;//out put
}else
if(nMode == 2){
options.c_lflag |=(ICANON | ECHO | ECHOE | ISIG);//input
options.c_oflag |=OPOST;//out put
}
if(tcsetattr(mTtyfd,TCSANOW,&options)
!= 0){
LOGE("tcsetattr device fail");
result = -1;
}
}
if(showLog
== 1){
LOGI("options c_cflag.CS7:%d,CS8:%d",options.c_cflag
& CS7,options.c_cflag & CS8);
LOGI("options c_cflag.PARENB:%d,PARODD:%d",options.c_cflag
& PARENB,options.c_cflag & PARODD);
LOGI("options c_iflag.INPCK%d,ISTRIP:%d",options.c_iflag
& INPCK,options.c_iflag & ISTRIP);
LOGI("option c_ispeed:%d,c_ospeed:%d",cfgetispeed(&options)
,cfgetospeed(&options));
LOGI("options c_cflag.CSTOPB:%d,",options.c_cflag
& CSTOPB);
LOGI("options c_cc.VTIME:%d,VMIN:%d",options.c_cc[VTIME],options.c_cc[VMIN]);
LOGI("options c_cflag.CLOCAL:%d,CREAD:%d",options.c_cflag
& CLOCAL,options.c_cflag&CREAD);
LOGI("options c_lflag.ICANON:%d,ECHO:%d,ECHOE:%d,ISIG:%d",options.c_lflag
& ICANON,options.c_lflag&ECHO,options.c_lflag&ECHOE,options.c_lflag&ISIG);
LOGI("options c_oflag.OPOST:%d,",options.c_oflag
&OPOST);
}
return
result;
}
static
int
JNICALL com_notioni_uart_manager_TtyNativeControl__setMode(JNIEnv *env,jobject clazz,int
nMode,int
showLog){
LOGW("com_notioni_uart_manager_TtyNativeControl__setMode");
return
set_mode(nMode,showLog);
}
static JNINativeMethod method_table[]
= {
{"native_setup","(Ljava/lang/Object;)V",(void*)com_notioni_uart_manager_TtyNativeControl_native_setup},
{"_openTty","()I",(void*)com_notioni_uart_manager_TtyNativeControl__openTty},
{"_closeTty","()I",(void*)com_notioni_uart_manager_TtyNativeControl__closeTty},
{"_sendMsgToTty","([B)I",(void*)com_notioni_uart_manager_TtyNativeControl__sendMsgToTty},
{"_receiveMsgFromTty","()V",(void*)com_notioni_uart_manager_TtyNativeControl__receiveMsgFromTty},
{"_configTty","(ICII)I",(void*)com_notioni_uart_manager_TtyNativeControl__configTty},
{"_setMode","(II)I",(void*)com_notioni_uart_manager_TtyNativeControl__setMode},
};
static
const
char* classPathName="com/notioni/uart/manager/TtyNativeControl";
static
int
register_com_notioni_uart_manager_TtyNativeControl(JNIEnv *env){
LOGW("register_com_notioni_uart_manager_TtyNativeControl");
jclass clazz;
clazz = env->FindClass(classPathName);
if(clazz
== NULL){
return
-1;
}
fields.post_event
= env->GetStaticMethodID(clazz,"postEventFromNative",
"(Ljava/lang/Object;IIILjava/lang/Object;)V");
if(fields.post_event
== NULL){
LOGE("Can't find
com/notioni/uart/manager.postEventFromNative");
return
-1;
}
returnAndroidRuntime::registerNativeMethods(env,classPathName,method_table,NELEM(method_table));
}
jint
JNI_OnLoad(JavaVM* vm,void*
reserved){
LOGW("JNI_OnLoad");
JNIEnv* env = NULL;
jint result = -1;
if(vm->GetEnv((void**)&env,JNI_VERSION_1_4)
!= JNI_OK){
goto
bail;
}
LOGW("register
mothod");
assert(env != NULL);
if(register_com_notioni_uart_manager_TtyNativeControl(env)
< 0){
goto
bail;
}
return
JNI_VERSION_1_4;
bail:
return
result;
}
4.
JAVA层封装本地方法
package com.notioni.uart.manager;
import com.notioni.uart.manager.TtyNativeControl.ReceiveCallback;
/*
*
单例模式
*/
public
class UARTCTLManager
{
private
TtyNativeControl mTtyControl;
private
boolean
mIsOpen =
false;
private
static UARTCTLManager
mManager;
private
UARTCTLManager(){
mTtyControl
= new TtyNativeControl();
}
public
static UARTCTLManager
getInstance(){
if(mManager
== null){
mManager
= new UARTCTLManager();
}
return
mManager;
}
/*
*
打开驱动
*/
public
int openDevice(){
int
o = mTtyControl.openTty();
o=1;
if(o
== 1){
mIsOpen
= true;
}
return
o;
}
/*
*
关闭驱动
*/
public
int closeDevice(){
int
c = mTtyControl.closeTty();
if(c
== 1){
mIsOpen
= false;
}
return
c;
}
/*
*
判断驱动是否打开
*/
public
boolean isOpenDevice(){
return
mIsOpen;
}
/*
*
发送数据
*/
public
int sendDataToDevice(byte[]
data){
return
mTtyControl.sendMsgToTty(data);
}
/*
*
注入接收数据回调方法
*/
public
void receiveDataFromDevice(ReceiveCallback
callback){
mTtyControl.receiveMsgFromTty(callback);
}
/**
*
设置串口数据位,校验位,速率,停止位
*
@param
databits 数据位
取值
位7或8
*
@param
event 校验类型
取值N ,E, O,,S
*
@param
speed 速率
取值 2400,4800,9600,115200
*
@param
stopBit 停止位
取值1
或者 2
*/
public
int configDevice(int
databits,char event,int
speed,int stopBit){
if(!mIsOpen){
return
-1;
}
int
re = mTtyControl.configTty(databits,
event, speed, stopBit);
return
re;
}
/**
*
设置串口通信模式,打印串口信息
*
@param
mode 是否使用原始模式(Raw Mode)方式来通讯
取值0,1,2
说明:0=nothing,1=Raw mode,2=no raw mode
*
@param
showLog 打印出串口信息Log
取值1,0
*
@return
*/
public
int setMode(int
mode ,int showLog){
return
mTtyControl.setMode(mode, showLog);
}
/**
*
*
接收数据回调接口,接收驱动送到的数据要实现这个回调接口
*/
public
interface ReceiveDataCallBack
extends ReceiveCallback{
}
}
5.
JAVA调用
Activity
package com.notioni.uart;
import com.notioni.uart.manager.TtyNativeControl;
import com.notioni.uart.manager.UARTCTLManager;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
public
class UARTCTLActivity
extends Activity
implements View.OnClickListener{
private
static
final String
TAG =
"UARTCTLActivity";
private
UARTCTLManager mUartctlManager;
private
Button mOpenOrCloseBtn;
private
Button mSendBtn;
private
EditText mSendText;
private
TextView mReceiveText;
private
ReceiveData mReceiveData;
/** Called when the activity is first created.
*/
@Override
public
void onCreate(Bundle
savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mUartctlManager
= UARTCTLManager.getInstance();
mReceiveData
= new ReceiveData();
mOpenOrCloseBtn
= (Button)findViewById(R.id.openOrcloseBtn);
mSendBtn
= (Button)findViewById(R.id.sendBtn);
mSendText
= (EditText)findViewById(R.id.sendMsg);
mReceiveText
= (TextView)findViewById(R.id.receiveMsg);
mOpenOrCloseBtn.setOnClickListener(this);
mSendBtn.setOnClickListener(this);
}
@Override
protected
void onResume() {
super.onResume();
}
@Override
public
void onClick(View
v) {
switch(v.getId()){
case
R.id.openOrcloseBtn://打开或关闭驱动
Log.i(TAG,
"isOpen:"+mUartctlManager.isOpenDevice());
if(mUartctlManager.isOpenDevice()){
mUartctlManager.closeDevice();
mOpenOrCloseBtn.setText(R.string.open);
}else{
int
i =mUartctlManager.openDevice();
Log.i(TAG,
"openDevice result:"+i);
mOpenOrCloseBtn.setText(R.string.close);
mUartctlManager.setMode(1,
1);//查看串口配置信息
}
break;
case
R.id.sendBtn:
openDevice();
int
re = mUartctlManager.sendDataToDevice(getSendText());
Log.i(TAG,
"send result:"+re);
break;
}
}
/*
*
打开驱动
*/
private
void openDevice(){
if(!mUartctlManager.isOpenDevice()){
mUartctlManager.openDevice();
mUartctlManager.receiveDataFromDevice(mReceiveData);
}
}
/*
*
关闭驱动
*/
public
void closeDevice(){
if(mUartctlManager.isOpenDevice()){
mUartctlManager.closeDevice();
}
}
/*
*
取出待发送的数据
*/
private
byte[] getSendText(){
String st =
mSendText.getText().toString()+"\r";
if(st
== null ||
"".equals(st)){
return
null;
}
return
st.getBytes();
}
/*
*
接收数据
*/
class
ReceiveData implements
UARTCTLManager.ReceiveDataCallBack{
@Override
public
void onReceiveData(byte[]
data, TtyNativeControl tty) {
if(mReceiveText
!= null && data !=
null){
Log.w(TAG,
"[onReceiveData] data:"+data.toString());
mReceiveText.setText(data.toString());
}
}
}
@Override
public
boolean onCreateOptionsMenu(Menu
menu) {
menu.add(1,1,0,R.string.config);
return
super.onCreateOptionsMenu(menu);
}
@Override
public
boolean onOptionsItemSelected(MenuItem
item) {
super.onOptionsItemSelected(item);
if(item.getItemId()
== 1){
Intent intent =
new Intent();
intent.setClass(this,
ConfigActivity.class);
startActivity(intent);
}
return
true;
}
@Override
protected
void onPause() {
super.onPause();
// closeDevice();
}
@Override
protected
void onDestroy() {
closeDevice();
super.onDestroy();
}
}
6.
JAVA配置串口属性
package com.notioni.uart;
import com.notioni.uart.manager.UARTCTLManager;
import android.os.Bundle;
import android.preference.ListPreference;
import android.preference.Preference;
import android.preference.PreferenceActivity;
import android.preference.PreferenceScreen;
import android.util.Log;
import android.widget.Toast;
public
class ConfigActivity
extends PreferenceActivity
implementsPreference.OnPreferenceChangeListener{
private
static
final String
TAG =
"ConfigActivity";
private
static
final String
KEY_DATABITS =
"tty_databits";
private
static
final String
KEY_EVENT =
"tty_event";
private
static
final String
KEY_SPEED =
"tty_speed";
private
static
final String
KEY_STOPBITS =
"tty_stopbits";
ListPreference
dataBitsPrefer ;
ListPreference
eventPrefer ;
ListPreference
speedPrefer ;
ListPreference
stopBitsPrefer ;
Object
dataBitsValues =
null;
Object
eventValues =
null;
Object
speedValues =
null;
Object
stopbitsValues =
null;
@Override
protected
void onCreate(Bundle
savedInstanceState) {
//
TODO Auto-generated
method stub
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.config_options);
PreferenceScreen prefSet = getPreferenceScreen();
dataBitsPrefer
= (ListPreference)prefSet.findPreference(KEY_DATABITS);
eventPrefer
= (ListPreference)prefSet.findPreference(KEY_EVENT);
speedPrefer
= (ListPreference)prefSet.findPreference(KEY_SPEED);
stopBitsPrefer
= (ListPreference)prefSet.findPreference(KEY_STOPBITS);
dataBitsPrefer.setValueIndex(0);
eventPrefer.setValueIndex(0);
speedPrefer.setValueIndex(0);
stopBitsPrefer.setValueIndex(0);
dataBitsPrefer.setOnPreferenceChangeListener(this);
eventPrefer.setOnPreferenceChangeListener(this);
speedPrefer.setOnPreferenceChangeListener(this);
stopBitsPrefer.setOnPreferenceChangeListener(this);
}
@Override
public
boolean onPreferenceChange(Preference
preference, Object newValue) {
if(preference
== dataBitsPrefer){
dataBitsValues
= newValue;
}else
if(preference ==
eventPrefer){
eventValues
= newValue;
}else
if(preference ==
speedPrefer){
speedValues
= newValue;
}else
if(preference ==
stopBitsPrefer){
stopbitsValues
= newValue;
}
Log.i(TAG,
"newValue:"+newValue);
return
false;
}
@Override
protected
void onPause() {
super.onPause();
UARTCTLManager mUartctlManager = UARTCTLManager.getInstance();
int
databits=7,speed=9600,stopbits=1;//设置默认值
char
event='N';//设置默认值
if(dataBitsValues
!= null){
databits = Integer.parseInt(dataBitsValues.toString());
}
if(eventValues
!= null){
event =
eventValues.toString().charAt(0);
}
if(speedValues
!= null){
speed = Integer.parseInt(speedValues.toString());
}
if(stopbitsValues
!= null){
stopbits = Integer.parseInt(stopbitsValues.toString());
}
if(!mUartctlManager.isOpenDevice()){
mUartctlManager.openDevice();
}
Log.e(TAG,"databit="+databits+",event="+event+",speed="+speed+",stopbits="+stopbits);
if(databits
== -1 || speed == -1 || stopbits == -1 || event=='Q'){
Toast.makeText(this,
"有参数没有设置,不去配置串口!",
Toast.LENGTH_LONG).show();
return;
}
mUartctlManager.configDevice(databits, event, speed, stopbits);
mUartctlManager.setMode(0, 1);//查看串口配置信息
// Log.e(TAG, "databit="+databits+",event="+event+",speed="+speed+",stopbits="+stopbits);
}
}
7.
config_options.xml
<?xml
version="1.0"
encoding="utf-8"?>
<PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:settings="http://schemas.android.com/apk/res/com.android.settings"
android:key="video_call_fallback_setting"
android:title="@string/tty_settings"
android:persistent="false">
<ListPreference
android:key="tty_databits"
android:title="@string/databits"
android:persistent="true"
android:entries="@array/databits_entries"
android:entryValues="@array/databits_values"
android:summary="data bits"/>
<ListPreference
android:key="tty_event"
android:title="@string/event"
android:persistent="true"
android:entries="@array/event_entries"
android:entryValues="@array/event_values"
android:summary="data bits"/>
<ListPreference
android:key="tty_speed"
android:title="@string/speed"
android:persistent="true"
android:entries="@array/speed_entries"
android:entryValues="@array/speed_values"
android:summary="data bits"/>
<ListPreference
android:key="tty_stopbits"
android:title="@string/stopbits"
android:persistent="true"
android:entries="@array/stopbits_entries"
android:entryValues="@array/stopbits_values"
android:summary="data bits"/>
</PreferenceScreen>
8.
main.xml
<?xml
version="1.0"
encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="60dip"
android:orientation="horizontal"
>
<Button
android:id="@+id/openOrcloseBtn"
android:layout_gravity="center"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/open"
/>
</LinearLayout>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="60dip"
android:orientation="horizontal"
>
<EditText
android:id="@+id/sendMsg"
android:layout_gravity="left"
android:layout_width="200dip"
android:layout_height="50dip"
/>
<Button
android:id="@+id/sendBtn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/send"
/>
</LinearLayout>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="100dip"
android:orientation="horizontal"
>
<TextView
android:id="@+id/receiveMsg"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/receiveData"
/>
</LinearLayout>
</LinearLayout>
9.
string.xml
<?xml
version="1.0"
encoding="utf-8"?>
<resources>
<string
name="hello">Hello World, UARTCTLActivity!</string>
<string
name="receiveData">Receive data show!</string>
<string
name="app_name">UARTCTL</string>
<string
name="open">Open</string>
<string
name="close">Close</string>
<string
name="send">Send</string>
<string
name="config">Config</string>
<string
name="tty_settings">Settings</string>
<string
name="databits">Data bits</string>
<string
name="event">Event</string>
<string
name="speed">Speed</string>
<string
name="stopbits">Stop bits</string>
<string-array
name="databits_entries">
<item>-1</item>
<item>7</item>
<item>8</item>
</string-array>
<string-array
name="databits_values">
<item>-1</item>
<item>7</item>
<item>8</item>
</string-array>
<string-array
name="event_entries">
<item>Settings</item>
<item>None</item>
<item>Event</item>
<item>Odd</item>
</string-array>
<string-array
name="event_values">
<item>Q</item>
<item>N</item>
<item>E</item>
<item>O</item>
</string-array>
<string-array
name="speed_entries">
<item>-1</item>
<item>B2400</item>
<item>B4800</item>
<item>B9600</item>
<item>B115200</item>
</string-array>
<string-array
name="speed_values">
<item>-1</item>
<item>2400</item>
<item>4800</item>
<item>9600</item>
<item>115200</item>
</string-array>
<string-array
name="stopbits_entries">
<item>-1</item>
<item>1</item>
<item>2</item>
</string-array>
<string-array
name="stopbits_values">
<item>-1</item>
<item>1</item>
<item>2</item>
</string-array>
</resources>
10.
Android.mk
LOCAL_PATH:=$(call
my-dir)
include
$(CLEAR_VARS)
LOCAL_MODULE_TAGS := optional
LOCAL_SRC_FILES :=
$(call all-java-files-under,src)
#LOCAL_JAVA_LIBRARIES := uart-ctl
LOCAL_JNI_SHARED_LIBRARIES := uart_ctl #so文件打包到apk中
LOCAL_PACKAGE_NAME := UARTCTL
#LOCAL_CERTIFICATE := platform
include
$(BUILD_PACKAGE)
include
$(LOCAL_PATH)/jni/Android.mk
include
$(call all-makefiles-under,$(LOCAL_PATH))
11.
jni/Android.mk
LOCAL_PATH:=$(call
my-dir)
include
$(CLEAR_VARS)
LOCAL_MODULE_TAGS := optional
LOCAL_SRC_FILES:= \
com_notioni_uart_manager_TtyNativeControl.cpp
LOCAL_C_INCLUDES := \
$(JNI_H_INCLUDE)
LOCAL_SHARED_LIBRARIES := \
libcutils \
libutils \
libui \
libandroid_runtime
LOCAL_PRELINK_MODULE := false
LOCAL_MODULE := uart_ctl
include
$(BUILD_SHARED_LIBRARY)
相关文章推荐
- Android通过JNI操作串口《二》
- Android通过JNI操作串口
- Android通过JNI操作串口《四》
- Android通过JNI操作串口《一》
- Android通过JNI操作串口《三》
- Android通过JNI实现与C语言的串口通讯操作蓝牙硬件模块
- [Android]通过JNI访问并操作Bitmap的元素,支持RGB565和ARGB8888
- [Android]通过JNI访问并操作Bitmap的元素,支持RGB565和ARGB8888
- android下如何通过jni监控wifi网络连接、dhcpcd执行和power电源控制
- 浅析android下如何通过jni监控wifi网络连接、dhcpcd执行和power电源控制
- 使用jni接口完成android本地程序的运行--具体的操作
- Android调用jni全过程,方便以后操作。
- Android通过JNI调用驱动程序(完全解析实例)
- 通过Android平台移植魂斗罗游戏来阐述下jni的用法(把魂斗罗游戏嵌入到FC游戏模拟器里,省去了SD卡加载ROM)
- 在Android中通过jni方式使用编译好的FFmpeg库-Android中使用FFmpeg媒体库
- Android JNI调用 – 文件操作
- 在Android中通过jni方式使用编译好的FFmpeg库-Android中使用FFmpeg媒体库(二)
- Android调用jni全过程,方便以后操作。
- 在android中通过JNI调用本地方法
- Android通过onDraw实现在View中绘图操作