Android Studio jni开发 串口通信

来源:互联网 发布:mac加载字幕 编辑:程序博客网 时间:2024/06/05 16:05

公司需求做串口通信,由于开发环境是Android Studio所以配置时出现很多问题.

这个是网上照搬的SerialPort类:

public class SerialPort {private static final String TAG = "SerialPort";/** Do not remove or rename the field mFd: it is used by native method close();*/private FileDescriptor mFd;private FileInputStream mFileInputStream;private FileOutputStream mFileOutputStream;public SerialPort(File device, int baudrate) throws SecurityException, IOException {/* Check access permission */if (!device.canRead() || !device.canWrite()) {try {/* Missing read/write permission, trying to chmod the file */Process su;su = Runtime.getRuntime().exec("/system/bin/su");String cmd = "chmod 777 " + device.getAbsolutePath() + "\n"+ "exit\n";/*String cmd = "chmod 777 /dev/s3c_serial0" + "\n"+ "exit\n";*/su.getOutputStream().write(cmd.getBytes());if ((su.waitFor() != 0) || !device.canRead()|| !device.canWrite()) {throw new SecurityException();}} catch (Exception e) {e.printStackTrace();throw new SecurityException();}}mFd = open(device.getAbsolutePath(), baudrate);if (mFd == null) {Log.e(TAG, "native open returns null");throw new IOException();}mFileInputStream = new FileInputStream(mFd);mFileOutputStream = new FileOutputStream(mFd);}// Getters and setterspublic InputStream getInputStream() {return mFileInputStream;}public OutputStream getOutputStream() {return mFileOutputStream;}// JNIprivate native static FileDescriptor open(String path, int baudrate);public native void close();static {System.loadLibrary("SerialPort");}}

点击"View->Tool Windows->Terminal",即在Studio中进行终端命令行工具.执行如下命令生成c语言头文件:
src\main\java>javah -jni com.serialport.main.SerialPort
创建c文件
右键>new>Folder>Jni Folder
将java文件夹下生成的com_serialport_main_SerialPort.h文件移动到main文件夹下的jni文件夹下
创建com_serialport_main_SerialPort.c文件,复制下面代码
//根据自己的h文件修改成一样的>>>>重要#include <com_serialport_main_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 "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)/** Class: android_serialport_SerialPort* Method: open* Signature: (Ljava/lang/String;II)Ljava/io/FileDescriptor;*/static speed_t getBaudrate(jint baudrate){switch(baudrate) {case 0: return B0;case 50: return B50;case 75: return B75;case 110: return B110;case 134: return B134;case 150: return B150;case 200: return B200;case 300: return B300;case 600: return B600;case 1200: return B1200;case 1800: return B1800;case 2400: return B2400;case 4800: return B4800;case 9600: return B9600;case 19200: return B19200;case 38400: return B38400;case 57600: return B57600;case 115200: return B115200;case 230400: return B230400;case 460800: return B460800;case 500000: return B500000;case 576000: return B576000;case 921600: return B921600;case 1000000: return B1000000;case 1152000: return B1152000;case 1500000: return B1500000;case 2000000: return B2000000;case 2500000: return B2500000;case 3000000: return B3000000;case 3500000: return B3500000;case 4000000: return B4000000;default: return -1;}}/** Class: cedric_serial_SerialPort* Method: open* Signature: (Ljava/lang/String;)V*///根据自己的h文件修改成一样的>>>>重要JNIEXPORT jobject JNICALL Java_com_serialport_main_SerialPort_open(JNIEnv *env, jobject 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");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 | O_SYNC);LOGD("open() fd = %d", fd);(*env)->ReleaseStringUTFChars(env, path, path_utf);if (fd == -1){/* Throw an exception */LOGE("Cannot open port");/* 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 */return NULL;}cfmakeraw(&cfg);cfsetispeed(&cfg, speed);cfsetospeed(&cfg, speed);if (tcsetattr(fd, TCSANOW, &cfg)){LOGE("tcsetattr() failed");close(fd);/* TODO: throw an exception */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*///根据自己的h文件修改成一样的>>>>重要JNIEXPORT void JNICALL Java_com_serialport_main_SerialPort_close(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);}

在根目录中的local.properties文件中添加代码
ndk.dir=D\:\\Android\\android-ndk-r10
android-ndk根据要求下载,由于机器要求不同,android-ndk的版本要求也不一样,我下载了4个版本只有这个r10可以用,看网上其他人好像用的版本也是有差异的

在build.gradle中添加代码

在defaultConfig下添加
ndk{abiFilter "armeabi"moduleName "SerialPort"ldLibs "log", "z", "m", "jnigraphics", "android"}

在android下添加
sourceSets{ //设置.so文件路径main{jniLibs.srcDirs = ['libs']}}

当有错误提示时:
检查项目属性,设置builders 选项;确保对.c更改自动生成.so文件;具体详见NDK环境搭建
删除项目libs/libserial_port.so文件,如果没有此文件完成第三步会自动生成,否则继续第一步;
修改serialport.c文件,移除fd = open(path_utf, O_RDWR | O_DIRECT | O_SYNC);中的 O_DIRECT选项;保存;//重要,因为我就遇到这个问题,修改后成功

因为是串口通信,所以测试机要有串口,还要root

这个不是类只是代码的使用集合:
FileOutputStream mOutputStream;FileInputStream mInputStream;SerialPort sp;//初始化 需注意要先获取root权限try {sp=new SerialPort(new File("/dev/ttyS4"),9600);} catch (SecurityException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}if(sp != null){mOutputStream=(FileOutputStream) sp.getOutputStream();mInputStream=(FileInputStream) sp.getInputStream();}//关闭sp.close();sp = null;try {mOutputStream.close();mOutputStream = null;mInputStream.close();mInputStream = null;} catch (IOException e) {e.printStackTrace();}//发送try {mOutputStream.write("write".getBytes());mOutputStream.write('\n');} catch (IOException e) {e.printStackTrace();}//接收Thread thread = new Thread(){@Overridepublic void run() {while (mInputStream != null){int size;try {int length = mInputStream.available();if (length > 0) {byte[] buffer = new byte[length];size = mInputStream.read(buffer);//该方法会阻塞线程直到接收到数据stringBuffer.append(new String(buffer, 0, size));handler.post(dataReceived);}} catch (IOException e) {e.printStackTrace();}}super.run();}};thread.start();StringBuffer stringBuffer = new StringBuffer();Handler handler = new Handler();DataReceived dataReceived = new DataReceived();private class DataReceived implements Runnable{@Overridepublic void run() {if(stringBuffer.length() != 0){String msg = stringBuffer.toString();//对接收的数据进行处理,我这里没有进行处理//比如一串字符串,会被分成好几个片段接收,像"abcd"可能被分开四次发送,这样接收就是"a","b","c","d"需要自己想办法拼接,做完这个我刚好辞职了,代码给忘记了,哈哈 stringBuffer.delete(0,stringBuffer.length());}}}





1 0
原创粉丝点击