2021-07-22 rochchip 3288 uart

2021-07-22  本文已影响0人  fjasmin

jni 源码

SerialAPI.c

#include <jni.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#include <arpa/inet.h>
#include <errno.h>
#include <linux/unistd.h>
#include <pthread.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include "termios.h"
#include <sys/ioctl.h>
#include <sys/select.h>
#include <sys/time.h>
#include <linux/input.h>
#include <android/log.h>
#include <math.h>
#include <fcntl.h>
#include <sys/epoll.h>


#define LOG_TAG "serialAPI"
#undef  LOG
#define LOGD(...)   //__android_log_print(ANDROID_LOG_DEBUG,LOG_TAG,__VA_ARGS__)

int rs485Fd = -1;
//配置串口参数
int set_opt(int fd, int nSpeed, int nBits, char nEvent, int nStop) {
    struct termios newtio, oldtio;
    if (tcgetattr(fd, &oldtio) != 0) {
        perror("SetupSerial 1");
        return -1;
    }
    bzero(&newtio, sizeof(newtio));
    newtio.c_cflag &= ~CSTOPB;
    newtio.c_cflag &= ~CSIZE;
    newtio.c_cflag |= (CLOCAL | CREAD);
    newtio.c_cflag &= ~CRTSCTS;

    /* set no software stream control */
    newtio.c_iflag &= ~(IXON | INLCR | ICRNL | IGNCR | IUCLC);
    /* set output mode with no define*/
    newtio.c_oflag &= ~OPOST;
    /* set input mode with non-format */
    newtio.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
    newtio.c_iflag |= IGNBRK|IGNPAR; //for 0xd,0x11,0x13

    switch (nBits) {
        case 7:
            newtio.c_cflag |= CS7;
            break;
        case 8:
            newtio.c_cflag |= CS8;
            break;
    }

    switch (nEvent) {
        case 'O':
            newtio.c_cflag |= PARENB;
            //  newtio.c_cflag |= PARODD;
            //  newtio.c_iflag |= (INPCK | ISTRIP);
            break;
        case 'E':
            newtio.c_iflag |= INPCK;
            newtio.c_cflag |= PARENB;
            newtio.c_cflag &= ~PARODD;
            break;
        case 'N':
            newtio.c_cflag &= ~PARENB;
            break;
    }

    switch (nSpeed) {
        case 2400:
            cfsetispeed(&newtio, B2400);
            cfsetospeed(&newtio, B2400);
            break;
        case 4800:
            cfsetispeed(&newtio, B4800);
            cfsetospeed(&newtio, B4800);
            break;
        case 9600:
            cfsetispeed(&newtio, B9600);
            cfsetospeed(&newtio, B9600);
            break;
        case 19200:
            cfsetispeed(&newtio, B19200);
            cfsetospeed(&newtio, B19200);
            break;
        case 38400:
            cfsetispeed(&newtio, B38400);
            cfsetospeed(&newtio, B38400);
            break;
        case 57600:
            cfsetispeed(&newtio, B57600);
            cfsetospeed(&newtio, B57600);
            break;
        case 115200:
            cfsetispeed(&newtio, B115200);
            cfsetospeed(&newtio, B115200);
            break;
        case 500000:
            cfsetispeed(&newtio, B500000);
            cfsetospeed(&newtio, B500000);
            break;
        case 1500000:
            cfsetispeed(&newtio, B1500000);
            cfsetospeed(&newtio, B1500000);
            break;
        default:
            cfsetispeed(&newtio, B9600);
            cfsetospeed(&newtio, B9600);
            break;
    }
    if (nStop == 1)
        newtio.c_cflag &= ~CSTOPB;
    else if (nStop == 2)
        newtio.c_cflag |= CSTOPB;
    newtio.c_cc[VTIME] = 0;
    newtio.c_cc[VMIN] = 0;
    tcflush(fd, TCIFLUSH);
    if ((tcsetattr(fd, TCSANOW, &newtio)) != 0) {
        perror("com set error");
        return -1;
    }
    return 0;
}

static int read_uart_data(int fd, char* data,  int len)
{
    struct timeval timeout;
    timeout.tv_sec = 2;
    timeout.tv_usec = 0;
    int ret = 0;
    memset(data,0,len);
    do {
        fd_set readfds;
        FD_ZERO(&readfds);
        FD_SET(fd, &readfds);
        //wait for 2 seconds if no data come
        ret = select(FD_SETSIZE, &readfds, NULL, NULL, &timeout);
        if (ret < 0)
            continue;
        if (FD_ISSET(fd, &readfds)) {
            ret = read( fd, data, len);
        }
    } while (ret < 0 && errno == EINTR);
    return ret;
}

