/**
*@Title:利用多线程同步通信机制实现串口通信
*@Introduce:主要完成根据特定的通信协议实现串口与PC上特定串口
* 通信软件的通信。测试版,只是完成主要框架,没有完全将协议的
* 所有通信方式方法做完。
* 其中包含的测试功能有:监听主机(PC上的软件)发送的特定请求,
* 能够识别类型,并解析包含里面的信息,并且自动回复,所写的根
* 据协议要求的固定消息结构体。
* 实现原理:多线程,同步,通信。
* 其中一个线程专门读取串口中从主机传递的信号,并通过识别出来
* 的长度(length),将一个完整的包截取下来,利用识别出来的类
* 型(type)将包以字符串缓存形式发往特定的处理线程。
* 特定的线程按操作分,有两类,一类主动发出请求信号等待主机回
* 应;另一类,等待主机发送请求,然后根据指令回应相关信息
* 说明:在这里,因为只是为了做功能测试,所以所有的解析并根据
* 相应信息内容做处理的操作统一简化为将内容打印出来显示。
*@Attention:主要难点代码中也有注释,这边稍微记录我的错误提醒
* 在这个同步通信机制中,不同线程通过一个全局的指针list_head
* m_req_list作为机制,所有需要的线程中传递的结构体都挂在它下
* 面,然后传递信息的结构体也有通用格式GeneralReqT,根据里面
* type参量确定不同类型,buffer存储需要传递的字符串信息。
*@Explain:包含的文件名有:dev_com_main.c(主函数所在文件)
* dev_com_main.h(主函数的头文件)
* list.h(特殊的list_head结构体的说明和相关函数宏的说明文件)
* crc16.c,crc16.h(CRC16校验码生成的函数体文件和头文件)
* linux下交叉编译试例:
* 确保上述文件都放在当前文件夹下,输入:
* #gcc -o dev dev_com_main.c crc16.c -I ./ -lpthread
* 交叉编译,更换gcc便好。
*@Author:wanney
*@Date:2014-10-25
*@e-Mail:wanney216@gmail.com
*@长江不择细流,泰山不辞抔土。
*/
#include "dev_com_main.h"
#include <pthread.h>
#include <malloc.h>
#define SHOWCHAR 1
#define SHOWHEX 0
#define HEADLOGO 0xaa55
//对于静态分配的互斥量, 可以把它设置为PTHREAD_MUTEX_INITIALIZER,
//或者调用pthread_mutex_init
static pthread_mutex_t m_mutex = PTHREAD_MUTEX_INITIALIZER;
//形成一个闭环,是当前结构体的前节点和后节点都指向本身。
static struct list_head m_req_list = {&m_req_list, &m_req_list};
//串口打开的初始化
//参数:串口设备的路径名 dev,设置整型的波特率(注意格式匹配)
//设备路径名出错会报错,波特率输出默认为:9600
//其他参数设默认值:数据位:8位,校验位:无,停止位:1位
int uart_open (char *dev, int baud)
{
struct termios tio;
int fd;
int baud_flags;
fd = open(dev, O_RDWR);
if(fd == -1) {
// fprintf(stdout, "open %s error!\n", dev);
return -1;
}
if(tcgetattr(fd, &tio) < 0) {
// fprintf(stdout, "tcgetattr error!\n");
close(fd);
return -1;
}
switch (baud) {
case 115200:
baud_flags = B115200;
break;
case 57600:
baud_flags = B57600;
break;
case 38400:
baud_flags = B38400;
break;
case 19200:
baud_flags = B19200;
break;
case 9600:
baud_flags = B9600;
break;
case 2400:
baud_flags = B2400;
break;
case 4800:
baud_flags = B4800;
break;
default:
baud_flags = B9600;
break;
}
fcntl(fd, F_SETFL,O_NONBLOCK);
tio.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG | ECHOE);
tio.c_iflag &= ~(ICRNL | INPCK | ISTRIP | IXON | BRKINT);
tio.c_iflag &= ~(CSIZE | PARENB | CSTOPB);
tio.c_oflag &= ~(OPOST);
tio.c_cflag = CS8 | baud_flags | CLOCAL | CREAD;
tio.c_cc[VMIN] = 0;
tio.c_cc[VTIME] = 0;
tcflush(fd, TCIFLUSH);
if(tcsetattr(fd, TCSAFLUSH, &tio) < 0) {
// fprintf(stdout,"tcsetattr error!\n");
close(fd);
return -1;
}
printf("open uart:%s, baud:%d", dev, baud);
return fd;
}
//初始化:从机参数查询消息的应答消息
void initAnsCheckInfoC(unsigned char * buf,pAnsCheckInfoC p_ans_check_info){
unsigned char buf_[26] ;
WORD crc16;
int i;
memset(buf_,0x00,sizeof(buf_));
p_ans_check_info->infohead.logo = HEADLOGO;
p_ans_check_info->infohead.type = 0x7006;
p_ans_check_info->infohead.length = 0x0e;
p_ans_check_info->infohead.flag = 0x00;
p_ans_check_info->infohead.number = 0x1111;
p_ans_check_info->infohead.version = 0x0001;
memset(p_ans_check_info->ter_mac,0x00,sizeof(p_ans_check_info->ter_mac));
p_ans_check_info->hb_period = 0x09;
p_ans_check_info->repeat_times = 0x05;
p_ans_check_info->timeover = 200;
p_ans_check_info->maintain_info = 0x00;
p_ans_check_info->reserve_1 = 0x00;
p_ans_check_info->reserve_2 = 0x00;
p_ans_check_info->reserve_3 = 0x00;
//内存拷贝
memcpy(buf,(unsigned char *)p_ans_check_info,sizeof(AnsCheckInfoC));
//调整双字节或四字节高低位顺序
word_buffer(buf,0,p_ans_check_info->infohead.logo);
word_buffer(buf,2,p_ans_check_info->infohead.length);
word_buffer(buf,4,p_ans_check_info->infohead.type);
word_buffer(buf,6,p_ans_check_info->infohead.flag);
word_buffer(buf,8,p_ans_check_info->infohead.number);
word_buffer(buf,10,p_ans_check_info->infohead.version);
word_buffer(buf,20,p_ans_check_info->timeover);
//如何减去两个字节再排序?
for(i = 0;i<sizeof(buf_);i++){
buf_[i] = *(buf + i);
}
//用于计算crc16校验码的值
crc16 = CRC16(0x0000,buf_,sizeof(buf_));
p_ans_check_info->check_code = crc16;
word_buffer(buf,26,crc16);
}
//发送主机的从机参数查询消息的应答消息的线程
//参数:串口的文件操作符
void * answer_check_info(void * data){
GeneralReqT checkInfo;
AnsCheckInfoC answer;
CheckInfoS request;
int fd = *(int *)data;
unsigned char * buf;
while(1){
buf = (unsigned char *)malloc(sizeof(AnsCheckInfoC));
memset(buf,0x00,sizeof(AnsCheckInfoC));
if (pthread_cond_init (&checkInfo.cond, NULL) != 0) {
printf ("set rtc fail");
return;
}
debug_trace;;
#if 0
char sendinfo[] = "hello world!\n";
char * psend = sendinfo;
length = write (fd, psend, sizeof(sendinfo));
printf("the length is %d \n",length);
#else
checkInfo.type = 0x8005;
//初始化数据request的数据
initAnsCheckInfoC(buf,&answer);
pthread_mutex_lock (&m_mutex);
list_add (&checkInfo.list, &m_req_list);
pthread_cond_wait (&checkInfo.cond, &m_mutex);
//读线程已经得到主机返回信号,可以测试了。
//printf("the checkinfo.request is : \n");
//print_frame((unsigned char *)&checkInfo.request,sizeof(CheckInfoS));
checkinfocpy(&request, checkInfo.buffer, sizeof(CheckInfoS));
printf("the checkinfo.request.infohead.type is %04x\n",request.infohead.type);
printf("the checkinfo.request.infohead.logo is %04x\n",request.infohead.logo);
printf("the checkinfo.request.infohead.length is %04x\n",request.infohead.length);
printf("the checkinfo.request.infohead.flag is %04x\n",request.infohead.flag);
checkInfo.time = 0;
printf("the buffer is :\n");
print_frame(buf,sizeof(AnsCheckInfoC));
write (fd, buf, sizeof(AnsCheckInfoC));
free(buf);
pthread_mutex_unlock (&m_mutex);
pthread_cond_destroy (&checkInfo.cond);
}
#endif
}
//打印字符串中指定长度的内容,用二进制显示出来。
static void print_frame (unsigned char *frame,int size)
{
int i;
unsigned char *buf = frame;
for (i=0; i<size;i++) {
printf ("%02x ", buf[i]);
}
printf ("\r\n");
}
//初始化从机心跳信号结构体,并填写传进来的写缓存buf。
void initInfoHeartbeatC(unsigned char * buf,pInfoHeartbeatC p_info_heart_heat){
unsigned char buf_[20] ;
WORD crc16;
int i;
memset(buf_,0x00,sizeof(buf_));
p_info_heart_heat->infohead.logo = 0xAA55;
p_info_heart_heat->infohead.type = 0x7003;
p_info_heart_heat->infohead.length = 0x0a;
p_info_heart_heat->infohead.flag = 0x02;
p_info_heart_heat->infohead.number = 0x1111;
p_info_heart_heat->infohead.version = 0x0001;
p_info_heart_heat->status = 0x00;
p_info_heart_heat->reserve = 0x00;
memset(p_info_heart_heat->ter_mac,0x00,sizeof(p_info_heart_heat->ter_mac));
memcpy(buf,(unsigned char *)p_info_heart_heat,sizeof(InfoHeartbeatC));
word_buffer(buf,0,p_info_heart_heat->infohead.logo);
word_buffer(buf,2,p_info_heart_heat->infoh