Newer
Older
ElectricDetector / app / src / main / cpp / serialPort.cpp
#include <termios.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <cstring>
#include <jni.h>

#include "android/log.h"

#define  LOG_TAG    "SerialPortJNI"

#define LOG_D(fmt, args...) __android_log_print(ANDROID_LOG_DEBUG,  LOG_TAG, fmt, ##args)
#define LOG_E(fmt, args...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, fmt, ##args)

static speed_t get_baud_rate(jint baud_rate) {
    switch (baud_rate) {
        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;
    }
}

extern "C"
JNIEXPORT jobject JNICALL
Java_com_casic_electric_detector_uart_SerialPort_open(JNIEnv *env, jobject thiz, jstring path,
                                                      jint baud_rate, jint flags) {
    int fd;
    speed_t speed;
    jobject file_descriptor;

    speed = get_baud_rate(baud_rate);
    if (speed == -1) {
        LOG_E("invalid baud_rate");
        return nullptr;
    }

    jboolean is_copy;
    const char *path_utf = env->GetStringUTFChars(path, &is_copy);
    fd = open(path_utf, O_RDWR | flags);
    LOG_D("open serial port %s with flags 0x%x", path_utf, O_RDWR | flags);
    env->ReleaseStringUTFChars(path, path_utf);
    if (fd == -1) {
        LOG_E("can not open Port");
        return nullptr;
    }

    struct termios cfg{};
    LOG_D("configure serial port %d", fd);
    if (tcgetattr(fd, &cfg)) {
        LOG_E("tcgetattr() failed");
        close(fd);
        return nullptr;
    }

    cfmakeraw(&cfg);
    cfsetispeed(&cfg, speed);
    cfsetospeed(&cfg, speed);

    if (tcsetattr(fd, TCSANOW, &cfg)) {
        LOG_E("tcsetattr() failed");
        close(fd);
        return nullptr;
    }

    //获取句柄
    jclass fd_class = env->FindClass("java/io/FileDescriptor");
    jmethodID fd_method_id = env->GetMethodID(fd_class, "<init>", "()V");

    char descriptor_buffer[16] = {0};
    strcat(descriptor_buffer, "descriptor");
    jfieldID descriptor_field_id = env->GetFieldID(fd_class, descriptor_buffer, "I");

    file_descriptor = env->NewObject(fd_class, fd_method_id);
    env->SetIntField(file_descriptor, descriptor_field_id, (jint) fd);

    return file_descriptor;
}

extern "C"
JNIEXPORT void JNICALL
Java_com_casic_electric_detector_uart_SerialPort_close(JNIEnv *env, jobject thiz) {
    jclass serial_port_class = env->GetObjectClass(thiz);
    jclass file_descriptor_class = env->FindClass("java/io/FileDescriptor");

    // fd 对应SerialPortKit里面的 fd
    char fd_buffer[4] = {0};
    strcat(fd_buffer, "fd");
    jfieldID fd_field_id = env->GetFieldID(serial_port_class, fd_buffer,
                                           "Ljava/io/FileDescriptor;");

    char descriptor_buffer[16] = {0};
    strcat(descriptor_buffer, "descriptor");
    jfieldID descriptor_field_id = env->GetFieldID(file_descriptor_class, descriptor_buffer, "I");

    jobject fd_obj = env->GetObjectField(thiz, fd_field_id);
    jint descriptor = env->GetIntField(fd_obj, descriptor_field_id);

    LOG_D("close(fd = %d)", descriptor);
    close(descriptor);
}