#include "calibration.h"
#include <QWSPointerCalibrationData>
#include <QPainter>
#include <QFile>
#include <QTimer>
#include <QApplication>
#include <QDesktopWidget>
#include <QMouseEvent>
#include <QScreen>
#include <QWSServer>
#include <QString>
#ifdef __arm__
static int sort_by_x(const void *a, const void *b)
{
return (((struct ts_sample *)a)->x - ((struct ts_sample *)b)->x);
}
static int sort_by_y(const void *a, const void *b)
{
return (((struct ts_sample *)a)->y - ((struct ts_sample *)b)->y);
}
#endif
Calibration::Calibration()
{
#ifdef __arm__
QRect desktop = QApplication::desktop()->geometry();
desktop.moveTo(QPoint(0, 0));
setGeometry(desktop);
setFocusPolicy(Qt::StrongFocus);
setFocus();
setModal(true);
int width = qt_screen->deviceWidth();
int height = qt_screen->deviceHeight();
int dx, dy;
QPoint *points = data.screenPoints;
dx = 50;
dy = 50;
points[0] = QPoint(dx, dy);
points[1] = QPoint(width - dx, dy);
points[2] = QPoint(width - dx, height - dy);
points[3] = QPoint(dx, height - dy);
points[4] = QPoint(width / 2, height / 2);
pressCount = 0;
#endif
}
Calibration::~Calibration()
{
}
int Calibration::exec()
{
#ifdef __arm__
activateWindow();
calibThread = new CalibThread;
if(calibThread->Config()){
connect(calibThread, SIGNAL(nextPoint()),
this, SLOT(OnNextPoint()), Qt::QueuedConnection);
calibThread->start();
int ret = QDialog::exec();
return ret;
}else{
delete calibThread;
return 0;
}
#endif
return 0;
}
void Calibration::paintEvent(QPaintEvent*)
{
QPainter p(this);
p.fillRect(rect(), Qt::white);
QPoint point = data.screenPoints[pressCount];
#ifdef __arm__
// Map to logical coordinates in case the screen is transformed
QSize screenSize(qt_screen->deviceWidth(), qt_screen->deviceHeight());
point = qt_screen->mapFromDevice(point, screenSize);
#endif
p.fillRect(point.x() - 6, point.y() - 1, 13, 3, Qt::black);
p.fillRect(point.x() - 1, point.y() - 6, 3, 13, Qt::black);
}
void Calibration::accept()
{
if(pressCount == 5){
Log_d("Calibration accept success, pressCount: 5");
}else{
Log_d("Error, pressCount is not 5");
return;
}
if (calibThread->Perform_calibration()) {
calibThread->Calibration_write();
} else {
Log_e("perform_calibration failed.");
}
delete calibThread;
#ifdef __arm__
QWSServer::instance()->closeMouse();
QWSServer::instance()->openMouse();
#endif
QDialog::accept();
}
void Calibration::OnNextPoint()
{
if (++pressCount < 5)
repaint();
else
accept();
}
CalibThread::CalibThread()
{
}
bool CalibThread::Config()
{
#ifdef __arm__
char *tsdevice = NULL;
if( (tsdevice = getenv("TSLIB_TSDEVICE")) != NULL ) {
ts = ts_open(tsdevice,0);
Log_d(QString("getenv TSLIB_TSDEVICE: %1").arg(tsdevice));
} else {
Log_e(QString("getenv TSLIB_TSDEVICE NULL").arg(tsdevice));
return false;
}
if (!ts) {
Log_e("ts NULL");
return false;
}
if (ts_config(ts)) {
Log_e("ts_config error");
return false;
}
xres = qt_screen->deviceWidth();
yres = qt_screen->deviceHeight();
Log_d(QString("ts_config ok, xres: %1, yres: %2").arg(xres).arg(yres));
return true;
#endif
return false;
}
bool CalibThread::Perform_calibration()
{
int j;
float n, x, y, x2, y2, xy, z, zx, zy;
float det, a, b, c, e, f, i;
float scaling = 65536.0;
// Get sums for matrix
n = x = y = x2 = y2 = xy = 0;
for(j=0;j<5;j++) {
n += 1.0;
x += (float)cal.x[j];
y += (float)cal.y[j];
x2 += (float)(cal.x[j]*cal.x[j]);
y2 += (float)(cal.y[j]*cal.y[j]);
xy += (float)(cal.x[j]*cal.y[j]);
}
// Get determinant of matrix -- check if determinant is too small
det = n*(x2*y2 - xy*xy) + x*(xy*y - x*y2) + y*(x*xy - y*x2);
if(det < 0.1 && det > -0.1) {
Log_e(QString("ts_calibrate: determinant is too small -- %1").arg(det));
return false;
}
// Get elements of inverse matrix
a = (x2*y2 - xy*xy)/det;
b = (xy*y - x*y2)/det;
c = (x*xy - y*x2)/det;
e = (n*y2 - y*y)/det;
f = (x*y - n*xy)/det;
i = (n*x2 - x*x)/det;
// Get sums for x calibration
z = zx = zy = 0;
for(j=0;j<5;j++) {
z += (float)cal.xfb[j];
zx += (float)(cal.xfb[j]*cal.x[j]);
zy += (float)(cal.xfb[j]*cal.y[j]);
}
// Now multiply out to get the calibration for framebuffer x coord
cal.a[0] = (int)((a*z + b*zx + c*zy)*(scaling));
cal.a[1] = (int)((b*z + e*zx + f*zy)*(scaling));
cal.a[2] = (int)((c*z + f*zx + i*zy)*(scaling));
//printf("%f %f %f\n",(a*z + b*zx + c*zy), (b*z + e*zx + f*zy), (c*z + f*zx + i*zy));
// Get sums for y calibration
z = zx = zy = 0;
for(j=0;j<5;j++) {
z += (float)cal.yfb[j];
zx += (float)(cal.yfb[j]*cal.x[j]);
zy += (float)(cal.yfb[j]*cal.y[j]);
}
// Now multiply out to get the calibration for framebuffer y coord
cal.a[3] = (int)((a*z + b*zx + c*zy)*(scaling));
cal.a[4] = (int)((b*z + e*zx + f*zy)*(scaling));
cal.a[5] = (int)((c*z + f*zx + i*zy)*(scaling));
//printf("%f %f %f\n",(a*z + b*zx + c*zy), (b*z + e*zx + f*zy), (c*z + f*zx + i*zy));
// If we got here, we're OK, so assign scaling to a[6] and return
cal.a[6] = (int)scaling;
return true;
}
int CalibThread::Calibration_write()
{
char *calfile = NULL;
char cal_buffer[256];
unsigned int len;
QFile file;
if ((calfile = getenv("TSLIB_CALIBFILE")) != NULL) {
file.setFileName(calfile);
if(!file.open(QIODevice::ReadWrite | QIODevice::Text)){
Log_e("file.open error");
return -1;
}
} else {
Log_e("TSLIB_CALIBFILE NULL");
return -2;
}
len = sprintf(cal_buffer,"%d %d %d %d %d %d %d %d %d ",
cal.a[1], cal.a[2], cal.a[0],
cal.a[4], cal.a[5], cal.a[3], cal.a[6],
xres, yres);
Log_d("Calibration constants: " + cal_buffer);
file.write(cal_buffer, len);
file.close();
return 0;
}
int CalibThread::getxy(tsdev *ts, int *x, int *y)
{
#ifdef __arm__
#define MAX_SAMPLES 128
struct ts_sample samp[MAX_SAMPLES];
int index, middle;
do {
if (ts_read_raw(ts, &samp[0], 1) < 0) {
perror("ts_read");
return -1;
}
} while (samp[0].pressure == 0);
/* Now collect up to MAX_SAMPLES touches into the samp array. */
index = 0;
do {
if (index < MAX_SAMPLES-1)
index++;
if (ts_read_raw(ts, &samp[index], 1) < 0) {
perror("ts_read");
return -2;
}
} while (samp[index].pressure > 0);
Log_d(QString("Took %1 samples...").arg(index));
middle = index/2;
if (x) {
qsort(samp, index, sizeof(struct ts_sample), sort_by_x);
if (index & 1)
*x = samp[middle].x;
else
*x = (samp[middle-1].x + samp[middle].x) / 2;
}
if (y) {
qsort(samp, index, sizeof(struct ts_sample), sort_by_y);
if (index & 1)
*y = samp[middle].y;
else
*y = (samp[middle-1].y + samp[middle].y) / 2;
}
return 0;
#else
return (int)ts + *x + *y;
#endif
}
void CalibThread::get_sample(tsdev *ts, calibration *cal, int index, int x, int y, char *name)
{
getxy(ts, &cal->x [index], &cal->y [index]);
cal->xfb [index] = x;
cal->yfb [index] = y;
Log_d(QString("%1 :