作者:Xandy



最近段时间一直在做android下串口通信的东东,大概功能是android系统端的ARM和系统外的一个MCU通信,通过android界面控制MCU上挂的设备,如radio、TV、BT等等,下面对这个过程作一个浅显的阐述,有错之处还望大家斧正……


我是直接在HAL层中通过两个线程对串口的设备节点/dev/ttymxc1进行读和写的,相应的代码如下:


    1. 1、init代码  
    2. /***************************************************************  
    3. ** fun:   init uart(/dev/ttymxc1);  
    4. ** in:      
    5. ** out:   fd sucess, -1 false;  
    6. ** init_mcuuart  
    7. ***************************************************************/  
    8. static int  init_mcuuart(void)  
    9. {  
    10.     int fd,var;  
    11.     portinfo pPort_info;  
    12.     int err;  
    13.   
    14.     dbg(DBG_DEBUG," init_mcuuart in");  
    15.       
    16.     //clear message buf  
    17.     memset(&pPort_info,0,sizeof(portinfo));  
    18.   
    19.     //alloc sent and receive buf  
    20. pSentMessagePackage = malloc(sizeof(msgpkg));  
    21. pReceiveMessagePackage = malloc(sizeof(msgpkg));  
    22.   
    23. fd=open_mcuport();  
    24.       
    25. >fd= fd;  
    26. >fd= fd;  
    27.       
    28. fd == -1)  
    29.     {  
    30.         LOGE("init_mcuuart open port error!");  
    31.       return -1;  
    32.     }  
    33.       
    34. pPort_info.baud_rate=COM1MCU_BAUD;  
    35. pPort_info.data_bits=COM1MCU_DATABIT;  
    36. pPort_info.flow_ctrl=COM1MCU_CTRL;  
    37. pPort_info.stop_bit=COM1MCU_STOPBIT;  
    38. pPort_info.parity=COM1MCU_PARITY;  
    39. pPort_info.port_fd=fd;  
    40.   
    41.     //pthread_mutex_lock(&pPort_info.portlock);  
    42. var = set_portLocked(&pPort_info);  
    43.     //pthread_mutex_unlock(&pPort_info.portlock);  
    44.       
    45. < 0)  
    46.     {  
    47.         LOGE("set_portLocked error!");  
    48.         return -1;  
    49.     }  
    50.   
    51.     //handshake message  
    52.     //messagePackage(&PowerOnHandShakeCmd,NULL);  
    53.       
    54.     //messagePackage(&TestCmd,"************com1mcu.c mode for test*********");  
    55.   
    56.     //uart send message thread  
    57. >uart_begin, 0, 0);  
    58. >uart_end, 0, 0);  
    59. >uart_inited = true;  
    60. err = pthread_create(&pSentMessagePackage->thread_id, NULL, &uartUploadData, (void *)pSentMessagePackage);  
    61.   
    62.     if(err != 0)  
    63.         LOGE("init_mcuuart pthread_create pSentMessagePackage error %s!",strerror(err));  
    64.   
    65.     //uart receive message thread and analyze it  
    66. >uart_begin, 0, 0);  
    67. >uart_end, 0, 0);  
    68. >uart_inited = true;  
    69. err = pthread_create(&pReceiveMessagePackage->thread_id, NULL, &uartDownloadData, (void *)pReceiveMessagePackage);  
    70.   
    71.     if(err != 0)  
    72.         LOGE("init_mcuuart pthread_create pReceiveMessagePackage error %s!",strerror(err));  
    73.   
    74.     return 0;                 
    75. }  
    76. 2、发送数据回调函数  
    77. /***************************************************************  
    78. ** fun:   uart send handle  
    79. ** in:    arg pSentMessagePackage  
    80. **out:     
    81. ** uartUploadData  
    82. ****************************************************************/  
    83. static void * uartUploadData(void * arg)  
    84. {  
    85. upData = (pMsgPkg)arg;  
    86.   
    87.     while(1)  
    88.     {  
    89. >uart_begin);  
    90. >uart_inited)  
    91.         {  
    92. >uart_end);  
    93.             break;  
    94.         }  
    95.         //No message to upload  
    96. >messageCnt <= 0)  
    97. >uart_begin);  
    98.   
    99. >SYNCCode = SYNCDATA1;      
    100.   
    101. #if 1          
    102.         if(!CRCCheck((uuint8*)upData,Send))    //CRC  
    103.         {  
    104.             LOGE("uartUploadData CRC Error!");  
    105. >uart_begin);  
    106.         }  
    107. #endif          
    108.   
    109. len = SYNCCodeLen(2)+CmdCnt(1)+CmdLen(1)+messageLen(N)+CRCLen(1)  
    110. >fd,upData,upData->messageLen+5);  
    111.   
    112. >uart_end);  
    113.   
    114. >messageCnt = 0;  
    115. >messageLen = 0;  
    116.     }  
    117.   
    118.     return true;  
    119. }  
    120. 3、接收数据回调函数  
    121. /***************************************************************  
    122. ** fun:   uart receive handle  
    123. ** in:    arg pReceiveMessagePackage  
    124. ** out:     
    125. ** uartDownloadData  
    126. ****************************************************************/  
    127. static void * uartDownloadData(void * arg)  
    128. {  
    129.     uuint8 buffer[RECMSGONCELEN];  
    130. pmsg = (pMsgPkg)arg;  
    131.     int len,i;  
    132.   
    133.     while(1)  
    134.     {      
    135. >uart_inited)  
    136.         {  
    137. >uart_end);  
    138.             break;  
    139.         }  
    140.           
    141. >fd,buffer,&len,RECMSGONCELEN,RECMSGTIMEOUT);  
    142.   
    143. > 0)  
    144.         {              
    145.             //copy the receive data to the big buf  
    146. i=0;i<len;i++)  
    147.             {  
    148. >pRecPoint >= RECMSGBUFLEN)  
    149. >pRecPoint = 0;  
    150.                   
    151. >pRecPoint] = buffer[i];  
    152. >pRecPoint++;  
    153.             }  
    154.               
    155.             memset(buffer,0,RECMSGONCELEN);  
    156.         }  
    157.   
    158. pAnalyzePoint=%d,pRecPoint=%d",pmsg->pAnalyzePoint,pmsg->pRecPoint);  
    159.   
    160.         //have new message and prev message have handout to app, analyze from the analyze Point  
    161. >pAnalyzePoint != pmsg->pRecPoint)&&(!pmsg->handOutFlag))  
    162. >pAnalyzePoint]));  
    163.     }  
    164.   
    165.     return true;      
    166. }






    JNI中的代码很简单,通过init、upload、download这三个HAL层中的函数接口对串进行初始化、写数据和读数据。

    写数据的时候,直接把java传过来的数据通过upload在HAL中加上数据头及CRC位,然后在写线程中写入串口设备节点……

    读数据的时候,在HAL中通过读数据的线程从串口设备节点中将数据读出后进行解析和CRC校验,如果CRC校验正常则把解析之后的数据通过JNI层传给java中进行使用。

    值得一提的是接收数据和解析数据的时候相应buffer的控制,我这里在接收数据的时候用的是一个环形buffer,容量为1KByte,这样做的目的的防止接收数据丢失。

     

    JAVA中的代码主要是两部分,一部分是实现写数据的方法,这个比较简单,封闭好JNI中的本地函数uart_upload就行了。别一部分是实现读数据的方法,这个有点麻烦,因为在我的系统里读数据的时候可能有主动上报的数据,也就是ARM这边没有请求,MCU那边如果有数据时会主动上报给ARM,比如MCU那边的按键信息等。我在读的方法里用了一个线程来处理这些,不停的扫描解析数据的buffer,当有正确的数据已经解析并存在于解析buffer中时,就在这个线程里通过广播的方式将消息广播出去,然后在APP中监听这个广播就行了,相应的代码比较多,这里就不发上来了!

    最后要强调一点的是,由于操作设备节点的时候,需要有system用户的权限,我是在相应的app的配置文件中增加了android:sharedUserId="android.uid.system"