代碼已經驗證過,沒問題 !但界面部分沒有貼,只是提供思路!java
代碼層次結構:android
|-----serial_communication_class---ios
| |-------src---------express
| |------com------apache
| |----object-----數組
| |------nvs------app
| |-----client------less
| |---MainActivity.javaide
| |----SerialJNI.javaui
| |--------jni-----------------------------------------------------
| |------- Android.mk
| |--------object_nvs_client_SerialJNI.c
| |--------Android.mk
| |---------AndroidManifest.xml
如今貼代碼:
-------------------------------------------SerialJNI.java---------------------------------------------------
package object.nvs.client;
public class SerialJNI{
public native int open_dev(String dev, int baudrate);
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
}
public byte[] bytes = new byte[32]; //Accessing Fields,用於裝載JNI中的返回數據
public void callback() {//方法回調,JNI中一有數據此方法就被回調一次,因此對數據的全部操做建議都放於此
int i;
for(i=0;i<32;i++){
System.out.println(bytes[i]&0xff);
}
}
}
---------------------------------------------------end--------------------------------------------------
應用層調用:
---------------------------------------------MainActivity.java-------------------------------------------
package object.nvs.client;
import com.test.serial.R;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.app.Activity;
public class MainActivity extends Activity {
final char stop2[]={0xFF,0x20,0x01,0x40,0x1D,0x07,0x12,0x01,0x0C,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xA4};
private Button btn_send;
SerialJNI serialPort;
int fd;
Thread thread;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btn_send = (Button)findViewById(R.id.button1);
serialPort = new SerialJNI();
fd = serialPort.open_dev("/dev/ttyS7", 38400);
thread = new Thread(new Runnable() {
private String TAG = "serial";
@Override
public void run() {
// TODO Auto-generated method stub
serialPort.receive_data(fd, 32);//此方法必須在APP起來時候就調用,串口初始化的的操做都在此方法裏,並且必須啓用線程來操做
Log.i(TAG , "do it receive_datadown");
}
});
thread.start();
btn_send.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
// TODO Auto-generated method stub
int ret = serialPort.send_command(fd, stop2, 32);
System.out.println("btn_send--- send command\n");
if(ret < 0)
System.out.println("send command error!\n");
}
});
--------------------------------------------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 <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 <pthread.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 32
int BaudRate = B9600;
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,0x20,0x02,0x01,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0E};
char stop[]={0xFF,0x20,0x02,0x02,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0F};
/*
*Native Method
*Method : setTermios
*/
void setTermios(struct termios * pNewtio, int uBaudRate)
{
bzero(pNewtio, sizeof(struct termios));
//8N1
pNewtio->c_cflag = uBaudRate | CS8 | CREAD | CLOCAL;
pNewtio->c_iflag = IGNPAR;
pNewtio->c_oflag = 0;
pNewtio->c_lflag = 0; //non ICANON
pNewtio->c_cc[VINTR] = 0;
pNewtio->c_cc[VQUIT] = 0;
pNewtio->c_cc[VERASE] = 0;
pNewtio->c_cc[VKILL] = 0;
pNewtio->c_cc[VEOF] = 4;
pNewtio->c_cc[VTIME] = 5;
pNewtio->c_cc[VMIN] = 0;
pNewtio->c_cc[VSWTC] = 0;
pNewtio->c_cc[VSTART] = 0;
pNewtio->c_cc[VSTOP] = 0;
pNewtio->c_cc[VSUSP] = 0;
pNewtio->c_cc[VEOL] = 0;
pNewtio->c_cc[VREPRINT] = 0;
pNewtio->c_cc[VDISCARD] = 0;
pNewtio->c_cc[VWERASE] = 0;
pNewtio->c_cc[VLNEXT] = 0;
pNewtio->c_cc[VEOL2] = 0;
}
/*
* Class: object_nvs_client_SerialJNI
* Method: open_dev
* Signature: (Ljava/lang/String;)I
*/
JNIEXPORT jint JNICALL Java_object_nvs_client_SerialJNI_open_1dev
(JNIEnv *env, jobject obj, jstring dev, jint baudrate){
int i;
const char *Dev_utf = (*env)->GetStringUTFChars(env, dev, JNI_FALSE);
int fd = open(Dev_utf, O_RDWR);
(*env)->ReleaseStringUTFChars(env, dev, Dev_utf);
if (-1 == fd)
{ /*設置數據位數*/
LOGE("Can't Open Serial Port\n");
return -1;
}
for(i=0; i<sizeof(speed_arr)/sizeof(int); i++)
{
if(baudrate == name_arr[i])
{
BaudRate = speed_arr[i];
break ;
}
}
LOGD("Open Serial Port:%s,set speed:%d\n", Dev_utf, baudrate);
return fd;
}
/*
* Class: object_nvs_client_SerialJNI
* Method: close_dev
* Signature: (I)I
*/
JNIEXPORT jint JNICALL Java_object_nvs_client_SerialJNI_close_1dev
(JNIEnv *env, jobject obj, jint fd){
close(fd);
return TRUE;
}
/*
* Native Method
* Method: set_Parity
*/
int serial_set_parity(int fd, int databits, int stopbits, int parity){
struct termios options;
if(tcgetattr(fd, &options) != 0)
{
LOGE("SetupSerial 1.");
return(FALSE);
}
options.c_cflag &= ~CSIZE;
switch(databits) /*設置數據位數*/
{
case 7:
options.c_cflag |= CS7;
break;
case 8:
options.c_cflag |= CS8;
break;
default:
LOGE("Unsupported data size");
return (FALSE);
}
switch(parity)
{
/* 沒有校驗 */
case 'n':
case 'N':
options.c_cflag &= ~PARENB; /* Clear parity enable */
options.c_iflag &= ~INPCK; /* Enable parity checking */
break;
/* 奇校驗 */
case 'o':
case 'O':
options.c_cflag |= (PARODD | PARENB); /* 設置爲奇效驗*/
options.c_iflag |= INPCK; /* Disnable parity checking */
break;
/* 偶校驗 */
case 'e':
case 'E':
options.c_cflag |= PARENB; /* Enable parity */
options.c_cflag &= ~PARODD; /* 轉換爲偶效驗*/
options.c_iflag |= INPCK; /* Disnable parity checking */
break;
case 'S':
case 's': /*as no parity*/
options.c_cflag &= ~PARENB;
options.c_cflag &= ~CSTOPB;
break;
default:
LOGE("Unsupported parity.");
return (FALSE);
}
/* 設置中止位*/
switch(stopbits)
{
case 1:
options.c_cflag &= ~CSTOPB;
break;
case 2:
options.c_cflag |= CSTOPB;
break;
default:
LOGE("Unsupported stop bits");
return (FALSE);
}
/* Set input parity option */
if(parity != 'n')
options.c_iflag |= INPCK;
options.c_cc[VTIME] = 150; // 15 seconds
options.c_cc[VMIN] = 0;
tcflush(fd,TCIFLUSH); /* Update the options and do it NOW */
if(tcsetattr(fd,TCSANOW,&options) != 0)
{
LOGE("SetupSerial 3");
return (FALSE);
}
return (TRUE);
}
void serial_close(int fd)
{
close(fd);
}
/*
* Class: object_nvs_client_SerialJNI
* Method: send_command
* Signature: (I[CI)I
*/
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);
//LOGD("Send_command %d\n", fd);
for(i=0;i<BUFSIZE;i++){
command[i] = (char)jc[i]&0xff;//java中char[]數組元素是char類型佔2個字節和jni中的jchar相同,要轉換成一個字節的char類型因此要去掉一個字節,方法就是將每一個元素&oxff
}
if(write(fd, command, BUFSIZE)>0)
{
LOGD("write success !\n");
}
else
{
LOGE("write failed!\n");
}
(*env)->ReleaseCharArrayElements(env, buff, jc, 0);
return 0;
}
/*
* Class: object_nvs_client_SerialJNI
* Method: receive_data
* Signature: (II)V
*/
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;
int sum = 0;
int nread,nwrite;
char buff[BUFSIZE+1];
char buff1[BUFSIZE+1];
char buff2[BUFSIZE+1];
struct termios oldtio, newtio;
struct timeval tv;
fd_set rfds;
bzero(buff, BUFSIZE+1);
bzero(buff1, BUFSIZE+1);
bzero(buff2, BUFSIZE+1);
tcgetattr(fd, &oldtio);
setTermios(&newtio, BaudRate);
tcflush(fd, TCIFLUSH);
tcsetattr(fd, TCSANOW, &newtio);
if (serial_set_parity(fd,8,1,'N') == FALSE)
{
LOGE("Set Parity Error\n");
serial_close(fd);
return;
}
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!");
serial_close(fd);
return; /* failed to find the field */
}
jmethodID mid = (*env)->GetMethodID(env, cls2, "callback", "()V");
if (mid == NULL)
{
LOGE("method not found!");
serial_close(fd);
return; /* method not found */
}
while(TRUE)
{
sum = 0;
sleep(1);
LOGD("wait wait...");
FD_ZERO(&rfds);
FD_SET(fd, &rfds);
if(select(1+fd, &rfds, &rfds, NULL, &tv)>0)
{
if(FD_ISSET(fd, &rfds))
{
nread=read(fd, buff, BUFSIZE);
LOGD("Accept date nread = %d, fd = %d", nread, fd);
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] == 0x20))
{
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;
//nwrite=write(fd, buff, BUFSIZE);
//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!");
nwrite=write(fd, resend, BUFSIZE);
if(nwrite == BUFSIZE)
{
if(memcpy(buff2, resend, nread) == NULL)
LOGE("resend buff memcpy to buff2 failed!");
//LOGD("write_resend_length=%d", nwrite);
}
}
tcflush(fd, TCIOFLUSH);
continue;
case 0X02:
switch(buff[3])
{
case 0x01:
LOGD("resend command!");
nwrite=write(fd, buff2, BUFSIZE);
if(nwrite == BUFSIZE)
{
if(memmove(buff2, buff2, nread) == NULL)
LOGE("resend buff memcpy to buff2 failed!\n");
//LOGD("write_buff2_length=%d", nwrite);
}
tcflush(fd, TCIOFLUSH);
continue;
case 0x02:
LOGD("stop send command!");
tcflush(fd, TCIOFLUSH);
continue;
case 0x03:
LOGD("open rf receive command!");
tcflush(fd, TCIOFLUSH);
continue;
case 0x04:
LOGD("open rf send command!");
tcflush(fd, TCIOFLUSH);
continue;
case 0x05:
LOGD("close rf command!");
tcflush(fd, TCIOFLUSH);
continue;
case 0x06:
LOGD("rf send command!");
tcflush(fd, TCIOFLUSH);
continue;
case 0x07:
LOGD("get client rf state!");
tcflush(fd, TCIOFLUSH);
continue;
default :
LOGD("other command!");
tcflush(fd, TCIOFLUSH);
continue;
}
case 0X03:
switch(buff[4])
{
case 0X01:
LOGD("Execute/receive successfully!");
tcflush(fd, TCIOFLUSH);
continue;
case 0X02:
LOGE("receive fail(client)!");
nwrite=write(fd, buff2, BUFSIZE);
if(nwrite == BUFSIZE)
{
if(memmove(buff2, buff2, nread) == NULL)
LOGE("resend buff memcpy to buff2 failed!\n");
//LOGD("write_buff2_length=%d\n", nwrite);
}
tcflush(fd, TCIOFLUSH);
continue;
case 0X03:
LOGD("not support!");
tcflush(fd, TCIOFLUSH);
continue;
case 0X04:
LOGE("Execute fail!");
nwrite=write(fd, buff2, BUFSIZE);
if(nwrite == BUFSIZE)
{
if(memmove(buff2, buff2, nread) == NULL)
LOGE("resend buff memcpy to buff2 failed!");
//LOGE("write_buff2_length=%d", nwrite);
}
tcflush(fd, TCIOFLUSH);
continue;
case 0X05:
LOGD("send success!");
tcflush(fd, TCIOFLUSH);
continue;
case 0X06:
LOGD("not response!");
tcflush(fd, TCIOFLUSH);
continue;
default:
LOGD("other state!");
tcflush(fd, TCIOFLUSH);
continue;
}
default :
LOGD("not correct fomart!");
tcflush(fd, TCIOFLUSH);
continue;
}
}else
{
LOGE("buff[nread-1] != (char)sum,Accept frame wrong!");
nwrite=write(fd, resend, BUFSIZE);
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);
serial_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="serial"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="17" />
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name="object.nvs.client.MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
-------------------------------------------------------end-------------------------------------------