I.MX6 Android Linux UART send receive with multi-thread and multi-mode demo
/******************************************************************************************* * 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"