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_ */