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 "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 31 using namespace android; 32 33 static jfieldID field_context; 34 35 static void 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 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 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 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 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 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 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 261 int register_android_hardware_SerialPort(JNIEnv *env) 262 { 263 jclass clazz = env->FindClass("android/hardware/SerialPort"); 264 if (clazz == NULL) { 265 ALOGE("Can't find android/hardware/SerialPort"); 266 return -1; 267 } 268 field_context = env->GetFieldID(clazz, "mNativeContext", "I"); 269 if (field_context == NULL) { 270 ALOGE("Can't find SerialPort.mNativeContext"); 271 return -1; 272 } 273 274 return AndroidRuntime::registerNativeMethods(env, "android/hardware/SerialPort", 275 method_table, NELEM(method_table)); 276 } 277