/*
 * 设置串口属性
 * baud: 波特率
 * dataBits:数据位数
 * parity: 校验
 * stopBits:停止位
*/
int native_setOpt(JNIEnv* env, jobject thiz, jint fd,  jint baud, jint dataBits, jint parity, jint stopBits) {

    //配置串口
    char tmp;
    if(parity == 0)
        tmp = 'N';
    else if(parity == 1)
        tmp = 'O';
    else if(parity == 2)
        tmp = 'E';
    LOGD("baudrate %d databits %d parity %c stopBits %d\n",baud, dataBits, tmp, stopBits);
    int nset = set_opt(fd, baud, dataBits, tmp, stopBits);
    if (nset == -1) {
        return -1;
    }
}

/*
wr: '0', 设置rs485模块为写模式
    '1', 设置rs485模块为读模式, 注意是字符串
*/
int control_rs485(char rd){
    int fd = open("/sys/class/io_control/rs485_con", O_RDWR | O_NOCTTY);
    if (fd == -1) {
        return 2;
    }
    write(fd, &rd, 1);
    close(fd);
}

/*
 * 打开串口
 * device: /dev/ttyS1 /dev/ttyS2之类的串口名字
 * */
int native_uartInit(JNIEnv* env, jobject thiz, jstring device) {
    //打开串口
    int fd;
    char* dev = (char*)(*env)->GetStringUTFChars(env,device,0);
    LOGD("Uart name %s\n", dev);
    fd = open(dev, O_RDWR);
    if (fd == -1) {
        LOGD("###OPEN %s fail\n", dev);
        return -1;
    }
    control_rs485('1');
    (*env)->ReleaseStringUTFChars(env,device, dev);
    return fd;
}
int native_uartDestroy(JNIEnv* env, jobject thiz, jint fd) {
    close(fd);
}
/**
 * 把数据发送出去
 * byteBuf:数据缓冲
 * length: 要发送数据的长度
 */
#define uart_tcdrain(fd) ioctl(fd, TCSBRK, 1)
int native_send(JNIEnv* env, jobject thiz, jint fd, jintArray intBuf, jint length) {
    int i,ret = -1;
    jboolean isCopy;
    if(fd == -1)
        return -1;

    jint* arr = (int*)(*env)->GetIntArrayElements(env,intBuf,&isCopy);

    unsigned char *xwdata = malloc(length*sizeof(unsigned char));

    for(i=0; i<length; i++) {
        xwdata[i] = (unsigned char)arr[i];
        LOGD("send  %x ",xwdata[i]);
    }
    //tcflush(fd,   TCIOFLUSH);
    tcflush(fd,   TCOFLUSH);
    ret = write(fd, xwdata, length);
    //tcdrain函数等待所有输出都被发送。若成功为0,出错为-1
    //usleep(5000);
    if( uart_tcdrain(fd)==-1 )
        ret = -1;
    (*env)->ReleaseIntArrayElements(env,intBuf,(jbyte*)arr, JNI_ABORT);
    free(xwdata);
    xwdata = NULL;
    return ret;

}

/**
 *读取串口数据
 * byteBuf: 数据缓冲
 * length: 要读取的数据长度
 * return :
 */
int native_recv(JNIEnv* env, jobject thiz, jint fd, jintArray intBuf, jint length) {

    int i,ret = -1;
    jboolean isCopy = JNI_FALSE;
    if(fd == -1)
        return -1;
    unsigned char *xrdata = malloc(length*sizeof(unsigned char));
    unsigned int *xrdataInt = malloc(length*sizeof(unsigned int));

    //int* arr = (int*)(*env)->GetIntArrayElements(env,intBuf,&isCopy);

    ret = read_uart_data(fd, xrdata, length);

    for(i=0; i<ret; i++) {
        xrdataInt[i] = xrdata[i];
        LOGD("recv  %x ",xrdataInt[i]);
    }
    (*env)->SetIntArrayRegion(env, intBuf, 0, length, xrdataInt);
    //(*env)->ReleaseIntArrayElements(env,intBuf,(jbyte*)arr, JNI_ABORT);
    LOGD("xrdata addr = 0x%p \n", xrdata);
    free(xrdata);
    free(xrdataInt);

    return ret;

}
/*
 * 把485设置为读模式或者写模式
 * read  1 : 设置为读模式
 *         0 : 设置为写模式
 * */
int native_setRS485ReadWrite(JNIEnv* env, jobject thiz, jint read) {
    if(read == 1) {
        control_rs485('1');
    } else {
        control_rs485('0');
    }
    return 0;
}



