summaryrefslogtreecommitdiff
path: root/NxWidgets/nxwm/src/ccalibration.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'NxWidgets/nxwm/src/ccalibration.cxx')
-rw-r--r--NxWidgets/nxwm/src/ccalibration.cxx543
1 files changed, 543 insertions, 0 deletions
diff --git a/NxWidgets/nxwm/src/ccalibration.cxx b/NxWidgets/nxwm/src/ccalibration.cxx
new file mode 100644
index 000000000..2ca132dac
--- /dev/null
+++ b/NxWidgets/nxwm/src/ccalibration.cxx
@@ -0,0 +1,543 @@
+/****************************************************************************
+ * NxWidgets/nxwm/src/capplicationwindow.cxx
+ *
+ * Copyright (C) 2012 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <gnutt@nuttx.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * 3. Neither the name NuttX, NxWidgets, nor the names of its contributors
+ * me be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <assert.h>
+#include <errno.h>
+#include <debug.h>
+
+#include "nxwmconfig.hxx"
+#include "nxwmglyphs.hxx"
+#include "ccalibration.hxx"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+/****************************************************************************
+ * Configuration
+ */
+
+#ifndef CONFIG_NX
+# error "NX is not enabled (CONFIG_NX)"
+#endif
+
+/**
+ * Positional/size data for the calibration lines and circles
+ */
+
+#define CALIBRATION_LEFTX 40
+#define CALIBRATION_RIGHTX (windowSize.w - 41)
+#define CALIBRATION_TOPY 40
+#define CALIBRATION_BOTTOMY (windowSize.h - 41)
+
+#define CALIBRATION_CIRCLE_RADIUS 16
+#define CALIBRATION_LINE_THICKNESS 2
+
+/****************************************************************************
+ * CCalibration Implementation Classes
+ ****************************************************************************/
+
+using namespace NxWM;
+
+/**
+ * CCalibration Constructor
+ *
+ * @param window. The window to use for the calibration display
+ * @param touchscreen. An instance of the class that wraps the touchscreen device.
+ */
+
+CCalibration::CCalibration(CFullScreenWindow *window, CTouchscreen *touchscreen)
+{
+ // Initialize state data
+
+ m_window = window;
+ m_touchscreen = touchscreen;
+ m_state = CALIB_NOT_STARTED;
+ m_stop = false;
+ m_touched = false;
+}
+
+/**
+ * CCalibration Destructor
+ */
+
+CCalibration::~CCalibration(void)
+{
+ // Although we did not create the window, the rule is that I have to dispose
+ // of it
+
+ delete m_window;
+}
+
+/**
+ * Each implementation of IApplication must provide a method to recover
+ * the contained IApplicationWindow instance.
+ */
+
+IApplicationWindow *CCalibration::getWindow(void) const
+{
+ return static_cast<IApplicationWindow*>(m_window);
+}
+
+/**
+ * Get the icon associated with the application
+ *
+ * @return An instance if IBitmap that may be used to rend the
+ * application's icon. This is an new IBitmap instance that must
+ * be deleted by the caller when it is no long needed.
+ */
+
+NXWidgets::IBitmap *CCalibration::getIcon(void)
+{
+ NXWidgets::CRlePaletteBitmap *bitmap =
+ new NXWidgets::CRlePaletteBitmap(&CONFIG_NXWM_CALIBRATION_ICON);
+
+ return bitmap;
+}
+
+/**
+ * Get the name string associated with the application
+ *
+ * @return A copy if CNxString that contains the name of the application.
+ */
+
+NXWidgets::CNxString CCalibration::getName(void)
+{
+ return NXWidgets::CNxString("Touchscreen Calibration");
+}
+
+/**
+ * Start the application (perhaps in the minimized state).
+ *
+ * @return True if the application was successfully started.
+ */
+
+bool CCalibration::run(void)
+{
+ // Provide the initial display
+
+ m_state = CALIB_NOT_STARTED;
+ stateMachine();
+
+ // Loop until calibration completes
+
+ while (!m_stop)
+ {
+ // Wait for the next raw touchscreen input
+
+ struct touch_sample_s sample;
+ while (!m_touchscreen->waitRawTouchData(sample));
+
+ // Then process the raw touchscreen input
+
+ touchscreenInput(sample);
+ }
+
+ return !m_stop;
+}
+
+/**
+ * Stop the application.
+ */
+
+void CCalibration::stop(void)
+{
+ m_stop = true;
+}
+
+/**
+ * The application window is hidden (either it is minimized or it is
+ * maximized, but it is not at the top of the hierarchy)
+ */
+
+void CCalibration::hide(void)
+{
+#warning "Revisit"
+}
+
+/**
+ * Redraw the entire window. The application has been maximized or
+ * otherwise moved to the top of the hierarchy. This method is called from
+ * CTaskbar when the application window must be displayed
+ */
+
+void CCalibration::redraw(void)
+{
+ // Reset the state machine and start over
+
+ if (m_state != CALIB_COMPLETE)
+ {
+ m_state = CALIB_NOT_STARTED;
+ stateMachine();
+ }
+}
+
+/**
+ * Wait for calibration data to be received.
+ *
+ * @return True if the calibration data was successfully obtained.
+ */
+
+bool CCalibration::waitCalibrationData(struct SCalibrationData &data)
+{
+ // Wait until calibration is finished
+
+ while (m_state != CALIB_COMPLETE)
+ {
+ int ret = sem_wait(&m_waitSem);
+ DEBUGASSERT(ret == 0 || errno == EINTR);
+ }
+
+ // Recover the window instance contained in the full screen window
+
+ NXWidgets::INxWindow *window = m_window->getWindow();
+
+ // Get the size of the fullscreen window
+
+ struct nxgl_size_s windowSize;
+ if (!window->getSize(&windowSize))
+ {
+ return false;
+ }
+
+ // Calculate the calibration parameters
+ //
+ // (scaledX - LEFTX) / (rawX - leftX) = (RIGHTX - LEFTX) / (rightX - leftX)
+ // scaledX = (rawX - leftX) * (RIGHTX - LEFTX) / (rightX - leftX) + LEFTX
+ // = rawX * xSlope + (LEFTX - leftX * xSlope)
+ // = rawX * xSlope + xOffset
+ //
+ // where:
+ // xSlope = (RIGHTX - LEFTX) / (rightX - leftX)
+ // xOffset = (LEFTX - leftX * xSlope)
+
+ b16_t leftX = (m_calibData[CALIB_UPPER_LEFT_INDEX].x +
+ m_calibData[CALIB_LOWER_LEFT_INDEX].x) << 15;
+ b16_t rightX = (m_calibData[CALIB_UPPER_RIGHT_INDEX].x +
+ m_calibData[CALIB_LOWER_RIGHT_INDEX].x) << 15;
+
+ data.xSlope = b16divb16(itob16(CALIBRATION_RIGHTX - CALIBRATION_LEFTX), (rightX - leftX));
+ data.xOffset = itob16(CALIBRATION_LEFTX) - b16mulb16(leftX, data.xSlope);
+
+ gdbg("New xSlope: %08x xOffset: %08x\n", data.xSlope, data.xOffset);
+
+ // Similarly for Y
+ //
+ // (scaledY - TOPY) / (rawY - topY) = (BOTTOMY - TOPY) / (bottomY - topY)
+ // scaledY = (rawY - topY) * (BOTTOMY - TOPY) / (bottomY - topY) + TOPY
+ // = rawY * ySlope + (TOPY - topY * ySlope)
+ // = rawY * ySlope + yOffset
+ //
+ // where:
+ // ySlope = (BOTTOMY - TOPY) / (bottomY - topY)
+ // yOffset = (TOPY - topY * ySlope)
+
+ b16_t topY = (m_calibData[CALIB_UPPER_LEFT_INDEX].y +
+ m_calibData[CALIB_UPPER_RIGHT_INDEX].y) << 15;
+ b16_t bottomY = (m_calibData[CALIB_LOWER_LEFT_INDEX].y +
+ m_calibData[CALIB_LOWER_RIGHT_INDEX].y) << 15;
+
+ data.ySlope = b16divb16(itob16(CALIBRATION_BOTTOMY - CALIBRATION_TOPY), (bottomY - topY));
+ data.yOffset = itob16(CALIBRATION_TOPY) - b16mulb16(topY, data.ySlope);
+
+ gdbg("New ySlope: %08x yOffset: %08x\n", data.ySlope, data.yOffset);
+ return true;
+}
+
+/**
+ * Accept raw touchscreen input.
+ *
+ * @param sample Touchscreen input sample
+ */
+
+void CCalibration::touchscreenInput(struct touch_sample_s &sample)
+{
+ // Is this a new touch event? Or is it a drag event?
+
+ if ((sample.point[0].flags & (TOUCH_DOWN|TOUCH_MOVE)) != 0)
+ {
+ // Yes.. but ignore drag events if we did not see the matching
+ // touch down event
+
+ if ((sample.point[0].flags & TOUCH_DOWN) != 0 || m_touched)
+ {
+ // Yes.. save the touch position and wait for the TOUCH_UP report
+
+ m_touchPos.x = sample.point[0].x;
+ m_touchPos.y = sample.point[0].y;
+
+ gvdbg("Touch id: %d flags: %02x x: %d y: %d h: %d w: %d pressure: %d\n",
+ sample.point[0].id, sample.point[0].flags, sample.point[0].x,
+ sample.point[0].y, sample.point[0].h, sample.point[0].w,
+ sample.point[0].pressure);
+
+ // Remember that we saw the touch down event
+
+ m_touched = true;
+ }
+ }
+
+ // Was the touch released?
+
+ else if ((sample.point[0].flags & TOUCH_UP) != 0)
+ {
+ // Yes.. did we see the matching pen down event?
+
+ if (m_touched)
+ {
+ // Yes.. invoke the state machine.
+
+ gvdbg("State: %d Screen x: %d y: %d Touch x: %d y: %d\n",
+ m_state, m_screenInfo.pos.x, m_screenInfo.pos.y,
+ m_touchPos.x, m_touchPos.y);
+
+ stateMachine();
+ }
+
+ // In any event, the touch is not down
+
+ m_touched = false;
+ }
+}
+
+/**
+ * This is the calibration state machine. It is called initially and then
+ * as new touchscreen data is received.
+ */
+
+void CCalibration::stateMachine(void)
+{
+ // Recover the window instance contained in the full screen window
+
+ NXWidgets::INxWindow *window = m_window->getWindow();
+
+ // Get the size of the fullscreen window
+
+ struct nxgl_size_s windowSize;
+ if (!window->getSize(&windowSize))
+ {
+ return;
+ }
+
+ switch (m_state)
+ {
+ default:
+ case CALIB_NOT_STARTED:
+ {
+ // Clear the entire screen
+ // Get the widget control associated with the full screen window
+
+ NXWidgets::CWidgetControl *control = window->getWidgetControl();
+
+ // Get the CCGraphicsPort instance for this window
+
+ NXWidgets::CGraphicsPort *port = control->getGraphicsPort();
+
+ // Fill the entire window with the background color
+
+ port->drawFilledRect(0, 0, windowSize.w, windowSize.h,
+ CONFIG_NXWM_DEFAULT_BACKGROUNDCOLOR);
+
+ // Then draw the first calibration screen
+
+ m_screenInfo.pos.x = CALIBRATION_LEFTX;
+ m_screenInfo.pos.y = CALIBRATION_TOPY;
+ m_screenInfo.lineColor = CONFIG_NXWM_CALIBRATION_LINECOLOR;
+ m_screenInfo.circleFillColor = CONFIG_NXWM_CALIBRATION_CIRCLECOLOR;
+ showCalibration();
+
+ // Then set up the current state
+
+ m_state = CALIB_UPPER_LEFT;
+ }
+ break;
+
+ case CALIB_UPPER_LEFT:
+ {
+ // A touch has been received while in the CALIB_UPPER_LEFT state.
+ // Save the touch data and set up the next calibration display
+
+ m_calibData[CALIB_UPPER_LEFT_INDEX].x = m_touchPos.x;
+ m_calibData[CALIB_UPPER_LEFT_INDEX].y = m_touchPos.y;
+
+ // Clear the previous screen by re-drawing it using the backgro9und
+ // color. That is much faster than clearing the whole display
+
+ m_screenInfo.lineColor = CONFIG_NXWM_CALIBRATION_BACKGROUNDCOLOR;
+ m_screenInfo.circleFillColor = CONFIG_NXWM_CALIBRATION_BACKGROUNDCOLOR;
+ showCalibration();
+
+ // Then draw the next calibration screen
+
+ m_screenInfo.pos.x = CALIBRATION_RIGHTX;
+ m_screenInfo.pos.y = CALIBRATION_TOPY;
+ m_screenInfo.lineColor = CONFIG_NXWM_CALIBRATION_LINECOLOR;
+ m_screenInfo.circleFillColor = CONFIG_NXWM_CALIBRATION_CIRCLECOLOR;
+ showCalibration();
+
+ // Then set up the current state
+
+ m_state = CALIB_UPPER_RIGHT;
+ }
+ break;
+
+ case CALIB_UPPER_RIGHT:
+ {
+ // A touch has been received while in the CALIB_UPPER_RIGHT state.
+ // Save the touch data and set up the next calibration display
+
+ m_calibData[CALIB_UPPER_RIGHT_INDEX].x = m_touchPos.x;
+ m_calibData[CALIB_UPPER_RIGHT_INDEX].y = m_touchPos.y;
+
+ // Clear the previous screen by re-drawing it using the backgro9und
+ // color. That is much faster than clearing the whole display
+
+ m_screenInfo.lineColor = CONFIG_NXWM_CALIBRATION_BACKGROUNDCOLOR;
+ m_screenInfo.circleFillColor = CONFIG_NXWM_CALIBRATION_BACKGROUNDCOLOR;
+ showCalibration();
+
+ // Then draw the next calibration screen
+
+ m_screenInfo.pos.x = CALIBRATION_RIGHTX;
+ m_screenInfo.pos.y = CALIBRATION_BOTTOMY;
+ m_screenInfo.lineColor = CONFIG_NXWM_CALIBRATION_LINECOLOR;
+ m_screenInfo.circleFillColor = CONFIG_NXWM_CALIBRATION_CIRCLECOLOR;
+ showCalibration();
+
+ // Then set up the current state
+
+ m_state = CALIB_LOWER_RIGHT;
+ }
+ break;
+
+ case CALIB_LOWER_RIGHT:
+ {
+ // A touch has been received while in the CALIB_LOWER_RIGHT state.
+ // Save the touch data and set up the next calibration display
+
+ m_calibData[CALIB_LOWER_RIGHT_INDEX].x = m_touchPos.x;
+ m_calibData[CALIB_LOWER_RIGHT_INDEX].y = m_touchPos.y;
+
+ // Clear the previous screen by re-drawing it using the backgro9und
+ // color. That is much faster than clearing the whole display
+
+ m_screenInfo.lineColor = CONFIG_NXWM_CALIBRATION_BACKGROUNDCOLOR;
+ m_screenInfo.circleFillColor = CONFIG_NXWM_CALIBRATION_BACKGROUNDCOLOR;
+ showCalibration();
+
+ // Then draw the next calibration screen
+
+ m_screenInfo.pos.x = CALIBRATION_LEFTX;
+ m_screenInfo.pos.y = CALIBRATION_BOTTOMY;
+ m_screenInfo.lineColor = CONFIG_NXWM_CALIBRATION_LINECOLOR;
+ m_screenInfo.circleFillColor = CONFIG_NXWM_CALIBRATION_CIRCLECOLOR;
+ showCalibration();
+
+ // Then set up the current state
+
+ m_state = CALIB_LOWER_LEFT;
+ }
+ break;
+
+ case CALIB_LOWER_LEFT:
+ {
+ // A touch has been received while in the CALIB_LOWER_LEFT state.
+ // Save the touch data and set up the next calibration display
+
+ m_calibData[CALIB_LOWER_LEFT_INDEX].x = m_touchPos.x;
+ m_calibData[CALIB_LOWER_LEFT_INDEX].y = m_touchPos.y;
+
+ // Inform any waiter that calibration is complete
+
+ m_state = CALIB_COMPLETE;
+ sem_post(&m_waitSem);
+ }
+ break;
+
+ case CALIB_COMPLETE:
+ // Might happen... do nothing if it does
+ break;
+ }
+
+ gvdbg("State: %d Screen x: %d y: %d\n",
+ m_state, m_screenInfo.pos.x, m_screenInfo.pos.y);
+}
+
+/**
+ * Presents the next calibration screen
+ *
+ * @param screenInfo Describes the next calibration screen
+ */
+
+void CCalibration::showCalibration(void)
+{
+ // Recover the window instance contained in the full screen window
+
+ NXWidgets::INxWindow *window = m_window->getWindow();
+
+ // Get the widget control associated with the full screen window
+
+ NXWidgets::CWidgetControl *control = window->getWidgetControl();
+
+ // Get the CCGraphicsPort instance for this window
+
+ NXWidgets::CGraphicsPort *port = control->getGraphicsPort();
+
+ // Get the size of the fullscreen window
+
+ struct nxgl_size_s windowSize;
+ if (!window->getSize(&windowSize))
+ {
+ return;
+ }
+
+ // Draw the circle at the center of the touch position
+
+ port->drawFilledCircle(&m_screenInfo.pos, CALIBRATION_CIRCLE_RADIUS,
+ m_screenInfo.circleFillColor);
+
+ /* Draw horizontal line */
+
+ port->drawFilledRect(0, m_screenInfo.pos.y, windowSize.w, CALIBRATION_LINE_THICKNESS,
+ m_screenInfo.lineColor);
+
+ /* Draw vertical line */
+
+ port->drawFilledRect(m_screenInfo.pos.x, 0, CALIBRATION_LINE_THICKNESS, windowSize.h,
+ m_screenInfo.lineColor);
+}