1 /*
2 * Copyright (C) 2011 The Android Open Source Project
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 #define LOG_TAG "SerialPortJNI"
18
19 #include "utils/Log.h"
20
21 #include "jni.h"
22 #include "JNIHelp.h"
23 #include "core_jni_helpers.h"
24
25 #include <stdio.h>
26 #include <sys/types.h>
27 #include <sys/stat.h>
28 #include <fcntl.h>
29 #include <termios.h>
30
31 using namespace android;
32
33 static jfieldID field_context;
34
35 static void
android_hardware_SerialPort_open(JNIEnv * env,jobject thiz,jobject fileDescriptor,jint speed)36 android_hardware_SerialPort_open(JNIEnv *env, jobject thiz, jobject fileDescriptor, jint speed)
37 {
38 switch (speed) {
39 case 50:
40 speed = B50;
41 break;
42 case 75:
43 speed = B75;
44 break;
45 case 110:
46 speed = B110;
47 break;
48 case 134:
49 speed = B134;
50 break;
51 case 150:
52 speed = B150;
53 break;
54 case 200:
55 speed = B200;
56 break;
57 case 300:
58 speed = B300;
59 break;
60 case 600:
61 speed = B600;
62 break;
63 case 1200:
64 speed = B1200;
65 break;
66 case 1800:
67 speed = B1800;
68 break;
69 case 2400:
70 speed = B2400;
71 break;
72 case 4800:
73 speed = B4800;
74 break;
75 case 9600:
76 speed = B9600;
77 break;
78 case 19200:
79 speed = B19200;
80 break;
81 case 38400:
82 speed = B38400;
83 break;
84 case 57600:
85 speed = B57600;
86 break;
87 case 115200:
88 speed = B115200;
89 break;
90 case 230400:
91 speed = B230400;
92 break;
93 case 460800:
94 speed = B460800;
95 break;
96 case 500000:
97 speed = B500000;
98 break;
99 case 576000:
100 speed = B576000;
101 break;
102 case 921600:
103 speed = B921600;
104 break;
105 case 1000000:
106 speed = B1000000;
107 break;
108 case 1152000:
109 speed = B1152000;
110 break;
111 case 1500000:
112 speed = B1500000;
113 break;
114 case 2000000:
115 speed = B2000000;
116 break;
117 case 2500000:
118 speed = B2500000;
119 break;
120 case 3000000:
121 speed = B3000000;
122 break;
123 case 3500000:
124 speed = B3500000;
125 break;
126 case 4000000:
127 speed = B4000000;
128 break;
129 default:
130 jniThrowException(env, "java/lang/IllegalArgumentException",
131 "Unsupported serial port speed");
132 return;
133 }
134
135 int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
136 // duplicate the file descriptor, since ParcelFileDescriptor will eventually close its copy
137 fd = dup(fd);
138 if (fd < 0) {
139 jniThrowException(env, "java/io/IOException", "Could not open serial port");
140 return;
141 }
142 env->SetIntField(thiz, field_context, fd);
143
144 struct termios tio;
145 if (tcgetattr(fd, &tio))
146 memset(&tio, 0, sizeof(tio));
147
148 tio.c_cflag = speed | CS8 | CLOCAL | CREAD;
149 // Disable output processing, including messing with end-of-line characters.
150 tio.c_oflag &= ~OPOST;
151 tio.c_iflag = IGNPAR;
152 tio.c_lflag = 0; /* turn of CANON, ECHO*, etc */
153 /* no timeout but request at least one character per read */
154 tio.c_cc[VTIME] = 0;
155 tio.c_cc[VMIN] = 1;
156 tcsetattr(fd, TCSANOW, &tio);
157 tcflush(fd, TCIFLUSH);
158 }
159
160 static void
android_hardware_SerialPort_close(JNIEnv * env,jobject thiz)161 android_hardware_SerialPort_close(JNIEnv *env, jobject thiz)
162 {
163 int fd = env->GetIntField(thiz, field_context);
164 close(fd);
165 env->SetIntField(thiz, field_context, -1);
166 }
167
168 static jint
android_hardware_SerialPort_read_array(JNIEnv * env,jobject thiz,jbyteArray buffer,jint length)169 android_hardware_SerialPort_read_array(JNIEnv *env, jobject thiz, jbyteArray buffer, jint length)
170 {
171 int fd = env->GetIntField(thiz, field_context);
172 jbyte* buf = (jbyte *)malloc(length);
173 if (!buf) {
174 jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
175 return -1;
176 }
177
178 int ret = read(fd, buf, length);
179 if (ret > 0) {
180 // copy data from native buffer to Java buffer
181 env->SetByteArrayRegion(buffer, 0, ret, buf);
182 }
183
184 free(buf);
185 if (ret < 0)
186 jniThrowException(env, "java/io/IOException", NULL);
187 return ret;
188 }
189
190 static jint
android_hardware_SerialPort_read_direct(JNIEnv * env,jobject thiz,jobject buffer,jint length)191 android_hardware_SerialPort_read_direct(JNIEnv *env, jobject thiz, jobject buffer, jint length)
192 {
193 int fd = env->GetIntField(thiz, field_context);
194
195 jbyte* buf = (jbyte *)env->GetDirectBufferAddress(buffer);
196 if (!buf) {
197 jniThrowException(env, "java/lang/IllegalArgumentException", "ByteBuffer not direct");
198 return -1;
199 }
200
201 int ret = read(fd, buf, length);
202 if (ret < 0)
203 jniThrowException(env, "java/io/IOException", NULL);
204 return ret;
205 }
206
207 static void
android_hardware_SerialPort_write_array(JNIEnv * env,jobject thiz,jbyteArray buffer,jint length)208 android_hardware_SerialPort_write_array(JNIEnv *env, jobject thiz, jbyteArray buffer, jint length)
209 {
210 int fd = env->GetIntField(thiz, field_context);
211 jbyte* buf = (jbyte *)malloc(length);
212 if (!buf) {
213 jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
214 return;
215 }
216 env->GetByteArrayRegion(buffer, 0, length, buf);
217
218 jint ret = write(fd, buf, length);
219 free(buf);
220 if (ret < 0)
221 jniThrowException(env, "java/io/IOException", NULL);
222 }
223
224 static void
android_hardware_SerialPort_write_direct(JNIEnv * env,jobject thiz,jobject buffer,jint length)225 android_hardware_SerialPort_write_direct(JNIEnv *env, jobject thiz, jobject buffer, jint length)
226 {
227 int fd = env->GetIntField(thiz, field_context);
228
229 jbyte* buf = (jbyte *)env->GetDirectBufferAddress(buffer);
230 if (!buf) {
231 jniThrowException(env, "java/lang/IllegalArgumentException", "ByteBuffer not direct");
232 return;
233 }
234 int ret = write(fd, buf, length);
235 if (ret < 0)
236 jniThrowException(env, "java/io/IOException", NULL);
237 }
238
239 static void
android_hardware_SerialPort_send_break(JNIEnv * env,jobject thiz)240 android_hardware_SerialPort_send_break(JNIEnv *env, jobject thiz)
241 {
242 int fd = env->GetIntField(thiz, field_context);
243 tcsendbreak(fd, 0);
244 }
245
246 static JNINativeMethod method_table[] = {
247 {"native_open", "(Ljava/io/FileDescriptor;I)V",
248 (void *)android_hardware_SerialPort_open},
249 {"native_close", "()V", (void *)android_hardware_SerialPort_close},
250 {"native_read_array", "([BI)I",
251 (void *)android_hardware_SerialPort_read_array},
252 {"native_read_direct", "(Ljava/nio/ByteBuffer;I)I",
253 (void *)android_hardware_SerialPort_read_direct},
254 {"native_write_array", "([BI)V",
255 (void *)android_hardware_SerialPort_write_array},
256 {"native_write_direct", "(Ljava/nio/ByteBuffer;I)V",
257 (void *)android_hardware_SerialPort_write_direct},
258 {"native_send_break", "()V", (void *)android_hardware_SerialPort_send_break},
259 };
260
register_android_hardware_SerialPort(JNIEnv * env)261 int register_android_hardware_SerialPort(JNIEnv *env)
262 {
263 jclass clazz = FindClassOrDie(env, "android/hardware/SerialPort");
264 field_context = GetFieldIDOrDie(env, clazz, "mNativeContext", "I");
265
266 return RegisterMethodsOrDie(env, "android/hardware/SerialPort",
267 method_table, NELEM(method_table));
268 }
269