且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

I.MX6 Android Linux UART send receive with multi-thread and multi-mode demo

更新时间:2022-08-12 20:37:18

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