AS SerialPort 编译依赖库
一.
1.1.新建工程 选择Native C++
1.1.
a.SerialPort.c
/* * Copyright 2009-2011 Cedric Priscal * * 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 <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) int fd; int xh_baudrate; #define TIOCSRS485 0x542F struct xh_serial_rs485 { unsigned long flags; /* RS485 feature flags */ unsigned long delay_rts_before_send; /* Delay before send (milliseconds) */ unsigned long delay_rts_after_send; /* Delay after send (milliseconds) */ }; 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; } } /** * 设置串口数据,校验位,速率,停止位 * @param nBits 类型 int数据位 取值 位7或8 * @param nEvent 类型 char 校验类型 取值N ,E, O,,S * @param mStop 类型 int 停止位 取值1 或者 2 */ int set_opt(jint nBits, jchar nEvent, jint nStop,jint baudrate) { LOGE("set_opt:nBits=%d,nEvent=%c,nStop=%d", nBits, nEvent, nStop); struct termios newtio; speed_t speed; if(tcgetattr(fd, & newtio) != 0) { LOGE("setup serial failure"); return -1; } /*波特率 */ { speed = getBaudrate(baudrate); if (speed == -1) { /* TODO: throw an exception */ LOGE("Invalid baudrate"); return NULL; } } bzero( & newtio, sizeof(newtio)); //c_cflag标志可以定义CLOCAL和CREAD,这将确保该程序不被其他端口控制和信号干扰,同时串口驱动将读取进入的数据。CLOCAL和CREAD通常总是被是能的 newtio.c_cflag |= CLOCAL | CREAD; cfmakeraw(&newtio); //设置波特率 cfsetispeed(&newtio, speed); cfsetospeed(&newtio, speed); 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: break; } switch(nEvent) //设置校验位 { case 'O': newtio.c_cflag |= PARENB; //enable parity checking newtio.c_cflag |= PARODD; //奇校验位 newtio.c_iflag |= (INPCK ); break; case 'E': newtio.c_cflag |= PARENB; // newtio.c_cflag &= ~PARODD; //偶校验位 newtio.c_iflag |= (INPCK); break; case 'N': newtio.c_cflag &= ~PARENB; //清除校验位 break; default: break; } newtio.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); /*Input*/ newtio.c_oflag &= ~OPOST; /*Output*/ 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] = 100;//设置等待时间 newtio.c_cc[VMIN] = 0;//设置最小接收字符 tcflush(fd, TCIFLUSH); if(tcsetattr(fd, TCSANOW, & newtio) != 0) { LOGE("options set error"); return -1; } LOGE("options set success"); return 1; } /* * Class: android_serialport_SerialPort * Method: open * Signature: (Ljava/lang/String;II)Ljava/io/FileDescriptor; */ JNIEXPORT jobject JNICALL Java_android_1serialport_1api_SerialPort_open (JNIEnv *env, jclass thiz, jstring path, jint baudrate, jint databits, jint stopbits, jchar parity) { LOGE("Java_android_1serialport_1api_SerialPort_open\n"); jobject mFileDescriptor; speed_t speed; xh_baudrate=baudrate; /* Check arguments */ { speed = getBaudrate(baudrate); if (speed == -1) { /* TODO: throw an exception */ LOGE("Invalid baudrate"); return NULL; } } /* Opening device */ { jint flags = 0; jboolean iscopy; const char *path_utf = (*env)->GetStringUTFChars(env, path, &iscopy); LOGD("Opening serial port %s with flags 0x%x", path_utf, O_RDWR | flags); fd = open(path_utf, O_RDWR | O_NONBLOCK); //fd=fd; 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; } } //配置校验位 停止位等等 //set_opt(databits, parity, stopbits,baudrate); /* 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_1serialport_1api_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); } /* * Class: cedric_serial_SerialPort * Method: close * Signature: ()V */ JNIEXPORT void JNICALL Java_android_1serialport_1api_SerialPort_write_1rs485_1length (JNIEnv *env, jobject thiz, jint count) { struct xh_serial_rs485 rs485conf; LOGD("count= %d xh_baudrate = %d \n", count,xh_baudrate); rs485conf.delay_rts_after_send = ((10 * count * 1000 ) / xh_baudrate) + 1 ; ioctl (fd, TIOCSRS485, &rs485conf); }
b.SerialPort.h
/* DO NOT EDIT THIS FILE - it is machine generated */ #include <jni.h> /* Header for class android_serialport_api_SerialPort */ #ifndef _Included_android_serialport_api_SerialPort #define _Included_android_serialport_api_SerialPort #ifdef __cplusplus extern "C" { #endif /* * Class: android_serialport_api_SerialPort * Method: open * Signature: (Ljava/lang/String;II)Ljava/io/FileDescriptor; */ JNIEXPORT jobject JNICALL Java_android_1serialport_1api_SerialPort_open (JNIEnv *, jclass, jstring, jint, jint,jint,jchar); /* * Class: android_serialport_api_SerialPort * Method: close * Signature: ()V */ JNIEXPORT void JNICALL Java_android_1serialport_1api_SerialPort_close (JNIEnv *, jobject); JNIEXPORT void JNICALL Java_android_1serialport_1api_SerialPort_write_rs485_length (JNIEnv *, jint); #ifdef __cplusplus } #endif #endif
c.CMakeLists.txt
# For more information about using CMake with Android Studio, read the # documentation: https://d.android.com/studio/projects/add-native-code.html # Sets the minimum version of CMake required to build the native library. cmake_minimum_required(VERSION 3.10.2) # Declares and names the project. project("serialport") # Creates and names a library, sets it as either STATIC # or SHARED, and provides the relative paths to its source code. # You can define multiple libraries, and CMake builds them for you. # Gradle automatically packages shared libraries with your APK. add_library( # Sets the name of the library. SerialPort # Sets the library as a shared library. SHARED # Provides a relative path to your source file(s). SerialPort.c) # Searches for a specified prebuilt library and stores the path as a # variable. Because CMake includes system libraries in the search path by # default, you only need to specify the name of the public NDK library # you want to add. CMake verifies that the library exists before # completing its build. find_library( # Sets the name of the path variable. log-lib # Specifies the name of the NDK library that # you want CMake to locate. log) # Specifies libraries CMake should link to your target library. You # can link multiple libraries, such as libraries you define in this # build script, prebuilt third-party libraries, or system libraries. target_link_libraries( # Specifies the target library. SerialPort # Links the target library to the log library # included in the NDK. ${log-lib})
E:\GatsbyDevelop\AndroidStuido\GatsbyASCode\GSerialPort\app\build\intermediates\cmake\debug\obj\arm64-v8a 下生成so文件
工程
1.3.
android_serialport_api
a.SerialPort.java 这个类主要用来加载SO文件 通过JNI的方式打开关闭串口
package android_serialport_api; import android.util.Log; import java.io.File; import java.io.FileDescriptor; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; 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, int dataBits, int stopBits, char parity) 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 666 " + device.getAbsolutePath() + "\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, dataBits, stopBits, parity); if (mFd == null) { Log.e(TAG, "native open returns null"); throw new IOException(); } mFileInputStream = new FileInputStream(mFd); mFileOutputStream = new FileOutputStream(mFd); } // Getters and setters public InputStream getInputStream() { return mFileInputStream; } public OutputStream getOutputStream() { return mFileOutputStream; } public void Write_Rs485_Length(int count) { write_rs485_length(count); } // JNI(调用java本地接口,实现串口的打开和关闭) /**串口有五个重要的参数:串口设备名,波特率,检验位,数据位,停止位 其中检验位一般默认位NONE,数据位一般默认为8,停止位默认为1*/ /** * @param path 串口设备的据对路径 * @param baudrate 波特率 * @param dataBits 数据位 * @param stopBits 停止位 * @param parity 校验位 */ private native static FileDescriptor open(String path, int baudrate, int dataBits, int stopBits, char parity); public native void close(); public native void write_rs485_length(int count); static {//加载jni下的C文件库 System.loadLibrary("serial_port"); } }
b.SerialPortFinder.java
/* * Copyright 2009-2011 Cedric Priscal * * 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 <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) int fd; int xh_baudrate; #define TIOCSRS485 0x542F struct xh_serial_rs485 { unsigned long flags; /* RS485 feature flags */ unsigned long delay_rts_before_send; /* Delay before send (milliseconds) */ unsigned long delay_rts_after_send; /* Delay after send (milliseconds) */ }; 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; } } /** * 设置串口数据,校验位,速率,停止位 * @param nBits 类型 int数据位 取值 位7或8 * @param nEvent 类型 char 校验类型 取值N ,E, O,,S * @param mStop 类型 int 停止位 取值1 或者 2 */ int set_opt(jint nBits, jchar nEvent, jint nStop,jint baudrate) { LOGE("set_opt:nBits=%d,nEvent=%c,nStop=%d", nBits, nEvent, nStop); struct termios newtio; speed_t speed; if(tcgetattr(fd, & newtio) != 0) { LOGE("setup serial failure"); return -1; } /*波特率 */ { speed = getBaudrate(baudrate); if (speed == -1) { /* TODO: throw an exception */ LOGE("Invalid baudrate"); return NULL; } } bzero( & newtio, sizeof(newtio)); //c_cflag标志可以定义CLOCAL和CREAD,这将确保该程序不被其他端口控制和信号干扰,同时串口驱动将读取进入的数据。CLOCAL和CREAD通常总是被是能的 newtio.c_cflag |= CLOCAL | CREAD; cfmakeraw(&newtio); //设置波特率 cfsetispeed(&newtio, speed); cfsetospeed(&newtio, speed); 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: break; } switch(nEvent) //设置校验位 { case 'O': newtio.c_cflag |= PARENB; //enable parity checking newtio.c_cflag |= PARODD; //奇校验位 newtio.c_iflag |= (INPCK ); break; case 'E': newtio.c_cflag |= PARENB; // newtio.c_cflag &= ~PARODD; //偶校验位 newtio.c_iflag |= (INPCK); break; case 'N': newtio.c_cflag &= ~PARENB; //清除校验位 break; default: break; } newtio.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); /*Input*/ newtio.c_oflag &= ~OPOST; /*Output*/ 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] = 100;//设置等待时间 newtio.c_cc[VMIN] = 0;//设置最小接收字符 tcflush(fd, TCIFLUSH); if(tcsetattr(fd, TCSANOW, & newtio) != 0) { LOGE("options set error"); return -1; } LOGE("options set success"); return 1; } /* * Class: android_serialport_SerialPort * Method: open * Signature: (Ljava/lang/String;II)Ljava/io/FileDescriptor; */ JNIEXPORT jobject JNICALL Java_android_1serialport_1api_SerialPort_open (JNIEnv *env, jclass thiz, jstring path, jint baudrate, jint databits, jint stopbits, jchar parity) { LOGE("Java_android_1serialport_1api_SerialPort_open\n"); jobject mFileDescriptor; speed_t speed; xh_baudrate=baudrate; /* Check arguments */ { speed = getBaudrate(baudrate); if (speed == -1) { /* TODO: throw an exception */ LOGE("Invalid baudrate"); return NULL; } } /* Opening device */ { jint flags = 0; jboolean iscopy; const char *path_utf = (*env)->GetStringUTFChars(env, path, &iscopy); LOGD("Opening serial port %s with flags 0x%x", path_utf, O_RDWR | flags); fd = open(path_utf, O_RDWR | O_NONBLOCK); //fd=fd; 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; } } //配置校验位 停止位等等 //set_opt(databits, parity, stopbits,baudrate); /* 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_1serialport_1api_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); } /* * Class: cedric_serial_SerialPort * Method: close * Signature: ()V */ JNIEXPORT void JNICALL Java_android_1serialport_1api_SerialPort_write_1rs485_1length (JNIEnv *env, jobject thiz, jint count) { struct xh_serial_rs485 rs485conf; LOGD("count= %d xh_baudrate = %d \n", count,xh_baudrate); rs485conf.delay_rts_after_send = ((10 * count * 1000 ) / xh_baudrate) + 1 ; ioctl (fd, TIOCSRS485, &rs485conf); }