开发文章

Android Studio 串口jni开发

1. 开发环境

Mac OS X , Android Studio 2.1.2

Mac OS X , Android Studio 2.1.2.pngMac OS X , Android Studio 2.1.2硬件配置.png

2. 创建新工程

创建SerialPortDemo工程, Minimum SDK 选择 API 19: Android 4.4。

创建SerialPortDemo工程.png

3. 工程环境

ndk 路径使用默认的, gradle version 2.10

ndk 路径使用默认的.png

ndk 路径使用默认路径.png

ndk 路径使用默认路径2.png

4. 切换工程显示方式

切换工程显示方式.png

5.修改build.gradle

注意是与app目录同级的build.gradle

修改classpath 对应的版本,请参考:https://sites.google.com/a/android.com/tools/tech-docs/new-build-system/gradle-experimental#TOC-Standalone-NDK-Plugin

gradle version 2.10 目前对应  "com.android.tools.build:gradle-experimental:0.7.0-alpha1"

修改build.gradle.png

06.修改app的build.gradle

注意:是app目录下的build.gradle

新的gradle 参考:https://sites.google.com/a/android.com/tools/tech-docs/new-build-system/gradle-experimental#TOC-Standalone-NDK-Plugin

请注意红框内的,否则会出现以下一些错误:

Error:Cause: org.gradle.api.internal.ExtensibleDynamicObject

Error:No signature of method: org.gradle.model.ModelMap.getDefaultProguardFile() is applicable for argument types: (java.lang.String) values: [proguard-android.txt]

修改app的build.gradle.png

07.创建jni目录

创建jni目录.png

SerialPort.h

复制内容到剪贴板
  1. #include <jni.h>    
  2.     
  3. #ifndef _Included_com_imlaidian_serialportdemo_serialapi_SerialPort    
  4. #define _Included_com_imlaidian_serialportdemo_serialapi_SerialPort    
  5.     
  6. #ifdef __cplusplus    
  7. extern "C" {    
  8. #endif    
  9.     
  10. // 命名格式: java_包名_类目录_类名_接口    
  11. JNIEXPORT jobject JNICALL Java_com_imlaidian_serialportdemo_serialapi_SerialPort_open    
  12.   (JNIEnv *, jclass, jstring, jint, jint);    
  13.     
  14.     
  15. JNIEXPORT void JNICALL Java_com_imlaidian_serialportdemo_serialapi_SerialPort_close    
  16.   (JNIEnv *, jobject);    
  17.     
  18. #ifdef __cplusplus    
  19. }    
  20. #endif    
  21.     
  22. #endif    

SerialPort.c

