2021SC@SDUSC 下面几篇文章主要围绕串口进行分析。 Android并没有包含串口的JNI, 需要我们自己实现。 ###接受串口数据的编程逻辑
SerialPort.h文件
#include <jni.h>
#ifndef _Included_android_serialport_api_SerialPort
#define _Included_android_serialport_api_SerialPort
设置宏,为了防止头文件的重复引用
#ifdef __cplusplus
extern "C" {
#endif
JNIEXPORT jobject JNICALL Java_sdu_cislc_lcms_cabinet_serial_api_SerialPort_open
(JNIEnv *, jclass, jstring, jint, jint);
JNIEXPORT void JNICALL Java_sdu_cislc_lcms_cabinet_serial_api_SerialPort_close
(JNIEnv *, jobject);
#ifdef __cplusplus
}
#endif
#endif
头文件中主要使用了一个陌生的语法**#ifdef __cplusplus extern “C”** 其主要作用就是主要作用就是为了能够正确实现C++代码调用其他C语言代码。加上extern "C"后,会指示编译器这部分代码按C语言的进行编译,在通过JNI调用底层C代码的时候不会出错。
SerialPort.c文件
getBaudrate函数
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;
}
采用switch函数,设置波特率函数会用到的数 通过speed_t getBaudRate(jint baudRate)可以获取波特率 注意没有匹配的数值时返回-1.
打开串口设备
JNIEXPORT jobject JNICALL Java_android_1serialport_1api_SerialPort_open
(JNIEnv *env, jobject object, jstring deviceName, jint baudRate)
这个函数与SerialPort.java中的open(String path, int baudRate)函数相关联
const char *device = env->GetStringUTFChars(deviceName, 0);
LOGI("Device=%s, BaudRate= %d", device, baudRate);
获取String的字符。不能直接的用device = deviceName;最后还要释放device指针。
int fd = -1;
do {
fd = open(device, O_RDWR);
if (-1 == fd) {
LOGE("Can't Open %s[%d]: %s", device, errno, strerror(errno));
break;
}
speed_t speed = getBaudRate(baudRate);
if (speed == -1) {
LOGE("Invalid baudRate");
break;
}
打开设备如果fd=-1则说明文件不能正常打开 若speed=-1则取得的波特率无效
struct termios Opt;
tcgetattr(fd, &Opt);
cfmakeraw(&Opt);
tcflush(fd, TCIFLUSH);
cfsetispeed(&Opt, speed);
cfsetospeed(&Opt, speed);
if (tcsetattr(fd, TCSANOW, &Opt) != 0) {
LOGE("SetupSerial![%d]: %s", errno, strerror(errno));
break;
}
设置串口参数: 、、、、、、要写的
jclass cFileDescriptor = env->FindClass("java/io/FileDescriptor");
jmethodID iFileDescriptor = env->GetMethodID(cFileDescriptor, "<init>", "()V");
jfieldID descriptorID = env->GetFieldID(cFileDescriptor, "descriptor", "I");
jobject fileDescriptor = env->NewObject(cFileDescriptor, iFileDescriptor);
env->SetIntField(fileDescriptor, descriptorID, (jint)fd);
用JNI函数创建一个FileDescriptor类的实例
env->ReleaseStringUTFChars(deviceName, device);
return fileDescriptor;
} while(0);
使用完device指针后进行释放,这个循环时一直进行的
if(fd != -1)
close(fd);
env->ReleaseStringUTFChars(deviceName, device);
return NULL;
在fd不等于-1时,关闭设备,并释放device指针。 完整代码:
JNIEXPORT jobject JNICALL Java_android_1serialport_1api_SerialPort_open
(JNIEnv *env, jobject object, jstring deviceName, jint baudRate)
{
const char *device = env->GetStringUTFChars(deviceName, 0);
LOGI("Device=%s, BaudRate= %d", device, baudRate);
int fd = -1;
do {
fd = open(device, O_RDWR);
if (-1 == fd) {
LOGE("Can't Open %s[%d]: %s", device, errno, strerror(errno));
break;
}
speed_t speed = getBaudRate(baudRate);
if (speed == -1) {
LOGE("Invalid baudRate");
break;
}
struct termios Opt;
tcgetattr(fd, &Opt);
cfmakeraw(&Opt);
tcflush(fd, TCIFLUSH);
cfsetispeed(&Opt, speed);
cfsetospeed(&Opt, speed);
if (tcsetattr(fd, TCSANOW, &Opt) != 0) {
LOGE("SetupSerial![%d]: %s", errno, strerror(errno));
break;
}
jclass cFileDescriptor = env->FindClass("java/io/FileDescriptor");
jmethodID iFileDescriptor = env->GetMethodID(cFileDescriptor, "<init>", "()V");
jfieldID descriptorID = env->GetFieldID(cFileDescriptor, "descriptor", "I");
jobject fileDescriptor = env->NewObject(cFileDescriptor, iFileDescriptor);
env->SetIntField(fileDescriptor, descriptorID, (jint)fd);
env->ReleaseStringUTFChars(deviceName, device);
return fileDescriptor;
} while(0);
if(fd != -1)
close(fd);
env->ReleaseStringUTFChars(deviceName, device);
return NULL;
}
关闭串口设备
此函数与与SerialPort.java中的close(FileDescriptor fd);函数相关联。
JNIEXPORT jboolean JNICALL Java_android_1serialport_1api_SerialPort_close
(JNIEnv *env, jobject object, jobject descriptor)
{
if(descriptor != NULL) {
jclass cFileDescriptor = env->FindClass("java/io/FileDescriptor");
jfieldID descriptorID = env->GetFieldID(cFileDescriptor, "descriptor", "I");
jint fd = env->GetIntField(descriptor, descriptorID);
close(fd);
}
return 1;
}
“descriptor”属性是在FileDescriptor类里的,要用JNI函数来得到参数descriptor里的“descriptor”属性值。
|