Android串口通信

6 篇文章 0 订阅
3 篇文章 0 订阅

类结构

在这里插入图片描述

Java层

SerialPortManager:对外提供单例类

public class SerialPortManager {

    NativeInterface nativeInterface;

    private SerialPortManager() {}

    private static class InstanceHolder {
        private static SerialPortManager instance = new SerialPortManager();
    }

    public static SerialPortManager getInstance() {
        return InstanceHolder.instance;
    }

    /**
     * 串口读取数据后回调方法
     * @param callback 回调Interface
     */
    public void setPortCallback(SerialPortCallback callback) {
        nativeInterface = new NativeInterface(callback);
    }

    /**
     * 获取设备可用串口列表
     * @return 串口列表
     */
    public String[] getDevices() {
        SerialPortFinder finder = new SerialPortFinder();
        return finder.getAllDevicesPath();
    }

    /**
     * 打开串口,同时启动串口读线程
     * @param strDeviceName 串口名称
     * @param baudRate 波特率
     * @return 成功/失败
     */
    public boolean open(String strDeviceName, int baudRate) {
        if (nativeInterface != null) {
            if (nativeInterface.open(strDeviceName, baudRate)) {
                nativeInterface.read();
                return true;
            }
        }
        return false;
    }

    /**
     * 发送数据
     * @param bytes 发送的byte数组
     * @return 发送成功字节数
     */
    public int writeBytes(byte[] bytes) {
        if (nativeInterface != null) {
            return nativeInterface.write(bytes);
        }
        return 0;
    }

    /**
     * 关闭串口
     */
    public void close() {
        if (nativeInterface != null) {
            nativeInterface.close();
        }
    }
}

NativeInterface:加载native层lib

public class NativeInterface {
    SerialPortCallback mCallback;
    // Used to load the 'native-lib' library on application startup.
    static {
        System.loadLibrary("serialport-lib");
    }

    public NativeInterface() {}

    public NativeInterface(SerialPortCallback callback) {
        mCallback = callback;
    }

	/**
	* native层调用java层方法,回传读取到的串口数据
	*/
    public void readFromTTY (byte[] bytes) {
        Log.d("NativeInterface", "read bytes size:" + bytes.length);
        if (mCallback != null) {
            mCallback.onPortCallback(bytes);
        }
    }

    public native boolean open(String strDeviceName, int baudRate);

    public native int write(byte[] bytes);

    public native void read();

    public native void close();
}

SerialPortCallback:读取串口数据后,回调interface

public interface SerialPortCallback {
    void onPortCallback(byte[] bytes);
}

C++层

#include <jni.h>
#include <string>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <termios.h>
#include <pthread.h>
#include "android/log.h"

const char *TAG = "serial_port";
#define LOGI(fmt, args...) __android_log_print(ANDROID_LOG_INFO,  TAG, fmt, ##args)
#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)

JavaVM* gJVM;
jobject gJObj;
int tty_fd = -1;
static volatile int gIsThreadExit = 0;

speed_t getBaudRate(jint baudRate) {
    switch (baudRate) {
        case 0: return B0;
        case 50: return B50;
        case 75: return B75;
        case 110: return B110;
        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;
        default: return -1;
    }
}

extern "C" JNIEXPORT jboolean JNICALL
Java_com_jdt_serialport_NativeInterface_open(
        JNIEnv* env,
        jobject  thiz, jstring deviceName, jint baudRate) {

    env->GetJavaVM(&gJVM);
    gJObj = env->NewGlobalRef(thiz);

    speed_t speed;
    if ((speed = getBaudRate(baudRate)) == -1) {
        LOGE("Invalid baud rate");
        return false;
    }

    jboolean isCopy;
    const char *pDeviceName = env->GetStringUTFChars(deviceName, &isCopy);
    LOGD("Opening serial port %s with baud rate %d", pDeviceName, baudRate);
    tty_fd = open(pDeviceName, O_RDWR /*| O_NOCTTY | O_NDELAY*/);
    env->ReleaseStringUTFChars(deviceName, pDeviceName);
    if (tty_fd < 0) {
        LOGE("Open failed : %s", pDeviceName);
        return false;
    }

    struct termios newtio, oldtio;
    bzero(&oldtio, sizeof(oldtio));
    if (tcgetattr(tty_fd, &oldtio) != 0) {
        LOGE("Open failed : get attr failed");
        close(tty_fd);
        return false;
    }

    bzero(&newtio, sizeof(newtio));
    cfsetispeed(&newtio, speed);
    cfsetospeed(&newtio, speed);

    newtio.c_cflag |= CLOCAL | CREAD;
    newtio.c_cflag &= ~CSIZE;
    newtio.c_cflag |= CS8;  //8位数据位
    newtio.c_cflag &= ~PARENB;  //无校验位
    newtio.c_cflag &= ~CSTOPB;  //停止位 1

    newtio.c_cc[VTIME] = 2; // 2 * (1/10)s
    newtio.c_cc[VMIN] = 6;	//读取6个字节立刻返回

//    newtio.c_iflag |= INPCK;
//    newtio.c_oflag &= ~OPOST;
    newtio.c_lflag &= ~ICANON;  //非标准模式
//    newtio.c_lflag |= ICANON;   //标准模式

    tcflush(tty_fd, TCIFLUSH);

    if (tcsetattr(tty_fd, TCSANOW, &newtio) != 0) {
        LOGE("Open failed : set attr failed");
        close(tty_fd);
        return false;
    }

    LOGD("Open tty fd:%d", tty_fd);

    return true;
}