复制内容到剪贴板
  1. /*   
  2.  * Copyright 2009-2011 Cedric Priscal   
  3.  *   
  4.  * Licensed under the Apache License, Version 2.0 (the "License");   
  5.  * you may not use this file except in compliance with the License.   
  6.  * You may obtain a copy of the License at   
  7.  *   
  8.  * http://www.apache.org/licenses/LICENSE-2.0   
  9.  *   
  10.  * Unless required by applicable law or agreed to in writing, software   
  11.  * distributed under the License is distributed on an "AS IS" BASIS,   
  12.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   
  13.  * See the License for the specific language governing permissions and   
  14.  * limitations under the License.   
  15.  */    
  16.     
  17.     
  18. #include <unistd.h>    
  19. #include <sys/types.h>    
  20. #include <sys/stat.h>    
  21. #include <fcntl.h>    
  22. #include <string.h>    
  23. #include <jni.h>    
  24.     
  25. #include "termios.h"    
  26. #include "SerialPort.h"    
  27.     
  28. #include "android/log.h"    
  29. static const char *TAG="serial_port";    
  30. #define LOGI(fmt, args...) __android_log_print(ANDROID_LOG_INFO,  TAG, fmt, ##args)    
  31. #define LOGD(fmt, args...) __android_log_print(ANDROID_LOG_DEBUG, TAG, fmt, ##args)    
  32. #define LOGE(fmt, args...) __android_log_print(ANDROID_LOG_ERROR, TAG, fmt, ##args)    
  33.     
  34. static speed_t getBaudrate(jint baudrate)    
  35. {    
  36.     switch(baudrate) {    
  37.     case 0: return B0;    
  38.     case 50: return B50;    
  39.     case 75: return B75;    
  40.     case 110: return B110;    
  41.     case 134: return B134;    
  42.     case 150: return B150;    
  43.     case 200: return B200;    
  44.     case 300: return B300;    
  45.     case 600: return B600;    
  46.     case 1200: return B1200;    
  47.     case 1800: return B1800;    
  48.     case 2400: return B2400;    
  49.     case 4800: return B4800;    
  50.     case 9600: return B9600;    
  51.     case 19200: return B19200;    
  52.     case 38400: return B38400;    
  53.     case 57600: return B57600;    
  54.     case 115200: return B115200;    
  55.     case 230400: return B230400;    
  56.     case 460800: return B460800;    
  57.     case 500000: return B500000;    
  58.     case 576000: return B576000;    
  59.     case 921600: return B921600;    
  60.     case 1000000: return B1000000;    
  61.     case 1152000: return B1152000;    
  62.     case 1500000: return B1500000;    
  63.     case 2000000: return B2000000;    
  64.     case 2500000: return B2500000;    
  65.     case 3000000: return B3000000;    
  66.     case 3500000: return B3500000;    
  67.     case 4000000: return B4000000;    
  68.     defaultreturn -1;    
  69.     }    
  70. }    
  71.     
  72. /*   
  73.  * Class:     android_serialport_SerialPort   
  74.  * Method:    open   
  75.  * Signature: (Ljava/lang/String;II)Ljava/io/FileDescriptor;   
  76.  */    
  77. JNIEXPORT jobject JNICALL Java_com_imlaidian_serialdemo_SerialPort_SerialPort_open    
  78.   (JNIEnv *env, jclass thiz, jstring path, jint baudrate, jint flags)    
  79. {    
  80.     int fd;    
  81.     speed_t speed;    
  82.     jobject mFileDescriptor;    
  83.     
  84.     /* Check arguments */    
  85.     {    
  86.         speed = getBaudrate(baudrate);    
  87.         if (speed == -1) {    
  88.             /* TODO: throw an exception */    
  89.             LOGE("Invalid baudrate");    
  90.             return NULL;    
  91.         }    
  92.     }    
  93.     
  94.     /* Opening device */    
  95.     {    
  96.         jboolean iscopy;    
  97.         const char *path_utf = (*env)->GetStringUTFChars(env, path, &iscopy);    
  98.         LOGD("Opening serial port %s with flags 0x%x", path_utf, O_RDWR | flags);    
  99.         fd = open(path_utf, O_RDWR | flags);    
  100.         LOGD("open() fd = %d", fd);    
  101.         (*env)->ReleaseStringUTFChars(env, path, path_utf);    
  102.         if (fd == -1)    
  103.         {    
  104.             /* Throw an exception */    
  105.             LOGE("Cannot open port");    
  106.             /* TODO: throw an exception */    
  107.             return NULL;    
  108.         }    
  109.     }    
  110.     
  111.     /* Configure device */    
  112.     {    
  113.         struct termios cfg;    
  114.         LOGD("Configuring serial port");    
  115.         if (tcgetattr(fd, &cfg))    
  116.         {    
  117.             LOGE("tcgetattr() failed");    
  118.             close(fd);    
  119.             /* TODO: throw an exception */    
  120.             return NULL;    
  121.         }    
  122.     
  123.         cfmakeraw(&cfg);    
  124.         cfsetispeed(&cfg, speed);    
  125.         cfsetospeed(&cfg, speed);    
  126.     
  127.         if (tcsetattr(fd, TCSANOW, &cfg))    
  128.         {    
  129.             LOGE("tcsetattr() failed");    
  130.             close(fd);    
  131.             /* TODO: throw an exception */    
  132.             return NULL;    
  133.         }    
  134.     }    
  135.     
  136.     /* Create a corresponding file descriptor */    
  137.     {    
  138.         jclass cFileDescriptor = (*env)->FindClass(env, "java/io/FileDescriptor");    
  139.         jmethodID iFileDescriptor = (*env)->GetMethodID(env, cFileDescriptor, "<init>""()V");    
  140.         jfieldID descriptorID = (*env)->GetFieldID(env, cFileDescriptor, "descriptor""I");    
  141.         mFileDescriptor = (*env)->NewObject(env, cFileDescriptor, iFileDescriptor);    
  142.         (*env)->SetIntField(env, mFileDescriptor, descriptorID, (jint)fd);    
  143.     }    
  144.     
  145.     return mFileDescriptor;    
  146. }    
  147.     
  148. /*   
  149.  * Class:     cedric_serial_SerialPort   
  150.  * Method:    close   
  151.  * Signature: ()V   
  152.  */    
  153. JNIEXPORT void JNICALL Java_com_imlaidian_serialdemo_SerialPort_SerialPort_close    
  154.   (JNIEnv *env, jobject thiz)    
  155. {    
  156.     jclass SerialPortClass = (*env)->GetObjectClass(env, thiz);    
  157.     jclass FileDescriptorClass = (*env)->FindClass(env, "java/io/FileDescriptor");    
  158.     
  159.     jfieldID mFdID = (*env)->GetFieldID(env, SerialPortClass, "mFd""Ljava/io/FileDescriptor;");    
  160.     jfieldID descriptorID = (*env)->GetFieldID(env, FileDescriptorClass, "descriptor""I");    
  161.     
  162.     jobject mFd = (*env)->GetObjectField(env, thiz, mFdID);    
  163.     jint descriptor = (*env)->GetIntField(env, mFd, descriptorID);    
  164.     
  165.     LOGD("close(fd = %d)", descriptor);    
  166.     close(descriptor);    
  167. }   

