diff --git a/_examples/touch_calibration/touch_calibration.cpp b/_examples/touch_calibration/touch_calibration.cpp new file mode 100644 index 0000000..09e900e --- /dev/null +++ b/_examples/touch_calibration/touch_calibration.cpp @@ -0,0 +1,185 @@ +/*************************************************************************** + * Copyright (C) 2010, 2011, 2012, 2013, 2014 by Terraneo Federico * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * As a special exception, if other files instantiate templates or use * + * macros or inline functions from this file, or you compile this file * + * and link it with other works to produce a work based on this file, * + * this file does not by itself cause the resulting work to be covered * + * by the GNU General Public License. However the source code for this * + * file must still be made available in accordance with the GNU General * + * Public License. This exception does not invalidate any other reasons * + * why a work based on this file might be covered by the GNU General * + * Public License. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, see * + ***************************************************************************/ +#include "mxgui/entry.h" +#include "mxgui/display.h" +#include "mxgui/misc_inst.h" +#include "mxgui/level2/input.h" +#include +#include +#include + +using namespace mxgui; + +// function to draw the crosses +static void drawCross(DrawingContext &dc, Point c, int r) +{ + dc.line(Point(c.x() - r, c.y()), Point(c.x() + r, c.y()), white); + dc.line(Point(c.x(), c.y() - r), Point(c.x(), c.y() + r), white); +} + +struct Calib +{ + double min, max; +}; + +// The transformation from RAW to pixels is performed through a linear transformation of the form: +// pixel = a * raw + b +static void calibrationFrom2Points(double raw1, double pix1, double raw2, double pix2, double W, Calib &out) +{ + double a = (pix2 - pix1) / (raw2 - raw1); + double b = pix1 - a * raw1; + + out.min = -b / a; + out.max = (W - b) / a; +} + +ENTRY() +{ + Display &display = DisplayManager::instance().getDisplay(); + InputHandler &backend = InputHandler::instance(); + + // calibration reset + backend.setTouchscreenCalibration(0.0, 0.0, 0.0, 0.0); + + const short w = display.getWidth() - 1; + const short h = display.getHeight() - 1; + + short oldX = 0, oldY = 0; + + // cross points array + Point targets[] = { + Point(30, 30), + Point(w - 30, 30), + Point(w - 30, h - 30), + Point(30, h - 30)}; + + enum State + { + WAIT_DOWN, + WAIT_UP + }; + State state = WAIT_DOWN; + + int idx = 0; + + DrawingContext dc(display); + drawCross(dc, targets[idx], 20); + + Point rawDatas[4]; + + for (;;) + { + Event e = backend.getEvent(); + + if (e.getEvent() != EventType::TouchDown && e.getEvent() != EventType::TouchMove && e.getEvent() != EventType::TouchUp) + { + continue; + } + + if (state == WAIT_DOWN) + { + if (e.getEvent() == EventType::TouchDown) + { + rawDatas[idx] = e.getPoint(); + + // I wait for the touch-up before showing the next cross. + state = WAIT_UP; + } + } + else + { + if (e.getEvent() == EventType::TouchUp) + { + idx++; + if (idx >= 4) + { + dc.clear(black); + + // compute the calibration parameters + Calib cx1, cy1, cx2, cy2; + + calibrationFrom2Points((double)rawDatas[0].x(), (double)targets[0].x(), + (double)rawDatas[2].x(), (double)targets[2].x(), + w, cx1); + + calibrationFrom2Points((double)rawDatas[0].y(), (double)targets[0].y(), + (double)rawDatas[2].y(), (double)targets[2].y(), + h, cy1); + + calibrationFrom2Points((double)rawDatas[1].x(), (double)targets[1].x(), + (double)rawDatas[3].x(), (double)targets[3].x(), + w, cx2); + + calibrationFrom2Points((double)rawDatas[1].y(), (double)targets[1].y(), + (double)rawDatas[3].y(), (double)targets[3].y(), + h, cy2); + + cx1.max = (cx1.max + cx2.max) / 2; + cx1.min = (cx1.min + cx2.min) / 2; + cy1.max = (cy1.max + cy2.max) / 2; + cy1.min = (cy1.min + cy2.min) / 2; + + backend.setTouchscreenCalibration(cx1.min, cx1.max, cy1.min, cy1.max); + for (;;) + { + Event e2 = backend.getEvent(); + switch (e2.getEvent()) + { + case EventType::ButtonA: + display.turnOff(); + return 0; + case EventType::TouchDown: + case EventType::TouchUp: + case EventType::TouchMove: + { + dc.line(Point(0, oldY), Point(w, oldY), black); + dc.line(Point(oldX, 0), Point(oldX, h), black); + oldX = e2.getPoint().x(); + oldY = e2.getPoint().y(); + + dc.line(Point(0, oldY), Point(w, oldY), white); + dc.line(Point(oldX, 0), Point(oldX, h), white); + char line[128]; + siprintf(line, "(%d, %d) ", oldX, oldY); + dc.write(Point(0, 0), line); + break; + } + default: + break; + } + } + } + + // mostra prossima croce + dc.clear(black); + drawCross(dc, targets[idx], 20); + + state = WAIT_DOWN; + } + } + } +} diff --git a/drivers/event_st25dvdiscovery.cpp b/drivers/event_st25dvdiscovery.cpp index 3f6671b..eae5e8d 100644 --- a/drivers/event_st25dvdiscovery.cpp +++ b/drivers/event_st25dvdiscovery.cpp @@ -35,6 +35,7 @@ #include "event_st25dvdiscovery.h" #include "miosix.h" +#include "kernel/scheduler/scheduler.h" #include "util/software_i2c.h" #include @@ -43,10 +44,20 @@ using namespace miosix; static Semaphore touchIntSema; +/** + * Touchscreen interrupt + */ +void __attribute__((naked)) EXTI9_5_IRQHandler() +{ + saveContext(); + asm volatile("bl EXTI9_5_HandlerImpl"); + restoreContext(); +} + /** * Touchscreen interrupt actual implementation */ -void EXTI9_5_HandlerImpl() +extern "C" void __attribute__((used)) EXTI9_5_HandlerImpl() { EXTI->PR = EXTI_PR_PR5; touchIntSema.IRQsignal(); @@ -54,6 +65,11 @@ void EXTI9_5_HandlerImpl() namespace mxgui { +static int g_xMin; +static int g_xMax; +static int g_yMin; +static int g_yMax; + typedef Gpio buttonKey; typedef Gpio joySel; typedef Gpio joyLeft; @@ -219,10 +235,17 @@ class STMPE811 const int xMax = 3800; const int yMin = 220; const int yMax = 3700; - x = (x - xMin) * 240 / (xMax - xMin); - y = (y - yMin) * 320 / (yMax - yMin); - x=min(239,max(0,x)); - y=min(319,max(0,y)); + int x = static_cast(tsData[0]) << 4 | tsData[1] >> 4; + int y = ((static_cast(tsData[1]) & 0xf) << 8) | tsData[2]; + y = 4095 - y; // Y is swapped + + if (g_xMax != g_xMin && g_yMax != g_yMin) + { + x = (x - g_xMin) * 240 / (g_xMax - g_xMin); + y = (y - g_yMin) * 320 / (g_yMax - g_yMin); + x = min(239, max(0, x)); + y = min(319, max(0, y)); + } #if defined(MXGUI_ORIENTATION_VERTICAL) lastTouchPoint=Point(x,y); @@ -263,7 +286,7 @@ static std::function eventCallback; static void callback(Event e) { { - FastGlobalIrqLock dLock; + FastInterruptDisableLock dLock; if(eventQueue.IRQput(e)==false) return; } if(eventCallback) eventCallback(); @@ -370,8 +393,7 @@ static void eventThread(void *) InputHandlerImpl::InputHandlerImpl() { { - GlobalIrqLock dLock; - IRQregisterIrq(dLock,EXTI9_5_IRQn,&EXTI9_5_HandlerImpl); + FastInterruptDisableLock dLock; buttonKey::mode(Mode::INPUT); interrupt::mode(Mode::INPUT); joySel::mode(Mode::INPUT); @@ -401,6 +423,14 @@ InputHandlerImpl::InputHandlerImpl() Thread::create(eventThread,STACK_MIN); } +void InputHandlerImpl::setTouchscreenCalibration(double xMin, double xMax, double yMin, double yMax) +{ + g_xMin = (int)xMin; + g_xMax = (int)xMax; + g_yMin = (int)yMin; + g_yMax = (int)yMax; +} + Event InputHandlerImpl::getEvent() { Event result; @@ -410,7 +440,7 @@ Event InputHandlerImpl::getEvent() Event InputHandlerImpl::popEvent() { - FastGlobalIrqLock dLock; + FastInterruptDisableLock dLock; Event result; if(eventQueue.isEmpty() == false) { eventQueue.IRQget(result); diff --git a/drivers/event_st25dvdiscovery.h b/drivers/event_st25dvdiscovery.h index eb0b9e9..e010efb 100644 --- a/drivers/event_st25dvdiscovery.h +++ b/drivers/event_st25dvdiscovery.h @@ -71,6 +71,8 @@ class InputHandlerImpl * \return the previous callback */ std::function registerEventCallback(std::function cb); + + void setTouchscreenCalibration(double xMin, double xMax, double yMin, double yMax); }; } //namespace mxgui diff --git a/level2/input.cpp b/level2/input.cpp index 27057e9..b52a07e 100644 --- a/level2/input.cpp +++ b/level2/input.cpp @@ -70,6 +70,13 @@ function InputHandler::registerEventCallback(function cb) return pImpl->registerEventCallback(cb); } +#if defined(_BOARD_STM32F415VG_ST25DVDISCOVERY) +void InputHandler::setTouchscreenCalibration(double xMin, double xMax, double yMin, double yMax) +{ + pImpl->setTouchscreenCalibration(xMin, xMax, yMin, yMax); +} +#endif + InputHandler::InputHandler(InputHandlerImpl *impl) : pImpl(impl) {} } //namespace mxgui diff --git a/level2/input.h b/level2/input.h index 77c4c31..d527934 100644 --- a/level2/input.h +++ b/level2/input.h @@ -201,6 +201,10 @@ class InputHandler */ std::function registerEventCallback(std::function cb); + #if defined(_BOARD_STM32F415VG_ST25DVDISCOVERY) + void setTouchscreenCalibration(double xMin, double xMax, double yMin, double yMax); + #endif + private: /** * Class cannot be copied