作者: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"