代码已经验证过,没问题 !
代码层次结构:
|-----serial_communication_class---
| |-------src---------
| |------com------
| |----object-----
| |------nvs------
| |-----client------
| |---MainActivity.java
| |----SerialJNI.java
| |--------jni-----------------------------------------------------
| |------- Android.mk
| |--------object_nvs_client_SerialJNI.c
| |--------Android.mk
| |---------AndroidManifest.xml
现在贴代码:
-------------------------------------------SerialJNI.java---------------------------------------------------
package object.nvs.client;
public class SerialJNI{
public native int OpenDev(String Dev);
public native void set_speed(int fd, int speed);
public native int set_Parity(int fd, int databits, int stopbits, int parity);
public native int send_command(int fd, char[] sb, int len);
public native void receive_data(int fd, int len);
public native int close_dev(int fd);
static{
System.loadLibrary("serialjni");//与jni中的Android.mk中的jni模块名LOCAL_MODULE:= libserialjni相比少了lib
}
private byte[] bytes = new byte[12]; //Accessing Fields,用于装载JNI中的返回数据
private void callback() {//方法回调,JNI中一有数据此方法就被回调一次,所以对数据的所有操作建议都放于此
int i;
for(i=0;i<12;i++){
System.out.println(bytes[i]&0xff);
}
}
private int fd;
public SerialJNI(String Dev, int speed, int databits, int stopbits, int parity)
{
fd = OpenDev(Dev);
set_speed(fd, speed);
if(set_Parity(fd, 8, 1, ‘N‘) == -1)
{
System.out.println("Set Parity Error");
return;
}
}
public int getSerialPort()
{
return fd;
}
}
---------------------------------------------------end--------------------------------------------------
应用层调用:
---------------------------------------------MainActivity.java-------------------------------------------
package object.nvs.client;
import java.io.BufferedWriter;
import java.io.File;
import android.os.Bundle;
import android.app.Activity;
public class MainActivity extends Activity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
char stop[]={0xFF,0x0B,0x01,0x40,0x25,0x07,0x00,0x01,0x0b,0x00,0x84};
SerialJNI serialPort = new SerialJNI("/dev/ttyS7", 9600, 8, 1, ‘N‘);
int fd = serialPort.getSerialPort();
for(int i=0; i<10; i++){
int ret = serialPort.send_command(fd, stop, 11);//只做演示,并未实际意义
if(ret < 0)
System.out.println("send command error!\n");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// serialPort.callback();
// serialPort.receive_data(fd, 11);
serialPort.close_dev(fd);
}
}
--------------------------------------------end--------------------------------------------------------
jni部分:
----------------------------------object_nvs_client_SerialJNI.c------------------------------
/*
* Copyright (C) 2009 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//#include "object_nvs_client_SerialJNI.h"
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
#include <errno.h>
#include <string.h>
#include <jni.h>
#include <android/log.h>
#include <sys/file.h>
#define LOG "serial-jni"
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,LOG,__VA_ARGS__)
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG,__VA_ARGS__)
#define LOGW(...) __android_log_print(ANDROID_LOG_WARN,LOG,__VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG,__VA_ARGS__)
#define LOGF(...) __android_log_print(ANDROID_LOG_FATAL,LOG,__VA_ARGS__)
#define TRUE 1
#define FALSE -1
#define BUFSIZE 11
static int speed_arr[] = {B115200,B38400,B19200,B9600,B4800,B2400,B1200,B300,
B38400,B19200,B9600,B4800,B2400,B1200,B300};
static int name_arr[] = {115200,38400,19200,9600,4800,2400,1200,300,
38400,19200,9600,4800,2400,1200,300};
char resend[]={0xFF,0x0B,0x02,0x01,0x0,0x0,0x0,0x0,0x0,0x0,0x0E};
char stop[]={0xFF,0x0B,0x02,0x02,0x0,0x0,0x0,0x0,0x0,0x0,0x0F};
/*
* Class: com_test_serial_MainActivity
* Method: open_dev
* Signature: (Ljava/lang/String;)I
*/
JNIEXPORT jint JNICALL Java_object_nvs_client_SerialJNI_OpenDev
(JNIEnv *env, jobject obj, jstring dev){
const char *Dev_utf = (*env)->GetStringUTFChars(env, dev, JNI_FALSE);
int fd = open(Dev_utf, O_RDWR|O_NOCTTY);
(*env)->ReleaseStringUTFChars(env, dev, Dev_utf);
if (-1 == fd)
{ /*设置数据位数*/
LOGE("Can‘t Open Serial Port\n");
return -1;
}
LOGD("Open Serial Port:%s\n",(char *)Dev_utf);
return fd;
}
/*
* Class: com_test_serial_MainActivity
* Method: close_dev
* Signature: (I)I
*/
JNIEXPORT jint JNICALL Java_object_nvs_client_SerialJNI_close_1dev
(JNIEnv *env, jobject obj, jint fd){
if(close(fd))
{
LOGE("close failed!\n");
return (FALSE);
}
else
{
LOGD("close success!\n");
return TRUE;
}
}
/*
* Class: com_test_serial_SerialJNI
* Method: set_speed
* Signature: (II)V
*/
JNIEXPORT void JNICALL Java_object_nvs_client_SerialJNI_set_1speed
(JNIEnv *env, jobject obj, jint fd, jint speed)
{
int i;
int status;
struct termios Opt;
for(i=0; i<sizeof(speed_arr)/sizeof(int); i++)
{
if(speed == name_arr[i])
{
tcflush(fd, TCIOFLUSH);
cfsetispeed(&Opt, speed_arr[i]);
cfsetospeed(&Opt, speed_arr[i]);
status = tcsetattr(fd, TCSANOW, &Opt);
if(status != 0)
perror("tcsetattr fd1\n");
return ;
}
tcflush(fd, TCIOFLUSH);
}
}
/*
* Class: com_test_serial_MainActivity
* Method: set_Parity
* Signature: (IIIC)I
*/
JNIEXPORT jint JNICALL Java_object_nvs_client_SerialJNI_set_1Parity
(JNIEnv *env, jobject obj, jint fd, jint databits, jint stopbits, jint parity)
{
struct termios opt;
if(tcgetattr(fd, &opt) != 0)
{
LOGE("SetupSerial 1\n");
return -1;
}
opt.c_cflag &= ~CSIZE;
opt.c_lflag &= ~(ICANON|ECHO|ECHOE|ISIG);
opt.c_oflag &= ~OPOST;
switch(databits)
{
case 7: opt.c_cflag |= CS7; break;
case 8: opt.c_cflag |= CS8; break;
default: LOGE("Unsupported data size\n");
return -1;
}
switch(parity)
{
case ‘n‘:
case ‘N‘: opt.c_cflag &= ~PARENB;
//opt.c_iflag &= ~INPCK;
break;
case ‘o‘:
case ‘O‘: opt.c_cflag |= (PARODD|PARENB);
opt.c_iflag |= INPCK;
break;
case ‘e‘:
case ‘E‘: opt.c_cflag |= PARENB;
opt.c_cflag &= ~PARODD;
opt.c_iflag |= INPCK;
break;
case ‘s‘:
case ‘S‘: opt.c_cflag &= ~PARENB;
opt.c_cflag &= ~CSTOPB;
break;
default: LOGE("Unsupported parity\n");
return -1;
}
switch(stopbits)
{
case 1: opt.c_cflag &= ~CSTOPB;
break;
case 2: opt.c_cflag |= CSTOPB;
break;
default: LOGE("Unsupported stop bits\n");
return -1;
}
// if (parity != ‘n‘) opt.c_iflag |= INPCK;
tcflush(fd,TCIFLUSH);
opt.c_cc[VTIME] = 150; /* 设置超时 15 seconds*/
opt.c_cc[VMIN] = 0;
tcflush(fd, TCIFLUSH);
if (tcsetattr(fd,TCSANOW,&opt) != 0)
{
LOGE("SetupSerial 3\n");
return -1;
}
return 0;
}
/*
* Class: com_test_serial_MainActivity
* Method: send_command
* Signature: (ILjava/lang/String;)Ljava/lang/String;
*/
JNIEXPORT jint JNICALL Java_object_nvs_client_SerialJNI_send_1command
(JNIEnv *env, jobject obj, jint fd, jcharArray buff, jint len){
int i;
char command[BUFSIZE+1] = {0};
jchar *jc = (*env)->GetCharArrayElements(env, buff, NULL);
for(i=0;i<BUFSIZE;i++){
command[i] = (char)jc[i]&0xff;//java中char[]数组元素是char类型占2个字节和jni中的jchar相同,要转换成一个字节的char类型所以要去掉一个字节,方法就是将每个元素&oxff
}
if(flock(fd,LOCK_EX)==0){//读写文件锁保护,后面还有很多地方用到
LOGD(" write lock!");
}else LOGD(" write lock fail!");
if(write(fd, command, len)>0)
{
LOGD("write success!\n");
}
else
{
LOGE("write failed!\n");
}
if(flock(fd,LOCK_UN)==0){//读写文件解锁
LOGD(" write unlock!");
}else LOGD("write unlock fail!");
(*env)->ReleaseCharArrayElements(env, buff, jc, 0);
return 0;
}
/*
* Class: com_test_serial_MainActivity
* Method: receive_data
* Signature: (II)Ljava/lang/String;
*/
JNIEXPORT void JNICALL Java_object_nvs_client_SerialJNI_receive_1data
(JNIEnv *env, jobject obj, jint fd, jint len){
jstring jstr;
jfieldID fid;
jbyteArray bytearray;
const char *str;
int i,sum=0;
int nread,nwrite;
fd_set rfds;
struct timeval tv;
char buff[BUFSIZE+1];
char buff1[BUFSIZE+1];
char buff2[BUFSIZE+1];
bzero(buff, BUFSIZE+1);
bzero(buff1, BUFSIZE+1);
bzero(buff2, BUFSIZE+1);
/*
struct termios oldtio, newtio;
tcgetattr(fd, &oldtio);
setTermios(&newtio, B38400);
tcsetattr(fd, TCSANOW, &newtio);
if (serial_set_parity(fd,8,1,‘N‘) == FALSE)
{
LOGE("Set Parity Error\n");
serial_close(fd);
return;
}
*/
tcflush(fd, TCIFLUSH);
tv.tv_sec=30;
tv.tv_usec=0;
bytearray = (*env)->NewByteArray(env,BUFSIZE+1);
jclass cls1 = (*env)->GetObjectClass(env, obj);
jclass cls2 = (*env)->GetObjectClass(env, obj);
fid = (*env)->GetFieldID(env, cls1, "bytes", "[B");
if (fid == NULL)
{
LOGE("failed to find the field!");
close(fd);
return; /* failed to find the field */
}
jmethodID mid = (*env)->GetMethodID(env, cls2, "callback", "()V");
if (mid == NULL)
{
LOGE("method not found!");
close(fd);
return; /* method not found */
}
while(TRUE)
{
sum = 0;
usleep(1000);
LOGD("wait wait...");
FD_ZERO(&rfds);
FD_SET(fd, &rfds);
if(select(1+fd, &rfds, &rfds, NULL, &tv)>0)
{
if(FD_ISSET(fd, &rfds))
{
if(flock(fd,LOCK_EX)==0){
LOGD("read lock!");
}else LOGD("read lock fail!");
nread=read(fd, buff, BUFSIZE);
if(flock(fd,LOCK_UN)==0){
LOGD(" read unlock!");
}else LOGD("read unlock fail!");
if(nread == BUFSIZE)
{
//LOGD("BUFSIZE:%d", BUFSIZE);
//printf("readlength=%d\n", nread);
buff[nread]=‘\0‘;
//printf("buff[1]=%c\n", buff[0]);
if((buff[0] == 0xff) && (buff[1] == 0x0b))
{
for(i=1;i<=nread-2;i++)
{
sum += buff[i];
//LOGD("buff[%d]=%0x, sum =%0x", i, buff[i], (char)sum);
}
//printf("(buff[0] == 0xff) && (buff[1] == 0x0b)\n");
if(buff[nread-1] == (char)sum)
{
LOGD("Accept frame correct!");
switch(buff[2])
{
case 0X01:
if(memcpy(buff1, buff, nread) != NULL)
{
//LOGD("memcpy success!");
buff[2]=0x03;
buff[nread-1] = buff[nread-1]+0x02;
if(flock(fd,LOCK_EX)==0){
LOGD(" write lock!");
}else LOGD(" write lock fail!");
nwrite=write(fd, buff, BUFSIZE);
if(flock(fd,LOCK_UN)==0){
LOGD(" write unlock!");
}else LOGD("write unlock fail!");
if(nwrite == BUFSIZE)
{
LOGD("write_response_length=%d", nwrite);
if(memcpy(buff2, buff, nread) != NULL)
//LOGD("response buff memcpy to buff2 success!");
(*env)->SetByteArrayRegion(env, bytearray, 0, BUFSIZE+1, buff1);
(*env)->SetObjectField(env, obj, fid, bytearray);
(*env)->CallVoidMethod(env, obj, mid);
}
}else
{
LOGE("memcpy fail!");
if(flock(fd,LOCK_EX)==0){
LOGD(" write lock!");
}else LOGD(" write lock fail!");
nwrite=write(fd, resend, BUFSIZE);
if(flock(fd,LOCK_UN)==0){
LOGD(" write unlock!");
}else LOGD("write unlock fail!");
if(nwrite == BUFSIZE)
{
if(memcpy(buff2, resend, nread) == NULL)
LOGE("resend buff memcpy to buff2 failed!");
//LOGD("write_resend_length=%d", nwrite);
}
}
continue;
case 0X02:
switch(buff[3])
{
case 0x01:
if(flock(fd,LOCK_EX)==0){
LOGD(" write lock!");
}else LOGD(" write lock fail!");
nwrite=write(fd, buff2, BUFSIZE);
if(flock(fd,LOCK_UN)==0){
LOGD(" write unlock!");
}else LOGD("write unlock fail!");
if(nwrite == BUFSIZE)
{
if(memmove(buff2, buff2, nread) == NULL)
LOGE("resend buff memcpy to buff2 failed!\n");
//LOGD("write_buff2_length=%d", nwrite);
}
continue;
case 0x02:
continue;
case 0x03:
continue;
case 0x04:
continue;
case 0x05:
continue;
case 0x06:
continue;
case 0x07:
continue;
default :
continue;
}
case 0X03:
switch(buff[4])
{
case 0X01:
continue;
case 0X02:
LOGE("receive fail!");
if(flock(fd,LOCK_EX)==0){
LOGD(" write lock!");
}else LOGD(" write lock fail!");
nwrite=write(fd, buff2, BUFSIZE);
if(flock(fd,LOCK_UN)==0){
LOGD(" write unlock!");
}else LOGD("write unlock fail!");
if(nwrite == BUFSIZE)
{
if(memmove(buff2, buff2, nread) == NULL)
LOGE("resend buff memcpy to buff2 failed!\n");
//LOGD("write_buff2_length=%d\n", nwrite);
}
continue;
case 0X03:
continue;
case 0X04:
LOGE("receive fail!");
if(flock(fd,LOCK_EX)==0){
LOGD("write lock!");
}else LOGD("write lock fail!");
nwrite=write(fd, buff2, BUFSIZE);
if(flock(fd,LOCK_UN)==0){
LOGD(" write unlock!");
}else LOGD("write unlock fail!");
if(nwrite == BUFSIZE)
{
if(memmove(buff2, buff2, nread) == NULL)
LOGE("resend buff memcpy to buff2 failed!");
//LOGE("write_buff2_length=%d", nwrite);
}
continue;
default:
continue;
}
default :
continue;
}
}else
{
LOGE("buff[nread-1] != (char)sum,Accept frame wrong!");
if(flock(fd,LOCK_EX)==0){
LOGD(" write lock!");
}else LOGD(" write lock fail!");
nwrite=write(fd, resend, BUFSIZE);
if(flock(fd,LOCK_UN)==0){
LOGD(" write unlock!");
}else LOGD("write unlock fail!");
if(nwrite == BUFSIZE)
{
if(memcpy(buff2, resend, nread) == NULL)
LOGE("resend buff memcpy to buff2 failed!\n");
//LOGD("write_resend_length=%d", nwrite);
}
}
}else
{
//LOGD("buff[0] != 0xff || buff[1] != 0x0b");
}
}
}
}
tcflush(fd, TCIOFLUSH);
}
// tcsetattr(fd, TCSANOW, &oldtio);
close(fd);
return;
}
----------------------------------------------end----------------------------------------------------------
顶层makefile:
---------------------------------------Android.mk---------------------------------------------
#
# Copyright (C) 2008 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# This makefile shows how to build a shared library and an activity that
# bundles the shared library and calls it using JNI.
TOP_LOCAL_PATH:= $(call my-dir)
# Build activity
LOCAL_PATH:= $(TOP_LOCAL_PATH)
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := optional
LOCAL_SRC_FILES := $(call all-subdir-java-files)
LOCAL_PACKAGE_NAME := Serial
LOCAL_JNI_SHARED_LIBRARIES := libSerialjni
LOCAL_PROGUARD_ENABLED := disabled
LOCAL_SDK_VERSION := current
include $(BUILD_PACKAGE)
# ============================================================
# Also build all of the sub-targets under this one: the shared library.
include $(call all-makefiles-under,$(LOCAL_PATH))
-------------------------------------------end--------------------------------------------------------------
jni下的MAKEFILE
-----------------------------------------Android.mk--------------------------------------------------------
#
# Copyright (C) 2008 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# This makefile supplies the rules for building a library of JNI code for
# use by our example of how to bundle a shared library with an APK.
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := optional
# This is the target being built.
LOCAL_MODULE:= libserialjni
LOCAL_LDLIBS :=-llog
# All of the source files that we will compile.
LOCAL_SRC_FILES:= \
object_nvs_client_SerialJNI.c
# All of the shared libraries we link against.
LOCAL_SHARED_LIBRARIES := \
libutils\
# No static libraries.
LOCAL_STATIC_LIBRARIES :=
# Also need the JNI headers.
LOCAL_C_INCLUDES += \
$(JNI_H_INCLUDE)\
# No special compiler flags.
LOCAL_CFLAGS +=
include $(BUILD_SHARED_LIBRARY)
--------------------------------------------------------end-----------------------------------------------
AndroidManifest.xml
--------------------------------------------AndroidManifest.xml--------------------------------------
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.test.serial">
<application android:label="serial">
<activity android:name="object.nvs.client.MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
-------------------------------------------------------end-------------------------------------------