/*
 * 打开RS485串口
 * */
jboolean native_rs485_Init(JNIEnv* env, jobject thiz) {
    if (rs485Fd > 0)
        return 1;
    //打开串口
    rs485Fd = open("/dev/ttyS3", O_RDWR);
    if (rs485Fd < 0) {
        return 0;
    }
    //配置串口
    int nset = set_opt(rs485Fd, 9600, 8, 'N', 1);
    if (nset < 0) {
        return 0;
    }
    control_rs485('1');
    return 1;
}

void native_rs485_Destroy(JNIEnv* env, jobject thiz) {
    close(rs485Fd);
    rs485Fd = -1;
}

/**
 * cardID:板子标号      doorID:门号                info: 单片机返回的数据
 * return 0表示获取信息成功,-1代表失败
 */
int native_rs485_OpenGrid(JNIEnv* env, jobject thiz, jint cardID,
                          jint doorID, jintArray info) {
    int* buf;
    int i, ret=-1, len,j;

    //协议五位  命令:0x8A   板地址:0X01-0XC8    锁地址:0X01—18    状态:0X11    校检码:前面几位异或
    char xwdata[5] = { 0X8A, (char) cardID, (char) doorID, 0x11 };
    char xrdata[5] = { 0 };
    char xrdata_tmp[50] = {0};

    int start;

    xwdata[4] = (xwdata[0] ^ xwdata[1] ^ xwdata[2] ^ xwdata[3]) & 0xff;
//  LOGD("Open cardId %d door %d\n",cardID,doorID);
    LOGD("open send:0x%x:0x%x:0x%x:0x%x:0x%x\n",xwdata[0],xwdata[1],xwdata[2],xwdata[3],xwdata[4]);
    tcflush(rs485Fd,   TCIOFLUSH);
    control_rs485('0');
    usleep(5000);
    write(rs485Fd, xwdata, 5);
    usleep(10000); //必须等待一段时间,rs485才会把数据发送出去
    control_rs485('1');
    ret = read_uart_data(rs485Fd, xrdata,5);
    if(ret <= 0) {
        LOGD("Open: fail to get uart data\n");

    }
    if((xrdata[0]==0x00) && (xrdata[1]==0x00)) {
        LOGD("###########open fail. board %d door %d#################\n",cardID,doorID);
    }
    //      LOGD("open ret:0x%x:0x%x:0x%x:0x%x:0x%x\n",xrdata[0],xrdata[1],xrdata[2],xrdata[3],xrdata[4]);


    buf = (int*)(*env)->GetIntArrayElements(env,info,NULL);
    if (buf == NULL)
        goto retern__;
    for(i=0;i<5;i++)
        buf[i] = xrdata[i];
    (*env)->ReleaseIntArrayElements(env,info, (jint*)buf, JNI_ABORT);
    retern__:
    return 0;

}

/**
 * 获取锁控板地址
 * info : 锁控板地址列表
 */
int native_rs485_GetBoardAddress(JNIEnv* env, jobject thiz, jint addrnum, jint maxNum, jintArray info) {
    int i,ret,boardIndex,j;
    int* buf;

    buf = (int*)(*env)->GetIntArrayElements(env,info,NULL);
    //协议五位  命令:0x81 板地址 0x01-0x0f  固定:0X01    状态:0X99    校检码:前面几位异或 0X19
    char xwdata[5] = { 0X81, 0X01, 0x01, 0x99 , 0x19};
    char xrdata[5] = { 0 };
    tcflush(rs485Fd,   TCIOFLUSH);
    control_rs485('0');
    boardIndex = 0;
    //遍历核心板,询问是否有回应
    for(i=0; i<maxNum; i++) {
        tcflush(rs485Fd,   TCIOFLUSH);
        control_rs485('0');
        usleep(5000);
        xwdata[1] = i;
        xwdata[4] = (xwdata[0] ^ xwdata[1] ^ xwdata[2] ^ xwdata[3]) & 0xff;
        write(rs485Fd, xwdata, 5);
        usleep(10000); //必须等待一段时间,rs485才会把数据发送出去
        control_rs485('1');
        ret = read_uart_data(rs485Fd, xrdata,5);
        if(ret <= 0) {
            LOGD("BoardAdress: fail to get uart data\n");
        }
        LOGD("BoardAdress ret %d:%d 0x%x:0x%x:0x%x:0x%x:0x%x\n",
             ret, i,xrdata[0],xrdata[1],xrdata[2],xrdata[3],xrdata[4]);
        if(ret != 0 && (xrdata[0] == 0x81) &&
           ((xrdata[0]^xrdata[1]^xrdata[2]^xrdata[3]^xrdata[4]) == 0x0)) {
            buf[boardIndex] = xrdata[1];
            boardIndex++;
            if (boardIndex >= addrnum)
                goto _return_;
        }
        usleep(200000);
    }
    LOGD("get address done\n");
    _return_:
    (*env)->ReleaseIntArrayElements(env, info, (jint*)buf, JNI_ABORT);
    return boardIndex;
}

