Android 串口通信

1.去github 搜索 AndroidSerial 看看别人的用例就行了.不过一般是google 项目翻写过来的.

2.去下载看看文档 链接

3.我的代码



#include <pthread.h>
#include <termios.h>
#include <stdio.h>
#include <unistd.h>

#include <sys/stat.h>
#include <fcntl.h>
#include <linux/serial_core.h>
#include <android/bitmap.h>
#include <jni.h>
#include "SerialPort.h"
#include <sys/ioctl.h>
#include <malloc.h>
#include "android/log.h"

static 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)
int pos[] = {128, 64, 32, 16, 8, 4, 2, 1};
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
const jbyte data[1];
void jniThrowException(JNIEnv *pEnv, const char *, const char *);
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:     android_serialport_SerialPort
 * Method:    open
 * Signature: (Ljava/lang/String;II)Ljava/io/FileDescriptor;
 * rrrr
 * uuuu
 */JNIEXPORT jobject JNICALL Java_android_1serialport_1api_SerialPort_open(
        JNIEnv *env, jclass thiz, jstring path, jint baudrate, jint flags) {
    int fd;
    speed_t speed;
    jobject mFileDescriptor;

    /* Check arguments */
    {
        speed = getBaudrate(baudrate);
        if (speed == -1) {

            LOGE("Invalid baudrate");
            return NULL;
        }
    }

    {
        jboolean iscopy;
        const char *path_utf = (*env)->GetStringUTFChars(env, path, &iscopy);
        LOGD("Opening serial port %s with flags 0x%x",
             path_utf, O_RDWR | 0);
        fd = open(path_utf, O_RDWR | O_NOCTTY | O_SYNC, S_IRWXU);

        LOGD("open() fd = %d", fd);
        (*env)->ReleaseStringUTFChars(env, path, path_utf);

        if (fd == -1) {

            LOGE("Cannot open port");

            return NULL;
        }

        LOGI("sync  %d:", sync);
    }

    /* Configure device */
    {
        struct termios cfg;
        LOGD("Configuring serial port");
        if (tcgetattr(fd, &cfg)) {
            LOGE("tcgetattr() failed");
            close(fd);
            return NULL;
        }

        cfmakeraw(&cfg);
        cfsetispeed(&cfg, speed);
        cfsetospeed(&cfg, speed);
        cfg.c_cflag |= CREAD | CLOCAL;
        cfg.c_cc[VMIN] = 0;
        cfg.c_cc[VTIME] = 0;
        if (flags == 1) {
            cfg.c_cflag &= ~CRTSCTS;
            cfg.c_iflag |= IXON | IXOFF | IXANY;
            LOGE("IXON flow control open");
        } else if (flags == 2) {
            cfg.c_iflag &= ~(IXON | IXOFF | IXANY);
            cfg.c_cflag |= CRTSCTS;

            LOGE("CRTSCTS flow control open");
        } else {
            cfg.c_cflag &= ~CRTSCTS;
            cfg.c_iflag &= ~(IXON | IXOFF | IXANY);
            LOGE("flow control not open");
        }

        if (tcsetattr(fd, TCSANOW, &cfg)) {
            LOGE("tcsetattr() failed");
            close(fd);
            /* TODO: throw an exception */
            return NULL;
        }
    }

    /* Create a corresponding file descriptor */
    {
        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);
    }

    struct serial_struct serial;
    ioctl(fd, TIOCGSERIAL, &serial);
    LOGE("波特率 %d", serial.baud_base);
    LOGE("访问方式 %d", serial.io_type);
    LOGE("串口几 %d", serial.port);
    LOGE("等待时长 %d", serial.closing_wait);
    LOGE("基地址 %d", serial.iomem_base);
    LOGE("缓冲区 %d", serial.xmit_fifo_size);
    /*  serial.xmit_fifo_size = 4096;
      int success=  ioctl(fd, TIOCSSERIAL, &serial);
      LOGI("是否成功 %d",success);*/
    int success = pthread_mutex_init(&mutex, NULL);
    LOGI("是否成功 %d", success);
    return mFileDescriptor;
}

