android 串口jni 开发流程


        第一步, 在eclipose里新建一个android工程,再新建一个 SerialPort.java文件

package android.serialport;


public class SerialPort {

//本类方法,这里略过,主要是调用jni方法以给其他类提供方法。
    ......

// JNI  方法
    private native static FileDescriptor open(String path, int baudrate) throws IOException;
    private native void native_close();
    private native int native_read_array(byte[] buffer, int length) throws IOException;
    private native int native_read_direct(ByteBuffer buffer, int length) throws IOException;
    private native int native_read_array_timeval(byte[] buffer, int length, int tv_sec, int tv_usec) throws IOException;
    private native int native_read_direct_timeval(ByteBuffer buffer, int length, int tv_sec, int tv_usec) throws IOException;
    private native void native_write_array(byte[] buffer, int length) throws IOException;
    private native void native_write_direct(ByteBuffer buffer, int length) throws IOException;
	static {
		System.loadLibrary("serial_port");
	}
}

        第二步,生成共享库头文件。进入eclipose刚才所新建工程的/bin/classes/目录下。可以看到其目录下的android/serialport/SerialPort.class文件,这个文件就是eclipose自动编译生成的classes文件。

        执行: javah android.serialport.SerialPort  (注意把目录符“/”换成“.”,而且没有.classes)

就会在当前目录下生成android_serialport_SerialPort.h 头文件,查看android_serialport_SerialPort.h有时会多余些错误处,如Java_android_serialport_SerialPort_native_1open函数名,明显多了一个“1”,此处不懂为什么多了个“1”。但千万不要去掉它.

       第三步,将刚才生成的H文件拷贝到jni源文件目录。因为我们这里是用ubuntu下ndk编译的。所以将android_serialport_SerialPort.h改名成SerialPort.h后,实现SerialPort.c文件,SerialPort.c就是要实现刚才SerialPort.h里面的所有方法。

SerialPort.h : 用javah 命令产生的

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class android_serialport_SerialPort */

#ifndef _Included_android_serialport_SerialPort
#define _Included_android_serialport_SerialPort
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     android_serialport_SerialPort
 * Method:    native_open
 * Signature: (Ljava/lang/String;I)Ljava/io/FileDescriptor;
 */
JNIEXPORT jobject JNICALL Java_android_serialport_SerialPort_native_1open
  (JNIEnv *, jclass, jstring, jint);

/*
 * Class:     android_serialport_SerialPort
 * Method:    native_close
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_android_serialport_SerialPort_native_1close
  (JNIEnv *, jobject);

/*
 * Class:     android_serialport_SerialPort
 * Method:    native_read_array
 * Signature: ([BI)I
 */
JNIEXPORT jint JNICALL Java_android_serialport_SerialPort_native_1read_1array
  (JNIEnv *, jobject, jbyteArray, jint);

/*
 * Class:     android_serialport_SerialPort
 * Method:    native_read_direct
 * Signature: (Ljava/nio/ByteBuffer;I)I
 */
JNIEXPORT jint JNICALL Java_android_serialport_SerialPort_native_1read_1direct
  (JNIEnv *, jobject, jobject, jint);

.........

#ifdef __cplusplus
}
#endif
#endif
SerialPort.c : 实现SerialPort.h中声明的函数

#include "termios.h"
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <jni.h>

#include "SerialPort.h"

#include "android/log.h"
static const char *TAG="serial_port";
#define LOGI(fmt, args...) __android_log_print(ANDROID_LOG_INFO,  TAG, fmt, ##args)
#define LOGD(fmt, args...) __android_log_print(ANDROID_LOG_DEBUG, TAG, fmt, ##args)
#define LOGE(fmt, args...) __android_log_print(ANDROID_LOG_ERROR, TAG, fmt, ##args)

//static jfieldID field_context;   // cannot define this , use this will anr.  why??????
/*
 * Class:     android_serialport_SerialPort
 * Method:    native_open
 * Signature: (Ljava/lang/String;I)Ljava/io/FileDescriptor;
 */
