150 lines
4.7 KiB
C
150 lines
4.7 KiB
C
#include "SerialPort.h"
|
|
|
|
#include <termios.h>
|
|
#include <pthread.h>
|
|
#include <unistd.h>
|
|
|
|
#define MAX_THREAD_LIMIT 32
|
|
|
|
|
|
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;
|
|
}
|
|
}
|
|
|
|
struct {
|
|
pthread_t tid;
|
|
jobject clazz;
|
|
} threads[MAX_THREAD_LIMIT];
|
|
JavaVM *vm;
|
|
jfieldID mFD;
|
|
jmethodID onNativeData;
|
|
|
|
void *comm_read() {
|
|
JNIEnv *env;
|
|
(*vm)->AttachCurrentThread(vm, &env, NULL);
|
|
jclass clazz = NULL;
|
|
for (int i = 0; i < MAX_THREAD_LIMIT; i++) {
|
|
if (pthread_equal(pthread_self(), threads[i].tid)) {
|
|
clazz = threads[i].clazz;
|
|
if (mFD == NULL || onNativeData == NULL) {
|
|
jclass obj = (*env)->GetObjectClass(env, clazz);
|
|
mFD = (*env)->GetFieldID(env, obj, "mFD", "I");
|
|
onNativeData = (*env)->GetMethodID(env, obj, "onNativeData", "([B)V");
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
if (clazz != NULL) {
|
|
int fd;
|
|
while ((fd = (*env)->GetIntField(env, clazz, mFD)) != -1) {
|
|
int size = 1024;
|
|
jbyte data[size];
|
|
int len = read(fd, data, size);
|
|
if (len > 0) {
|
|
jbyteArray bytes = (*env)->NewByteArray(env, len);
|
|
(*env)->SetByteArrayRegion(env, bytes, 0, len, data);
|
|
(*env)->CallVoidMethod(env, clazz, onNativeData, bytes);
|
|
} else if (len < 0) {
|
|
// DETECT: Hardware level error (e.g. unplugged)
|
|
// Send a specific error byte like 0x0E to trigger the Error result in Repository
|
|
jbyteArray errorBytes = (*env)->NewByteArray(env, 1);
|
|
jbyte err = 0x0E;
|
|
(*env)->SetByteArrayRegion(env, errorBytes, 0, 1, &err);
|
|
(*env)->CallVoidMethod(env, clazz, onNativeData, errorBytes);
|
|
}
|
|
usleep(10000);
|
|
}
|
|
}
|
|
if (vm != NULL) {
|
|
int isFree = 1;
|
|
for (int i = 0; i < MAX_THREAD_LIMIT; i++) {
|
|
if (threads[i].clazz != NULL) {
|
|
if (threads[i].clazz == clazz) {
|
|
(*env)->DeleteGlobalRef(env, clazz);
|
|
threads[i].clazz = clazz = NULL;
|
|
} else {
|
|
isFree = 0;
|
|
if (clazz == NULL) break;
|
|
}
|
|
}
|
|
}
|
|
(*vm)->DetachCurrentThread(vm);
|
|
if (isFree) {
|
|
onNativeData = NULL;
|
|
mFD = NULL;
|
|
vm = NULL;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
JNIEXPORT void JNICALL
|
|
Java_com_laseroptek_raman_data_source_serial_SerialPort_open(JNIEnv *env, jclass clazz, int fd, int baudrate) {
|
|
tcflush(fd, TCIOFLUSH);
|
|
struct termios cfg;
|
|
tcgetattr(fd, &cfg);
|
|
cfmakeraw(&cfg);
|
|
speed_t speed = getBaudrate(baudrate);
|
|
cfsetispeed(&cfg, speed);
|
|
cfsetospeed(&cfg, speed);
|
|
tcsetattr(fd, TCSANOW, &cfg);
|
|
for (int i = 0; i < MAX_THREAD_LIMIT; i++) {
|
|
if (threads[i].clazz == NULL) {
|
|
if (vm == NULL) {
|
|
(*env)->GetJavaVM(env, &vm);
|
|
}
|
|
threads[i].clazz = (*env)->NewGlobalRef(env, clazz);
|
|
pthread_create(&threads[i].tid, NULL, comm_read, NULL);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
JNIEXPORT void JNICALL
|
|
Java_com_laseroptek_raman_data_source_serial_SerialPort_write(JNIEnv *env, __unused jclass _, int fd, jbyteArray bytes) {
|
|
jbyte *data = (*env)->GetByteArrayElements(env, bytes, NULL);
|
|
if (data != NULL) {
|
|
write(fd, data, (*env)->GetArrayLength(env, bytes));
|
|
(*env)->ReleaseByteArrayElements(env, bytes, data, JNI_ABORT);
|
|
}
|
|
}
|
|
|
|
JNIEXPORT void JNICALL
|
|
Java_com_laseroptek_raman_data_source_serial_SerialPort_close(__unused JNIEnv *_, __unused jclass __, int fd) {
|
|
close(fd);
|
|
}
|