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)(structtslib_module_info *inf, struct ts_sample *samp, int nr);
       int (*fini)(structtslib_module_info *inf);
       int (*stat)(structtslib_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)
    {
       returninfo->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 inputdevice '%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游戏机;