extern "C" JNIEXPORT void JNICALL
Java_com_jdt_serialport_NativeInterface_close(
        JNIEnv* env,
        jobject /* this */) {
    gIsThreadExit = 1;
    close(tty_fd);
    LOGD("native read thread stop");
}

static void* native_thread_exec(void* arg) {
    JNIEnv *env;
    gJVM->AttachCurrentThread(&env, nullptr);
    jclass jclz = env->GetObjectClass(gJObj);
    if (jclz == nullptr) {
        LOGE("Failed to find java class");
        return nullptr;
    }

    jmethodID methodId = env->GetMethodID(jclz, "readFromTTY", "([B)V");
    if (methodId == nullptr) {
        LOGE("Failed to get java method id");
        return nullptr;
    }

    int rv;
    u_char r_buf[128];
    fd_set rset;

    while (!gIsThreadExit) {
        FD_ZERO(&rset);
        FD_SET(tty_fd, &rset);

        struct timeval tv;
        tv.tv_sec = 3;
        tv.tv_usec = 0;

        LOGD("Select tty fd:%d", tty_fd);
        rv = select(tty_fd + 1, &rset, NULL, NULL, &tv);
        if (rv < 0) {
            LOGE("select failed:%s", strerror(errno));
            break;
        }
        if (0 == rv) {
            LOGE("select time out");
            if (1 == gIsThreadExit) {
                LOGD("select time out, read thread exit");
                break;
            }
            continue;
        }

        memset(r_buf, 0, sizeof(r_buf));
        rv = read(tty_fd, r_buf, 128);
        if (rv < 0) {
            LOGE("read failed:%s", strerror(errno));
            break;
        }

        LOGD("read len: %d", rv);
        jbyteArray buffer = env->NewByteArray(rv);
        env->SetByteArrayRegion(buffer, 0, rv, (jbyte*)r_buf);
        env->CallVoidMethod(gJObj, methodId, buffer);
    }

    gJVM->DetachCurrentThread();
    return nullptr;
}

extern "C" JNIEXPORT void JNICALL
Java_com_jdt_serialport_NativeInterface_read(
        JNIEnv* env,
        jobject  /*thiz*/) {

    gIsThreadExit = 0;
    pthread_t threadId;
    if (pthread_create(&threadId, NULL, native_thread_exec, NULL) != 0) {
        LOGE("pthread create failed");
        return;
    }
}

extern "C" JNIEXPORT jint JNICALL
Java_com_jdt_serialport_NativeInterface_write(
        JNIEnv* env,
        jobject /* this */, jbyteArray arrayData) {

    jbyte *pBytes = env->GetByteArrayElements(arrayData, 0);
    jsize len = env->GetArrayLength(arrayData);

    int count = write(tty_fd, pBytes, len);
    if (count == len) {
        return count;
    } else {
        LOGE("write error");
        tcflush(tty_fd, TCOFLUSH);
        return -1;
    }
}

使用

获取单例类对象

SerialPortManager mManager = SerialPortManager.getInstance();

设置串口数据listener

mManager.setPortCallback(this); //当前类implements SerialPortCallback

@Override
public void onPortCallback(byte[] bytes) {	// 此方法运行在子线程
    String strCallbackData = ByteUtil.bytes2HexStr(bytes);
    Log.d("Devices", "callback data: " + strCallbackData);
}

查找串口

String[] devices = mManager.getDevices();

打开串口

boolean opened = mManager.open("/dev/tty1", 9600);

发送数据

byte[] bytes = {(byte)0x80, 0x00, 0x15, (byte)0xA0, (byte)0x01, (byte)0x05, (byte)0x31};
mManager.writeBytes(bytes);

关闭串口

SerialPortManager.getInstance().close();
  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值