android_serialport_api hacking
1 /************************************************************************************ 2 * 3 * android_serialport_api hacking 4 * 5 * 声明: 6 * 1. 这是android_serialport_api的jni源代码解读; 7 * 2. 源代码url: https://code.google.com/p/android-serialport-api/ 8 * 3. 可以从中知道JNI是如何查找类,创建对象,访问对象的属性等等内容; 9 * 10 * 11 * Copyright 2009-2011 Cedric Priscal 12 * 13 * Licensed under the Apache License, Version 2.0 (the "License"); 14 * you may not use this file except in compliance with the License. 15 * You may obtain a copy of the License at 16 * 17 * http://www.apache.org/licenses/LICENSE-2.0 18 * 19 * Unless required by applicable law or agreed to in writing, software 20 * distributed under the License is distributed on an "AS IS" BASIS, 21 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 22 * See the License for the specific language governing permissions and 23 * limitations under the License. 24 * 25 * 26 * 27 * 相关参考: 28 * 1. 访问JAVA中的字段(jfieldID): http://www.cnblogs.com/lijunamneg/archive/2012/12/22/2829023.html 29 * 2. JNIEnv解析: http://blog.csdn.net/freechao/article/details/7692239 30 * 3. The Java™ Native Interface Programmer’s Guide and Specification 31 * 32 *****************************************************************************/ 33 34 #include <termios.h> 35 #include <unistd.h> 36 #include <sys/types.h> 37 #include <sys/stat.h> 38 #include <fcntl.h> 39 #include <string.h> 40 #include <jni.h> 41 42 #include "SerialPort.h" 43 44 #include "android/log.h" 45 46 /** 47 * 定义一些宏,方便写调试代码 48 */ 49 static const char *TAG="serial_port"; 50 #define LOGI(fmt, args...) __android_log_print(ANDROID_LOG_INFO, TAG, fmt, ##args) 51 #define LOGD(fmt, args...) __android_log_print(ANDROID_LOG_DEBUG, TAG, fmt, ##args) 52 #define LOGE(fmt, args...) __android_log_print(ANDROID_LOG_ERROR, TAG, fmt, ##args) 53 54 static speed_t getBaudrate(jint baudrate) 55 { 56 switch(baudrate) { 57 case 0: return B0; 58 case 50: return B50; 59 case 75: return B75; 60 case 110: return B110; 61 case 134: return B134; 62 case 150: return B150; 63 case 200: return B200; 64 case 300: return B300; 65 case 600: return B600; 66 case 1200: return B1200; 67 case 1800: return B1800; 68 case 2400: return B2400; 69 case 4800: return B4800; 70 case 9600: return B9600; 71 case 19200: return B19200; 72 case 38400: return B38400; 73 case 57600: return B57600; 74 case 115200: return B115200; 75 case 230400: return B230400; 76 case 460800: return B460800; 77 case 500000: return B500000; 78 case 576000: return B576000; 79 case 921600: return B921600; 80 case 1000000: return B1000000; 81 case 1152000: return B1152000; 82 case 1500000: return B1500000; 83 case 2000000: return B2000000; 84 case 2500000: return B2500000; 85 case 3000000: return B3000000; 86 case 3500000: return B3500000; 87 case 4000000: return B4000000; 88 default: return -1; 89 } 90 } 91 92 /* 93 * Class: com_android_aplex_SerialPort 94 * Method: open 95 * Signature: (Ljava/lang/String;II)Ljava/io/FileDescriptor; 96 */ 97 JNIEXPORT jobject JNICALL Java_com_android_aplex_SerialPort_open 98 (JNIEnv *env, jclass thiz, jstring path, jint baudrate, jint flags) 99 { 100 101 int fd; 102 speed_t speed; 103 jobject mFileDescriptor; //保存文件描述符的对象引用 104 105 // Check arguments 106 { 107 speed = getBaudrate(baudrate); 108 if (speed == -1) { 109 // TODO: throw an exception 110 LOGE("Invalid baudrate"); 111 return NULL; 112 } 113 } 114 115 // Opening device 116 { 117 jboolean iscopy; 118 /** 119 * 将Java的字符串转换成C中的字符串 120 */ 121 const char *path_utf = (*env)->GetStringUTFChars(env, path, &iscopy); 122 LOGD("Opening serial port %s with flags 0x%x", path_utf, O_RDWR | flags); 123 fd = open(path_utf, O_RDWR | flags); 124 LOGD("open() fd = %d", fd); 125 /** 126 * 和前面的GetStringUTFChars一对用法,相当于malloc和free 127 */ 128 (*env)->ReleaseStringUTFChars(env, path, path_utf); 129 if (fd == -1) 130 { 131 // Throw an exception 132 LOGE("Cannot open port"); 133 // TODO: throw an exception 134 return NULL; 135 } 136 } 137 138 // Configure device 139 { 140 struct termios cfg; 141 LOGD("Configuring serial port"); 142 if (tcgetattr(fd, &cfg)) 143 { 144 LOGE("tcgetattr() failed"); 145 close(fd); 146 // TODO: throw an exception 147 return NULL; 148 } 149 150 cfmakeraw(&cfg); 151 cfsetispeed(&cfg, speed); 152 cfsetospeed(&cfg, speed); 153 154 if (tcsetattr(fd, TCSANOW, &cfg)) 155 { 156 LOGE("tcsetattr() failed"); 157 close(fd); 158 // TODO: throw an exception 159 return NULL; 160 } 161 } 162 163 // Create a corresponding file descriptor 164 { 165 /** 166 * Returns a reference to the named class or interface. 167 * 这个相当于在当前虚拟机加载的所有的类中找这个类:java/io/FileDescriptor 168 */ 169 jclass cFileDescriptor = (*env)->FindClass(env, "java/io/FileDescriptor"); 170 /** 171 * To obtain the method ID of a constructor, supply "<init>" as the method name and “V” as the return type. 172 * 获取类中的无参构造函数 173 */ 174 jmethodID iFileDescriptor = (*env)->GetMethodID(env, cFileDescriptor, "<init>", "()V"); 175 jfieldID descriptorID = (*env)->GetFieldID(env, cFileDescriptor, "descriptor", "I"); 176 /** 177 * Constructs a new object. The method ID indicates which constructor method to invoke. This ID may be obtained by calling 178 * GetMethodID with "<init>" as the method name and “V” as the return type. The constructor must be defined in the class 179 * referred to by clazz, not one of its superclasses. 180 * 生成一个类对象 181 */ 182 mFileDescriptor = (*env)->NewObject(env, cFileDescriptor, iFileDescriptor); 183 /** 184 * Sets the value of an instance field of an object. The obj reference must not be NULL. 185 * 设置对象的值 186 */ 187 (*env)->SetIntField(env, mFileDescriptor, descriptorID, (jint)fd); 188 } 189 190 return mFileDescriptor; 191 192 } 193 194 /* 195 * Class: com_android_aplex_SerialPort 196 * Method: close 197 * Signature: ()V 198 */ 199 JNIEXPORT void JNICALL Java_com_android_aplex_SerialPort_close 200 (JNIEnv *env, jobject thiz) 201 { 202 /** 203 * Returns the class of an object. The obj reference must not be NULL. 204 * thiz为java层传入的对象,GetObjectClass相当于获得这个对象的类,名字取得不错 205 */ 206 jclass SerialPortClass = (*env)->GetObjectClass(env, thiz); 207 /** 208 * FindClass initializes the class or interface it returns. 209 * 这个相当于在当前虚拟机加载的所有的类中找这个类:java/io/FileDescriptor 210 */ 211 jclass FileDescriptorClass = (*env)->FindClass(env, "java/io/FileDescriptor"); 212 /** 213 * Returns the field ID for an instance field of a class 214 * 通过域名、域类型获取类对应的域ID号 215 */ 216 jfieldID mFdID = (*env)->GetFieldID(env, SerialPortClass, "mFd", "Ljava/io/FileDescriptor;"); 217 jfieldID descriptorID = (*env)->GetFieldID(env, FileDescriptorClass, "descriptor", "I"); 218 /** 219 * Returns the value of a field of an instance. The field to access is specified by a field ID. 220 * 通过对象对应域的ID号获取域对象,或者值 221 */ 222 jobject mFd = (*env)->GetObjectField(env, thiz, mFdID); 223 jint descriptor = (*env)->GetIntField(env, mFd, descriptorID); 224 225 LOGD("close(fd = %d)", descriptor); 226 close(descriptor); 227 228 }