JNIEXPORT jobject JNICALL Java_android_serialport_SerialPort_native_1open
  (JNIEnv *env, jclass thiz, jstring path, jint baudrate)
{
        int fd;
        speed_t speed;
        jobject mFileDescriptor;

        /* Check arguments */
        {
                speed = getBaudrate(baudrate);
                if (speed == -1) {
                        /* TODO: throw an exception */
                        LOGE("Invalid baudrate");
                        jniThrowException(env, "java/io/IOException bad baudrate!!!!!", NULL);
                        return NULL;
                }
        }

        /* Opening device */
        {
                jboolean iscopy;
                const char *path_utf = (*env)->GetStringUTFChars(env, path, &iscopy);
                LOGD("Opening serial port %s", path_utf);

                fd = open(path_utf, O_RDWR);
                LOGD("open() fd = %d", fd);
        //      (*env)->SetIntField(env,thiz, field_context, fd);  // cannot define this , use this will anr.  why??????
                (*env)->ReleaseStringUTFChars(env, path, path_utf);
                if (fd == -1)
                {
                        /* Throw an exception */
                        LOGE("Cannot open port");
                        jniThrowException(env, "java/io/IOException", NULL);
                                  /* TODO: throw an exception */
                        return NULL;
                }
        }

        /* Configure device */
        {
                struct termios cfg;
                LOGD("Configuring serial port");
                if (tcgetattr(fd, &cfg))
                {
                        LOGE("tcgetattr() failed");
                        close(fd);
                        /* TODO: throw an exception */
                        jniThrowException(env, "java/io/IOException", NULL);
                        return NULL;
                }

                cfmakeraw(&cfg);
                cfsetispeed(&cfg, speed);
                cfsetospeed(&cfg, speed);

                if (tcsetattr(fd, TCSANOW, &cfg))
                {
                        LOGE("tcsetattr() failed");
                        close(fd);
                        /* TODO: throw an exception */
                        jniThrowException(env, "java/io/IOException", NULL);
                        return NULL;
                }
        }

        /* Create a corresponding file descriptor */
        {
                jclass cFileDescriptor = (*env)->FindClass(env, "java/io/FileDescriptor");
                jmethodID iFileDescriptor = (*env)->GetMethodID(env, cFileDescriptor, "<init>", "()V");
                jfieldID descriptorID = (*env)->GetFieldID(env, cFileDescriptor, "descriptor", "I");
                mFileDescriptor = (*env)->NewObject(env, cFileDescriptor, iFileDescriptor);
                (*env)->SetIntField(env, mFileDescriptor, descriptorID, (jint)fd);
        }
       

        return mFileDescriptor;
}

/*
 * Class:     cedric_serial_SerialPort
 * Method:    close
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_android_serialport_SerialPort_native_1close
  (JNIEnv *env, jobject thiz)
{
        jclass SerialPortClass = (*env)->GetObjectClass(env, thiz);
        jclass FileDescriptorClass = (*env)->FindClass(env, "java/io/FileDescriptor");

        jfieldID mFdID = (*env)->GetFieldID(env, SerialPortClass, "mFd", "Ljava/io/FileDescriptor;");
        jfieldID descriptorID = (*env)->GetFieldID(env, FileDescriptorClass, "descriptor", "I");

        jobject mFd = (*env)->GetObjectField(env, thiz, mFdID);
        jint descriptor = (*env)->GetIntField(env, mFd, descriptorID);

        LOGD("close(fd = %d)", descriptor);
        close(descriptor);
}

..........

第四步,编写Android.mk

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

TARGET_PLATFORM := android-3
LOCAL_MODULE    := serial_port
LOCAL_SRC_FILES := SerialPort/SerialPort.c JNIHelp.cpp
LOCAL_LDLIBS    := -llog
include $(BUILD_SHARED_LIBRARY)

第五步,编译,执行ndk-build命令,将会产生serial_port.so文件

第六步,将serial_port.so文件拷贝到eclipse项目 project/libs/armeabi/下,至此OK。





  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值