add commit
This commit is contained in:
149
app/src/main/cpp/SerialPort.c
Normal file
149
app/src/main/cpp/SerialPort.c
Normal file
@@ -0,0 +1,149 @@
|
||||
#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);
|
||||
}
|
||||
Reference in New Issue
Block a user