|||
在前面的几篇手记中,已经完成了基本工作平台的搭建。Qt的应用程序已经能够在am335x的linux3.2.0平台上运行,点击触摸屏也能够进行操作了。但是现在有一个小的bug,在运行qt应用程序前如果USB接口的触摸屏断开,或者运行中触摸屏断开,之后如果触摸屏设备又自动恢复,应用程序是不能自动恢复触摸屏的工作,只能退出应用程序然后再重新启动应用程序,才能继续使用触摸屏。这个bug对于工控机就是一个比较严重的问题,设备正在工作,不可能强行退出程序重新启动来恢复对触摸屏的响应,所以我们需要修改qt以及tslib的源程序,来增加自动检测触摸屏设备,并自动恢复应用程序对触摸屏的响应的功能。
通过分析qt5.4.1的源程序发现,qt gui中初始化触摸屏事件是使用的QTsLibMouseHandler这个类,在这个类的构造函数中:
m_dev =ts_open(device.constData(), 1);
if (!m_dev) {
qErrnoWarning(errno,"ts_open() failed.");
return ;
}
上面的代码我们可以分析出来,启动qt应用程序时如果不能正确打开tslib触摸屏,则会错误退出并继续运行qt应用程序,但是如果正确打开了tslib设备并正确设置参数后,会注册signal-slot以及notifier:
if(fd >= 0) {
m_notify = new QSocketNotifier(fd, QSocketNotifier::Read, this);
connect(m_notify, SIGNAL(activated(int)), this, SLOT(readMouseData()));
} else {
qWarning("Cannot open mouse input device '%s': %s",device.constData(), strerror(errno));
}
上述代码执行成功后,corelib会通过qeventdispatcherunix.cpp中的doSelect来检查注册的notifier以及调度signal-slot。对于工控的要求,这里的doSelect有一个小小的缺陷,就是当select返回错误时,doSelect将会禁止出错的notifier和signal-slot。这样,当触摸屏设备出现错误时,doSelect将会禁止QTsLibMouseHandler注册的notifier和signal-slot,即使后续触摸屏设备自动恢复了,qt也不能正常继续使用触摸屏,必须重新启动qt程序,重新执行上述的QTsLibMouseHandler构造函数,才能够继续使用触摸屏设备。
我做了两个大的修改,来解决这个问题:
A、修改tslib,增加一个ts_status函数,用来提供给用户程序获取USB触摸屏的设备状态,该函数返回-1表示USB触摸屏出现问题,不能读取数据。返回0表示USB触摸屏工作正常。
同时在tslib的插件中添加相应的读取状态的函数,顶层的ts_status是通过下一层的接口函数来获取设备信息,所以需要在每一层都增加相应的函数。
在tslib/src下添加一个ts_status.c的文件,添加ts_status函数(省事,我将这个函数增加到了ts_read.c中,没有增加ts_status.c文件,并需要在tslib.h中添加函数申明):
int ts_status(struct tsdev *ts)
{
int result;
result=ts->list->ops->stat(ts->list);
return result;
}
修改ts_filter.h,增加获取状态的函数到结构中:
struct tslib_ops {
int (*read)(struct tslib_module_info *inf, struct ts_sample *samp, int nr);
int (*fini)(struct tslib_module_info *inf);
int (*stat)(struct tslib_module_info *inf); //增加获取状态的函数
};
修改tslib/plugins下的dejitter,input-raw,linear,pthres和variance,其中input-raw与触摸屏设备有关,我这里使用linux的usb设备,所以使用这个模块,其他四个是灵敏度,滤波等模块。input-raw.c:
static int ts_input_stat(struct tslib_module_info *inf)
{
struct tslib_input *i = (struct tslib_input *)inf;
int ret=check_fd(i);
return ret;
}
static const struct tslib_ops __ts_input_ops = {
.read = ts_input_read,
.fini = ts_input_fini,
.stat = ts_input_stat, //增加函数
};
修改dejitter.c,linear.c,pthres.c和variance.c,添加相应的函数。这里只列出pthres的修改,其他三个模块的修改和pthres相同:
static int pthres_stat(struct tslib_module_info *info)
{
return info->next->ops->stat(info->next);
}
static const struct tslib_ops pthres_ops =
{
.read = pthres_read,
.fini = pthres_fini,
.stat = pthres_stat,
};
B、修改qt5.4.1的源程序,在QTsLibMouseHandler中添加一个守护进程,用来通过ts_status不断获取USB触摸屏的状态,当状态为不能读取数据时,注销注册的触摸屏事件管理器,并不断尝试重新打开触摸屏设备。
如果守护进程成功的重新打开了触摸屏设备,则重新注册触摸屏事件管理器。守护进程是一个1秒钟的定时器。
在QTsLibMouseHandler类中添加一个devTsLib变量,用于保存Tslib设备的信息。修改构造函数,增加下面红色的两行代码:
if (device.isEmpty())device = QByteArrayLiteral("/dev/input/event1");
devTslib=device; //保存设备信息
m_Timer=startTimer(1000); //增加一个1秒的定时器,用作守护进程
m_dev = ts_open(device.constData(), 1);
if (!m_dev) {
qErrnoWarning(errno, "ts_open() failed.");
return ;
}
然后实现守护进程:
void QTsLibMouseHandler::timerEvent(QTimerEvent *event)
{
if(m_dev){
if(ts_status(m_dev)==-1){
qDebug()<<"the tslib device was disconnect.";
ts_close(m_dev);
m_dev=0;
disconnect(m_notify, SIGNAL(activated(int)), this, SLOT(readMouseData()));
delete(m_notify);
}
} else {
qDebug()<<"re-open the tslib device.";
m_dev =ts_open(devTslib.constData(), 1);
if(m_dev){
ts_config(m_dev);
int fd =ts_fd(m_dev);
if (fd >= 0) {
m_notify = new QSocketNotifier(fd,QSocketNotifier::Read, this);
connect(m_notify, SIGNAL(activated(int)), this, SLOT(readMouseData()));
qDebug()<<"open the tslib device sucessful.";
} else {
qWarning("Cannot open mouse input device '%s': %s", devTslib.constData(), strerror(errno));
}
} else {
qDebug()<<"could not open the tslib device.";
}
}
}
先重新编译tslib,并将编译后的tslib安装到需要的位置。
然后编译qt5.4.1的gui,并将编译后的libqt5gui相关的6个文件拷贝到需要的位置。
通过上述的修改源程序,解决了两个问题:
1、启动qt程序前,触摸屏设备没有准备好,导致的qt程序启动后,即使触摸屏设备正常了,qt程序也不能恢复使用触摸屏的问题。
2、qt程序启动后,能够正常使用触摸屏设备,但是由于触摸屏设备意外异常后,即使触摸屏设备自动恢复正常,qt程序也不能自动恢复使用触摸屏的问题。
现在,就完成了开发平台的基础搭建工作,一共做了以下的工作:
1、安装ubuntu14.04,并安装相应的软件,交叉编译工具,nfs和tftp服务;
2、在ti官网下载uboot,linux kernel,并配置交叉编译环境,进行正确编译,生成MLO、u-boot.img、uImage;
3、修改uboot,和kernel,尤其是kernel,支持定制am335x平台的各硬件;
4、下载tslib1.6.0,并交叉编译;
5、下载mkfs工具包,并编译生成mkfs.ubifs工具,用于制作ubi文件镜像;
6、下载qt5.4.1,并交叉编译,生成用于开发am335x平台qt程序的开发包;
7、修改tslib和qt5.4.1,用于支持特殊功能;
8、编写一个qt应用程序,交叉编译并正确运行于am335x上。
后续将进行的工作:
1、UART1将使用为RS485通信,修改omap-serail.c,增加一个GPIO,用于控制MAX487的数据发送和接收;
2、业余时间移植SGX Graphics_SDK_5010102到kernel3.2.0,实现图形加速和3D,准备自己开发一款3D游戏机;
(原创文章,转载请注明出处)
(未经本人同意,不得用于商业用途)