/*
 * Class:     cedric_serial_SerialPort
 * Method:    close
 * Signature: ()V
 */JNIEXPORT void JNICALL Java_android_1serialport_1api_SerialPort_close(
        JNIEnv *env, jobject thiz) {
    jclass SerialPortClass = (*env)->GetObjectClass(env, thiz);
    jclass FileDescriptorClass = (*env)->FindClass(env,
                                                   "java/io/FileDescriptor");

    jfieldID mFdID = (*env)->GetFieldID(env, SerialPortClass, "mFd",
                                        "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);

    LOGD("close(fd = %d)", descriptor);
    pthread_mutex_destroy(&mutex);
    close(descriptor);
}
/*
 * *TCIFLUSH  清除输入队列 0
   *TCOFLUSH  清除输出队列 1
   *TCIOFLUSH 清除输入、输出队列 2
 *
 * */

JNIEXPORT void JNICALL Java_android_1serialport_1api_SerialPort_flush(JNIEnv *env, jobject thiz,

                                                                      jint flag) {

    jclass SerialPortClass = (*env)->GetObjectClass(env, thiz);
    jclass FileDescriptorClass = (*env)->FindClass(env,
                                                   "java/io/FileDescriptor");

    jfieldID mFdID = (*env)->GetFieldID(env, SerialPortClass, "mFd",
                                        "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);
    tcflush(descriptor, flag);
    LOGI("flush", "清空" + flag);

}

JNIEXPORT void JNICALL Java_android_1serialport_1api_SerialPort_tcDrain(JNIEnv *env, jobject thiz) {

    jclass SerialPortClass = (*env)->GetObjectClass(env, thiz);
    jclass FileDescriptorClass = (*env)->FindClass(env,
                                                   "java/io/FileDescriptor");

    jfieldID mFdID = (*env)->GetFieldID(env, SerialPortClass, "mFd",
                                        "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);
    int i = tcdrain(descriptor);
    LOGE("直到数据 % d:", i);


}
/**
 * TCIOFF
Transmit a STOP character, intended to suspend input data.
TCION
Transmit a START character, intended to restart input data.
TCOOFF
Suspend output.
TCOON
Restart output.
 */
JNIEXPORT void JNICALL Java_android_1serialport_1api_SerialPort_tcFlow(JNIEnv *env, jobject
thiz, jint flag) {

    jclass SerialPortClass = (*env)->GetObjectClass(env, thiz);
    jclass FileDescriptorClass = (*env)->FindClass(env,
                                                   "java/io/FileDescriptor");

    jfieldID mFdID = (*env)->GetFieldID(env, SerialPortClass, "mFd",
                                        "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);
    int i = tcflow(descriptor, flag);
    LOGE("tcflow % d:", i);


}

JNIEXPORT jint JNICALL Java_android_1serialport_1api_SerialPort_write
        (JNIEnv *env, jclass thiz, jint fd, jbyteArray cmd, jint offset, jint size) {
    pthread_mutex_lock(&mutex);


    jbyte *data = (*env)->GetByteArrayElements(env, cmd, NULL);
    int send = write(fd, data, size);
    (*env)->ReleaseByteArrayElements(env, cmd, data, 0);
    if (send<0){
        jniThrowException(env,
                          "java/io/IOException", NULL);
    }
    // (*env)->DeleteLocalRef(env, data);
    pthread_mutex_unlock(&mutex);

    return send;
}

JNIEXPORT jint JNICALL Java_android_1serialport_1api_SerialPort_read
        (JNIEnv *env, jclass thiz, jint fd, jbyteArray cmd, jint offset, jint size) {
    pthread_mutex_lock(&mutex);

    jbyte *buf = (jbyte *) malloc(size);
    if (!buf) {
        jniThrowException(env,
                          "java/lang/OutOfMemoryError", NULL);
        return -1;
    }

    int ret = read(fd, buf, size);
    if (ret > 0) {
        (*env)->SetByteArrayRegion(env,cmd,
                                   0, ret, buf);
    }
    free(buf);
    if (ret < 0) {
        jniThrowException(env,
                          "java/io/IOException", NULL);
    }
    // (*env)->DeleteLocalRef(env, data);
    pthread_mutex_unlock(&mutex);
    return ret;
}

JNIEXPORT jint JNICALL Java_android_1serialport_1api_SerialPort_getInfo
        (JNIEnv *env, jclass thiz, jint fd) {

    struct serial_icounter_struct info;
    ioctl(fd, TIOCGICOUNT, &info);
    LOGE("打印接收 =%d", info.tx);
    LOGE("打印发送 =%d", info.rx);
    LOGE("打印发送溢出 =%d", info.overrun);
    LOGE("数据溢出 =%d", info.buf_overrun);
    LOGE("中断计数 =%d", info.brk);
    LOGE("frame =%d", info.frame);
    LOGE("反转 =%d", info.reserved);
    LOGE("cts =%d", info.cts);
    LOGE("dsr =%d", info.dsr);


    return info.tx;
}



void jniThrowException(JNIEnv *pEnv, const char *throwName, const char *message) {
    jclass throwClass = (*pEnv)->FindClass(pEnv,throwName);
    if (throwClass) {

        return;
    }
    ( *pEnv)->ThrowNew(pEnv,throwClass, message);

}

ps:注意的一些地方.1.死锁 2.在读之前先用flush 清除未读出的数据 在发送打印机状态指令之后先延迟 几十毫秒后在读.3.用户反映硬流控不能用 ,但是这代码在linux 系统上能用.4.可以将fd 变量缓存起来6.使用write 方法可以将一个一个字节的传,你使用FileOutputStream.write 方法里面也是一个一个字节的传的;

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值