/*
 * 获取协议ID
 * cardID : 锁控板卡地址
 * info : 返回板卡程序协议
 */
int native_rs485_GetProtocalID(JNIEnv* env, jobject thiz,jint cardID, jintArray info) {
    int i,ret,boardIndex,j;
    int* buf;
    buf = (int*)(*env)->GetIntArrayElements(env,info,NULL);
    //协议五位  命令:0X91, boardaddress, 0xfe, 0xfe , 0x6f
    char xwdata[5] = { 0X91, 0X0, 0xfe, 0xfe , 0x6f};
    char xrdata[5] = { 0 };

    xwdata[1] = cardID;
    xwdata[4] = (xwdata[0] ^ xwdata[1] ^ xwdata[2] ^ xwdata[3]) & 0xff;
    tcflush(rs485Fd,   TCIOFLUSH);
    control_rs485('0');
    usleep(5000);
    write(rs485Fd, xwdata, 5);
    usleep(10000); //必须等待一段时间,rs485才会把数据发送出去
    control_rs485('1');
    ret = read_uart_data(rs485Fd, xrdata,5);
    if(ret <= 0) {
        LOGD("Protocal: fail to get uart data\n");
    }

    LOGD("Protocal ret %d, 0x%x:0x%x:0x%x:0x%x:0x%x\n",
         ret,xrdata[0],xrdata[1],xrdata[2],xrdata[3],xrdata[4]);

    for(i=0;i<5;i++)
        buf[i] = xrdata[i];
    (*env)->ReleaseIntArrayElements(env,info, (jint*)buf, JNI_ABORT);
    return 0;


}

/**
 * 获取锁的状态
 *
 * cardID:板子标号      doorID:门号                info: 单片机返回的数据
 */
int native_rs485_GetDoorState(JNIEnv* env, jobject thiz, jint boardID, jint doorID, jintArray info) {

    int i, len,ret;
    //协议五位  命令:0x80 板地址:0X01-0xC8   锁地址:0x00-0x18  命令:0x33    校检码:前面几位异或
    char xwdata[5] = { 0X80, (char)boardID, (char)doorID, 0x33};
    char xrdata[7] = { 0 };

    if(doorID == 0)
        len = 7;
    else
        len = 5;

    xwdata[4] = (xwdata[0] ^ xwdata[1] ^ xwdata[2] ^ xwdata[3]) & 0xff;
    //LOGD("get state send:0x%x:0x%x:0x%x:0x%x:0x%x\n",xwdata[0],xwdata[1],xwdata[2],xwdata[3],xwdata[4]);
    tcflush(rs485Fd,   TCIOFLUSH);
    control_rs485('0');
    usleep(5000);
    write(rs485Fd, xwdata, 5);
    usleep(10000);
    control_rs485('1');


    ret = read_uart_data(rs485Fd, xrdata,len);
    if(ret <= 0) {
        LOGD("State: fail to get uart data\n");
    }
    //ret = read(uart_fd, xrdata, len);
    if((xrdata[0]==0x00) && (xrdata[1]==0x00)) {
        LOGD("###########get state fail. board %d door %d#################\n",boardID,doorID );
    }
    LOGD("state ret %d, 0x%x:0x%x:0x%x:0x%x:0x%x:0x%x:0x%x\n",
         ret,xrdata[0],xrdata[1],xrdata[2],xrdata[3],xrdata[4],xrdata[5],xrdata[6]);

    int* buf;

    buf = (int*)(*env)->GetIntArrayElements(env,info,NULL);

    for(i=0;i<len;i++)
        buf[i] = xrdata[i];
    (*env)->ReleaseIntArrayElements(env,info, (jint*)buf, JNI_ABORT);
    return 0;
}