由于api 19 之后的 termios.h 里面的函数有调整,因此调试过程中,出现

java.lang.UnsatisfiedLinkError: dlopen failed: cannot locate symbol "tcgetattr" referenced by "libserialport.so"...

解决方法:

将api 19  的 termios.h 拷贝到 jni 目录下

termios.h

复制内容到剪贴板
  1. /*   
  2.  * Copyright (C) 2008 The Android Open Source Project   
  3.  * All rights reserved.   
  4.  *   
  5.  * Redistribution and use in source and binary forms, with or without   
  6.  * modification, are permitted provided that the following conditions   
  7.  * are met:   
  8.  *  * Redistributions of source code must retain the above copyright   
  9.  *    notice, this list of conditions and the following disclaimer.   
  10.  *  * Redistributions in binary form must reproduce the above copyright   
  11.  *    notice, this list of conditions and the following disclaimer in   
  12.  *    the documentation and/or other materials provided with the   
  13.  *    distribution.   
  14.  *   
  15.  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS   
  16.  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT   
  17.  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS   
  18.  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE   
  19.  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,   
  20.  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,   
  21.  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS   
  22.  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED   
  23.  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,   
  24.  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT   
  25.  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF   
  26.  * SUCH DAMAGE.   
  27.  */    
  28. #ifndef _TERMIOS_H_    
  29. #define _TERMIOS_H_    
  30.     
  31. #include <sys/cdefs.h>    
  32. #include <sys/ioctl.h>    
  33. #include <sys/types.h>    
  34. #include <stdint.h>    
  35. #include <linux/termios.h>    
  36.     
  37. __BEGIN_DECLS    
  38.     
  39. /* Redefine these to match their ioctl number */    
  40. #undef  TCSANOW    
  41. #define TCSANOW    TCSETS    
  42.     
  43. #undef  TCSADRAIN    
  44. #define TCSADRAIN  TCSETSW    
  45.     
  46. #undef  TCSAFLUSH    
  47. #define TCSAFLUSH  TCSETSF    
  48.     
  49. static __inline__ int tcgetattr(int fd, struct termios *s)    
  50. {    
  51.     return ioctl(fd, TCGETS, s);    
  52. }    
  53.     
  54. static __inline__ int tcsetattr(int fd, int __opt, const struct termios *s)    
  55. {    
  56.     return ioctl(fd, __opt, (void *)s);    
  57. }    
  58.     
  59. static __inline__ int tcflow(int fd, int action)    
  60. {    
  61.     return ioctl(fd, TCXONC, (void *)(intptr_t)action);    
  62. }    
  63.     
  64. static __inline__ int tcflush(int fd, int __queue)    
  65. {    
  66.     return ioctl(fd, TCFLSH, (void *)(intptr_t)__queue);    
  67. }    
  68.     
  69. static __inline__ pid_t tcgetsid(int fd)    
  70. {    
  71.     pid_t _pid;    
  72.     return ioctl(fd, TIOCGSID, &_pid) ? (pid_t)-1 : _pid;    
  73. }    
  74.     
  75. static __inline__ int tcsendbreak(int fd, int __duration)    
  76. {    
  77.     return ioctl(fd, TCSBRKP, (void *)(uintptr_t)__duration);    
  78. }    
  79.     
  80. static __inline__ speed_t cfgetospeed(const struct termios *s)    
  81. {    
  82.     return (speed_t)(s->c_cflag & CBAUD);    
  83. }    
  84.     
  85. static __inline__ int cfsetospeed(struct termios *s, speed_t  speed)    
  86. {    
  87.     s->c_cflag = (s->c_cflag & ~CBAUD) | (speed & CBAUD);    
  88.     return 0;    
  89. }    
  90.     
  91. static __inline__ speed_t cfgetispeed(const struct termios *s)    
  92. {    
  93.     return (speed_t)(s->c_cflag & CBAUD);    
  94. }    
  95.     
  96. static __inline__ int cfsetispeed(struct termios *s, speed_t  speed)    
  97. {    
  98.     s->c_cflag = (s->c_cflag & ~CBAUD) | (speed & CBAUD);    
  99.     return 0;    
  100. }    
  101.     
  102. static __inline__ void cfmakeraw(struct termios *s)    
  103. {    
  104.     s->c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON);    
  105.     s->c_oflag &= ~OPOST;    
  106.     s->c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);    
  107.     s->c_cflag &= ~(CSIZE|PARENB);    
  108.     s->c_cflag |= CS8;    
  109. }    
  110.     
  111. __END_DECLS    
  112.     
  113. #endif /* _TERMIOS_H_ */    

