From 97c5e5722980dd885fe70b95ae63198257e745c8 Mon Sep 17 00:00:00 2001 From: giacomo3008 Date: Wed, 25 Mar 2026 10:49:27 +0100 Subject: [PATCH 1/2] Add touchscreen calibration st25dvdiscovery --- .../touch_calibration/touch_calibration.cpp | 191 +++++ drivers/event_st25dvdiscovery.cpp | 693 +++++++++--------- drivers/event_st25dvdiscovery.h | 67 +- level2/input.cpp | 61 +- level2/input.h | 325 ++++---- 5 files changed, 788 insertions(+), 549 deletions(-) create mode 100644 _examples/touch_calibration/touch_calibration.cpp diff --git a/_examples/touch_calibration/touch_calibration.cpp b/_examples/touch_calibration/touch_calibration.cpp new file mode 100644 index 0000000..f9dccaa --- /dev/null +++ b/_examples/touch_calibration/touch_calibration.cpp @@ -0,0 +1,191 @@ +/*************************************************************************** + * 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..606ed27 100644 --- a/drivers/event_st25dvdiscovery.cpp +++ b/drivers/event_st25dvdiscovery.cpp @@ -14,7 +14,7 @@ * 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, * @@ -52,380 +52,409 @@ void EXTI9_5_HandlerImpl() touchIntSema.IRQsignal(); } -namespace mxgui { - -typedef Gpio buttonKey; -typedef Gpio joySel; -typedef Gpio joyLeft; -typedef Gpio joyRight; -typedef Gpio joyUp; -typedef Gpio joyDown; -typedef Gpio scl; -typedef Gpio sda; -typedef Gpio interrupt; - -typedef SoftwareI2C ioExtI2C; - -/** - * The registers of the stmpe811 touchscreen controller - */ -enum stmpe811regs -{ - SYS_CTRL1=0x03, - SYS_CTRL2=0x04, - INT_CTRL=0x09, - GPIO_SET_PIN=0x10, - GPIO_CLR_PIN=0x11, - GPIO_MP_STA=0x12, - GPIO_DIR=0x13, - GPIO_ALT_FUNC=0x17, - INT_EN=0x0a, - INT_STA=0x0B, - TSC_CTRL=0x40, - TSC_CFG=0x41, - FIFO_TH=0x4a, - FIFO_STA=0x4b, - TSC_DATA_XYZ=0xd7, - FIFO_SIZE=0x4C -}; - -template -class STMPE811 +namespace mxgui { -public: - /** - * Write into a register in the stmpe811 - * \param reg register number - * \param val value to be written in the register - */ - void writeReg(unsigned char reg, unsigned char val) - { - I2C::sendStart(); - I2C::send(Addr); - I2C::send(reg); - I2C::send(val); - I2C::sendStop(); - } - - /** - * Read from a register of the stmpe811 - * \param reg register number - * \param n number of bytes to read from register - * \param pointer to a memory area of at least n bytes where the read data will - * be stored - */ - void readReg(unsigned char reg, int n, unsigned char *result) - { - if (n <= 0) return; - I2C::sendStart(); - I2C::send(Addr); - I2C::send(reg); - I2C::sendStop(); - I2C::sendStart(); - I2C::send(Addr | 1); - for (int i = 0; i < n - 1; i++) result[i] = I2C::recvWithAck(); - result[n - 1] = I2C::recvWithNack(); - I2C::sendStop(); - } + 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; + typedef Gpio joyRight; + typedef Gpio joyUp; + typedef Gpio joyDown; + typedef Gpio scl; + typedef Gpio sda; + typedef Gpio interrupt; + + typedef SoftwareI2C ioExtI2C; /** - * Perform initial configuration of the chip. + * The registers of the stmpe811 touchscreen controller */ - void init(void) + enum stmpe811regs { - // To let the I2C voltages settle - Thread::sleep(5); - - writeReg(SYS_CTRL1, 0x02); // SOFT_RESET=1 - Thread::sleep(10); - writeReg(SYS_CTRL1, 0x00); // SOFT_RESET=0 - Thread::sleep(2); - writeReg(SYS_CTRL2, 0x08); // !GPIO_OFF !TSC_OFF !ADC_OFF - } - - /** - * Clear the stmpe811 fifo - */ - void touchFifoClear() + SYS_CTRL1 = 0x03, + SYS_CTRL2 = 0x04, + INT_CTRL = 0x09, + GPIO_SET_PIN = 0x10, + GPIO_CLR_PIN = 0x11, + GPIO_MP_STA = 0x12, + GPIO_DIR = 0x13, + GPIO_ALT_FUNC = 0x17, + INT_EN = 0x0a, + INT_STA = 0x0B, + TSC_CTRL = 0x40, + TSC_CFG = 0x41, + FIFO_TH = 0x4a, + FIFO_STA = 0x4b, + TSC_DATA_XYZ = 0xd7, + FIFO_SIZE = 0x4C + }; + + template + class STMPE811 { - writeReg(FIFO_STA, 0x01); // RESET FIFO - writeReg(FIFO_STA, 0x00); // RESET FIFO - } + public: + /** + * Write into a register in the stmpe811 + * \param reg register number + * \param val value to be written in the register + */ + void writeReg(unsigned char reg, unsigned char val) + { + I2C::sendStart(); + I2C::send(Addr); + I2C::send(reg); + I2C::send(val); + I2C::sendStop(); + } - /** - * Configure the chip as a resistive touchscreen controller. - */ - - void initTouch() - { - //Total time to read the touchscreen is - //TDD*2+SETTLING*3+AVE*17.2us*3= ~ 17.5ms - writeReg(TSC_CFG,0xe4); //TSC_CFG= AVE=8, TDD=1ms, SETTLING=5ms - writeReg(FIFO_TH,0x01); //FIFO_TH= 1 - touchFifoClear(); - - //This may allow the chip to go out of hibernate once touch detected - writeReg(INT_CTRL,0x01); - writeReg(INT_EN,0x03); - - // TSC_CTRL values: - // 1 bit 0 enabled: yes - // 001 bit 1:3 TSC mode: X, Y only - // 011 bit 4:6 tracking index (minimum ADC delta for triggering move): 16 - // 0 bit 7 TSC status (read only) - writeReg(TSC_CTRL,0b0'011'001'1); - writeReg(FIFO_TH,0x01); - } + /** + * Read from a register of the stmpe811 + * \param reg register number + * \param n number of bytes to read from register + * \param pointer to a memory area of at least n bytes where the read data will + * be stored + */ + void readReg(unsigned char reg, int n, unsigned char *result) + { + if (n <= 0) + return; + I2C::sendStart(); + I2C::send(Addr); + I2C::send(reg); + I2C::sendStop(); + I2C::sendStart(); + I2C::send(Addr | 1); + for (int i = 0; i < n - 1; i++) + result[i] = I2C::recvWithAck(); + result[n - 1] = I2C::recvWithNack(); + I2C::sendStop(); + } + /** + * Perform initial configuration of the chip. + */ + void init(void) + { + // To let the I2C voltages settle + Thread::sleep(5); + + writeReg(SYS_CTRL1, 0x02); // SOFT_RESET=1 + Thread::sleep(10); + writeReg(SYS_CTRL1, 0x00); // SOFT_RESET=0 + Thread::sleep(2); + writeReg(SYS_CTRL2, 0x08); // !GPIO_OFF !TSC_OFF !ADC_OFF + } - /** - * \return the touch point or (-1,-1) if no touch is in progress - */ - Point getTouchData() - { - unsigned char ctrl; - // Check if touch detected by polling the CTRL register - readReg(TSC_CTRL, 1, &ctrl); - if ((ctrl & 0x80) == 0) + /** + * Clear the stmpe811 fifo + */ + void touchFifoClear() { - // No touch - lastTouchPoint = Point(-1, -1); - return lastTouchPoint; - }else + writeReg(FIFO_STA, 0x01); // RESET FIFO + writeReg(FIFO_STA, 0x00); // RESET FIFO + } + + /** + * Configure the chip as a resistive touchscreen controller. + */ + + void initTouch() { - // Touch detected, check if there are samples in FIFO. - // Even if a touch is detected, the FIFO may be empty if: - // - the first/next sample is not yet ready (for example because of - // settling time) - // - the pen is standing still and window tracking has discarded - // some samples - // In this case, reading from TSC_DATA_XYZ will return all zeros. - // To avoid returning incorrect event coordinates we check the FIFO - // level, and if it is zero we simply return the last point again. - unsigned char fifoFillLevel; - readReg(FIFO_SIZE, 1, &fifoFillLevel); - if (fifoFillLevel == 0) return lastTouchPoint; - - // Read the new sample - unsigned char tsData[3]; - readReg(TSC_DATA_XYZ, 3, tsData); + // Total time to read the touchscreen is + // TDD*2+SETTLING*3+AVE*17.2us*3= ~ 17.5ms + writeReg(TSC_CFG, 0xe4); // TSC_CFG= AVE=8, TDD=1ms, SETTLING=5ms + writeReg(FIFO_TH, 0x01); // FIFO_TH= 1 touchFifoClear(); - 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 - - // Apply calibration. Values may vary from unit to unit - const int xMin = 240; - 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)); - - #if defined(MXGUI_ORIENTATION_VERTICAL) - lastTouchPoint=Point(x,y); - #elif defined(MXGUI_ORIENTATION_HORIZONTAL) - lastTouchPoint=Point(319-y,x); - #elif defined(MXGUI_ORIENTATION_VERTICAL_MIRRORED) - lastTouchPoint=Point(239-x,319-y); - #elif defined(MXGUI_ORIENTATION_HORIZONTAL_MIRRORED) - lastTouchPoint=Point(y,239-x); - #else - #error unknown orientation - #endif - - return lastTouchPoint; + + // This may allow the chip to go out of hibernate once touch detected + writeReg(INT_CTRL, 0x01); + writeReg(INT_EN, 0x03); + + // TSC_CTRL values: + // 1 bit 0 enabled: yes + // 001 bit 1:3 TSC mode: X, Y only + // 011 bit 4:6 tracking index (minimum ADC delta for triggering move): 16 + // 0 bit 7 TSC status (read only) + writeReg(TSC_CTRL, 0b0'011'001'1); + writeReg(FIFO_TH, 0x01); } - } - /** - * Get GPIO pin state - * @returns Bitmask with the state of each pin (1 for high, 0 for low) - */ - unsigned char getGPIOState() - { - unsigned char res; - readReg(GPIO_MP_STA, 1, &res); - return res; - } + /** + * \return the touch point or (-1,-1) if no touch is in progress + */ + Point getTouchData() + { + unsigned char ctrl; + // Check if touch detected by polling the CTRL register + readReg(TSC_CTRL, 1, &ctrl); + if ((ctrl & 0x80) == 0) + { + // No touch + lastTouchPoint = Point(-1, -1); + return lastTouchPoint; + } + else + { + // Touch detected, check if there are samples in FIFO. + // Even if a touch is detected, the FIFO may be empty if: + // - the first/next sample is not yet ready (for example because of + // settling time) + // - the pen is standing still and window tracking has discarded + // some samples + // In this case, reading from TSC_DATA_XYZ will return all zeros. + // To avoid returning incorrect event coordinates we check the FIFO + // level, and if it is zero we simply return the last point again. + unsigned char fifoFillLevel; + readReg(FIFO_SIZE, 1, &fifoFillLevel); + if (fifoFillLevel == 0) + return lastTouchPoint; + + // Read the new sample + unsigned char tsData[3]; + readReg(TSC_DATA_XYZ, 3, tsData); + touchFifoClear(); + 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); +#elif defined(MXGUI_ORIENTATION_HORIZONTAL) + lastTouchPoint = Point(319 - y, x); +#elif defined(MXGUI_ORIENTATION_VERTICAL_MIRRORED) + lastTouchPoint = Point(239 - x, 319 - y); +#elif defined(MXGUI_ORIENTATION_HORIZONTAL_MIRRORED) + lastTouchPoint = Point(y, 239 - x); +#else +#error unknown orientation +#endif + + return lastTouchPoint; + } + } -private: - Point lastTouchPoint = Point(-1,-1); -}; + /** + * Get GPIO pin state + * @returns Bitmask with the state of each pin (1 for high, 0 for low) + */ + unsigned char getGPIOState() + { + unsigned char res; + readReg(GPIO_MP_STA, 1, &res); + return res; + } -static STMPE811 touchCtrl; + private: + Point lastTouchPoint = Point(-1, -1); + }; -static Queue eventQueue; -static std::function eventCallback; + static STMPE811 touchCtrl; -static void callback(Event e) -{ + static Queue eventQueue; + static std::function eventCallback; + + static void callback(Event e) { - FastGlobalIrqLock dLock; - if(eventQueue.IRQput(e)==false) return; + { + FastGlobalIrqLock dLock; + if (eventQueue.IRQput(e) == false) + return; + } + if (eventCallback) + eventCallback(); } - if(eventCallback) eventCallback(); -} -template -class ButtonState -{ -public: - void update(bool newState) + template + class ButtonState { - if(newState) + public: + void update(bool newState) { - if(lastState==false) callback(Event(Type,EventDirection::DOWN)); - lastState=true; - } else { - if(lastState==true) callback(Event(Type,EventDirection::UP)); - lastState=false; + if (newState) + { + if (lastState == false) + callback(Event(Type, EventDirection::DOWN)); + lastState = true; + } + else + { + if (lastState == true) + callback(Event(Type, EventDirection::UP)); + lastState = false; + } } - } -private: - bool lastState=false; -}; + private: + bool lastState = false; + }; -static void waitForTouchOrButton() -{ - long long t = miosix::getTime(); - // Wait until the touchscreen interrupt fires or 20ms - if (!touchIntSema.reset()) touchIntSema.timedWait(t+20000000LL); - touchCtrl.writeReg(INT_STA,0x03); -} + static void waitForTouchOrButton() + { + long long t = miosix::getTime(); + // Wait until the touchscreen interrupt fires or 20ms + if (!touchIntSema.reset()) + touchIntSema.timedWait(t + 20000000LL); + touchCtrl.writeReg(INT_STA, 0x03); + } -static void eventThread(void *) -{ - ButtonState aButton; - ButtonState joyButton; - ButtonState upButton; - ButtonState downButton; - ButtonState leftButton; - ButtonState rightButton; - ButtonState aButtonDown; - ButtonState joyButtonDown; - ButtonState upButtonDown; - ButtonState downButtonDown; - ButtonState leftButtonDown; - ButtonState rightButtonDown; - bool tPrev=false, oldButtonKey = false, oldjoySel = false, oldjoyDown = false, oldjoyLeft = false, oldjoyRight = false, oldjoyUp = false ; - Point pOld; - for(;;) + static void eventThread(void *) { - waitForTouchOrButton(); - aButton.update(!buttonKey::value()); - joyButton.update(!joySel::value()); - downButton.update(!joyDown::value()); - leftButton.update(!joyLeft::value()); - rightButton.update(!joyRight::value()); - upButton.update(!joyUp::value()); - - aButtonDown.update(!buttonKey::value() && buttonKey::value()!= oldButtonKey); - joyButtonDown.update(!joySel::value() && joySel::value()!= oldjoySel); - downButtonDown.update(!joyDown::value() && joyDown::value()!= oldjoyDown); - leftButtonDown.update(!joyLeft::value() && joyLeft::value()!= oldjoyLeft); - rightButtonDown.update(!joyRight::value() && joyRight::value()!= oldjoyRight); - upButtonDown.update(!joyUp::value() && joyUp::value()!= oldjoyUp); - - oldButtonKey = buttonKey::value(); - oldjoySel = joySel::value(); - oldjoyDown = joyDown::value(); - oldjoyLeft = joyLeft::value(); - oldjoyRight = joyRight::value(); - oldjoyUp = joyUp::value(); - - //Check touchscreen - Point p=touchCtrl.getTouchData(); - if(p.x()>=0) //Is someone touching the screen? + ButtonState aButton; + ButtonState joyButton; + ButtonState upButton; + ButtonState downButton; + ButtonState leftButton; + ButtonState rightButton; + ButtonState aButtonDown; + ButtonState joyButtonDown; + ButtonState upButtonDown; + ButtonState downButtonDown; + ButtonState leftButtonDown; + ButtonState rightButtonDown; + bool tPrev = false, oldButtonKey = false, oldjoySel = false, oldjoyDown = false, oldjoyLeft = false, oldjoyRight = false, oldjoyUp = false; + Point pOld; + for (;;) { - //Ok, someone is touching the screen - //Did the touch point differ that much from the previous? - if(abs(pOld.x()-p.x())>0 || abs(pOld.y()-p.y())>0 || !tPrev) + waitForTouchOrButton(); + aButton.update(!buttonKey::value()); + joyButton.update(!joySel::value()); + downButton.update(!joyDown::value()); + leftButton.update(!joyLeft::value()); + rightButton.update(!joyRight::value()); + upButton.update(!joyUp::value()); + + aButtonDown.update(!buttonKey::value() && buttonKey::value() != oldButtonKey); + joyButtonDown.update(!joySel::value() && joySel::value() != oldjoySel); + downButtonDown.update(!joyDown::value() && joyDown::value() != oldjoyDown); + leftButtonDown.update(!joyLeft::value() && joyLeft::value() != oldjoyLeft); + rightButtonDown.update(!joyRight::value() && joyRight::value() != oldjoyRight); + upButtonDown.update(!joyUp::value() && joyUp::value() != oldjoyUp); + + oldButtonKey = buttonKey::value(); + oldjoySel = joySel::value(); + oldjoyDown = joyDown::value(); + oldjoyLeft = joyLeft::value(); + oldjoyRight = joyRight::value(); + oldjoyUp = joyUp::value(); + + // Check touchscreen + Point p = touchCtrl.getTouchData(); + if (p.x() >= 0) // Is someone touching the screen? { - pOld=p; - if(tPrev==false) - callback(Event(EventType::TouchDown,pOld,EventDirection::DOWN)); - else callback(Event(EventType::TouchMove,pOld,EventDirection::DOWN)); - } - tPrev=true; - } else { - //No, no one is touching the screen - if(tPrev==true) + // Ok, someone is touching the screen + // Did the touch point differ that much from the previous? + if (abs(pOld.x() - p.x()) > 0 || abs(pOld.y() - p.y()) > 0 || !tPrev) + { + pOld = p; + if (tPrev == false) + callback(Event(EventType::TouchDown, pOld, EventDirection::DOWN)); + else + callback(Event(EventType::TouchMove, pOld, EventDirection::DOWN)); + } + tPrev = true; + } + else { - touchCtrl.touchFifoClear(); - callback(Event(EventType::TouchUp,pOld,EventDirection::UP)); + // No, no one is touching the screen + if (tPrev == true) + { + touchCtrl.touchFifoClear(); + callback(Event(EventType::TouchUp, pOld, EventDirection::UP)); + } + tPrev = false; } - tPrev=false; } } -} -// -// class InputHandlerImpl -// + // + // class InputHandlerImpl + // -InputHandlerImpl::InputHandlerImpl() -{ + InputHandlerImpl::InputHandlerImpl() { - GlobalIrqLock dLock; - IRQregisterIrq(dLock,EXTI9_5_IRQn,&EXTI9_5_HandlerImpl); - buttonKey::mode(Mode::INPUT); - interrupt::mode(Mode::INPUT); - joySel::mode(Mode::INPUT); - joyDown::mode(Mode::INPUT); - joyLeft::mode(Mode::INPUT); - joyRight::mode(Mode::INPUT); - ioExtI2C::init(); + { + GlobalIrqLock dLock; + IRQregisterIrq(dLock, EXTI9_5_IRQn, &EXTI9_5_HandlerImpl); + buttonKey::mode(Mode::INPUT); + interrupt::mode(Mode::INPUT); + joySel::mode(Mode::INPUT); + joyDown::mode(Mode::INPUT); + joyLeft::mode(Mode::INPUT); + joyRight::mode(Mode::INPUT); + ioExtI2C::init(); + } + + // Init the touchscreen controller + touchCtrl.init(); + touchCtrl.initTouch(); + + // Turn on SYSCFG peripheral + RCC->APB2ENR |= RCC_APB2ENR_SYSCFGEN; + RCC_SYNC(); + + // Configure touchscreen interrupt + SYSCFG->EXTICR[1] = (SYSCFG->EXTICR[1] & ~SYSCFG_EXTICR2_EXTI5_Msk) | (8 << SYSCFG_EXTICR2_EXTI5_Pos); + EXTI->IMR |= EXTI_IMR_MR5; + EXTI->FTSR |= EXTI_FTSR_TR5; + NVIC_EnableIRQ(EXTI9_5_IRQn); + NVIC_SetPriority(EXTI9_5_IRQn, 15); // Low priority + + // Note that this class is instantiated only once. Otherwise + // we'd have to think a way to avoid creating multiple threads + Thread::create(eventThread, STACK_MIN); } - // Init the touchscreen controller - touchCtrl.init(); - touchCtrl.initTouch(); - - // Turn on SYSCFG peripheral - RCC->APB2ENR |= RCC_APB2ENR_SYSCFGEN; - RCC_SYNC(); - - // Configure touchscreen interrupt - SYSCFG->EXTICR[1] = (SYSCFG->EXTICR[1] & ~SYSCFG_EXTICR2_EXTI5_Msk) | (8 << SYSCFG_EXTICR2_EXTI5_Pos); - EXTI->IMR |= EXTI_IMR_MR5; - EXTI->FTSR |= EXTI_FTSR_TR5; - NVIC_EnableIRQ(EXTI9_5_IRQn); - NVIC_SetPriority(EXTI9_5_IRQn,15); //Low priority - - //Note that this class is instantiated only once. Otherwise - //we'd have to think a way to avoid creating multiple threads - 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; - eventQueue.get(result); - return result; -} + Event InputHandlerImpl::getEvent() + { + Event result; + eventQueue.get(result); + return result; + } -Event InputHandlerImpl::popEvent() -{ - FastGlobalIrqLock dLock; - Event result; - if(eventQueue.isEmpty() == false) { - eventQueue.IRQget(result); - } else { - result = Event(EventType::None); + Event InputHandlerImpl::popEvent() + { + FastGlobalIrqLock dLock; + Event result; + if (eventQueue.isEmpty() == false) + { + eventQueue.IRQget(result); + } + else + { + result = Event(EventType::None); + } + return result; } - return result; -} -function InputHandlerImpl::registerEventCallback(function cb) -{ - swap(eventCallback,cb); - return cb; -} + function InputHandlerImpl::registerEventCallback(function cb) + { + swap(eventCallback, cb); + return cb; + } -} //namespace mxgui +} // namespace mxgui #endif // _BOARD_STM32F415VG_ST25DVDISCOVERY diff --git a/drivers/event_st25dvdiscovery.h b/drivers/event_st25dvdiscovery.h index eb0b9e9..1692660 100644 --- a/drivers/event_st25dvdiscovery.h +++ b/drivers/event_st25dvdiscovery.h @@ -30,49 +30,52 @@ #pragma once #ifndef MXGUI_LIBRARY -//#error "This is header is private, it can be used only within mxgui." -//#error "If your code depends on a private header, it IS broken." -#endif //MXGUI_LIBRARY +// #error "This is header is private, it can be used only within mxgui." +// #error "If your code depends on a private header, it IS broken." +#endif // MXGUI_LIBRARY #include #include "level2/input.h" #ifdef _BOARD_STM32F415VG_ST25DVDISCOVERY -namespace mxgui { - -/** - * Implementation class to handle events in the Mp3v2 backend - */ -class InputHandlerImpl +namespace mxgui { -public: - InputHandlerImpl(); /** - * \return an event, blocking + * Implementation class to handle events in the Mp3v2 backend */ - Event getEvent(); + class InputHandlerImpl + { + public: + InputHandlerImpl(); - /** - * \return an event, nonblocking. A default constructed event is returned - * if there are no events. - */ - Event popEvent(); - - /** - * Register a callback that will be called every time an event is generated - * - * Note: the thread calling the callback has a very small stack. - * - * Note: concurrent access to this member function causes undefined behaviour - * - * \param cb new callback to register - * \return the previous callback - */ - std::function registerEventCallback(std::function cb); -}; + /** + * \return an event, blocking + */ + Event getEvent(); + + /** + * \return an event, nonblocking. A default constructed event is returned + * if there are no events. + */ + Event popEvent(); + + /** + * Register a callback that will be called every time an event is generated + * + * Note: the thread calling the callback has a very small stack. + * + * Note: concurrent access to this member function causes undefined behaviour + * + * \param cb new callback to register + * \return the previous callback + */ + std::function registerEventCallback(std::function cb); + + void setTouchscreenCalibration(double xMin, double xMax, double yMin, double yMax); + }; -} //namespace mxgui +} // namespace mxgui #endif //_BOARD_STM32F415VG_ST25DVDISCOVERY diff --git a/level2/input.cpp b/level2/input.cpp index 27057e9..995adc9 100644 --- a/level2/input.cpp +++ b/level2/input.cpp @@ -42,36 +42,47 @@ using namespace std; -namespace mxgui { +namespace mxgui +{ -// -// class InputHandler -// + // + // class InputHandler + // -InputHandler& InputHandler::instance() -{ - static InputHandlerImpl implementation; - static InputHandler singleton(&implementation); - return singleton; -} + InputHandler &InputHandler::instance() + { + static InputHandlerImpl implementation; + static InputHandler singleton(&implementation); + return singleton; + } -Event InputHandler::getEvent() -{ - return pImpl->getEvent(); -} + Event InputHandler::getEvent() + { + return pImpl->getEvent(); + } -Event InputHandler::popEvent() -{ - return pImpl->popEvent(); -} + Event InputHandler::popEvent() + { + return pImpl->popEvent(); + } -function InputHandler::registerEventCallback(function cb) -{ - return pImpl->registerEventCallback(cb); -} + 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) {} + InputHandler::InputHandler(InputHandlerImpl *impl) : pImpl(impl) {} -} //namespace mxgui +} // namespace mxgui -#endif //MXGUI_LEVEL_2 +#endif // MXGUI_LEVEL_2 diff --git a/level2/input.h b/level2/input.h index 77c4c31..ac758e0 100644 --- a/level2/input.h +++ b/level2/input.h @@ -43,176 +43,181 @@ #ifdef MXGUI_LEVEL_2 -namespace mxgui { - -class EventDirection +namespace mxgui { -public: - /** - * Event direction is used to distinguish button events being pressed or - * released - */ - enum D + + class EventDirection { - DOWN, ///< Button is being pressed - UP ///< Button is being released + public: + /** + * Event direction is used to distinguish button events being pressed or + * released + */ + enum D + { + DOWN, ///< Button is being pressed + UP ///< Button is being released + }; + + private: + EventDirection(); }; -private: - EventDirection(); -}; - -/** - * \ingroup pub_iface_2 - * Generic event class. Events are the object type used to dispatch events - * such as button presses or touchscreen taping to applications. - * An Event has an associated type, which is implementation-defined depending - * on the board on which mxgui is ported (different boards have different - * number of buttons), and a point used to represent touchscreen point of touch - * for boards that have a touchscreen. - */ -class Event -{ -public: - /** - * Default constructor - */ - Event(): e(EventType::Default), k(0), d(false), p(-1,-1) {} - - /** - * Constructor for events without a position information - * \param e event type - */ - explicit Event(EventType::E e): e(e), k(0), d(false), p(-1,-1) {} - - /** - * Constructor for events without a position information - * \param e event type - */ - explicit Event(EventType::E e, EventDirection::D d) - : e(e), k(0), d(d==EventDirection::UP), p(-1,-1) {} /** - * Constructor for events that also carry a position information - * \param e event type - * \param p point + * \ingroup pub_iface_2 + * Generic event class. Events are the object type used to dispatch events + * such as button presses or touchscreen taping to applications. + * An Event has an associated type, which is implementation-defined depending + * on the board on which mxgui is ported (different boards have different + * number of buttons), and a point used to represent touchscreen point of touch + * for boards that have a touchscreen. */ - Event(EventType::E e, Point p): e(e), k(0), d(false), p(p) {} - - /** - * Constructor for events that also carry a position information - * \param e event type - * \param p point - */ - Event(EventType::E e, Point p, EventDirection::D d) - : e(e), k(0), d(d==EventDirection::UP), p(p) {} - - /** - * Constructor for events that also carry a key information - * \param e even type - * \param k key data - */ - explicit Event(EventType::E e, char k): e(e), k(k), d(false), p(-1,-1) {} - - /** - * \return the event information - */ - EventType::E getEvent() const { return e; } - - /** - * \return true if the event has a valid point associated with it - */ - bool hasValidPoint() const { return p.x()>=0; } - - /** - * \return the point information - */ - Point getPoint() const { return p; } - - /** - * \return the event direction, either DOWN or UP - */ - EventDirection::D getDirection() const + class Event { - return d ? EventDirection::UP : EventDirection::DOWN; - } - - /** - * \return true if the event has a valid key associated with it - */ - bool hasValidKey() const { return k!=0; } - - /** - * \return the key information - */ - char getKey() const { return k; } - -private: - EventType::E e; - char k; - bool d; - Point p; -}; - -class InputHandlerImpl; //Forward declaration - -/** - * \ingroup pub_iface_2 - * This class contains member function to retrieve events from the system. - */ -class InputHandler -{ -public: - /** - * \return an instance of this class (singleton) - */ - static InputHandler& instance(); + public: + /** + * Default constructor + */ + Event() : e(EventType::Default), k(0), d(false), p(-1, -1) {} + + /** + * Constructor for events without a position information + * \param e event type + */ + explicit Event(EventType::E e) : e(e), k(0), d(false), p(-1, -1) {} + + /** + * Constructor for events without a position information + * \param e event type + */ + explicit Event(EventType::E e, EventDirection::D d) + : e(e), k(0), d(d == EventDirection::UP), p(-1, -1) {} + + /** + * Constructor for events that also carry a position information + * \param e event type + * \param p point + */ + Event(EventType::E e, Point p) : e(e), k(0), d(false), p(p) {} + + /** + * Constructor for events that also carry a position information + * \param e event type + * \param p point + */ + Event(EventType::E e, Point p, EventDirection::D d) + : e(e), k(0), d(d == EventDirection::UP), p(p) {} + + /** + * Constructor for events that also carry a key information + * \param e even type + * \param k key data + */ + explicit Event(EventType::E e, char k) : e(e), k(k), d(false), p(-1, -1) {} + + /** + * \return the event information + */ + EventType::E getEvent() const { return e; } + + /** + * \return true if the event has a valid point associated with it + */ + bool hasValidPoint() const { return p.x() >= 0; } + + /** + * \return the point information + */ + Point getPoint() const { return p; } + + /** + * \return the event direction, either DOWN or UP + */ + EventDirection::D getDirection() const + { + return d ? EventDirection::UP : EventDirection::DOWN; + } + + /** + * \return true if the event has a valid key associated with it + */ + bool hasValidKey() const { return k != 0; } + + /** + * \return the key information + */ + char getKey() const { return k; } + + private: + EventType::E e; + char k; + bool d; + Point p; + }; - /** - * \return A valid event. Blocking. - */ - Event getEvent(); + class InputHandlerImpl; // Forward declaration /** - * \return A valid event or a default-constructed event if no events - * available. Nonblocking. + * \ingroup pub_iface_2 + * This class contains member function to retrieve events from the system. */ - Event popEvent(); - - /** - * \internal - * Register a callback that is called whenever a new event is available. - * Only one callback can be registered at any time, so registering a new - * callback removes the previous one, which is returned. - * - * Note: this member function is used internally by the window manager to - * be notified when an event occurs. Thus, user code registering a callback - * will make the window manager non-functional. - * - * Note: the thread calling the callback has a very small stack. - * - * Note: concurrent access to this memebr function causes undefined behaviour - * - * Note: to get the event from the callback, always use popEvent() and not - * getEvent(), because if another thread gets the event before you, deadlock - * will occur - * - * \param cb new callback to register - * \return the previous callback - */ - std::function registerEventCallback(std::function cb); - -private: - /** - * Class cannot be copied - */ - InputHandler(const InputHandler&); - InputHandler& operator= (const InputHandler&); - - InputHandler(InputHandlerImpl *impl); - - InputHandlerImpl *pImpl; //Implementation detal -}; + class InputHandler + { + public: + /** + * \return an instance of this class (singleton) + */ + static InputHandler &instance(); + + /** + * \return A valid event. Blocking. + */ + Event getEvent(); + + /** + * \return A valid event or a default-constructed event if no events + * available. Nonblocking. + */ + Event popEvent(); + + /** + * \internal + * Register a callback that is called whenever a new event is available. + * Only one callback can be registered at any time, so registering a new + * callback removes the previous one, which is returned. + * + * Note: this member function is used internally by the window manager to + * be notified when an event occurs. Thus, user code registering a callback + * will make the window manager non-functional. + * + * Note: the thread calling the callback has a very small stack. + * + * Note: concurrent access to this memebr function causes undefined behaviour + * + * Note: to get the event from the callback, always use popEvent() and not + * getEvent(), because if another thread gets the event before you, deadlock + * will occur + * + * \param cb new callback to register + * \return the previous callback + */ + 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 + */ + InputHandler(const InputHandler &); + InputHandler &operator=(const InputHandler &); + + InputHandler(InputHandlerImpl *impl); + + InputHandlerImpl *pImpl; // Implementation detal + }; -} //namespace mxgui +} // namespace mxgui -#endif //MXGUI_LEVEL_2 +#endif // MXGUI_LEVEL_2 From 6c896dddb5dff462c0a79c235203cc120d6b4f4e Mon Sep 17 00:00:00 2001 From: giacomo3008 Date: Sat, 28 Mar 2026 13:05:37 +0100 Subject: [PATCH 2/2] Touchscreen Files formatted --- .../touch_calibration/touch_calibration.cpp | 54 +- drivers/event_st25dvdiscovery.cpp | 721 +++++++++--------- drivers/event_st25dvdiscovery.h | 67 +- level2/input.cpp | 62 +- level2/input.h | 329 ++++---- 5 files changed, 611 insertions(+), 622 deletions(-) diff --git a/_examples/touch_calibration/touch_calibration.cpp b/_examples/touch_calibration/touch_calibration.cpp index f9dccaa..09e900e 100644 --- a/_examples/touch_calibration/touch_calibration.cpp +++ b/_examples/touch_calibration/touch_calibration.cpp @@ -48,10 +48,7 @@ struct Calib // 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) +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; @@ -98,9 +95,7 @@ ENTRY() { Event e = backend.getEvent(); - if (e.getEvent() != EventType::TouchDown && - e.getEvent() != EventType::TouchMove && - e.getEvent() != EventType::TouchUp) + if (e.getEvent() != EventType::TouchDown && e.getEvent() != EventType::TouchMove && e.getEvent() != EventType::TouchUp) { continue; } @@ -120,7 +115,6 @@ ENTRY() if (e.getEvent() == EventType::TouchUp) { idx++; - if (idx >= 4) { dc.clear(black); @@ -155,28 +149,28 @@ ENTRY() 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; - } + 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; + } } } diff --git a/drivers/event_st25dvdiscovery.cpp b/drivers/event_st25dvdiscovery.cpp index 606ed27..eae5e8d 100644 --- a/drivers/event_st25dvdiscovery.cpp +++ b/drivers/event_st25dvdiscovery.cpp @@ -14,7 +14,7 @@ * 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, * @@ -35,6 +35,7 @@ #include "event_st25dvdiscovery.h" #include "miosix.h" +#include "kernel/scheduler/scheduler.h" #include "util/software_i2c.h" #include @@ -43,418 +44,418 @@ 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(); } -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; - typedef Gpio joyRight; - typedef Gpio joyUp; - typedef Gpio joyDown; - typedef Gpio scl; - typedef Gpio sda; - typedef Gpio interrupt; - - typedef SoftwareI2C ioExtI2C; +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; +typedef Gpio joyRight; +typedef Gpio joyUp; +typedef Gpio joyDown; +typedef Gpio scl; +typedef Gpio sda; +typedef Gpio interrupt; + +typedef SoftwareI2C ioExtI2C; + +/** + * The registers of the stmpe811 touchscreen controller + */ +enum stmpe811regs +{ + SYS_CTRL1=0x03, + SYS_CTRL2=0x04, + INT_CTRL=0x09, + GPIO_SET_PIN=0x10, + GPIO_CLR_PIN=0x11, + GPIO_MP_STA=0x12, + GPIO_DIR=0x13, + GPIO_ALT_FUNC=0x17, + INT_EN=0x0a, + INT_STA=0x0B, + TSC_CTRL=0x40, + TSC_CFG=0x41, + FIFO_TH=0x4a, + FIFO_STA=0x4b, + TSC_DATA_XYZ=0xd7, + FIFO_SIZE=0x4C +}; + +template +class STMPE811 +{ +public: /** - * The registers of the stmpe811 touchscreen controller + * Write into a register in the stmpe811 + * \param reg register number + * \param val value to be written in the register */ - enum stmpe811regs + void writeReg(unsigned char reg, unsigned char val) { - SYS_CTRL1 = 0x03, - SYS_CTRL2 = 0x04, - INT_CTRL = 0x09, - GPIO_SET_PIN = 0x10, - GPIO_CLR_PIN = 0x11, - GPIO_MP_STA = 0x12, - GPIO_DIR = 0x13, - GPIO_ALT_FUNC = 0x17, - INT_EN = 0x0a, - INT_STA = 0x0B, - TSC_CTRL = 0x40, - TSC_CFG = 0x41, - FIFO_TH = 0x4a, - FIFO_STA = 0x4b, - TSC_DATA_XYZ = 0xd7, - FIFO_SIZE = 0x4C - }; - - template - class STMPE811 + I2C::sendStart(); + I2C::send(Addr); + I2C::send(reg); + I2C::send(val); + I2C::sendStop(); + } + + /** + * Read from a register of the stmpe811 + * \param reg register number + * \param n number of bytes to read from register + * \param pointer to a memory area of at least n bytes where the read data will + * be stored + */ + void readReg(unsigned char reg, int n, unsigned char *result) { - public: - /** - * Write into a register in the stmpe811 - * \param reg register number - * \param val value to be written in the register - */ - void writeReg(unsigned char reg, unsigned char val) - { - I2C::sendStart(); - I2C::send(Addr); - I2C::send(reg); - I2C::send(val); - I2C::sendStop(); - } + if (n <= 0) return; + I2C::sendStart(); + I2C::send(Addr); + I2C::send(reg); + I2C::sendStop(); + I2C::sendStart(); + I2C::send(Addr | 1); + for (int i = 0; i < n - 1; i++) result[i] = I2C::recvWithAck(); + result[n - 1] = I2C::recvWithNack(); + I2C::sendStop(); + } - /** - * Read from a register of the stmpe811 - * \param reg register number - * \param n number of bytes to read from register - * \param pointer to a memory area of at least n bytes where the read data will - * be stored - */ - void readReg(unsigned char reg, int n, unsigned char *result) - { - if (n <= 0) - return; - I2C::sendStart(); - I2C::send(Addr); - I2C::send(reg); - I2C::sendStop(); - I2C::sendStart(); - I2C::send(Addr | 1); - for (int i = 0; i < n - 1; i++) - result[i] = I2C::recvWithAck(); - result[n - 1] = I2C::recvWithNack(); - I2C::sendStop(); - } + /** + * Perform initial configuration of the chip. + */ + void init(void) + { + // To let the I2C voltages settle + Thread::sleep(5); + + writeReg(SYS_CTRL1, 0x02); // SOFT_RESET=1 + Thread::sleep(10); + writeReg(SYS_CTRL1, 0x00); // SOFT_RESET=0 + Thread::sleep(2); + writeReg(SYS_CTRL2, 0x08); // !GPIO_OFF !TSC_OFF !ADC_OFF + } - /** - * Perform initial configuration of the chip. - */ - void init(void) - { - // To let the I2C voltages settle - Thread::sleep(5); - - writeReg(SYS_CTRL1, 0x02); // SOFT_RESET=1 - Thread::sleep(10); - writeReg(SYS_CTRL1, 0x00); // SOFT_RESET=0 - Thread::sleep(2); - writeReg(SYS_CTRL2, 0x08); // !GPIO_OFF !TSC_OFF !ADC_OFF - } + /** + * Clear the stmpe811 fifo + */ + void touchFifoClear() + { + writeReg(FIFO_STA, 0x01); // RESET FIFO + writeReg(FIFO_STA, 0x00); // RESET FIFO + } - /** - * Clear the stmpe811 fifo - */ - void touchFifoClear() - { - writeReg(FIFO_STA, 0x01); // RESET FIFO - writeReg(FIFO_STA, 0x00); // RESET FIFO - } + /** + * Configure the chip as a resistive touchscreen controller. + */ + + void initTouch() + { + //Total time to read the touchscreen is + //TDD*2+SETTLING*3+AVE*17.2us*3= ~ 17.5ms + writeReg(TSC_CFG,0xe4); //TSC_CFG= AVE=8, TDD=1ms, SETTLING=5ms + writeReg(FIFO_TH,0x01); //FIFO_TH= 1 + touchFifoClear(); + + //This may allow the chip to go out of hibernate once touch detected + writeReg(INT_CTRL,0x01); + writeReg(INT_EN,0x03); + + // TSC_CTRL values: + // 1 bit 0 enabled: yes + // 001 bit 1:3 TSC mode: X, Y only + // 011 bit 4:6 tracking index (minimum ADC delta for triggering move): 16 + // 0 bit 7 TSC status (read only) + writeReg(TSC_CTRL,0b0'011'001'1); + writeReg(FIFO_TH,0x01); + } - /** - * Configure the chip as a resistive touchscreen controller. - */ - void initTouch() + /** + * \return the touch point or (-1,-1) if no touch is in progress + */ + Point getTouchData() + { + unsigned char ctrl; + // Check if touch detected by polling the CTRL register + readReg(TSC_CTRL, 1, &ctrl); + if ((ctrl & 0x80) == 0) { - // Total time to read the touchscreen is - // TDD*2+SETTLING*3+AVE*17.2us*3= ~ 17.5ms - writeReg(TSC_CFG, 0xe4); // TSC_CFG= AVE=8, TDD=1ms, SETTLING=5ms - writeReg(FIFO_TH, 0x01); // FIFO_TH= 1 - touchFifoClear(); - - // This may allow the chip to go out of hibernate once touch detected - writeReg(INT_CTRL, 0x01); - writeReg(INT_EN, 0x03); - - // TSC_CTRL values: - // 1 bit 0 enabled: yes - // 001 bit 1:3 TSC mode: X, Y only - // 011 bit 4:6 tracking index (minimum ADC delta for triggering move): 16 - // 0 bit 7 TSC status (read only) - writeReg(TSC_CTRL, 0b0'011'001'1); - writeReg(FIFO_TH, 0x01); - } - - /** - * \return the touch point or (-1,-1) if no touch is in progress - */ - Point getTouchData() + // No touch + lastTouchPoint = Point(-1, -1); + return lastTouchPoint; + }else { - unsigned char ctrl; - // Check if touch detected by polling the CTRL register - readReg(TSC_CTRL, 1, &ctrl); - if ((ctrl & 0x80) == 0) - { - // No touch - lastTouchPoint = Point(-1, -1); - return lastTouchPoint; - } - else + // Touch detected, check if there are samples in FIFO. + // Even if a touch is detected, the FIFO may be empty if: + // - the first/next sample is not yet ready (for example because of + // settling time) + // - the pen is standing still and window tracking has discarded + // some samples + // In this case, reading from TSC_DATA_XYZ will return all zeros. + // To avoid returning incorrect event coordinates we check the FIFO + // level, and if it is zero we simply return the last point again. + unsigned char fifoFillLevel; + readReg(FIFO_SIZE, 1, &fifoFillLevel); + if (fifoFillLevel == 0) return lastTouchPoint; + + // Read the new sample + unsigned char tsData[3]; + readReg(TSC_DATA_XYZ, 3, tsData); + touchFifoClear(); + 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 + + // Apply calibration. Values may vary from unit to unit + const int xMin = 240; + const int xMax = 3800; + const int yMin = 220; + const int yMax = 3700; + 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) { - // Touch detected, check if there are samples in FIFO. - // Even if a touch is detected, the FIFO may be empty if: - // - the first/next sample is not yet ready (for example because of - // settling time) - // - the pen is standing still and window tracking has discarded - // some samples - // In this case, reading from TSC_DATA_XYZ will return all zeros. - // To avoid returning incorrect event coordinates we check the FIFO - // level, and if it is zero we simply return the last point again. - unsigned char fifoFillLevel; - readReg(FIFO_SIZE, 1, &fifoFillLevel); - if (fifoFillLevel == 0) - return lastTouchPoint; - - // Read the new sample - unsigned char tsData[3]; - readReg(TSC_DATA_XYZ, 3, tsData); - touchFifoClear(); - 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); -#elif defined(MXGUI_ORIENTATION_HORIZONTAL) - lastTouchPoint = Point(319 - y, x); -#elif defined(MXGUI_ORIENTATION_VERTICAL_MIRRORED) - lastTouchPoint = Point(239 - x, 319 - y); -#elif defined(MXGUI_ORIENTATION_HORIZONTAL_MIRRORED) - lastTouchPoint = Point(y, 239 - x); -#else -#error unknown orientation -#endif - - return lastTouchPoint; + 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); + #elif defined(MXGUI_ORIENTATION_HORIZONTAL) + lastTouchPoint=Point(319-y,x); + #elif defined(MXGUI_ORIENTATION_VERTICAL_MIRRORED) + lastTouchPoint=Point(239-x,319-y); + #elif defined(MXGUI_ORIENTATION_HORIZONTAL_MIRRORED) + lastTouchPoint=Point(y,239-x); + #else + #error unknown orientation + #endif + + return lastTouchPoint; } + } - /** - * Get GPIO pin state - * @returns Bitmask with the state of each pin (1 for high, 0 for low) - */ - unsigned char getGPIOState() - { - unsigned char res; - readReg(GPIO_MP_STA, 1, &res); - return res; - } + /** + * Get GPIO pin state + * @returns Bitmask with the state of each pin (1 for high, 0 for low) + */ + unsigned char getGPIOState() + { + unsigned char res; + readReg(GPIO_MP_STA, 1, &res); + return res; + } - private: - Point lastTouchPoint = Point(-1, -1); - }; +private: + Point lastTouchPoint = Point(-1,-1); +}; - static STMPE811 touchCtrl; +static STMPE811 touchCtrl; - static Queue eventQueue; - static std::function eventCallback; +static Queue eventQueue; +static std::function eventCallback; - static void callback(Event e) +static void callback(Event e) +{ { - { - FastGlobalIrqLock dLock; - if (eventQueue.IRQput(e) == false) - return; - } - if (eventCallback) - eventCallback(); + FastInterruptDisableLock dLock; + if(eventQueue.IRQput(e)==false) return; } + if(eventCallback) eventCallback(); +} - template - class ButtonState +template +class ButtonState +{ +public: + void update(bool newState) { - public: - void update(bool newState) + if(newState) { - if (newState) - { - if (lastState == false) - callback(Event(Type, EventDirection::DOWN)); - lastState = true; - } - else - { - if (lastState == true) - callback(Event(Type, EventDirection::UP)); - lastState = false; - } + if(lastState==false) callback(Event(Type,EventDirection::DOWN)); + lastState=true; + } else { + if(lastState==true) callback(Event(Type,EventDirection::UP)); + lastState=false; } + } - private: - bool lastState = false; - }; +private: + bool lastState=false; +}; - static void waitForTouchOrButton() - { - long long t = miosix::getTime(); - // Wait until the touchscreen interrupt fires or 20ms - if (!touchIntSema.reset()) - touchIntSema.timedWait(t + 20000000LL); - touchCtrl.writeReg(INT_STA, 0x03); - } +static void waitForTouchOrButton() +{ + long long t = miosix::getTime(); + // Wait until the touchscreen interrupt fires or 20ms + if (!touchIntSema.reset()) touchIntSema.timedWait(t+20000000LL); + touchCtrl.writeReg(INT_STA,0x03); +} - static void eventThread(void *) +static void eventThread(void *) +{ + ButtonState aButton; + ButtonState joyButton; + ButtonState upButton; + ButtonState downButton; + ButtonState leftButton; + ButtonState rightButton; + ButtonState aButtonDown; + ButtonState joyButtonDown; + ButtonState upButtonDown; + ButtonState downButtonDown; + ButtonState leftButtonDown; + ButtonState rightButtonDown; + bool tPrev=false, oldButtonKey = false, oldjoySel = false, oldjoyDown = false, oldjoyLeft = false, oldjoyRight = false, oldjoyUp = false ; + Point pOld; + for(;;) { - ButtonState aButton; - ButtonState joyButton; - ButtonState upButton; - ButtonState downButton; - ButtonState leftButton; - ButtonState rightButton; - ButtonState aButtonDown; - ButtonState joyButtonDown; - ButtonState upButtonDown; - ButtonState downButtonDown; - ButtonState leftButtonDown; - ButtonState rightButtonDown; - bool tPrev = false, oldButtonKey = false, oldjoySel = false, oldjoyDown = false, oldjoyLeft = false, oldjoyRight = false, oldjoyUp = false; - Point pOld; - for (;;) + waitForTouchOrButton(); + aButton.update(!buttonKey::value()); + joyButton.update(!joySel::value()); + downButton.update(!joyDown::value()); + leftButton.update(!joyLeft::value()); + rightButton.update(!joyRight::value()); + upButton.update(!joyUp::value()); + + aButtonDown.update(!buttonKey::value() && buttonKey::value()!= oldButtonKey); + joyButtonDown.update(!joySel::value() && joySel::value()!= oldjoySel); + downButtonDown.update(!joyDown::value() && joyDown::value()!= oldjoyDown); + leftButtonDown.update(!joyLeft::value() && joyLeft::value()!= oldjoyLeft); + rightButtonDown.update(!joyRight::value() && joyRight::value()!= oldjoyRight); + upButtonDown.update(!joyUp::value() && joyUp::value()!= oldjoyUp); + + oldButtonKey = buttonKey::value(); + oldjoySel = joySel::value(); + oldjoyDown = joyDown::value(); + oldjoyLeft = joyLeft::value(); + oldjoyRight = joyRight::value(); + oldjoyUp = joyUp::value(); + + //Check touchscreen + Point p=touchCtrl.getTouchData(); + if(p.x()>=0) //Is someone touching the screen? { - waitForTouchOrButton(); - aButton.update(!buttonKey::value()); - joyButton.update(!joySel::value()); - downButton.update(!joyDown::value()); - leftButton.update(!joyLeft::value()); - rightButton.update(!joyRight::value()); - upButton.update(!joyUp::value()); - - aButtonDown.update(!buttonKey::value() && buttonKey::value() != oldButtonKey); - joyButtonDown.update(!joySel::value() && joySel::value() != oldjoySel); - downButtonDown.update(!joyDown::value() && joyDown::value() != oldjoyDown); - leftButtonDown.update(!joyLeft::value() && joyLeft::value() != oldjoyLeft); - rightButtonDown.update(!joyRight::value() && joyRight::value() != oldjoyRight); - upButtonDown.update(!joyUp::value() && joyUp::value() != oldjoyUp); - - oldButtonKey = buttonKey::value(); - oldjoySel = joySel::value(); - oldjoyDown = joyDown::value(); - oldjoyLeft = joyLeft::value(); - oldjoyRight = joyRight::value(); - oldjoyUp = joyUp::value(); - - // Check touchscreen - Point p = touchCtrl.getTouchData(); - if (p.x() >= 0) // Is someone touching the screen? + //Ok, someone is touching the screen + //Did the touch point differ that much from the previous? + if(abs(pOld.x()-p.x())>0 || abs(pOld.y()-p.y())>0 || !tPrev) { - // Ok, someone is touching the screen - // Did the touch point differ that much from the previous? - if (abs(pOld.x() - p.x()) > 0 || abs(pOld.y() - p.y()) > 0 || !tPrev) - { - pOld = p; - if (tPrev == false) - callback(Event(EventType::TouchDown, pOld, EventDirection::DOWN)); - else - callback(Event(EventType::TouchMove, pOld, EventDirection::DOWN)); - } - tPrev = true; - } - else + pOld=p; + if(tPrev==false) + callback(Event(EventType::TouchDown,pOld,EventDirection::DOWN)); + else callback(Event(EventType::TouchMove,pOld,EventDirection::DOWN)); + } + tPrev=true; + } else { + //No, no one is touching the screen + if(tPrev==true) { - // No, no one is touching the screen - if (tPrev == true) - { - touchCtrl.touchFifoClear(); - callback(Event(EventType::TouchUp, pOld, EventDirection::UP)); - } - tPrev = false; + touchCtrl.touchFifoClear(); + callback(Event(EventType::TouchUp,pOld,EventDirection::UP)); } + tPrev=false; } } +} - // - // class InputHandlerImpl - // +// +// class InputHandlerImpl +// - InputHandlerImpl::InputHandlerImpl() +InputHandlerImpl::InputHandlerImpl() +{ { - { - GlobalIrqLock dLock; - IRQregisterIrq(dLock, EXTI9_5_IRQn, &EXTI9_5_HandlerImpl); - buttonKey::mode(Mode::INPUT); - interrupt::mode(Mode::INPUT); - joySel::mode(Mode::INPUT); - joyDown::mode(Mode::INPUT); - joyLeft::mode(Mode::INPUT); - joyRight::mode(Mode::INPUT); - ioExtI2C::init(); - } - - // Init the touchscreen controller - touchCtrl.init(); - touchCtrl.initTouch(); - - // Turn on SYSCFG peripheral - RCC->APB2ENR |= RCC_APB2ENR_SYSCFGEN; - RCC_SYNC(); - - // Configure touchscreen interrupt - SYSCFG->EXTICR[1] = (SYSCFG->EXTICR[1] & ~SYSCFG_EXTICR2_EXTI5_Msk) | (8 << SYSCFG_EXTICR2_EXTI5_Pos); - EXTI->IMR |= EXTI_IMR_MR5; - EXTI->FTSR |= EXTI_FTSR_TR5; - NVIC_EnableIRQ(EXTI9_5_IRQn); - NVIC_SetPriority(EXTI9_5_IRQn, 15); // Low priority - - // Note that this class is instantiated only once. Otherwise - // we'd have to think a way to avoid creating multiple threads - Thread::create(eventThread, STACK_MIN); + FastInterruptDisableLock dLock; + buttonKey::mode(Mode::INPUT); + interrupt::mode(Mode::INPUT); + joySel::mode(Mode::INPUT); + joyDown::mode(Mode::INPUT); + joyLeft::mode(Mode::INPUT); + joyRight::mode(Mode::INPUT); + ioExtI2C::init(); } - 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; - } + // Init the touchscreen controller + touchCtrl.init(); + touchCtrl.initTouch(); + + // Turn on SYSCFG peripheral + RCC->APB2ENR |= RCC_APB2ENR_SYSCFGEN; + RCC_SYNC(); + + // Configure touchscreen interrupt + SYSCFG->EXTICR[1] = (SYSCFG->EXTICR[1] & ~SYSCFG_EXTICR2_EXTI5_Msk) | (8 << SYSCFG_EXTICR2_EXTI5_Pos); + EXTI->IMR |= EXTI_IMR_MR5; + EXTI->FTSR |= EXTI_FTSR_TR5; + NVIC_EnableIRQ(EXTI9_5_IRQn); + NVIC_SetPriority(EXTI9_5_IRQn,15); //Low priority + + //Note that this class is instantiated only once. Otherwise + //we'd have to think a way to avoid creating multiple threads + Thread::create(eventThread,STACK_MIN); +} - Event InputHandlerImpl::getEvent() - { - Event result; - eventQueue.get(result); - return result; - } +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::popEvent() - { - FastGlobalIrqLock dLock; - Event result; - if (eventQueue.isEmpty() == false) - { - eventQueue.IRQget(result); - } - else - { - result = Event(EventType::None); - } - return result; - } +Event InputHandlerImpl::getEvent() +{ + Event result; + eventQueue.get(result); + return result; +} - function InputHandlerImpl::registerEventCallback(function cb) - { - swap(eventCallback, cb); - return cb; +Event InputHandlerImpl::popEvent() +{ + FastInterruptDisableLock dLock; + Event result; + if(eventQueue.isEmpty() == false) { + eventQueue.IRQget(result); + } else { + result = Event(EventType::None); } + return result; +} + +function InputHandlerImpl::registerEventCallback(function cb) +{ + swap(eventCallback,cb); + return cb; +} -} // namespace mxgui +} //namespace mxgui #endif // _BOARD_STM32F415VG_ST25DVDISCOVERY diff --git a/drivers/event_st25dvdiscovery.h b/drivers/event_st25dvdiscovery.h index 1692660..e010efb 100644 --- a/drivers/event_st25dvdiscovery.h +++ b/drivers/event_st25dvdiscovery.h @@ -30,52 +30,51 @@ #pragma once #ifndef MXGUI_LIBRARY -// #error "This is header is private, it can be used only within mxgui." -// #error "If your code depends on a private header, it IS broken." -#endif // MXGUI_LIBRARY +//#error "This is header is private, it can be used only within mxgui." +//#error "If your code depends on a private header, it IS broken." +#endif //MXGUI_LIBRARY #include #include "level2/input.h" #ifdef _BOARD_STM32F415VG_ST25DVDISCOVERY -namespace mxgui +namespace mxgui { + +/** + * Implementation class to handle events in the Mp3v2 backend + */ +class InputHandlerImpl { +public: + InputHandlerImpl(); /** - * Implementation class to handle events in the Mp3v2 backend + * \return an event, blocking */ - class InputHandlerImpl - { - public: - InputHandlerImpl(); - - /** - * \return an event, blocking - */ - Event getEvent(); + Event getEvent(); - /** - * \return an event, nonblocking. A default constructed event is returned - * if there are no events. - */ - Event popEvent(); - - /** - * Register a callback that will be called every time an event is generated - * - * Note: the thread calling the callback has a very small stack. - * - * Note: concurrent access to this member function causes undefined behaviour - * - * \param cb new callback to register - * \return the previous callback - */ - std::function registerEventCallback(std::function cb); + /** + * \return an event, nonblocking. A default constructed event is returned + * if there are no events. + */ + Event popEvent(); + + /** + * Register a callback that will be called every time an event is generated + * + * Note: the thread calling the callback has a very small stack. + * + * Note: concurrent access to this member function causes undefined behaviour + * + * \param cb new callback to register + * \return the previous callback + */ + std::function registerEventCallback(std::function cb); - void setTouchscreenCalibration(double xMin, double xMax, double yMin, double yMax); - }; + void setTouchscreenCalibration(double xMin, double xMax, double yMin, double yMax); +}; -} // namespace mxgui +} //namespace mxgui #endif //_BOARD_STM32F415VG_ST25DVDISCOVERY diff --git a/level2/input.cpp b/level2/input.cpp index 995adc9..b52a07e 100644 --- a/level2/input.cpp +++ b/level2/input.cpp @@ -42,47 +42,43 @@ using namespace std; -namespace mxgui -{ +namespace mxgui { - // - // class InputHandler - // +// +// class InputHandler +// - InputHandler &InputHandler::instance() - { - static InputHandlerImpl implementation; - static InputHandler singleton(&implementation); - return singleton; - } +InputHandler& InputHandler::instance() +{ + static InputHandlerImpl implementation; + static InputHandler singleton(&implementation); + return singleton; +} - Event InputHandler::getEvent() - { - return pImpl->getEvent(); - } +Event InputHandler::getEvent() +{ + return pImpl->getEvent(); +} - Event InputHandler::popEvent() - { - return pImpl->popEvent(); - } +Event InputHandler::popEvent() +{ + return pImpl->popEvent(); +} - function InputHandler::registerEventCallback(function cb) - { - return pImpl->registerEventCallback(cb); - } +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); - } +void InputHandler::setTouchscreenCalibration(double xMin, double xMax, double yMin, double yMax) +{ + pImpl->setTouchscreenCalibration(xMin, xMax, yMin, yMax); +} #endif - InputHandler::InputHandler(InputHandlerImpl *impl) : pImpl(impl) {} +InputHandler::InputHandler(InputHandlerImpl *impl) : pImpl(impl) {} -} // namespace mxgui +} //namespace mxgui -#endif // MXGUI_LEVEL_2 +#endif //MXGUI_LEVEL_2 diff --git a/level2/input.h b/level2/input.h index ac758e0..d527934 100644 --- a/level2/input.h +++ b/level2/input.h @@ -43,181 +43,180 @@ #ifdef MXGUI_LEVEL_2 -namespace mxgui -{ +namespace mxgui { - class EventDirection +class EventDirection +{ +public: + /** + * Event direction is used to distinguish button events being pressed or + * released + */ + enum D { - public: - /** - * Event direction is used to distinguish button events being pressed or - * released - */ - enum D - { - DOWN, ///< Button is being pressed - UP ///< Button is being released - }; - - private: - EventDirection(); + DOWN, ///< Button is being pressed + UP ///< Button is being released }; +private: + EventDirection(); +}; + +/** + * \ingroup pub_iface_2 + * Generic event class. Events are the object type used to dispatch events + * such as button presses or touchscreen taping to applications. + * An Event has an associated type, which is implementation-defined depending + * on the board on which mxgui is ported (different boards have different + * number of buttons), and a point used to represent touchscreen point of touch + * for boards that have a touchscreen. + */ +class Event +{ +public: + /** + * Default constructor + */ + Event(): e(EventType::Default), k(0), d(false), p(-1,-1) {} /** - * \ingroup pub_iface_2 - * Generic event class. Events are the object type used to dispatch events - * such as button presses or touchscreen taping to applications. - * An Event has an associated type, which is implementation-defined depending - * on the board on which mxgui is ported (different boards have different - * number of buttons), and a point used to represent touchscreen point of touch - * for boards that have a touchscreen. + * Constructor for events without a position information + * \param e event type */ - class Event - { - public: - /** - * Default constructor - */ - Event() : e(EventType::Default), k(0), d(false), p(-1, -1) {} - - /** - * Constructor for events without a position information - * \param e event type - */ - explicit Event(EventType::E e) : e(e), k(0), d(false), p(-1, -1) {} - - /** - * Constructor for events without a position information - * \param e event type - */ - explicit Event(EventType::E e, EventDirection::D d) - : e(e), k(0), d(d == EventDirection::UP), p(-1, -1) {} - - /** - * Constructor for events that also carry a position information - * \param e event type - * \param p point - */ - Event(EventType::E e, Point p) : e(e), k(0), d(false), p(p) {} - - /** - * Constructor for events that also carry a position information - * \param e event type - * \param p point - */ - Event(EventType::E e, Point p, EventDirection::D d) - : e(e), k(0), d(d == EventDirection::UP), p(p) {} - - /** - * Constructor for events that also carry a key information - * \param e even type - * \param k key data - */ - explicit Event(EventType::E e, char k) : e(e), k(k), d(false), p(-1, -1) {} - - /** - * \return the event information - */ - EventType::E getEvent() const { return e; } - - /** - * \return true if the event has a valid point associated with it - */ - bool hasValidPoint() const { return p.x() >= 0; } - - /** - * \return the point information - */ - Point getPoint() const { return p; } - - /** - * \return the event direction, either DOWN or UP - */ - EventDirection::D getDirection() const - { - return d ? EventDirection::UP : EventDirection::DOWN; - } - - /** - * \return true if the event has a valid key associated with it - */ - bool hasValidKey() const { return k != 0; } - - /** - * \return the key information - */ - char getKey() const { return k; } - - private: - EventType::E e; - char k; - bool d; - Point p; - }; + explicit Event(EventType::E e): e(e), k(0), d(false), p(-1,-1) {} + + /** + * Constructor for events without a position information + * \param e event type + */ + explicit Event(EventType::E e, EventDirection::D d) + : e(e), k(0), d(d==EventDirection::UP), p(-1,-1) {} - class InputHandlerImpl; // Forward declaration + /** + * Constructor for events that also carry a position information + * \param e event type + * \param p point + */ + Event(EventType::E e, Point p): e(e), k(0), d(false), p(p) {} + + /** + * Constructor for events that also carry a position information + * \param e event type + * \param p point + */ + Event(EventType::E e, Point p, EventDirection::D d) + : e(e), k(0), d(d==EventDirection::UP), p(p) {} + + /** + * Constructor for events that also carry a key information + * \param e even type + * \param k key data + */ + explicit Event(EventType::E e, char k): e(e), k(k), d(false), p(-1,-1) {} + + /** + * \return the event information + */ + EventType::E getEvent() const { return e; } + + /** + * \return true if the event has a valid point associated with it + */ + bool hasValidPoint() const { return p.x()>=0; } /** - * \ingroup pub_iface_2 - * This class contains member function to retrieve events from the system. + * \return the point information */ - class InputHandler + Point getPoint() const { return p; } + + /** + * \return the event direction, either DOWN or UP + */ + EventDirection::D getDirection() const { - public: - /** - * \return an instance of this class (singleton) - */ - static InputHandler &instance(); - - /** - * \return A valid event. Blocking. - */ - Event getEvent(); - - /** - * \return A valid event or a default-constructed event if no events - * available. Nonblocking. - */ - Event popEvent(); - - /** - * \internal - * Register a callback that is called whenever a new event is available. - * Only one callback can be registered at any time, so registering a new - * callback removes the previous one, which is returned. - * - * Note: this member function is used internally by the window manager to - * be notified when an event occurs. Thus, user code registering a callback - * will make the window manager non-functional. - * - * Note: the thread calling the callback has a very small stack. - * - * Note: concurrent access to this memebr function causes undefined behaviour - * - * Note: to get the event from the callback, always use popEvent() and not - * getEvent(), because if another thread gets the event before you, deadlock - * will occur - * - * \param cb new callback to register - * \return the previous callback - */ - 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 - */ - InputHandler(const InputHandler &); - InputHandler &operator=(const InputHandler &); - - InputHandler(InputHandlerImpl *impl); - - InputHandlerImpl *pImpl; // Implementation detal - }; + return d ? EventDirection::UP : EventDirection::DOWN; + } + + /** + * \return true if the event has a valid key associated with it + */ + bool hasValidKey() const { return k!=0; } + + /** + * \return the key information + */ + char getKey() const { return k; } + +private: + EventType::E e; + char k; + bool d; + Point p; +}; + +class InputHandlerImpl; //Forward declaration + +/** + * \ingroup pub_iface_2 + * This class contains member function to retrieve events from the system. + */ +class InputHandler +{ +public: + /** + * \return an instance of this class (singleton) + */ + static InputHandler& instance(); + + /** + * \return A valid event. Blocking. + */ + Event getEvent(); + + /** + * \return A valid event or a default-constructed event if no events + * available. Nonblocking. + */ + Event popEvent(); + + /** + * \internal + * Register a callback that is called whenever a new event is available. + * Only one callback can be registered at any time, so registering a new + * callback removes the previous one, which is returned. + * + * Note: this member function is used internally by the window manager to + * be notified when an event occurs. Thus, user code registering a callback + * will make the window manager non-functional. + * + * Note: the thread calling the callback has a very small stack. + * + * Note: concurrent access to this memebr function causes undefined behaviour + * + * Note: to get the event from the callback, always use popEvent() and not + * getEvent(), because if another thread gets the event before you, deadlock + * will occur + * + * \param cb new callback to register + * \return the previous callback + */ + 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 + */ + InputHandler(const InputHandler&); + InputHandler& operator= (const InputHandler&); + + InputHandler(InputHandlerImpl *impl); + + InputHandlerImpl *pImpl; //Implementation detal +}; -} // namespace mxgui +} //namespace mxgui -#endif // MXGUI_LEVEL_2 +#endif //MXGUI_LEVEL_2