Home | History | Annotate | Download | only in jni
      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