static const JNINativeMethod methods1[] = {
        {"uartInit", "(Ljava/lang/String;)I", (void *)native_uartInit},
        {"uartDestroy", "(I)I", (void *)native_uartDestroy},
        {"setOpt", "(IIIII)I", (void *)native_setOpt},
        {"send", "(I[II)I", (void *)native_send},
        {"recv", "(I[II)I", (void *)native_recv},
        {"setRS485WriteRead", "(I)I", (void *)native_setRS485ReadWrite},

};
static const JNINativeMethod methods2[] = {
        {"rs485Init", "()Z", (void *)native_rs485_Init},
        {"rs485Destroy", "()V", (void *)native_rs485_Destroy},
        {"rs485GetBoardAddress", "(II[I)I", (void *)native_rs485_GetBoardAddress},
        {"rs485OpenGrid", "(II[I)I", (void *)native_rs485_OpenGrid},
        {"rs485GetDoorState", "(II[I)I", (void *)native_rs485_GetDoorState},
        {"rs485GetProtocalID", "(I[I)I", (void *)native_rs485_GetProtocalID},
};

jint JNI_OnLoad(JavaVM *jvm, void *reserved)
{
    JNIEnv *env;
    jclass cls1, cls2;

    if ((*jvm)->GetEnv(jvm, (void **)&env, JNI_VERSION_1_6)) {
        return JNI_ERR; /* JNI version not supported */
    }
    cls1 = (*env)->FindClass(env, "com/smatek/uart/UartComm");
    if (cls1 == NULL) {
        return JNI_ERR;
    }
    cls2 = (*env)->FindClass(env, "com/smatek/uart/UartComm$Rs485");
    if (cls1 == NULL) {
        return JNI_ERR;
    }

    if ((*env)->RegisterNatives(env, cls1, methods1, sizeof(methods1)/sizeof(methods1[0])) < 0)
        return JNI_ERR;
    if ((*env)->RegisterNatives(env, cls2, methods2, sizeof(methods2)/sizeof(methods2[0])) < 0)
        return JNI_ERR;

    return JNI_VERSION_1_4;
}

termios.h

/*
 * Copyright (C) 2008 The Android Open Source Project
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *  * Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *  * Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */
#ifndef _TERMIOS_H_
#define _TERMIOS_H_

#include <sys/cdefs.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <stdint.h>
#include <linux/termios.h>

__BEGIN_DECLS

/* Redefine these to match their ioctl number */
#undef  TCSANOW
#define TCSANOW    TCSETS

#undef  TCSADRAIN
#define TCSADRAIN  TCSETSW

#undef  TCSAFLUSH
#define TCSAFLUSH  TCSETSF

static __inline__ int tcgetattr(int fd, struct termios *s)
{
    return ioctl(fd, TCGETS, s);
}

static __inline__ int tcsetattr(int fd, int __opt, const struct termios *s)
{
    return ioctl(fd, __opt, (void *)s);
}

static __inline__ int tcflow(int fd, int action)
{
    return ioctl(fd, TCXONC, (void *)(intptr_t)action);
}

static __inline__ int tcflush(int fd, int __queue)
{
    return ioctl(fd, TCFLSH, (void *)(intptr_t)__queue);
}

static __inline__ pid_t tcgetsid(int fd)
{
    pid_t _pid;
    return ioctl(fd, TIOCGSID, &_pid) ? (pid_t)-1 : _pid;
}

static __inline__ int tcsendbreak(int fd, int __duration)
{
    return ioctl(fd, TCSBRKP, (void *)(uintptr_t)__duration);
}

static __inline__ speed_t cfgetospeed(const struct termios *s)
{
    return (speed_t)(s->c_cflag & CBAUD);
}

static __inline__ int cfsetospeed(struct termios *s, speed_t  speed)
{
    s->c_cflag = (s->c_cflag & ~CBAUD) | (speed & CBAUD);
    return 0;
}

static __inline__ speed_t cfgetispeed(const struct termios *s)
{
    return (speed_t)(s->c_cflag & CBAUD);
}

static __inline__ int cfsetispeed(struct termios *s, speed_t  speed)
{
    s->c_cflag = (s->c_cflag & ~CBAUD) | (speed & CBAUD);
  return 0;
}

static __inline__ void cfmakeraw(struct termios *s)
{
    s->c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON);
    s->c_oflag &= ~OPOST;
    s->c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
    s->c_cflag &= ~(CSIZE|PARENB);
    s->c_cflag |= CS8;
}

static __inline int cfsetspeed(struct termios* s, speed_t speed) {
  // TODO: check 'speed' is valid.
  s->c_cflag = (s->c_cflag & ~CBAUD) | (speed & CBAUD);
  return 0;
}

static __inline int tcdrain(int fd) {
  // A non-zero argument to TCSBRK means "don't send a break".
  // The drain is a side-effect of the ioctl!
  return ioctl(fd, TCSBRK, __BIONIC_CAST(static_cast, unsigned long, 1));
}

__END_DECLS

#endif /* _TERMIOS_H_ */


上一篇 下一篇

猜你喜欢

热点阅读