此处参考:

http://jp1017.github.io /2016/06/30/jni-开发错误之-java-lang-UnsatisfiedLinkError-dlopen-failed- cannot-locate-symbol-tcgetattr-referenced-by-libserial-port-so/

http://www.eoeandroid.com/thread-914514-1-1.html

08.创建串口native接口类

创建串口native接口类.png

 

 

SerialPort.java

复制内容到剪贴板
  1. /*  
  2.  * Copyright 2009 Cedric Priscal  
  3.  *   
  4.  * Licensed under the Apache License, Version 2.0 (the "License");  
  5.  * you may not use this file except in compliance with the License.  
  6.  * You may obtain a copy of the License at  
  7.  *   
  8.  * http://www.apache.org/licenses/LICENSE-2.0  
  9.  *   
  10.  * Unless required by applicable law or agreed to in writing, software  
  11.  * distributed under the License is distributed on an "AS IS" BASIS,  
  12.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  
  13.  * See the License for the specific language governing permissions and  
  14.  * limitations under the License.   
  15.  */    
  16.     
  17. package com.imlaidian.serialportdemo.serialapi;    
  18.     
  19. import java.io.File;    
  20. import java.io.FileReader;    
  21. import java.io.IOException;    
  22. import java.io.LineNumberReader;    
  23. import java.util.Iterator;    
  24. import java.util.Vector;    
  25.     
  26. import android.util.Log;    
  27.     
  28. public class SerialPortFinder {    
  29.     
  30.     public class Driver {    
  31.         public Driver(String name, String root) {    
  32.             mDriverName = name;    
  33.             mDeviceRoot = root;    
  34.         }    
  35.         private String mDriverName;    
  36.         private String mDeviceRoot;    
  37.         Vector<File> mDevices = null;    
  38.         public Vector<File> getDevices() {    
  39.             if (mDevices == null) {    
  40.                 mDevices = new Vector<File>();    
  41.                 File dev = new File("/dev");    
  42.                 File[] files = dev.listFiles();    
  43.                 int i;    
  44.                 for (i=0; i<files.length; i++) {    
  45.                     if (files[i].getAbsolutePath().startsWith(mDeviceRoot)) {    
  46.                         Log.d(TAG, "Found new device: " + files[i]);    
  47.                         mDevices.add(files[i]);    
  48.                     }    
  49.                 }    
  50.             }    
  51.             return mDevices;    
  52.         }    
  53.         public String getName() {    
  54.             return mDriverName;    
  55.         }    
  56.     }    
  57.     
  58.     private static final String TAG = "SerialPort";    
  59.     
  60.     private Vector<Driver> mDrivers = null;    
  61.     
  62.     Vector<Driver> getDrivers() throws IOException {    
  63.         if (mDrivers == null) {    
  64.             mDrivers = new Vector<Driver>();    
  65.             LineNumberReader r = new LineNumberReader(new FileReader("/proc/tty/drivers"));    
  66.             String l;    
  67.             while((l = r.readLine()) != null) {    
  68.                 // Issue 3:    
  69.                 // Since driver name may contain spaces, we do not extract driver name with split()    
  70.                 String drivername = l.substring(00x15).trim();    
  71.                 String[] w = l.split(" +");    
  72.                 if ((w.length >= 5) && (w[w.length-1].equals("serial"))) {    
  73.                     Log.d(TAG, "Found new driver " + drivername + " on " + w[w.length-4]);    
  74.                     mDrivers.add(new Driver(drivername, w[w.length-4]));    
  75.                 }    
  76.             }    
  77.             r.close();    
  78.         }    
  79.         return mDrivers;    
  80.     }    
  81.     
  82.     public String[] getAllDevices() {    
  83.         Vector<String> devices = new Vector<String>();    
  84.         // Parse each driver    
  85.         Iterator<Driver> itdriv;    
  86.         try {    
  87.             itdriv = getDrivers().iterator();    
  88.             while(itdriv.hasNext()) {    
  89.                 Driver driver = itdriv.next();    
  90.                 Iterator<File> itdev = driver.getDevices().iterator();    
  91.                 while(itdev.hasNext()) {    
  92.                     String device = itdev.next().getName();    
  93.                     String value = String.format("%s (%s)", device, driver.getName());    
  94.                     devices.add(value);    
  95.                 }    
  96.             }    
  97.         } catch (IOException e) {    
  98.             e.printStackTrace();    
  99.         }    
  100.         return devices.toArray(new String[devices.size()]);    
  101.     }    
  102.     
  103.     public String[] getAllDevicesPath() {    
  104.         Vector<String> devices = new Vector<String>();    
  105.         // Parse each driver    
  106.         Iterator<Driver> itdriv;    
  107.         try {    
  108.             itdriv = getDrivers().iterator();    
  109.             while(itdriv.hasNext()) {    
  110.                 Driver driver = itdriv.next();    
  111.                 Iterator<File> itdev = driver.getDevices().iterator();    
  112.                 while(itdev.hasNext()) {    
  113.                     String device = itdev.next().getAbsolutePath();    
  114.                     devices.add(device);    
  115.                 }    
  116.             }    
  117.         } catch (IOException e) {    
  118.             e.printStackTrace();    
  119.         }    
  120.         return devices.toArray(new String[devices.size()]);    
  121.     }    
  122. }    

最终目录结构如下

最终目录结构如下.png

09. gradle sync同步

gradle sync同步.png

 

10. 生成.so 路径

生成.so 路径.png

 

感谢 __Jun__ 支持 磐实编程网 原文地址:
blog.csdn.net/caojengineer/article/details/51838394

文章信息

发布时间:2016-07-06

作者:__Jun__

发布者:aquwcw

浏览次数: