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 *
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 }