转载请注明出处:http://blog.csdn.net/a512337862/article/details/76035464
其实关于Android的串口通信Google早已提供了一个开源的工具,具体地址如下:https://github.com/cepr/android-serialport-api,大家可以自行下载。但是本人觉得这个demo有点过于复杂,所以在这个demo的基础上进行了一些封装,方便大家使用,勉强算得上是一个工具类。
串口操作
对于Android串口操作,基本上就是对应串口文件的读写,所以基本思路就是:
1.对串口文件进行配置(波特率等),打开串口文件
2.读写串口
3.关闭串口文件
但是这里需要注意的是Android/Java中读写串口需要用到FileDescriptor类(文件描述符),具体的大家可以参考:http://blog.csdn.net/morningsun1990/article/details/19639583。
代码分析
JNI
因为本篇是基于android-serialport-api 的,JNI自然是无法跳过的坑,至于JNI如何使用,网上的教程多不胜数,这里也不班门弄斧了,可以自行上网搜索。这里提醒一下大家注意下面这点:
- 不同的项目,包含native方法的类对应的路径一般都不相同,所以通过javah -jni指令生成的.h文件名以及方法名也不同,那对应的.c文件方法名以及包含的.h头文件也需要修改。例如,android-serialport-api中的.h文件生成的方法名如下:
但是我这边的.h中的方法名则是:
下面贴一下跟JNI层相关的代码:
.c文件
//
// Created by ZhangHao on 2016/7/29.
//
#include <termios.h>
#include <unistd.h>
#include <fcntl.h>
#include <jni.h>
#include <android/log.h>
#include "com_serialPort_SerialPort.h"
static const char *TAG = "serial_port";
#define LOGD(fmt, args...) __android_log_print(ANDROID_LOG_DEBUG, TAG, fmt, ##args)
#define LOGE(fmt, args...) __android_log_print(ANDROID_LOG_ERROR, TAG, fmt, ##args)
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;
}
}
/*
* Class: com_sona_utils_SerialPort
* Method: open
* Signature: (Ljava/lang/String;II)Ljava/io/FileDescriptor;
*/
JNIEXPORT jobject JNICALL Java_com_serialPort_SerialPort_open
(JNIEnv *env, jclass thiz, jstring path, jint baudrate, jint flags) {
LOGE("JNI START");
int fd;
speed_t speed;
jobject mFileDescriptor;
/* Check arguments */
{
speed = getBaudrate(baudrate);
if (speed == -1) {
/* TODO: throw an exception */
LOGE("Invalid baudrate");
return NULL;
}
}
/* Opening device */
{
jboolean iscopy;
const char *path_utf = (*env)->GetStringUTFChars(env, path, &iscopy);
LOGD("Opening serial port %s with flags 0x%x", path_utf, O_RDWR | flags);
fd = open(path_utf, O_RDWR | O_NOCTTY | O_NDELAY);//O_RDWR | flags
LOGD("open() fd = %d", fd);
(*env)->ReleaseStringUTFChars(env, path, path_utf);
if (fd == -1) {
/* Throw an exception */
LOGE("Cannot open port");
/* TODO: throw an exception */
return NULL;
}
if (fcntl(fd, F_SETFL, 0) < 0)
LOGD("fcntl failed!\n");
else
LOGD("fcntl=%d\n", fcntl(fd, F_SETFL, 0));
}
/* Configure device */
{
struct termios cfg;
LOGD("Configuring serial port");
if (tcgetattr(fd, &cfg)) {
LOGE("tcgetattr() failed");
close(fd);
/* TODO: throw an exception */
return NULL;
}
cfmakeraw(&cfg);
cfg.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
tcflush(fd, TCIFLUSH);
cfg.c_cc[VTIME] = 0;
cfg.c_cc[VMIN] = 0; //Update the Opt and do it now
cfsetispeed(&cfg, speed);
cfsetospeed(&cfg, speed);
if (tcsetattr(fd, TCSANOW, &cfg)) {
LOGE("tcsetattr() failed");
close(fd);
/* TODO: throw an exception */
return NULL;
}
}