一、tslib移植
1. 从https://github.com/libts/tslib/releases下载tslib最新源码 ,并解压
依次执行以下命令
#./autogen.sh
#echo "ac_cv_func_malloc_0_nonnull=yes" >arm-linux.cache
#CC=aarch64-linux-gnu-gcc ./configure --host=arm-linux --prefix=/opt/Qt5.12.3/tslib-1.20/tx2install --cache-file=arm-linux.cache
make && make install
2. 修改安装目录tx2install/etc/ts.conf
# module_raw input
改为:
module_raw input
二、QT5.12.3 移植
1.http://download.qt.io/archive/qt/5.12/5.12.3/single/ 下载 qt-everywhere-src-5.12.3.tar.xz
并解压
#xz -d qt-everywhere-src-5.12.3.tar.xz
#tar xvz qt-everywhere-src-5.12.3.tar
2.修改qtbase/mkspecs/linux-arm-gnueabi-g++/qmake.conf
MAKEFILE_GENERATOR = UNIX
CONFIG += incremental
QMAKE_INCREMENTAL_STYLE = sublib
QT_QPA_DEFAULT_PLATFORM = linuxfb:fb=/dev/fb0
QMAKE_CFLAGS_RELEASE += -O2
QMAKE_CXXFLAGS_RELEASE += -O2
# modifications to g++.conf
QMAKE_CC = aarch64-linux-gnu-gcc
QMAKE_CXX = aarch64-linux-gnu-g++
QMAKE_LINK = aarch64-linux-gnu-g++
QMAKE_LINK_SHLIB = aarch64-linux-gnu-g++
# modifications to linux.conf
QMAKE_AR = aarch64-linux-gnu-ar cqs
QMAKE_OBJCOPY = aarch64-linux-gnu-objcopy
QMAKE_NM = aarch64-linux-gnu-nm -P
QMAKE_STRIP = aarch64-linux-gnu-strip
3.配置 创建myconfiure文件,并且设置未可执行
#touch myconfigure
#chmod +x myconfigure
文件内容
./configure -prefix ./tx2install \
-release -opensource -make libs -xplatform linux-arm-gnueabi-g++ \
-optimized-qmake -pch -qt-libjpeg -qt-zlib -no-opengl -skip qt3d \
-skip qtcanvas3d -skip qtpurchasing -no-sse2 -no-openssl -no-cups \
-no-glib -no-iconv -nomake examples -nomake tools -skip qtvirtualkeyboard \
-force-asserts -no-evdev -no-mtdev \
-tslib \
-I/opt/Qt5.12.3/tslib-1.20/tx2install/include \
-L/opt/Qt5.12.3/tslib-1.20/tx2install/lib
使用tslib 时候必须加上-no-evdev -no-mtdev ,evdev本来支持多点触摸则与tslib造成冲突, LCD触摸可能出现坐标错误情况
4. 修改 qtbase/src/plugins/platforms/linuxfb/qlinuxfbscreen.cpp 及 qlinuxfbscreen.h(因我的LCD是MIPI 接口的竖屏,需要更改为横屏,内核默认RGB 和LCD确实BGR)
qlinuxfbscreen.h
private:
QStringList mArgs;
int mFbFd;
int mTtyFd;
int mRotation;
QImage mFbScreenImage;
int mBytesPerLine;
int mOldTtyMode;
struct {
uchar *data;
int offset, size;
} mMmap;
QPainter *mBlitter;
bool mSwapRgb;
qlinuxfbscreen.cpp
#include <linux/fb.h>
QT_BEGIN_NAMESPACE
typedef struct {
QImage::Format format;
bool swapRgb;
} FbFormat;
static int openFramebufferDevice(const QString &dev)
static QSizeF determinePhysicalSize(const fb_var_screeninfo &vinfo, const QSize &mmSize, const QSize &res)
{
int mmWidth = mmSize.width(), mmHeight = mmSize.height();
if (mmWidth <= 0 && mmHeight <= 0) {
if (vinfo.width != 0 && vinfo.height != 0
&& vinfo.width != UINT_MAX && vinfo.height != UINT_MAX) {
mmWidth = vinfo.width;
mmHeight = vinfo.height;
} else {
const int dpi = 100;
mmWidth = qRound(res.width() * 25.4 / dpi);
mmHeight = qRound(res.height() * 25.4 / dpi);
}
} else if (mmWidth > 0 && mmHeight <= 0) {
mmHeight = res.height() * mmWidth/res.width();
} else if (mmHeight > 0 && mmWidth <= 0) {
mmWidth = res.width() * mmHeight/res.height();
}
return QSize(mmWidth, mmHeight);
}
static FbFormat determineFormat(const fb_var_screeninfo &info, int depth)
{
const fb_bitfield rgba[4] = { info.red, info.green,
info.blue, info.transp };
FbFormat fbFormat;
fbFormat.format = QImage::Format_Invalid;
fbFormat.swapRgb = false;
switch (depth) {
case 32: {
const fb_bitfield argb8888[4] = {{16, 8, 0}, {8, 8, 0},
{0, 8, 0}, {24, 8, 0}};
const fb_bitfield abgr8888[4] = {{0, 8, 0}, {8, 8, 0},
{16, 8, 0}, {24, 8, 0}};
if (memcmp(rgba, argb8888, 4 * sizeof(fb_bitfield)) == 0) {
fbFormat.format = QImage::Format_ARGB32;
} else if (memcmp(rgba, argb8888, 3 * sizeof(fb_bitfield)) == 0) {
fbFormat.format = QImage::Format_RGB32;
} else if (memcmp(rgba, abgr8888, 3 * sizeof(fb_bitfield)) == 0) {
fbFormat.format = QImage::Format_RGB32;
fbFormat.swapRgb = true;
// pixeltype = BGRPixel;
}
break;
}
case 24: {
const fb_bitfield rgb888[4] = {{16, 8, 0}, {8, 8, 0},
{0, 8, 0}, {0, 0, 0}};
const fb_bitfield bgr888[4] = {{0, 8, 0}, {8, 8, 0},
{16, 8, 0}, {0, 0, 0}};
if (memcmp(rgba, rgb888, 3 * sizeof(fb_bitfield)) == 0) {
fbFormat.format = QImage::Format_RGB888;
} else if (memcmp(rgba, bgr888, 3 * sizeof(fb_bitfield)) == 0) {
fbFormat.format = QImage::Format_RGB888;
fbFormat.swapRgb = true;
// pixeltype = BGRPixel;
}
break;
}
case 18: {
const fb_bitfield rgb666[4] = {{12, 6, 0}, {6, 6, 0},
{0, 6, 0}, {0, 0, 0}};
if (memcmp(rgba, rgb666, 3 * sizeof(fb_bitfield)) == 0)
fbFormat.format = QImage::Format_RGB666;
break;
}
case 16: {
const fb_bitfield rgb565[4] = {{11, 5, 0}, {5, 6, 0},
{0, 5, 0}, {0, 0, 0}};
const fb_bitfield bgr565[4] = {{0, 5, 0}, {5, 6, 0},
{11, 5, 0}, {0, 0, 0}};
if (memcmp(rgba, rgb565, 3 * sizeof(fb_bitfield)) == 0) {
fbFormat.format = QImage::Format_RGB16;
} else if (memcmp(rgba, bgr565, 3 * sizeof(fb_bitfield)) == 0) {
fbFormat.format = QImage::Format_RGB16;
fbFormat.swapRgb = true;
// pixeltype = BGRPixel;
}
break;
}
case 15: {
const fb_bitfield rgb1555[4] = {{10, 5, 0}, {5, 5, 0},
{0, 5, 0}, {15, 1, 0}};
const fb_bitfield bgr1555[4] = {{0, 5, 0}, {5, 5, 0},
{10, 5, 0}, {15, 1, 0}};
if (memcmp(rgba, rgb1555, 3 * sizeof(fb_bitfield)) == 0) {
fbFormat.format = QImage::Format_RGB555;
} else if (memcmp(rgba, bgr1555, 3 * sizeof(fb_bitfield)) == 0) {
fbFormat.format = QImage::Format_RGB555;
fbFormat.swapRgb = true;
// pixeltype = BGRPixel;
}
break;
}
case 12: {
const fb_bitfield rgb444[4] = {{8, 4, 0}, {4, 4, 0},
{0, 4, 0}, {0, 0, 0}};
if (memcmp(rgba, rgb444, 3 * sizeof(fb_bitfield)) == 0)
fbFormat.format = QImage::Format_RGB444;
break;
}
case 8:
break;
case 1:
fbFormat.format = QImage::Format_Mono; //###: LSB???
break;
default:
break;
}
return fbFormat;
}
static int openTtyDevice(const QString &device)
QLinuxFbScreen::QLinuxFbScreen(const QStringList &args)
: mArgs(args), mFbFd(-1), mTtyFd(-1), mBlitter(0),mRotation(90),mSwapRgb(false)
{
mMmap.data = 0;
}
bool QLinuxFbScreen::initialize()
{
QRegularExpression ttyRx(QLatin1String("tty=(.*)"));
QRegularExpression fbRx(QLatin1String("fb=(.*)"));
QRegularExpression mmSizeRx(QLatin1String("mmsize=(\\d+)x(\\d+)"));
QRegularExpression sizeRx(QLatin1String("size=(\\d+)x(\\d+)"));
QRegularExpression offsetRx(QLatin1String("offset=(\\d+)x(\\d+)"));
QRegularExpression rotationRx(QLatin1String("rotation=(0|90|180|270)"));
QString fbDevice, ttyDevice;
QSize userMmSize;
QRect userGeometry;
bool doSwitchToGraphicsMode = true;
for (const QString &arg : qAsConst(mArgs)) {
QRegularExpressionMatch match;
if (arg == QLatin1String("nographicsmodeswitch"))
doSwitchToGraphicsMode = false;
else if (arg.contains(mmSizeRx, &match))
userMmSize = QSize(match.captured(1).toInt(), match.captured(2).toInt());
else if (arg.contains(sizeRx, &match))
userGeometry.setSize(QSize(match.captured(1).toInt(), match.captured(2).toInt()));
else if (arg.contains(offsetRx, &match))
userGeometry.setTopLeft(QPoint(match.captured(1).toInt(), match.captured(2).toInt()));
else if (arg.contains(ttyRx, &match))
ttyDevice = match.captured(1);
else if (arg.contains(fbRx, &match))
fbDevice = match.captured(1);
else if (arg.contains(rotationRx, &match))
mRotation = match.captured(1).toInt();
}
if (ioctl(mFbFd, FBIOGET_VSCREENINFO, &vinfo)) {
qErrnoWarning(errno, "Error reading variable information");
return false;
}
mDepth = determineDepth(vinfo);
mBytesPerLine = finfo.line_length;
QRect geometry = determineGeometry(vinfo, userGeometry);
QRect originalGeometry = geometry;
if( 90 == mRotation || 270 == mRotation )
{
int tmp = geometry.width();
geometry.setWidth(geometry.height());
geometry.setHeight(tmp);
}
mGeometry = QRect(QPoint(0, 0), geometry.size());
FbFormat fbFormat = determineFormat(vinfo, mDepth);
mFormat = fbFormat.format;
mSwapRgb = fbFormat.swapRgb;
// mPhysicalSize = determinePhysicalSize(vinfo, userMmSize, geometry.size());
mPhysicalSize = determinePhysicalSize(vinfo, userMmSize, originalGeometry.size());
// mmap the framebuffer
mMmap.size = finfo.smem_len;
uchar *data = (unsigned char *)mmap(0, mMmap.size, PROT_READ | PROT_WRITE, MAP_SHARED, mFbFd, 0);
if ((long)data == -1) {
qErrnoWarning(errno, "Failed to mmap framebuffer");
return false;
}
// mMmap.offset = geometry.y() * mBytesPerLine + geometry.x() * mDepth / 8;
mMmap.offset = originalGeometry.y() * mBytesPerLine + originalGeometry.x() * mDepth / 8;
mMmap.data = data + mMmap.offset;
QFbScreen::initializeCompositor();
// mFbScreenImage = QImage(mMmap.data, geometry.width(), geometry.height(), mBytesPerLine, mFormat);
mFbScreenImage = QImage(mMmap.data, originalGeometry.width(), originalGeometry.height(), mBytesPerLine, mFormat);
mCursor = new QFbCursor(this);
mTtyFd = openTtyDevice(ttyDevice);
QRegion QLinuxFbScreen::doRedraw()
{
QRegion touched = QFbScreen::doRedraw();
if (touched.isEmpty())
return touched;
if (!mBlitter)
mBlitter = new QPainter(&mFbScreenImage);
const QVector<QRect> rects = touched.rects();
mBlitter->setCompositionMode(QPainter::CompositionMode_Source);
for (int i = 0; i < rects.size(); ++i){
if( 90 == mRotation || 270 == mRotation )
{
mBlitter->translate(mGeometry.height()/2, mGeometry.width()/2);
}
else if( 180 == mRotation )
{
mBlitter->translate(mGeometry.width()/2, mGeometry.height()/2);
}
if( mRotation != 0 )
{
mBlitter->rotate(mRotation);
mBlitter->translate(-mGeometry.width()/2, -mGeometry.height()/2);
}
if (mSwapRgb) {
mBlitter->drawImage(rects[i], mScreenImage.rgbSwapped(),rects[i]);
}
else {
mBlitter->drawImage(rects[i], mScreenImage, rects[i]);
}
mBlitter->resetTransform();
}
return touched;
}
5.编译
make -j4 && make install
编译完成后,在源码根目录./tx2install目录下生成TX2 QT库
6.移植库到TX2根文件系统
6.1文件系统默认自带的QT库删除掉
#rm -rf /usr/lib/aarch64-linux-gnu/libQt*
6.2拷贝移植后的QT 到 TX2 根文件系统
cp -arf ./tx2install/* /usr/local/Qt5.12.3/
6.3增加环境变量(根据具体的屏幕分辨率 尺寸进行设置)
export QTEDIR=/usr/local/Qt5.12.3
export QT_QPA_FONTDIR=$QTEDIR/lib/fonts
export QT_QPA_PLATFORM_PLUGIN_PATH=$QTEDIR/plugins
export QT_QPA_PLATFORM=linuxfb:fb=/dev/fb0:size=720x1280:mmSize=720x1280:offset==0x0:tty=/dev/tty1
export QWS_DISPLAY=LinuxFB:mmWidth68:mmHeight121:0
export TSLIB_ROOT=/usr/local/tslib1.20
export TSLIB_TSDEVICE=/dev/input/event0
export TSLIB_TSEVENTTYPE=input
export TSLIB_CALIBFILE=$TSLIB_ROOT/etc/pointercal
export TSLIB_CONFFILE=$TSLIB_ROOT/etc/ts.conf
export TSLIB_PLUGINDIR=$TSLIB_ROOT/lib/ts
export TSLIB_FBDEVICE=/dev/fb0
export TSLIB_CONSOLEDEVICE=none
export QT_QPA_GENERIC_PLUGINS=tslib:$TSLIB_TSDEVICE
export LD_LIBRARY_PATH=/usr/local/Qt5.12.3/lib:$TSLIB_ROOT/lib
export LD_PRELOAD=$TSLIB_ROOT/lib/libts.so:$QTEDIR/plugins/platforms/libqlinuxfb.so
6.4将字体文件拷贝至TX2文件系统
/usr/local/Qt5.12.3/lib/fonts
6.5增加QT库搜索路径
在 /etc/ld.so.conf 添加/usr/local/Qt5.12.3/lib /usr/local/tslib1.20/lib
include /etc/ld.so.conf.d/*.conf
/usr/local/Qt5.12.3/lib
/usr/local/tslib1.20/lib
7.主机编译QT 程序
1.添加qmake 执行路径
在 /etc/environment添加qmake的路径至PATH /opt/Qt5.12.3/qt-everywhere-src-5.12.3/tx2install/bin/
2.设置QMAKESPEC环境变量
export QMAKESPEC=/opt/Qt5.12.3/qt-everywhere-src-5.12.3/tx2install/mkspecs/linux-arm-gnueabi-g++/
3.执行qmake 创建makefile,编译ARM端运行的程序
qmake -project QT+=widgets 创建 .pro工程文件
qmake -o Makefile
make
若需要旋转LCD
export QT_QPA_PLATFORM=linuxfb:fb=/dev/fb0:size=720x1280:mmSize=720x1280:offset=0x0:tty=/dev/tty1:rotation=90
或者运行程序时加入参数: ./app -platform linuxfb:fb=/dev/fb0:rotatio=90
运行时 需要在 /etc/rc.local中添加以下代码
chmod -x /usr/sbin/lightdm
systemctl disable lightdm.service
echo 2 > /sys/class/graphics/fb0/blank
echo 1 > /sys/class/graphics/fb0/blank
echo 0 > /sys/class/graphics/fb0/blank