blob: 3ff24468e3aa66f069f930b2b49475e173566957 [file] [log] [blame]
Mike Lockwoodb01e8bf2011-08-29 20:11:07 -04001/*
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"
Steven Moreland2279b252017-07-19 09:50:45 -070022#include <nativehelper/JNIHelp.h>
Andreas Gampeed6b9df2014-11-20 22:02:20 -080023#include "core_jni_helpers.h"
Mike Lockwoodb01e8bf2011-08-29 20:11:07 -040024
25#include <stdio.h>
26#include <sys/types.h>
27#include <sys/stat.h>
28#include <fcntl.h>
29#include <termios.h>
30
31using namespace android;
32
33static jfieldID field_context;
34
35static void
36android_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
Nick Kralevich4b3a08c2019-01-28 10:39:10 -0800137 fd = fcntl(fd, F_DUPFD_CLOEXEC, 0);
Mike Lockwoodb01e8bf2011-08-29 20:11:07 -0400138 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;
Girts Folkmanisd3622e92011-10-13 17:24:43 -0700149 // Disable output processing, including messing with end-of-line characters.
150 tio.c_oflag &= ~OPOST;
Mike Lockwoodb01e8bf2011-08-29 20:11:07 -0400151 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
160static void
161android_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
168static jint
169android_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
190static jint
191android_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
207static void
208android_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
224static void
225android_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
Mike Lockwood7dbc4b42011-09-23 11:43:42 -0400239static void
240android_hardware_SerialPort_send_break(JNIEnv *env, jobject thiz)
241{
242 int fd = env->GetIntField(thiz, field_context);
243 tcsendbreak(fd, 0);
244}
245
Daniel Micay76f6a862015-09-19 17:31:01 -0400246static const JNINativeMethod method_table[] = {
Mike Lockwoodb01e8bf2011-08-29 20:11:07 -0400247 {"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},
Mike Lockwood7dbc4b42011-09-23 11:43:42 -0400258 {"native_send_break", "()V", (void *)android_hardware_SerialPort_send_break},
Mike Lockwoodb01e8bf2011-08-29 20:11:07 -0400259};
260
261int register_android_hardware_SerialPort(JNIEnv *env)
262{
Andreas Gampeed6b9df2014-11-20 22:02:20 -0800263 jclass clazz = FindClassOrDie(env, "android/hardware/SerialPort");
264 field_context = GetFieldIDOrDie(env, clazz, "mNativeContext", "I");
Mike Lockwoodb01e8bf2011-08-29 20:11:07 -0400265
Andreas Gampeed6b9df2014-11-20 22:02:20 -0800266 return RegisterMethodsOrDie(env, "android/hardware/SerialPort",
Mike Lockwoodb01e8bf2011-08-29 20:11:07 -0400267 method_table, NELEM(method_table));
268}