Не удается получить доступ к целочисленному полю через проект JNI в Android - PullRequest
0 голосов
/ 04 декабря 2018

У меня есть проект Android, для которого у меня есть следующий код в моем файле c

JNIEXPORT void JNICALL Java_com_mersoft_labconco_controller_JNIStore_closeUART
        (JNIEnv *env, jobject thiz) {
    jclass SerialPortClass = (*env)->GetObjectClass(env, thiz);
    jclass FileDescriptorClass = (*env)->FindClass(env, "java/io/FileDescriptor");

    jfieldID mFdID = (*env)->GetFieldID(env, SerialPortClass, "fileDescriptor", "Ljava/io/FileDescriptor;");
    jfieldID descriptorID = (*env)->GetFieldID(env, FileDescriptorClass, "descriptor", "I");

    jobject mFd = (*env)->GetObjectField(env, thiz, mFdID);
    jint descriptor = (*env)->GetIntField(env, mFd, descriptorID);
//  LOGE("Closing port: %i", descriptor);
    close(descriptor);
}

И я предоставляю все свои методы JNI в отдельном классе с именем JNITStore

class JNIStore {

    @Synchronized
    @Throws(IOBException::class, IOBI2cReadException::class)
    external fun sendAndReceiveCommandi2c(array: ByteArray, numberOfRequestBytes: Int, numberOfResponseBytes: Int, address: Int): ByteArray

    var fileDescriptor: FileDescriptor? = null

    external fun openUART(): FileDescriptor

    external fun closeUART()

    @Synchronized
    external fun updateAccessory(filename: String): Boolean

    init {
        System.loadLibrary("main")
    }
}

Это дает мне сообщение об ошибке:

ОШИБКА JNI: GetIntField для недопустимой ссылки (0x0)

Насколько я могу судить, мой код на C правильно установленвверх по файловому дескриптору, чтобы получить его целочисленное поле здесь

jint descriptor = (*env)->GetIntField(env, mFd, descriptorID);

Единственная причина, по которой я мог подумать, что он возвращает неверную ссылку, заключается в том, что он может быть нулевым значением, так как он инициализируется как таковой, но это я даю ему значение до того, как этот closeUart вызов функции сделан.

Есть ли что-нибудь еще, что может быть причиной этого?

РЕДАКТИРОВАТЬ: Вот код для openUART

JNIEXPORT jobject JNICALL Java_com_mersoft_labconco_controller_JNISTORE_openUART
        (JNIEnv *env, jclass thiz) {
    int baudrate = 115200;
    int fd;
    speed_t speed;
    jobject mFileDescriptor;
    struct serial_rs485 rs485conf;
    speed = getBaudrate(baudrate);
    if (speed == -1) {
        LOGE("Invalid baudrate");
        throwJavaException(env, "Invalid baudrate");
        return NULL;
    }
    fd = open("/dev/ttyO1", O_RDWR);
    if (fd == -1) {
        /* Throw an exception */
        LOGE("Cannot open port");
        throwJavaException(env, "Cannot open port");
        return NULL;
    }
//  LOGE("Opened port %i", fd);

    struct termios cfg;
    if (tcgetattr(fd, &cfg)) {
        LOGE("tcgetattr() failed");
        close(fd);
        throwJavaException(env, "tcgetattr() failed");
        return NULL;
    }

    cfmakeraw(&cfg);
    cfsetispeed(&cfg, speed);
    cfsetospeed(&cfg, speed);
    cfg.c_cflag |= PARODD;
    cfg.c_cflag |= PARENB;
    cfg.c_cflag |= (CLOCAL | CREAD);
    cfg.c_cflag |= CSTOPB;

    //test Flags
//  cfg.c_iflag |= (IXON | IXOFF | IXANY);
//  cfg.c_iflag |= (INPCK | ISTRIP);
//  cfg.c_iflag |= (ISTRIP | PARMRK);


    if (tcsetattr(fd, TCSANOW, &cfg)) {
        LOGE("tcsetattr() failed");
        close(fd);
        throwJavaException(env, "tcsetattr() failed");
        return NULL;
    }

    rs485conf.flags |= SER_RS485_ENABLED;
    rs485conf.flags |= SER_RS485_RTS_ON_SEND;
    rs485conf.flags |= SER_RS485_RTS_AFTER_SEND;
//    rs485conf.flags &= ~SER_RS485_RTS_AFTER_SEND;
    //rs485conf.flags |= SER_RS485_USE_GPIO;
    //rs485conf.gpio_pin  = 13;//13;

    if (ioctl(fd, TIOCSRS485, &rs485conf) < 0) {
        LOGE("ioctl error\n");
    }

    jclass cFileDescriptor = (*env)->FindClass(env, "java/io/FileDescriptor");
    jmethodID iFileDescriptor = (*env)->GetMethodID(env, cFileDescriptor, "<init>", "()V");
    jfieldID descriptorID = (*env)->GetFieldID(env, cFileDescriptor, "descriptor", "I");
    mFileDescriptor = (*env)->NewObject(env, cFileDescriptor, iFileDescriptor);
    (*env)->SetIntField(env, mFileDescriptor, descriptorID, (jint) fd);

    return mFileDescriptor;
}

1 Ответ

0 голосов
/ 04 декабря 2018

Эта строка

jobject mFd = (*env)->GetObjectField(env, thiz, mFdID);

вернет null, потому что ваш код kotlin никогда не инициализирует его для действительной ссылки на объект, но null, см. Ваш код:

var fileDescriptor: FileDescriptor? = null

Итак, ниже строки

jint descriptor = (*env)->GetIntField(env, mFd, descriptorID); 

пытается получить поле int для объекта null, то есть mFd, и сработает ниже ошибки:

ОШИБКА JNI:GetIntField для недопустимой ссылки (0x0)

Вам необходимо назначить действительную ссылку на mFd со стороны kotlin, чтобы код JNI работал правильно.

...