/*******************************************************************************************
* I.MX6 Android Linux UART send receive with multi-thread and multi-mode demo
* 声明:
* 1. 本软件是为了测试Android底层的Linux驱动以及硬件是否存在缺陷而编写的测试软件;
* 2. 本软件可以设置为发送、接收、发送并接收模式,并且提供q+enter键退出程序;
* 3. 本人是采用NDK的方式进行编译的,并采用autorun.sh脚本进行调用,主要是不想敲太多键盘;
* 4. 本程序并不打算给出太多的注释,没有理由;
* 5. 如果想知道波特率更多细节,可以参考本人的《I.MX6 Linux Serial Baud Rate hacking》。
*
* 2015-8-22 晴 深圳 南山平山村 曾剑锋
******************************************************************************************/
\\\\\\\\\-*- 目录 -*-////////
| 一、cat uartRS.c |
| 二、cat Android.mk |
| 三、cat autorun.sh |
\\\\\\\\\\\\\\\//////////////
一、cat uartRS.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
#include <errno.h>
#include <pthread.h>
#define SENDWORKMODE 1
#define RECVWORKMODE 2
#define SENDANDRECVWORKMODE 3
int serial_fd = 0;
int serialNumber = 0;
int baudRate = 0;
int workMode = 0; // 1 send; 2 recv; 3 send and recv
char serialString[20] = {0};
char sendString[512] = {0};
char recvString[512] = {0};
int help ( int argc );
int initSerial ( void );
int getBaudRate ( char *baudRateString );
void getSerial ( char* commandLineserialString );
int getWorkMode ( char *workMode );
int uart_send ( int fd, char *data, int datalen );
int uart_recv ( int fd, char *data, int datalen );
pthread_t recv_thread;
void *recvDataThread ( void *arg );
pthread_t quitOut_thread;
void *quitOutThead ( void *arg );
int main(int argc, char **argv)
{
if ( help( argc ) != 0)
return -1;
getSerial ( argv[1] );
baudRate = getBaudRate ( argv[2] );
workMode = getWorkMode ( argv[3] );
initSerial ();
if ( workMode == RECVWORKMODE || workMode == SENDANDRECVWORKMODE ) {
pthread_create ( &recv_thread, NULL, recvDataThread, NULL );
}
pthread_create ( &quitOut_thread, NULL, quitOutThead, NULL );
int i = 0;
while ( 1 ) {
if ( workMode == SENDWORKMODE || workMode == SENDANDRECVWORKMODE ) {
sprintf ( sendString, "%03d: %s\r\n", i++, argv[4] );
uart_send ( serial_fd, sendString, strlen ( sendString ) );
}
usleep ( 100000 );
}
close ( serial_fd );
return 0;
}
int getWorkMode ( char *workModeString ) {
int ret = atoi( workModeString );
switch ( ret ) {
case 1 :
printf ( "workMode: send.\n" );
break;
case 2 :
printf ( "workMode: recv.\n" );
break;
case 3 :
printf ( "workMode: send and recv.\n" );
break;
default:
printf ( "none of this workMode.\n" );
exit ( 0 );
}
return ret;
}
void *quitOutThead(void *arg) {
//system("stty raw -echo"); can't work well in Android linux
char ch = '\0';
while ( 1 ) {
scanf ( "%c", &ch );
if ( ch == 'q' || ch == 'Q' ) {
exit ( 0 );
}
}
}
void *recvDataThread(void *arg) {
int ret = 0;
int i = 0;
while ( 1 ) {
ret = uart_recv ( serial_fd, recvString, sizeof(recvString) );
printf ( "%03d %s\n", i++, recvString );
bzero ( recvString, sizeof(recvString) );
usleep ( 100000 );
}
}
int help( int argc ) {
if ( argc != 5 ) {
printf ( "USAGE:\n" );
printf ( " command <serial absolute path> <baudRate> <workMode> <send String>\n" );
printf ( " example:\n" );
printf ( " ./uartRS /dev/ttymxc1 115200 3 \"1234567890ABCDEFG\"\n" );
return -1;
}
return 0;
}
int uart_recv(int fd, char *data, int datalen) {
int ret = 0;
ret = read ( fd, data, datalen );
return ret;
}
int uart_send(int fd, char *data, int datalen) {
int len = 0;
len = write ( fd, data, datalen ); //实际写入的长度
if(len == datalen) {
return len;
} else {
tcflush(fd, TCOFLUSH); //TCOFLUSH刷新写入的数据但不传送
return -1;
}
return 0;
}
int initSerial( void ) {
//serial_fd = open( serialString, O_RDWR | O_NOCTTY | O_NDELAY );
serial_fd = open ( serialString, O_RDWR );
if ( serial_fd < 0 ) {
perror ( "open" );
return -1;
}
// 串口主要设置结构体termios <termios.h>
struct termios options;
/**
* tcgetattr函数用于获取与终端相关的参数,参数fd为终端的文件描述符,
* 返回的结果保存在termios结构体中
*/
tcgetattr ( serial_fd, &options );
/**2. 修改所获得的参数*/
options.c_cflag |= (CLOCAL | CREAD); //设置控制模式状态,本地连接,接收使能
options.c_cflag &= ~CSIZE; //字符长度,设置数据位之前一定要屏掉这个位
options.c_cflag &= ~CRTSCTS; //无硬件流控
options.c_cflag |= CS8; //8位数据长度
options.c_cflag &= ~CSTOPB; //1位停止位
options.c_iflag |= IGNPAR; //无奇偶检验位
options.c_oflag = 0; //输出模式
options.c_lflag = 0; //不激活终端模式
cfsetospeed ( &options, baudRate ); //设置波特率
//cfsetospeed(&options, B2000000); //设置波特率
/* 设置新属性,TCSANOW:所有改变立即生效*/
tcflush ( serial_fd, TCIFLUSH ); //溢出数据可以接收,但不读
tcsetattr ( serial_fd, TCSANOW, &options );
return 0;
}
void getSerial ( char* commandLineserialString ) {
sprintf ( serialString, "%s", commandLineserialString );
printf ( "serialString : %s.\n", serialString );
}
/**
* 该函数之所以采用这种方式,主要是为了波特率出错时方便调试
*/
int getBaudRate ( char* baudRateString ) {
int ret = atoi ( baudRateString );
switch ( ret ) {
case 0:
printf ( "baudRate %s.\n", "0" );
ret = B0;
break;
case 50:
printf ( "baudRate %s.\n", "50" );
ret = B50;
break;
case 75:
printf ( "baudRate %s.\n", "75" );
ret = B75;
break;
case 110:
printf ( "baudRate %s.\n", "110" );
ret = B110;
break;
case 134:
printf ( "baudRate %s.\n", "134" );
ret = B134;
break;
case 150:
printf ( "baudRate %s.\n", "150" );
ret = B150;
break;
case 200:
printf ( "baudRate %s.\n", "200" );
ret = B200;
break;
case 300:
printf ( "baudRate %s.\n", "300" );
ret = B300;
break;
case 600:
printf ( "baudRate %s.\n", "600" );
ret = B600;
break;
case 1200:
printf ( "baudRate %s.\n", "1200" );
ret = B1200;
break;
case 1800:
printf ( "baudRate %s.\n", "1800" );
ret = B1800;
break;
case 2400:
printf ( "baudRate %s.\n", "2400" );
ret = B2400;
break;
case 4800:
printf ( "baudRate %s.\n", "4800" );
ret = B4800;
break;
case 9600:
printf ( "baudRate %s.\n", "9600" );
ret = B9600;
break;
case 19200:
printf ( "baudRate %s.\n", "19200" );
ret = B19200;
break;
case 38400:
printf ( "baudRate %s.\n", "38400" );
ret = B38400;
break;
case 57600:
printf ( "baudRate %s.\n", "57600" );
ret = B57600;
break;
case 115200:
printf ( "baudRate %s.\n", "115200" );
ret = B115200;
break;
case 230400:
printf ( "baudRate %s.\n", "230400" );
ret = B230400;
break;
case 460800:
printf ( "baudRate %s.\n", "460800" );
ret = B460800;
break;
case 500000:
printf ( "baudRate %s.\n", "500000" );
ret = B500000;
break;
case 576000:
printf ( "baudRate %s.\n", "576000" );
ret = B576000;
break;
case 921600:
printf ( "baudRate %s.\n", "921600" );
ret = B921600;
break;
case 1000000:
printf ( "baudRate %s.\n", "1000000" );
ret = B1000000;
break;
case 1152000:
printf ( "baudRate %s.\n", "1152000" );
ret = B1152000;
break;
case 1500000:
printf ( "baudRate %s.\n", "1500000" );
ret = B1500000;
break;
case 2000000:
printf ( "baudRate %s.\n", "2000000" );
ret = B2000000;
break;
case 2500000:
printf ( "baudRate %s.\n", "2500000" );
ret = B2500000;
break;
case 3000000:
printf ( "baudRate %s.\n", "3000000" );
ret = B3000000;
break;
case 3500000:
printf ( "baudRate %s.\n", "3500000" );
ret = B3500000;
break;
case 4000000:
printf ( "baudRate %s.\n", "4000000" );
ret = B4000000;
break;
default:
printf ( "baudRate is not exist %s.\n", "0" );
ret = B0;
}
//printf ("baudRate %s.\n", baudRateString);
return ret;
}
二、cat Android.mk
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := uartRs
#LOCAL_STATIC_LIBRARIES :=libpthread
#LOCAL_SHARED_LIBRARIES :=libpthread
LOCAL_STATIC_LIBRARIES :=libpthread
LOCAL_SRC_FILES := uartRS.c
#LOCAL_LDLIBS += -lpthread
include $(BUILD_EXECUTABLE)
三、cat autorun.sh
# ./uartRS <serial absolute path> <baudRate> <work mode> <send String>
# 1.serial absolute path
# the absolute path for serial port, example:
# /dev/ttymxc1
# 2. referrence baudrate:
# 0
# 50
# 75
# 110
# 134
# 150
# 200
# 300
# 600
# 1200
# 1800
# 2400
# 4800
# 9600
# 19200
# 38400
# 57600
# 115200
# 230400
# 460800
# 500000
# 576000
# 921600
# 1000000
# 1152000
# 1500000
# 2000000
# 2500000
# 3000000
# 3500000
# 4000000
# 3. work mode
# 1. send;
# 2. recv;
# 3. send and recv
# 4. send string
# the string what you want to send
chmod 777 ./uartRS # give excute-permission
# ./uartRS <serial absolute path> <baudRate> <work mode> <send String>
./uartRS /dev/ttymxc1 115200 3 "1234567890ABCDEF"