linux 下基于特定通信协议利用多线程同步通信机制实现的串口通信

来源:互联网 发布:快餐厅软件 编辑:程序博客网 时间:2024/04/29 04:17
  1. </pre><pre name="code" class="cpp">/** 
  2.  *@Title:利用多线程同步通信机制实现串口通信 
  3.  *@Introduce:主要完成根据特定的通信协议实现串口与PC上特定串口 
  4.  *  通信软件的通信。测试版,只是完成主要框架,没有完全将协议的 
  5.  *  所有通信方式方法做完。 
  6.  *  其中包含的测试功能有:监听主机(PC上的软件)发送的特定请求, 
  7.  *  能够识别类型,并解析包含里面的信息,并且自动回复,所写的根 
  8.  *  据协议要求的固定消息结构体。 
  9.  *  实现原理:多线程,同步,通信。 
  10.  *  其中一个线程专门读取串口中从主机传递的信号,并通过识别出来    
  11.  *  的长度(length),将一个完整的包截取下来,利用识别出来的类 
  12.  *  型(type)将包以字符串缓存形式发往特定的处理线程。 
  13.  *  特定的线程按操作分,有两类,一类主动发出请求信号等待主机回 
  14.  *  应;另一类,等待主机发送请求,然后根据指令回应相关信息 
  15.  *  说明:在这里,因为只是为了做功能测试,所以所有的解析并根据 
  16.  *  相应信息内容做处理的操作统一简化为将内容打印出来显示。 
  17.  *@Attention:主要难点代码中也有注释,这边稍微记录我的错误提醒 
  18.  *  在这个同步通信机制中,不同线程通过一个全局的指针list_head 
  19.  *  m_req_list作为机制,所有需要的线程中传递的结构体都挂在它下 
  20.  *  面,然后传递信息的结构体也有通用格式GeneralReqT,根据里面 
  21.  *  type参量确定不同类型,buffer存储需要传递的字符串信息。 
  22.  *@Explain:包含的文件名有:dev_com_main.c(主函数所在文件) 
  23.  *             dev_com_main.h(主函数的头文件) 
  24.  *  list.h(特殊的list_head结构体的说明和相关函数宏的说明文件) 
  25.  *  crc16.c,crc16.h(CRC16校验码生成的函数体文件和头文件) 
  26.  *  linux下交叉编译试例: 
  27.  *  确保上述文件都放在当前文件夹下,输入: 
  28.  *  #gcc -o dev dev_com_main.c crc16.c -I ./ -lpthread 
  29.  *  交叉编译,更换gcc便好。 
  30.  *@Author:wanney     
  31.  *@Date:2014-10-25 
  32.  *@e-Mail:wanney216@gmail.com 
  33.  *@长江不择细流,泰山不辞抔土。 
  34.  */  

