本装置现阶段实现的基本功能如下:(1)RFID读卡器接收到便签信息并通过串口发送给6410开发板,6410根据《XSS协议》对数据进行封装,其作为tcp client通过socket 与服务器进行通信,这类6410只是将串口数据转发给网口,只是一个单向的通信过程。
(2)另一类是是tcp client发给server后,还需要接收server的回复。接收到的回复信息后要进行两类操作:控制功能(LED灯)和界面显示(触摸屏显示)。
所有的源代码在http://download.csdn.net/detail/mashang123456789/7026585
这里面包括单向和双向通信过程,在双向通信过程中控制LED和生成txt文件,供qt显示时使用。
注意:用了一些自己编写的API,后面会将所有工程文件上传,方便学习使用,这里只介绍核心代码。
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <errno.h> #include <string.h> #include <sys/stat.h> #include <fcntl.h> #include <assert.h> #include <netdb.h> #include <sys/types.h> #include <netinet/in.h> #include <sys/socket.h> #include "../wrap.h" #define SERV_PORT 2000 int main(int argc,char ** argv) { int led_fd,k;//LEDs int sockfd,n_selt; int n,i; FILE *matchfile; // declare FILE pointers生成的文件的描述符 int fp,comnum;//串口文件描述符,从串口读到的个数 //char buf[100]; char com_buf[17]={0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00};//存储从串口读到的设备号,天线号,ID号 char buf_send[18]={0xAA,0x01,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0xEE};//通信协议2_1:向上位机发送设备号,ID号,请求下灰 char buf_rece[14];//通信协议2_2:上位机返回匹配信息,是否允许下灰14 struct sockaddr_in servaddr; fd_set rfds;//,wfds; struct timeval timeout={900,0};//900s led_fd = open( "/dev/leds", 0); // LED灯初始化 if (led_fd<0) { printf("opne device error\n"); exit(1); } else printf("open successful\n"); for(k=0; k< 4; k++) //关闭所有LEDS ioctl(led_fd,0,k);//第二个参数是开1|关0,第三个参数是led标号 从0~3 fp=open_port(fp,2);//接ARM11Tiny6410开发板靠近USB口和黄色视频输出线的串口 /*设置串口:波特率9600,数据位8位,无校验位,停止位1位*/ if(set_opt(fp,9600,8,'N',1)<0) { perror("Set_opt error!\n"); return; } sockfd=Socket(AF_INET,SOCK_STREAM,0); bzero(&servaddr, sizeof(servaddr)); servaddr.sin_family = AF_INET; inet_pton(AF_INET, "192.168.1.100", &servaddr.sin_addr); servaddr.sin_port = htons(SERV_PORT); Connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr)); while(1){ sleep(1); while( (comnum=read(fp,com_buf,sizeof(com_buf))) == 0 ){//从串口读取RFID,没有就延时再读 sleep(1); } printf("reading for com is %d\n",comnum); buf_send[2] = com_buf[1]; //将从串口读到的RFID数据存储,添加设备号 for(i=2; i<14; i++) buf_send[i+1] = com_buf[i]; //添加ID号 printf("Sending to server:\n"); for(i=0; i< 18; i++) printf("%X ",buf_send[i]); printf("\n"); //tt: write(sockfd, buf_send, sizeof(buf_send)); if(buf_send[2] > 0x03){ //4-15号设备对应的PLC才会收到数据 usleep(1000); FD_ZERO(&rfds); FD_SET(sockfd,&rfds); // FD_ZERO(&wfds); // FD_SET(sockfd,&wfds); n_selt=select(sockfd+1,&rfds,NULL,NULL,&timeout); switch(n_selt){ case -1: perror("select error\n"); exit(0);break; case 0: perror("time out\n");break; //goto tt ; default: if(FD_ISSET(sockfd,&rfds)){ printf("Receving from server:\n"); n = read(sockfd, buf_rece, sizeof(buf_rece)); if ( (matchfile = fopen("match.txt", "w")) == NULL ) //文件初始化match.txt,参数w:没有就新建,每次都覆盖 { fprintf(stderr, "I couldn't open the file \"match.txt\"\n"); exit(2); } for(i=0;i<sizeof(buf_rece);i++){ //车牌号,灰级,匹配信息(控制台)显示部分 if((i>=3)&&(i<=8)){ printf("%c ",buf_rece[i]); fprintf(matchfile,"%c",buf_rece[i]); //保存6位车牌号到match.txt } else printf("%X ",buf_rece[i]); } printf("\n"); fprintf(matchfile,"%c",','); //写入一个分割符号 fprintf(matchfile,"%c",buf_rece[9]+0x30); //灰级1 2 3 fprintf(matchfile,"%c",','); //写入一个分割符号 if(0x11 == buf_rece[10]) fprintf(matchfile,"%c",'1'); //匹配 1 else fprintf(matchfile,"%c",'2'); //不匹配2 if (fclose(matchfile) != 0) //不关闭的话,文件里面没有内容 fprintf(stderr,"Error matchfile closing files\n"); if(0x11 == buf_rece[10]) //控制部分 { for(k=0; k< 4; k++) ioctl(led_fd,1,k); //匹配成功,开灯 sleep(10); for(k=0; k< 4; k++) ioctl(led_fd,0,k); //延时30s关闭 } else { for(k=0; k< 4; k++) ioctl(led_fd,0,k); } } } } } Close(sockfd); return 0; }注释:上面标红的if判断语句
if(buf_send[2] > 0x03){ //4-15号设备对应的PLC才会收到数据,说明1 2 3号设备进行单项通信;4号及4号以上的设备进行的是双向通信。
其工作原理是每隔500ms读取match.txt文件一次并把其内容显示到触摸屏上
1)介绍main.cpp,标红的
//中文支持三行语句是让程序支持中文显示的。
#include <QtGui/QApplication> #include "widget.h" #include <QTextCodec> //UTF-8 Head file int main(int argc, char *argv[]) { QApplication a(argc, argv); //中文支持 QTextCodec::setCodecForLocale(QTextCodec::codecForName("UTF-8")); QTextCodec::setCodecForTr(QTextCodec::codecForName("UTF-8")); //支持Tr中文 QTextCodec::setCodecForCStrings(QTextCodec::codecForName("UTF-8"));//支持中文文件名显示 Widget w; w.show(); return a.exec(); }2)介绍widget.h,标红的语句
void on_fileChanged();是声明一个自定义的槽函数
#ifndef WIDGET_H #define WIDGET_H #include <QWidget> namespace Ui { class Widget; } class Widget : public QWidget { Q_OBJECT public: explicit Widget(QWidget *parent = 0); ~Widget(); private slots: void on_fileChanged(); private: Ui::Widget *ui; }; #endif // WIDGET_H3)介绍widget.cpp,这是程序最核心的部分
#include "widget.h" #include "ui_widget.h" #include <QTextCodec> #include <QTextStream> #include <QFile> #include <QString> #include <QDebug> #include <QFileSystemWatcher> #include <QtGui> #include <QTimer> #include <QBitArray> Widget::Widget(QWidget *parent) : QWidget(parent), ui(new Ui::Widget) { ui->setupUi(this); QTimer *timer = new QTimer(this); connect(timer, SIGNAL(timeout()), this, SLOT(on_fileChanged())); timer->start(500); } Widget::~Widget() { delete ui; } void Widget::on_fileChanged() { QTextCodec * code=QTextCodec::codecForName("utf8"); QFile file("match.txt"); if(!file.open(QIODevice::ReadOnly | QIODevice::Text)) { qDebug()<<"QT Cannot open file for Reading"; return; } QTextStream stream(&file); stream.setCodec(code); ui->lineEdit->clear(); ui->lineEdit_2->clear(); ui->lineEdit_3->clear(); while(stream.atEnd()==0) { QString line=stream.readLine(); QStringList list=line.split(","); ui->lineEdit->setText(tr("鄂")+list.at(0)); int i=list.at(1).toInt(); switch(i) { case 1: ui->lineEdit_2->setText(tr("一级"));break; case 2: ui->lineEdit_2->setText(tr("二级"));break; case 3: ui->lineEdit_2->setText(tr("三级"));break; case 4: ui->lineEdit_2->setText(tr("原灰"));break; default: break; } switch(list.at(2).toInt()) { case 1:ui->lineEdit_3->setText(tr("匹配"));break; case 2:ui->lineEdit_3->setText(tr("不匹配"));break; default: break; } } }match。txt文件内容如下图
要让所有的程序按照预期的运行,第一步是关掉Tiny6410开机自启动的led流水灯,不然不能获得led灯的控制权了;第二步关掉Tiny6410开机自启动的Qtopia,不然回造成显示界面的重叠混乱;第三步后台运行我们自己写的qt程序;第四步启动arm版上的通信程序(注:需要先启动tcp server),至此整个通信所有的准备工作都完成了。
我将上面的四步工作整合成一个sh文件,操作更加简便。
start_qt_client.sh
#!/bin/sh /etc/rc.d/init.d/leds stop killall qpe killall quicklauncher killall qss # Three to close Qtopia qt ./match & # run in background ./all_client