#include "calibration.h"
#include <QPainter>
#include <QFile>
#include <QTimer>
#include <QApplication>
#include <QDesktopWidget>
#include <QMouseEvent>
#include <QString>
#include <QFileInfo>
#define __ARCH_OMAPL138__
#ifdef __ARCH_OMAPL138__
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 __ARCH_OMAPL138__
screen = QApplication::primaryScreen();
QRect desktop = QApplication::desktop()->geometry();
desktop.moveTo(QPoint(0, 0));
setGeometry(desktop);
setFocusPolicy(Qt::StrongFocus);
setFocus();
setModal(true);
int width = screen->geometry().width();
int height = screen->geometry().height();
int dx, dy;
QPoint *points = 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 __ARCH_OMAPL138__
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::power_on_self_calibrate()
{
QFileInfo info;
QString calfile;
if ((calfile = getenv("TSLIB_CALIBFILE")) == NULL) {
calfile = "/etc/pointercal";
}
info.setFile(calfile);
if (!info.isFile()) {
exec();
}
}
void Calibration::paintEvent(QPaintEvent*)
{
QPainter p(this);
p.fillRect(rect(), Qt::white);
QPoint point = screenPoints[pressCount];
#ifdef __ARCH_OMAPL138__
// Map to logical coordinates in case the screen is transformed
QSize screenSize(screen->geometry().width(), screen->geometry().height());
point = QApplication::desktop()->mapFromGlobal(point);
#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) {
}
else
{
return;
}
if (calibThread->Perform_calibration()) {
calibThread->Calibration_write();
} else {
}
delete calibThread;
QDialog::accept();
}
void Calibration::OnNextPoint()
{
if (++pressCount < 5)
repaint();
else
accept();
}
CalibThread::CalibThread()
{
ts = NULL;
}
CalibThread::~CalibThread()
{
#ifdef __ARCH_OMAPL138__
if (ts) {
ts_close(ts);
ts = NULL;
}
#endif
}
bool CalibThread::Config()
{
#ifdef __ARCH_OMAPL138__
char *tsdevice = NULL;
if( (tsdevice = getenv("TSLIB_TSDEVICE")) != NULL ) {
ts = ts_open(tsdevice, 0);
} else {
ts = ts_open("/dev/input/event0", 0);
}
if (!ts) {
return false;
}
if (ts_config(ts)) {
return false;
}
xres = QApplication::primaryScreen()->geometry().width();
yres = QApplication::primaryScreen()->geometry().height();
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) {
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));
// 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)){
return -1;
}
} else {
file.setFileName("/etc/pointercal");
if(!file.open(QIODevice::ReadWrite | QIODevice::Text)){
return -1;
}
}
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);
file.write(cal_buffer, len);
file.close();
return 0;
}
int CalibThread::getxy(
#ifdef __ARCH_OMAPL138__
struct tsdev
#else
int
#endif
*ts, int *x, int *y)
{
#ifdef __ARCH_OMAPL138__
#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);
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(
#ifdef __ARCH_OMAPL138__
struct tsdev
#else
int
#endif
*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;
}
void CalibThread::run()
{
get_sample (ts, &cal, 0, 50, 50, (char*)"Top left");
emit nextPoint();
get_sample (ts, &cal, 1, xres - 50, 50, (char*)"Top right");
emit nextPoint();
get_sample (ts, &cal, 2, xres - 50, yres - 50, (char*)"Bot right");
emit nextPoint();
get_sample (ts, &cal, 3, 50, yres - 50, (char*)"Bot left