[cpp] view plaincopy
  1. #include "dev_com_main.h"  
  2. #include <pthread.h>  
  3. #include <malloc.h>   
  4. #define SHOWCHAR 1  
  5. #define SHOWHEX  0  
  6. #define HEADLOGO 0xaa55  
  7.   
  8. //对于静态分配的互斥量, 可以把它设置为PTHREAD_MUTEX_INITIALIZER,   
  9. //或者调用pthread_mutex_init  
  10. static pthread_mutex_t m_mutex = PTHREAD_MUTEX_INITIALIZER;  
  11. //形成一个闭环,是当前结构体的前节点和后节点都指向本身。  
  12. static struct list_head m_req_list = {&m_req_list, &m_req_list};  
  13. //串口打开的初始化  
  14. //参数:串口设备的路径名 dev,设置整型的波特率(注意格式匹配)  
  15. //设备路径名出错会报错,波特率输出默认为:9600  
  16. //其他参数设默认值:数据位:8位,校验位:无,停止位:1位  
  17. int  uart_open (char *dev, int baud)  
  18. {  
  19.     struct termios tio;  
  20.     int fd;  
  21.     int baud_flags;  
  22.   
  23.     fd = open(dev, O_RDWR);  
  24.     if(fd == -1) {  
  25.     //  fprintf(stdout, "open %s error!\n", dev);  
  26.         return -1;  
  27.     }  
  28.   
  29.     if(tcgetattr(fd, &tio) < 0) {  
  30.     //  fprintf(stdout, "tcgetattr error!\n");  
  31.         close(fd);  
  32.         return -1;  
  33.     }  
  34.   
  35.     switch (baud) {  
  36.     case 115200:  
  37.         baud_flags = B115200;  
  38.         break;  
  39.     case 57600:  
  40.         baud_flags = B57600;  
  41.         break;  
  42.     case 38400:  
  43.         baud_flags = B38400;  
  44.         break;  
  45.     case 19200:  
  46.         baud_flags = B19200;  
  47.         break;  
  48.     case 9600:  
  49.         baud_flags = B9600;  
  50.         break;  
  51.     case 2400:  
  52.         baud_flags = B2400;  
  53.         break;  
  54.     case 4800:  
  55.         baud_flags = B4800;  
  56.         break;  
  57.     default:  
  58.         baud_flags = B9600;  
  59.         break;  
  60.     }  
  61.   
  62.     fcntl(fd, F_SETFL,O_NONBLOCK);      
  63.     tio.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG | ECHOE);  
  64.     tio.c_iflag &= ~(ICRNL | INPCK | ISTRIP | IXON | BRKINT);  
  65.     tio.c_iflag &= ~(CSIZE | PARENB | CSTOPB);  
  66.     tio.c_oflag &= ~(OPOST);  
  67.     tio.c_cflag = CS8 | baud_flags | CLOCAL | CREAD;  
  68.     tio.c_cc[VMIN] = 0;  
  69.     tio.c_cc[VTIME] = 0;  
  70.   
  71.     tcflush(fd, TCIFLUSH);  
  72.     if(tcsetattr(fd, TCSAFLUSH, &tio) < 0) {  
  73.     //  fprintf(stdout,"tcsetattr error!\n");  
  74.         close(fd);  
  75.         return -1;  
  76.     }  
  77.   
  78.     printf("open uart:%s, baud:%d", dev, baud);  
  79.     return fd;  
  80. }  
  81.   
  82. //初始化:从机参数查询消息的应答消息  
  83. void initAnsCheckInfoC(unsigned char * buf,pAnsCheckInfoC p_ans_check_info){  
  84.         unsigned char buf_[26] ;  
  85.         WORD crc16;  
  86.         int i;  
  87.         memset(buf_,0x00,sizeof(buf_));       
  88.         p_ans_check_info->infohead.logo = HEADLOGO;  
  89.     p_ans_check_info->infohead.type = 0x7006;  
  90.     p_ans_check_info->infohead.length = 0x0e;  
  91.     p_ans_check_info->infohead.flag = 0x00;  
  92.     p_ans_check_info->infohead.number = 0x1111;  
  93.     p_ans_check_info->infohead.version = 0x0001;  
  94.     memset(p_ans_check_info->ter_mac,0x00,sizeof(p_ans_check_info->ter_mac));  
  95.     p_ans_check_info->hb_period = 0x09;  
  96.     p_ans_check_info->repeat_times = 0x05;  
  97.     p_ans_check_info->timeover = 200;  
  98.     p_ans_check_info->maintain_info = 0x00;  
  99.     p_ans_check_info->reserve_1 = 0x00;  
  100.     p_ans_check_info->reserve_2 = 0x00;  
  101.     p_ans_check_info->reserve_3 = 0x00;  
  102.     //内存拷贝  
  103.     memcpy(buf,(unsigned char *)p_ans_check_info,sizeof(AnsCheckInfoC));  
  104.     //调整双字节或四字节高低位顺序  
  105.     word_buffer(buf,0,p_ans_check_info->infohead.logo);  
  106.     word_buffer(buf,2,p_ans_check_info->infohead.length);  
  107.     word_buffer(buf,4,p_ans_check_info->infohead.type);  
  108.     word_buffer(buf,6,p_ans_check_info->infohead.flag);  
  109.     word_buffer(buf,8,p_ans_check_info->infohead.number);  
  110.     word_buffer(buf,10,p_ans_check_info->infohead.version);  
  111.     word_buffer(buf,20,p_ans_check_info->timeover);  
  112.     //如何减去两个字节再排序?      
  113.     for(i = 0;i<sizeof(buf_);i++){  
  114.         buf_[i] = *(buf + i);     
  115.     }  
  116.     //用于计算crc16校验码的值  
  117.     crc16 = CRC16(0x0000,buf_,sizeof(buf_));  
  118.     p_ans_check_info->check_code = crc16;  
  119.     word_buffer(buf,26,crc16);  
  120. }  
  121.   
  122. //发送主机的从机参数查询消息的应答消息的线程  
  123. //参数:串口的文件操作符  
  124. void * answer_check_info(void * data){  
  125.       
  126.     GeneralReqT checkInfo;  
  127.     AnsCheckInfoC answer;  
  128.     CheckInfoS request;  
  129.     int fd = *(int *)data;  
  130.     unsigned char * buf;  
  131.     while(1){     
  132.         buf = (unsigned char *)malloc(sizeof(AnsCheckInfoC));  
  133.         memset(buf,0x00,sizeof(AnsCheckInfoC));  
  134.     if (pthread_cond_init (&checkInfo.cond, NULL) != 0) {  
  135.         printf ("set rtc fail");  
  136.         return;  
  137.     }  
  138.         debug_trace;;  
  139. #if 0      
  140.     char sendinfo[] = "hello world!\n";  
  141.     char * psend = sendinfo;  
  142.     length = write (fd, psend, sizeof(sendinfo));  
  143.     printf("the length is %d \n",length);  
  144. #else  
  145.         checkInfo.type = 0x8005;  
  146.         //初始化数据request的数据  
  147.         initAnsCheckInfoC(buf,&answer);  
  148.     pthread_mutex_lock (&m_mutex);  
  149.     list_add (&checkInfo.list, &m_req_list);                                 
  150.     pthread_cond_wait (&checkInfo.cond, &m_mutex);  
  151.     //读线程已经得到主机返回信号,可以测试了。  
  152.     //printf("the checkinfo.request is : \n");  
  153.         //print_frame((unsigned char *)&checkInfo.request,sizeof(CheckInfoS));  
  154.         checkinfocpy(&request, checkInfo.buffer, sizeof(CheckInfoS));  
  155.     printf("the checkinfo.request.infohead.type is %04x\n",request.infohead.type);  
  156.     printf("the checkinfo.request.infohead.logo is %04x\n",request.infohead.logo);  
  157.     printf("the checkinfo.request.infohead.length is %04x\n",request.infohead.length);  
  158.     printf("the checkinfo.request.infohead.flag is %04x\n",request.infohead.flag);  
  159.     checkInfo.time = 0;  
  160.     printf("the buffer is :\n");  
  161.     print_frame(buf,sizeof(AnsCheckInfoC));  
  162.     write (fd, buf, sizeof(AnsCheckInfoC));  
  163.     free(buf);  
  164.     pthread_mutex_unlock (&m_mutex);  
  165.     pthread_cond_destroy (&checkInfo.cond);  
  166.   }  
  167. #endif  
  168. }  
  169.   
  170. //打印字符串中指定长度的内容,用二进制显示出来。  
  171. static void print_frame (unsigned char *frame,int size)  
  172. {  
  173.     int i;  
  174.     unsigned char *buf = frame;  
  175.     for (i=0; i<size;i++) {  
  176.         printf ("%02x ", buf[i]);  
  177.     }  
  178.     printf ("\r\n");  
  179. }  
  180.   
  181. //初始化从机心跳信号结构体,并填写传进来的写缓存buf。  
  182. void initInfoHeartbeatC(unsigned char * buf,pInfoHeartbeatC p_info_heart_heat){  
  183.         unsigned char buf_[20] ;  
  184.         WORD crc16;  
  185.         int i;  
  186.         memset(buf_,0x00,sizeof(buf_));  
  187.         p_info_heart_heat->infohead.logo = 0xAA55;  
  188.     p_info_heart_heat->infohead.type = 0x7003;  
  189.     p_info_heart_heat->infohead.length = 0x0a;  
  190.     p_info_heart_heat->infohead.flag = 0x02;  
  191.     p_info_heart_heat->infohead.number = 0x1111;  
  192.     p_info_heart_heat->infohead.version = 0x0001;  
  193.     p_info_heart_heat->status = 0x00;  
  194.     p_info_heart_heat->reserve = 0x00;  
  195.     memset(p_info_heart_heat->ter_mac,0x00,sizeof(p_info_heart_heat->ter_mac));  
  196.         memcpy(buf,(unsigned char *)p_info_heart_heat,sizeof(InfoHeartbeatC));  
  197.         word_buffer(buf,0,p_info_heart_heat->infohead.logo);  
  198.     word_buffer(buf,2,p_info_heart_heat->infohead.length);  
  199.     word_buffer(buf,4,p_info_heart_heat->infohead.type);  
  200.     word_buffer(buf,6,p_info_heart_heat->infohead.flag);  
  201.     word_buffer(buf,8,p_info_heart_heat->infohead.number);  
  202.     word_buffer(buf,10,p_info_heart_heat->infohead.version);  
  203.       
  204.     //如何减去两个字节再排序?  
  205.     for(i = 0;i<20;i++){  
  206.         buf_[i] = *(buf + i);     
  207.     }  
  208.     crc16 = CRC16(0x0000,buf_,20);  
  209.         p_info_heart_heat->check_code = crc16;  
  210.         word_buffer(buf,20,crc16);  
  211. }  
  212.   
  213. //主机回应心跳信号的解析函数,功能:  
  214. //将缓存buf从大端传输的存储中转存到小端模式存储  
  215. //原理:将机构体中相应的双字节高低位交换一下  
  216. void infoHeartbeatcpy(pInfoHeartbeatS p_info_heart_heat, unsigned char *buf, int size)  
  217. {  
  218.     memcpy((unsigned char *)p_info_heart_heat,buf,size);  
  219.     p_info_heart_heat->infohead.logo = word_to_int(*buf,*(buf+1));  
  220.     p_info_heart_heat->infohead.length   = word_to_int(*(buf+2),*(buf+3));  
  221.     p_info_heart_heat->infohead.type = word_to_int(*(buf+4),*(buf+5));  
  222.     p_info_heart_heat->infohead.flag = word_to_int(*(buf+6),*(buf+7));  
  223.     p_info_heart_heat->infohead.number   = word_to_int(*(buf+8),*(buf+9));  
  224.     p_info_heart_heat->infohead.version  = word_to_int(*(buf+10),*(buf+11));  
  225.     p_info_heart_heat->check_code = word_to_int(*(buf+20),*(buf+21));  
  226. }  
  227.   
  228. //发送心跳消息的线程  
  229. //参数:串口文件操作符  
  230. void * request_heart_beat(void *data){  
  231.         GeneralReqT hebe;  
  232.         InfoHeartbeatC request;                           
  233.         InfoHeartbeatS answer;  
  234.         int length;  
  235.         int fd = *(int *)data;  
  236.         unsigned char * buf ;  
  237.         debug_trace;  
  238.     while(1){  
  239.         buf = (unsigned char *)malloc(sizeof(InfoHeartbeatC));  
  240.         memset(buf,0x00,sizeof(InfoHeartbeatC));  
  241.     if (pthread_cond_init (&hebe.cond, NULL) != 0) {  
  242.         printf ("set rtc fail");  
  243.         return;  
  244.     }  
  245. #if 0      
  246.     char sendinfo[] = "hello world!\n";  
  247.     char * psend = sendinfo;  
  248.     length = write (fd, psend, sizeof(sendinfo));  
  249.     printf("the length is %d \n",length);  
  250. #else  
  251.         //初始化数据request的数据  
  252.     //pthread_mutex_lock (&m_mutex);  
  253.     //pic_crack (&hebe.request);  
  254.         //初始化需要发送的数据  
  255.         initInfoHeartbeatC(buf,&request);  
  256.     write (fd, buf, sizeof(InfoHeartbeatC));  
  257.     printf("the buffer of heart beat is \n");  
  258.         print_frame (buf,sizeof(InfoHeartbeatC));  
  259.         hebe.type = 0x8002;  
  260.     list_add (&hebe.list, &m_req_list);  
  261.     //因为这个线程还没有放到等待队列上,所以调用pthread_cond_wait前  
  262.     //要先锁互斥量,即调用pthread_mutex_lock(),pthread_cond_wait在  
  263.     //把线程放进阻塞队列后,自动对mutex进行解锁,使得其它线程可以获  
  264.     //得加锁的权利。这样其它线程才能对临界资源进行访问并在适当的时  
  265.     //候唤醒这个阻塞的进程。当pthread_cond_wait返回的时候又自动给  
  266.     //mutex加锁。  
  267.     //实际上加解锁过程如下:  
  268.     /***************pthread_cond_wait()的使用方法*******************/  
  269.         //pthread_mutex_lock(&qlock); /*lock*/  
  270.         //pthread_cond_wait(&qready, &qlock); /*block-->unlock-->wait() return-->lock*/  
  271.         //pthread_mutex_unlock(&qlock); /*unlock*/  
  272.         /***************************************************************/                                                                                 
  273.     //pthread_cond_wait (&hebe.cond, &m_mutex);  
  274.     //读线程已经得到主机返回信号,可以测试了。  
  275.     printf("the answer from the client:\n");  
  276.         print_frame(hebe.buffer,sizeof(InfoHeartbeatS));  
  277.         //infoHeartbeatcpy(&answer, hebe.buffer,sizeof(InfoHeartbeatS));  
  278.         printf("the heart beat type is %04x",answer.infohead.type);  
  279.         printf("the heart beat logo is %04x",answer.infohead.logo);  
  280.     //pthread_mutex_unlock (&m_mutex);  
  281.     pthread_cond_destroy (&hebe.cond);  
  282.     sleep(1);  
  283.   }  
  284.   
  285. #endif  
  286. }  
  287. //主机请求查询从机参数的信号解析函数,功能:  
  288. //将缓存buf从大端传输的存储中转存到小端模式存储  
  289. //原理:将机构体中相应的双字节高低位交换一下  
  290. void checkinfocpy(pCheckInfoS p_check_info, unsigned char *buf, int size)  
  291. {  
  292.     memcpy((unsigned char *)p_check_info,buf,size);  
  293.     p_check_info->infohead.logo  = word_to_int(*buf,*(buf+1));  
  294.     p_check_info->infohead.length    = word_to_int(*(buf+2),*(buf+3));  
  295.     p_check_info->infohead.type  = word_to_int(*(buf+4),*(buf+5));  
  296.     p_check_info->infohead.flag  = word_to_int(*(buf+6),*(buf+7));  
  297.     p_check_info->infohead.number    = word_to_int(*(buf+8),*(buf+9));  
  298.     p_check_info->infohead.version   = word_to_int(*(buf+10),*(buf+11));  
  299.     p_check_info->check_code = word_to_int(*(buf+18),*(buf+19));  
  300.       
  301. }  
  302.   
  303.   
  304.   
  305.   
  306. //用来监听串口输入信息的线程  
  307. //主要功能:将所读出来的串口字节流识别出来  
  308. //并且根据它的类型将它们裁剪成一个个有效  
  309. //的消息体。  
  310. //参数:无。  
  311. //数据传输按照网络字节序,即大端模式传递字和双字  
  312. void *thread_read(void *data){  
  313.     //一直循环地监听com口是否有数据,是否符合消息头  
  314.     int * pfd = (int *)data;  
  315.     //printf("the pfd is %d\n",*pfd);  
  316.     unsigned char rbuf[64];  
  317.   unsigned char frame[64];  
  318.     fd_set readfds;  
  319.     struct timeval tv;  
  320.   int ret, i, wpos = 0;  
  321.   int FLAG = 0;//0:最初状态,1:第一次进来  
  322.   WORD length,type;  
  323.   struct list_head *pos, *n;  
  324.   //pheartbeatReqT p_wait;  
  325.   //pInfoHeartbeatS p_answer;  
  326.   pGeneralReqT p_wait;  
  327.   pCheckInfoS p_answer;  
  328.   
  329.     tv.tv_sec = 0;  
  330.     tv.tv_usec = 100000; // 100ms  
  331. /*****************以上为初始化变量过程*****************/  
  332. //  
  333.     while (1)  
  334.     {  
  335.         FD_ZERO(&readfds);  
  336.         FD_SET(*pfd,&readfds);  
  337.         //select读串口的阻塞等待函数,  
  338.         //返回:1、数字0:times is error。  
  339.         //2、数字-1:表示连接出现异常返回。  
  340.         //3、default(ret > 0):状态则是正常连接执行  
  341.         //参数tv为链接超时时间,结构体:秒和微秒两位,NULL表示不限时间  
  342.         ret = select((*pfd)+1, &readfds, NULL, NULL, &tv);  
  343.         //不用判断其他的情况。如果操作的状态改变,这边就能察觉  
  344.         if (ret > 0) {  
  345.             //为多串口的操作监听函数操作,这句判断则表明如果是当前这个串口的  
  346.             //文件操作符有数据响应,并执行以下步骤,如果不是则退出本次循环!  
  347.       if(!FD_ISSET(*pfd,&readfds))  
  348.                 continue;  
  349.             //读取串口数据到缓存区rbuf里面,最多一次读64个字节  
  350.       
  351.             ret = read(*pfd, rbuf, sizeof(rbuf));  
  352.             if(ret > 0) {                                    //读取成功,并且ret表示读取到的字节数  
  353.         for (i=0; i<ret; i++) {            
  354. #if 0                     
  355.                     printf(" %x \n ",rbuf[i]);  
  356. #else  
  357.         //按位取出所有字节来分别进行以下操作  
  358.         //该过程为打包过程,将数据流按固定结构体格式打包好  
  359.           if (wpos == 0 ) {                   
  360.             if(rbuf[i] == 0xAA&&rbuf[i+1] == 0x55){  
  361.                     frame[wpos++] = rbuf[i];  
  362.                     frame[wpos++] = rbuf[i+1];  
  363.                     FLAG = 1;                                   //赋值一次,作为第一次进来的标志  
  364.             }  
  365.           }  
  366.           else {  
  367.             //判断完标志为之后,将剩余的字节依次往缓存frame  
  368.             if(FLAG == 1){  
  369.                 i++;//由于一次性判断了两位,所以,这边ret第一次进来是要加一!  
  370.                 FLAG = 0;           //第一次已经进来,消除该标志  
  371.             }  
  372.             //printf("the wpos is %d \n",wpos);  
  373.             //获取长度信息。  
  374.             frame[wpos++] = rbuf[i];  
  375.             if(wpos > 6){  
  376.                 length = word_to_int(frame[2],frame[3]);  
  377.                 type = word_to_int(frame[4],frame[5]);  
  378.                 //printf("the answer length is %d \n",length);  
  379.             }  
  380.             if (wpos == length + 12) {  //判断是否长度已到目标结构体长度                         
  381.               wpos = 0;//这时因为若循环未结束则继续上述步骤,收取下一个包。  
  382.               //判断包类型,这里先假设为info_answer_hss(主机对从机通用应答类消息的回复)  
  383.               //将收到的包,强制转换为目标结构体格式  
  384.               //p_answer = (pCheckInfoS) frame;  
  385.               //printf("the answer is %x \n",(char *) frame);  
  386.               // 收到一个ok的包   
  387.               //pic_uncrack (p_answer);         //将收到的包解码  
  388.               //遍历已有的列表  
  389.               printf("the received buffer is \n");  
  390.               print_frame(frame,length + 12);  
  391.               list_for_each (pos, &m_req_list) {  
  392.                 p_wait = list_entry(pos,GeneralReqT,list);  
  393.                 //判断所得的包名是否符合类型  
  394.                 //printf("the request.infohead.type is %x\n",p_wait->type);  
  395.                 //printf("p_answer->infohead.type is %x\n",type);  
  396.                 if (p_wait->type == type) {  
  397.                     //将准备好的  
  398.                   memcpy (p_wait->buffer, frame, length + 12);  
  399.                   pthread_cond_signal (&p_wait->cond);  
  400.                                     list_del (pos);  
  401.                   break;  
  402.                 }  
  403.               }  
  404.               pthread_mutex_unlock (&m_mutex);  
  405.             }  
  406.           }  
  407. #endif  
  408.         }  
  409.       }  
  410.         }  
  411.   
  412. #if 0  
  413.       // 超时处理  
  414.       if (tv.tv_usec < 10000) {  
  415.         tv.tv_sec = 0;  
  416.         tv.tv_usec = 100000; // 100ms  
  417.         pthread_mutex_lock (&m_mutex);          //线程同步互斥,锁  
  418.         list_for_each_safe (pos, n, &m_req_list) {  
  419.           p_wait = list_entry(pos,heartbeatReqT,list);  
  420.           p_wait->time += 100;  
  421.           p_wait->answer.cmd = 0;  
  422.           if (p_wait->time > 1000) {  
  423.             list_del (pos);  
  424.             pthread_cond_signal (&p_wait->cond);//唤醒线程  
  425.           }  
  426.         }  
  427.         pthread_mutex_unlock (&m_mutex);    //线程同步互斥,解锁  
  428.       }   
  429. #endif  
  430.     }  
  431. #if 0  
  432.   // 清理资源  
  433.   pthread_mutex_lock (&m_mutex);  
  434.   list_for_each_safe (pos, n, &m_req_list) {  
  435.     p_wait = list_entry(pos,heartbeatReqT,list);  
  436.     p_wait->answer.cmd = 0;  
  437.     list_del (pos);  
  438.     pthread_cond_signal (&p_wait->cond);  
  439.   }  
  440.   pthread_mutex_unlock (&m_mutex);  
  441.     return NULL;  
  442. #endif  
  443. }  
  444.   
  445.   
  446. //双字节的字节交换顺序。网络传输默认为大端模式,  
  447. //本地存储目前为小端存储和运算。  
  448. WORD word_to_int(BYTE one,BYTE two){  
  449.     WORD tmp = (WORD)one<<8;    //右移一个字节,需要移动八位  
  450.     tmp = tmp + (WORD)two;  
  451.     return tmp;  
  452. }  
  453. //将小端存储的双字节按大端方式填入缓存buf中  
  454. //功能:根据需要替换的双字节在缓存中的偏移位置,将其高低位互换  
  455. //buf:需要更换顺序的buf缓存,  
  456. //offset:双字节在缓存中的偏移位置  
  457. //word:该爽字节需要替换成的值  
  458. void    word_buffer(unsigned char * buf,int offset,WORD word){  
  459.     BYTE tmp1 = word&0x00ff ;           //(低八位)  
  460.     BYTE tmp2 = word >> 8;                //(高八位)  
  461.     *(buf + offset) = tmp2;  
  462.     *(buf + offset + 1) = tmp1;   
  463. }  
  464.   
  465.   
  466.   
  467. int main(){  
  468.     int fd;  
  469.     pthread_t read_com_t,check_info_com_t,heart_beat_com_t;       
  470.     //初始化串口  
  471.     fd = uart_open("/dev/ttyS1",57600);  
  472.     if(fd == -1){  
  473.         printf("open the com and set it.it's failed!");  
  474.         return -1;  
  475.     }  
  476.     printf("the path = \"/dev/ttyS1\"\n");  
  477.     printf("the paud = 57600 bps \n");  
  478.     //printf("the fd is %d",fd);  
  479. #if 1  
  480.     if(pthread_create(&read_com_t,NULL,(void *)thread_read,(void *)&fd) == -1){  
  481.         printf("Create the thread of read error!\n");  
  482.         return -1;  
  483.     }  
  484.     if(pthread_create(&check_info_com_t,NULL,(void *)answer_check_info,(void *)&fd) == -1){  
  485.         printf("Create the thread of write error!\n");  
  486.         return -1;  
  487.     }  
  488.     if(pthread_create(&heart_beat_com_t,NULL,(void *)request_heart_beat,(void *)&fd) == -1){  
  489.         printf("Create the thread of write error!\n");  
  490.         return -1;  
  491.     }  
  492. #endif  
  493.     //等待 线程结束  
  494.     pthread_join(read_com_t, NULL);  
  495.   pthread_join(check_info_com_t, NULL);  
  496.   pthread_join(heart_beat_com_t, NULL);  
  497.     return 0;  
  498. }  
由于注释上面已经说得比较清楚了,所以希望大家能看到代码,主要流程如上面所述,关键内容还是在于线程通信的框架

如备注里面所说的pthread_cond_wait的用法,是关键。

其次便是那个所谓的list_head的结构体宏。这边我打算另起一问,专门介绍这种list的使用方法和技巧!

源代码下载:  http://download.csdn.net/detail/wanney216/8079915


转载请说明:http://blog.csdn.net/wanney216/article/details/40450847

0 0
原创粉丝点击