diff options
author | Mike Lockwood <lockwood@android.com> | 2011-08-29 20:11:07 -0400 |
---|---|---|
committer | Mike Lockwood <lockwood@google.com> | 2012-02-10 10:51:19 -0800 |
commit | b01e8bf57b7492b77e3445db51471edcbadda75e (patch) | |
tree | efbff9d0094660d195d46322a23ce7bbd1a453ad /core/jni | |
parent | 341ff2b08380fcab0f2313fb4feca732cf70f840 (diff) | |
download | frameworks_base-b01e8bf57b7492b77e3445db51471edcbadda75e.zip frameworks_base-b01e8bf57b7492b77e3445db51471edcbadda75e.tar.gz frameworks_base-b01e8bf57b7492b77e3445db51471edcbadda75e.tar.bz2 |
New Serial Manager API:
SerialManager: provides access to serial ports
SerialPort: for reading and writing data to and from serial ports
IO with both array based and direct ByteBuffers is supported.
Accessing serial ports requires android.permission.SERIAL_PORT permission
Each platform must configure list of supported serial ports in the
config_serialPorts resource overlay
(this is needed to prevent apps from accidentally accessing the bluetooth
or other system UARTs).
In addition, the platform uevent.rc file must set the owner to the
/dev/tty* files to "system" so the framework can access the port.
Signed-off-by: Mike Lockwood <lockwood@android.com>
Diffstat (limited to 'core/jni')
-rw-r--r-- | core/jni/Android.mk | 1 | ||||
-rw-r--r-- | core/jni/AndroidRuntime.cpp | 2 | ||||
-rw-r--r-- | core/jni/android_hardware_SerialPort.cpp | 266 |
3 files changed, 269 insertions, 0 deletions
diff --git a/core/jni/Android.mk b/core/jni/Android.mk index 39b84bb..78e8df3 100644 --- a/core/jni/Android.mk +++ b/core/jni/Android.mk @@ -126,6 +126,7 @@ LOCAL_SRC_FILES:= \ android_media_ToneGenerator.cpp \ android_hardware_Camera.cpp \ android_hardware_SensorManager.cpp \ + android_hardware_SerialPort.cpp \ android_hardware_UsbDevice.cpp \ android_hardware_UsbDeviceConnection.cpp \ android_hardware_UsbRequest.cpp \ diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp index 8a3063f..3067e75 100644 --- a/core/jni/AndroidRuntime.cpp +++ b/core/jni/AndroidRuntime.cpp @@ -76,6 +76,7 @@ extern int register_android_opengl_jni_GLES20(JNIEnv* env); extern int register_android_hardware_Camera(JNIEnv *env); extern int register_android_hardware_SensorManager(JNIEnv *env); +extern int register_android_hardware_SerialPort(JNIEnv *env); extern int register_android_hardware_UsbDevice(JNIEnv *env); extern int register_android_hardware_UsbDeviceConnection(JNIEnv *env); extern int register_android_hardware_UsbRequest(JNIEnv *env); @@ -1157,6 +1158,7 @@ static const RegJNIRec gRegJNI[] = { REG_JNI(register_com_android_internal_os_ZygoteInit), REG_JNI(register_android_hardware_Camera), REG_JNI(register_android_hardware_SensorManager), + REG_JNI(register_android_hardware_SerialPort), REG_JNI(register_android_hardware_UsbDevice), REG_JNI(register_android_hardware_UsbDeviceConnection), REG_JNI(register_android_hardware_UsbRequest), diff --git a/core/jni/android_hardware_SerialPort.cpp b/core/jni/android_hardware_SerialPort.cpp new file mode 100644 index 0000000..e67153b --- /dev/null +++ b/core/jni/android_hardware_SerialPort.cpp @@ -0,0 +1,266 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "SerialPortJNI" + +#include "utils/Log.h" + +#include "jni.h" +#include "JNIHelp.h" +#include "android_runtime/AndroidRuntime.h" + +#include <stdio.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <termios.h> + +using namespace android; + +static jfieldID field_context; + +static void +android_hardware_SerialPort_open(JNIEnv *env, jobject thiz, jobject fileDescriptor, jint speed) +{ + switch (speed) { + case 50: + speed = B50; + break; + case 75: + speed = B75; + break; + case 110: + speed = B110; + break; + case 134: + speed = B134; + break; + case 150: + speed = B150; + break; + case 200: + speed = B200; + break; + case 300: + speed = B300; + break; + case 600: + speed = B600; + break; + case 1200: + speed = B1200; + break; + case 1800: + speed = B1800; + break; + case 2400: + speed = B2400; + break; + case 4800: + speed = B4800; + break; + case 9600: + speed = B9600; + break; + case 19200: + speed = B19200; + break; + case 38400: + speed = B38400; + break; + case 57600: + speed = B57600; + break; + case 115200: + speed = B115200; + break; + case 230400: + speed = B230400; + break; + case 460800: + speed = B460800; + break; + case 500000: + speed = B500000; + break; + case 576000: + speed = B576000; + break; + case 921600: + speed = B921600; + break; + case 1000000: + speed = B1000000; + break; + case 1152000: + speed = B1152000; + break; + case 1500000: + speed = B1500000; + break; + case 2000000: + speed = B2000000; + break; + case 2500000: + speed = B2500000; + break; + case 3000000: + speed = B3000000; + break; + case 3500000: + speed = B3500000; + break; + case 4000000: + speed = B4000000; + break; + default: + jniThrowException(env, "java/lang/IllegalArgumentException", + "Unsupported serial port speed"); + return; + } + + int fd = jniGetFDFromFileDescriptor(env, fileDescriptor); + // duplicate the file descriptor, since ParcelFileDescriptor will eventually close its copy + fd = dup(fd); + if (fd < 0) { + jniThrowException(env, "java/io/IOException", "Could not open serial port"); + return; + } + env->SetIntField(thiz, field_context, fd); + + struct termios tio; + if (tcgetattr(fd, &tio)) + memset(&tio, 0, sizeof(tio)); + + tio.c_cflag = speed | CS8 | CLOCAL | CREAD; + tio.c_iflag = IGNPAR; + tio.c_lflag = 0; /* turn of CANON, ECHO*, etc */ + /* no timeout but request at least one character per read */ + tio.c_cc[VTIME] = 0; + tio.c_cc[VMIN] = 1; + tcsetattr(fd, TCSANOW, &tio); + tcflush(fd, TCIFLUSH); +} + +static void +android_hardware_SerialPort_close(JNIEnv *env, jobject thiz) +{ + int fd = env->GetIntField(thiz, field_context); + close(fd); + env->SetIntField(thiz, field_context, -1); +} + +static jint +android_hardware_SerialPort_read_array(JNIEnv *env, jobject thiz, jbyteArray buffer, jint length) +{ + int fd = env->GetIntField(thiz, field_context); + jbyte* buf = (jbyte *)malloc(length); + if (!buf) { + jniThrowException(env, "java/lang/OutOfMemoryError", NULL); + return -1; + } + + int ret = read(fd, buf, length); + if (ret > 0) { + // copy data from native buffer to Java buffer + env->SetByteArrayRegion(buffer, 0, ret, buf); + } + + free(buf); + if (ret < 0) + jniThrowException(env, "java/io/IOException", NULL); + return ret; +} + +static jint +android_hardware_SerialPort_read_direct(JNIEnv *env, jobject thiz, jobject buffer, jint length) +{ + int fd = env->GetIntField(thiz, field_context); + + jbyte* buf = (jbyte *)env->GetDirectBufferAddress(buffer); + if (!buf) { + jniThrowException(env, "java/lang/IllegalArgumentException", "ByteBuffer not direct"); + return -1; + } + + int ret = read(fd, buf, length); + if (ret < 0) + jniThrowException(env, "java/io/IOException", NULL); + return ret; +} + +static void +android_hardware_SerialPort_write_array(JNIEnv *env, jobject thiz, jbyteArray buffer, jint length) +{ + int fd = env->GetIntField(thiz, field_context); + jbyte* buf = (jbyte *)malloc(length); + if (!buf) { + jniThrowException(env, "java/lang/OutOfMemoryError", NULL); + return; + } + env->GetByteArrayRegion(buffer, 0, length, buf); + + jint ret = write(fd, buf, length); + free(buf); + if (ret < 0) + jniThrowException(env, "java/io/IOException", NULL); +} + +static void +android_hardware_SerialPort_write_direct(JNIEnv *env, jobject thiz, jobject buffer, jint length) +{ + int fd = env->GetIntField(thiz, field_context); + + jbyte* buf = (jbyte *)env->GetDirectBufferAddress(buffer); + if (!buf) { + jniThrowException(env, "java/lang/IllegalArgumentException", "ByteBuffer not direct"); + return; + } + int ret = write(fd, buf, length); + if (ret < 0) + jniThrowException(env, "java/io/IOException", NULL); +} + +static JNINativeMethod method_table[] = { + {"native_open", "(Ljava/io/FileDescriptor;I)V", + (void *)android_hardware_SerialPort_open}, + {"native_close", "()V", (void *)android_hardware_SerialPort_close}, + {"native_read_array", "([BI)I", + (void *)android_hardware_SerialPort_read_array}, + {"native_read_direct", "(Ljava/nio/ByteBuffer;I)I", + (void *)android_hardware_SerialPort_read_direct}, + {"native_write_array", "([BI)V", + (void *)android_hardware_SerialPort_write_array}, + {"native_write_direct", "(Ljava/nio/ByteBuffer;I)V", + (void *)android_hardware_SerialPort_write_direct}, +}; + +int register_android_hardware_SerialPort(JNIEnv *env) +{ + jclass clazz = env->FindClass("android/hardware/SerialPort"); + if (clazz == NULL) { + ALOGE("Can't find android/hardware/SerialPort"); + return -1; + } + field_context = env->GetFieldID(clazz, "mNativeContext", "I"); + if (field_context == NULL) { + ALOGE("Can't find SerialPort.mNativeContext"); + return -1; + } + + return AndroidRuntime::registerNativeMethods(env, "android/hardware/SerialPort", + method_table, NELEM(method_table)); +} |