/* * Copyright 2009 Cedric Priscal * * 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. */ #include #include #include #include #include #include #include #include "android/log.h" static const char *TAG="serial_port"; #define LOGI(fmt, args...) __android_log_print(ANDROID_LOG_INFO, TAG, fmt, ##args) #define LOGD(fmt, args...) __android_log_print(ANDROID_LOG_DEBUG, TAG, fmt, ##args) #define LOGE(fmt, args...) __android_log_print(ANDROID_LOG_ERROR, TAG, fmt, ##args) #ifdef __cplusplus extern "C" { #endif /* * Class: com_android_barcode_SerialPort * Method: open * Signature: (Ljava/lang/String;I)I */ JNIEXPORT jint JNICALL Java_com_android_barcode_SerialPort_open (JNIEnv *, jclass, jstring, jint); /* * Class: com_android_barcode_SerialPort * Method: write * Signature: (ILjava/lang/String;I)I */ JNIEXPORT jint JNICALL Java_com_android_barcode_SerialPort_write (JNIEnv *, jobject, jint, jstring, jint); /* * Class: com_android_barcode_SerialPort * Method: read * Signature: (II)[B */ JNIEXPORT jbyteArray JNICALL Java_com_android_barcode_SerialPort_read (JNIEnv *, jobject, jint, jint); /* * Class: com_android_barcode_SerialPort * Method: close * Signature: (I)V */ JNIEXPORT void JNICALL Java_com_android_barcode_SerialPort_close (JNIEnv *, jobject, jint); #ifdef __cplusplus } #endif static speed_t getBaudrate(jint baudrate) { switch(baudrate) { case 0: return B0; case 50: return B50; case 75: return B75; case 110: return B110; case 134: return B134; case 150: return B150; case 200: return B200; case 300: return B300; case 600: return B600; case 1200: return B1200; case 1800: return B1800; case 2400: return B2400; case 4800: return B4800; case 9600: return B9600; case 19200: return B19200; case 38400: return B38400; case 57600: return B57600; case 115200: return B115200; case 230400: return B230400; case 460800: return B460800; case 500000: return B500000; case 576000: return B576000; case 921600: return B921600; case 1000000: return B1000000; case 1152000: return B1152000; case 1500000: return B1500000; case 2000000: return B2000000; case 2500000: return B2500000; case 3000000: return B3000000; case 3500000: return B3500000; case 4000000: return B4000000; default: return -1; } } /* * Class: cedric_serial_SerialPort * Method: open * Signature: (Ljava/lang/String;)V */ JNIEXPORT jint JNICALL Java_com_android_barcode_SerialPort_open (JNIEnv *env, jobject thiz, jstring path, jint baudrate) { int fd; speed_t speed; /* Check arguments */ { speed = getBaudrate(baudrate); if (speed == -1) { /* TODO: throw an exception */ LOGE("Invalid baudrate"); } } /* Opening device */ { jboolean iscopy; const char *path_utf = (*env)->GetStringUTFChars(env, path, &iscopy); LOGD("Opening serial port %s", path_utf); fd = open(path_utf, O_RDWR | O_SYNC); LOGD("open() fd = %d", fd); (*env)->ReleaseStringUTFChars(env, path, path_utf); if (fd == -1) { /* Throw an exception */ LOGE("Cannot open port"); /* TODO: throw an exception */ } } /* Configure device */ { struct termios cfg; LOGD("Configuring serial port"); if (tcgetattr(fd, &cfg)) { LOGE("tcgetattr() failed"); close(fd); /* TODO: throw an exception */ } cfmakeraw(&cfg); cfsetispeed(&cfg, speed); cfsetospeed(&cfg, speed); /*******************************/ cfg.c_cflag &= ~CSIZE; cfg.c_lflag &= ~(ICANON|ECHO|ECHOE|ISIG); cfg.c_oflag &= ~OPOST; //'8' bit cfg.c_cflag |= CS8; //'N' PARENB cfg.c_cflag &= ~PARENB; cfg.c_iflag &= ~INPCK; //'1' STOP cfg.c_cflag &= ~CSTOPB; cfg.c_cc[VTIME] = 15; cfg.c_cc[VMIN] = 0; tcflush(fd, TCIFLUSH); /*********************************/ if (tcsetattr(fd, TCSANOW, &cfg)) { LOGE("tcsetattr() failed"); close(fd); /* TODO: throw an exception */ } } return fd; } /* * Class: cedric_serial_SerialPort * Method: write * Signature: ()V */ JNIEXPORT jint JNICALL Java_com_android_barcode_SerialPort_write (JNIEnv *env, jobject obj, jint fd, jstring str, jint len) { jboolean iscopy; const char *buff_utf = (*env)->GetStringUTFChars(env, str, &iscopy); int wlen = 0; wlen = write(fd, buff_utf, len); if(wlen > 0) { LOGD("Write serial port %s\n", buff_utf); } else { LOGE("Write failed\n"); } (*env)->ReleaseStringUTFChars(env, str, buff_utf); LOGD("Write finish!\n"); return wlen; } /* * Class: cedric_serial_SerialPort * Method: read * Signature: ()V */ JNIEXPORT jbyteArray JNICALL Java_com_android_barcode_SerialPort_read (JNIEnv *env, jobject obj, jint fd, jint len) { int reval; int nread = 0; char buff[len]; char result[len]; struct timeval tv; jbyteArray jba; fd_set rfds; while(1) { FD_ZERO(&rfds); FD_SET(fd, &rfds); tv.tv_sec = 0; tv.tv_usec = 100000; if ((reval = select(1 + fd, &rfds, NULL, NULL, &tv)) > 0) { if(FD_ISSET(fd, &rfds)) { int temp = read(fd, buff + nread, len); nread += temp; LOGD("%i us is used", 100000 - tv.tv_usec); LOGD("wo have data %d\n", temp); } } else if(reval == 0 && nread != 0) //timeout means { // int ffd; buff[nread]=0; // ffd = open("/data/ndk", O_WRONLY | O_TRUNC); // write(ffd, buff, nread); // close(ffd); int i, j; for(i = 0, j = 0; i < nread; i++) { if(buff[i] != 0) { result[j] = buff[i]; j++; } // LOGD("0x%2x ", buff[i]); } //LOGD("\n"); //result[j] = 0; jba = (*env)->NewByteArray(env, j); (*env)->SetByteArrayRegion(env, jba, 0, j, result); /* jba = (*env)->NewByteArray(env, nread); (*env)->SetByteArrayRegion(env, jba, 0, nread, buff);*/ LOGD("readlength=%d\n, reallength=%d\n, all data received!\n", nread, j); return jba; } else { return NULL; } } } /* * Class: cedric_serial_SerialPort * Method: close * Signature: ()V */ JNIEXPORT void JNICALL Java_com_android_barcode_SerialPort_close (JNIEnv *env, jobject obj, jint fd) { close(fd); }