blob: e67153bcfabff52d3864bf7935d475d7c98c3758 [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"
22#include "JNIHelp.h"
23#include "android_runtime/AndroidRuntime.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
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
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 tio.c_iflag = IGNPAR;
150 tio.c_lflag = 0; /* turn of CANON, ECHO*, etc */
151 /* no timeout but request at least one character per read */
152 tio.c_cc[VTIME] = 0;
153 tio.c_cc[VMIN] = 1;
154 tcsetattr(fd, TCSANOW, &tio);
155 tcflush(fd, TCIFLUSH);
156}
157
158static void
159android_hardware_SerialPort_close(JNIEnv *env, jobject thiz)
160{
161 int fd = env->GetIntField(thiz, field_context);
162 close(fd);
163 env->SetIntField(thiz, field_context, -1);
164}
165
166static jint
167android_hardware_SerialPort_read_array(JNIEnv *env, jobject thiz, jbyteArray buffer, jint length)
168{
169 int fd = env->GetIntField(thiz, field_context);
170 jbyte* buf = (jbyte *)malloc(length);
171 if (!buf) {
172 jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
173 return -1;
174 }
175
176 int ret = read(fd, buf, length);
177 if (ret > 0) {
178 // copy data from native buffer to Java buffer
179 env->SetByteArrayRegion(buffer, 0, ret, buf);
180 }
181
182 free(buf);
183 if (ret < 0)
184 jniThrowException(env, "java/io/IOException", NULL);
185 return ret;
186}
187
188static jint
189android_hardware_SerialPort_read_direct(JNIEnv *env, jobject thiz, jobject buffer, jint length)
190{
191 int fd = env->GetIntField(thiz, field_context);
192
193 jbyte* buf = (jbyte *)env->GetDirectBufferAddress(buffer);
194 if (!buf) {
195 jniThrowException(env, "java/lang/IllegalArgumentException", "ByteBuffer not direct");
196 return -1;
197 }
198
199 int ret = read(fd, buf, length);
200 if (ret < 0)
201 jniThrowException(env, "java/io/IOException", NULL);
202 return ret;
203}
204
205static void
206android_hardware_SerialPort_write_array(JNIEnv *env, jobject thiz, jbyteArray buffer, jint length)
207{
208 int fd = env->GetIntField(thiz, field_context);
209 jbyte* buf = (jbyte *)malloc(length);
210 if (!buf) {
211 jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
212 return;
213 }
214 env->GetByteArrayRegion(buffer, 0, length, buf);
215
216 jint ret = write(fd, buf, length);
217 free(buf);
218 if (ret < 0)
219 jniThrowException(env, "java/io/IOException", NULL);
220}
221
222static void
223android_hardware_SerialPort_write_direct(JNIEnv *env, jobject thiz, jobject buffer, jint length)
224{
225 int fd = env->GetIntField(thiz, field_context);
226
227 jbyte* buf = (jbyte *)env->GetDirectBufferAddress(buffer);
228 if (!buf) {
229 jniThrowException(env, "java/lang/IllegalArgumentException", "ByteBuffer not direct");
230 return;
231 }
232 int ret = write(fd, buf, length);
233 if (ret < 0)
234 jniThrowException(env, "java/io/IOException", NULL);
235}
236
237static JNINativeMethod method_table[] = {
238 {"native_open", "(Ljava/io/FileDescriptor;I)V",
239 (void *)android_hardware_SerialPort_open},
240 {"native_close", "()V", (void *)android_hardware_SerialPort_close},
241 {"native_read_array", "([BI)I",
242 (void *)android_hardware_SerialPort_read_array},
243 {"native_read_direct", "(Ljava/nio/ByteBuffer;I)I",
244 (void *)android_hardware_SerialPort_read_direct},
245 {"native_write_array", "([BI)V",
246 (void *)android_hardware_SerialPort_write_array},
247 {"native_write_direct", "(Ljava/nio/ByteBuffer;I)V",
248 (void *)android_hardware_SerialPort_write_direct},
249};
250
251int register_android_hardware_SerialPort(JNIEnv *env)
252{
253 jclass clazz = env->FindClass("android/hardware/SerialPort");
254 if (clazz == NULL) {
255 ALOGE("Can't find android/hardware/SerialPort");
256 return -1;
257 }
258 field_context = env->GetFieldID(clazz, "mNativeContext", "I");
259 if (field_context == NULL) {
260 ALOGE("Can't find SerialPort.mNativeContext");
261 return -1;
262 }
263
264 return AndroidRuntime::registerNativeMethods(env, "android/hardware/SerialPort",
265 method_table, NELEM(method_table));
266}