mirror of
https://gitea.osmocom.org/sim-card/simtrace2.git
synced 2026-03-16 21:28:33 +03:00
370 lines
13 KiB
C
370 lines
13 KiB
C
/* ----------------------------------------------------------------------------
|
|
* ATMEL Microcontroller Software Support
|
|
* ----------------------------------------------------------------------------
|
|
* Copyright (c) 2009, Atmel Corporation
|
|
*
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions are met:
|
|
*
|
|
* - Redistributions of source code must retain the above copyright notice,
|
|
* this list of conditions and the disclaimer below.
|
|
*
|
|
* Atmel's name may not be used to endorse or promote products derived from
|
|
* this software without specific prior written permission.
|
|
*
|
|
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
|
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
|
|
* DISCLAIMED. IN NO EVENT SHALL ATMEL 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.
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
/**
|
|
* \file
|
|
*
|
|
* Implementation of touchscreen driver device irrelevance code.
|
|
*/
|
|
|
|
/*----------------------------------------------------------------------------
|
|
* Headers
|
|
*----------------------------------------------------------------------------*/
|
|
|
|
#include "board.h"
|
|
|
|
#include <assert.h>
|
|
#include <stdint.h>
|
|
#include <string.h>
|
|
|
|
/*----------------------------------------------------------------------------
|
|
* Definitions
|
|
*----------------------------------------------------------------------------*/
|
|
|
|
/** Size in pixels of calibration points. */
|
|
#define POINTS_SIZE 4
|
|
/** Maximum difference in pixels between the test point and the measured point. */
|
|
#define POINTS_MAX_ERROR 8
|
|
|
|
/** Delay at the end of calibartion for result display */
|
|
#define DELAY_RESULT_DISPLAY 4000000
|
|
|
|
/*----------------------------------------------------------------------------
|
|
* Types
|
|
*----------------------------------------------------------------------------*/
|
|
|
|
/** \brief Point used during the touchscreen calibration process. */
|
|
typedef struct _CalibrationPoint {
|
|
|
|
/** Coordinate of point along the X-axis of the screen. */
|
|
uint32_t x;
|
|
/** Coordinate of point along the Y-axis of the screen. */
|
|
uint32_t y;
|
|
/** Calibration data of point. */
|
|
uint32_t data[2];
|
|
|
|
} CalibrationPoint;
|
|
|
|
/*----------------------------------------------------------------------------
|
|
* Variables
|
|
*----------------------------------------------------------------------------*/
|
|
|
|
/** indicates if the touch screen has been calibrated. */
|
|
/** If not, Callback functions are not called. */
|
|
static volatile uint8_t bCalibrationOk = 0;
|
|
/** Slope for interpoling touchscreen measurements along the X-axis. */
|
|
static int32_t xSlope;
|
|
/** Slope for interpoling touchscreen measurements along the Y-axis. */
|
|
static int32_t ySlope;
|
|
|
|
/** Calibration points. */
|
|
static CalibrationPoint calibrationPoints[] = {
|
|
|
|
/* Top-left corner calibration point */
|
|
{
|
|
BOARD_LCD_WIDTH / 10,
|
|
BOARD_LCD_HEIGHT / 10,
|
|
{0, 0}
|
|
},
|
|
/* Top-right corner calibration point */
|
|
{
|
|
BOARD_LCD_WIDTH - BOARD_LCD_WIDTH / 10,
|
|
BOARD_LCD_HEIGHT / 10,
|
|
{0, 0}
|
|
},
|
|
/* Bottom-right corner calibration point */
|
|
{
|
|
BOARD_LCD_WIDTH - BOARD_LCD_WIDTH / 10,
|
|
BOARD_LCD_HEIGHT - BOARD_LCD_HEIGHT / 10,
|
|
{0, 0}
|
|
},
|
|
/* Bottom-left corner calibration point */
|
|
{
|
|
BOARD_LCD_WIDTH / 10,
|
|
BOARD_LCD_HEIGHT - BOARD_LCD_HEIGHT / 10,
|
|
{0, 0}
|
|
}
|
|
};
|
|
|
|
/** Test point */
|
|
static const CalibrationPoint testPoint = {
|
|
BOARD_LCD_WIDTH / 2,
|
|
BOARD_LCD_HEIGHT / 2,
|
|
{0, 0}
|
|
};
|
|
|
|
/*----------------------------------------------------------------------------
|
|
* Local functions
|
|
*----------------------------------------------------------------------------*/
|
|
|
|
/**
|
|
* \brief Display a calibration point on the given buffer.
|
|
*
|
|
* \param pPoint Calibration point to display.
|
|
*/
|
|
static void DrawCalibrationPoint(const CalibrationPoint *pPoint)
|
|
{
|
|
LCDD_DrawRectangleWithFill(pPoint->x - POINTS_SIZE / 2,
|
|
pPoint->y - POINTS_SIZE / 2,
|
|
POINTS_SIZE,
|
|
POINTS_SIZE,
|
|
COLOR_RED);
|
|
}
|
|
|
|
/**
|
|
* \brief Clears a calibration point from the given buffer.
|
|
*
|
|
* \param pPoint Calibration point to clear.
|
|
*/
|
|
static void ClearCalibrationPoint(const CalibrationPoint *pPoint)
|
|
{
|
|
LCDD_DrawRectangleWithFill(pPoint->x - POINTS_SIZE / 2,
|
|
pPoint->y - POINTS_SIZE / 2,
|
|
POINTS_SIZE,
|
|
POINTS_SIZE,
|
|
COLOR_WHITE);
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------
|
|
* Exported functions
|
|
*----------------------------------------------------------------------------*/
|
|
|
|
/**
|
|
* \brief Indicates if the calibration of the touch screen is Ok.
|
|
*
|
|
* \return 1 calibration Ok, 0 if not.
|
|
*/
|
|
uint8_t TSDCom_IsCalibrationOk(void)
|
|
{
|
|
if (bCalibrationOk == 1) {
|
|
return 1;
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* \brief Interpolates the provided raw measurements using the previously calculated
|
|
* slope. The resulting x and y coordinates are stored in an array.
|
|
*
|
|
* \param pData Raw measurement data, as returned by TSD_GetRawMeasurement().
|
|
* \param pPoint Array in which x and y will be stored.
|
|
*/
|
|
void TSDCom_InterpolateMeasurement(const uint32_t *pData, uint32_t *pPoint)
|
|
{
|
|
pPoint[0] = calibrationPoints[0].x
|
|
- (((int32_t) calibrationPoints[0].data[0] - (int32_t) pData[0]) * 1024)
|
|
/ xSlope;
|
|
|
|
pPoint[1] = calibrationPoints[0].y
|
|
- (((int32_t) calibrationPoints[0].data[1] - (int32_t) pData[1]) * 1024)
|
|
/ ySlope;
|
|
|
|
if(pPoint[0] & 0x80000000) /* Is pPoint[0] negative ? */
|
|
{
|
|
pPoint[0] = 0;
|
|
}
|
|
|
|
if(pPoint[0] > BOARD_LCD_WIDTH) /* Is pPoint[0] bigger than the LCD width ? */
|
|
{
|
|
pPoint[0] = BOARD_LCD_WIDTH;
|
|
}
|
|
|
|
if(pPoint[1] & 0x80000000) /* Is pPoint[1] negative ? */
|
|
{
|
|
pPoint[1] = 0;
|
|
}
|
|
|
|
if(pPoint[1] > BOARD_LCD_HEIGHT) /* Is pPoint[1] bigger than the LCD width ? */
|
|
{
|
|
pPoint[1] = BOARD_LCD_HEIGHT;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* \brief Performs the calibration process using the provided buffer to display
|
|
* information.
|
|
*
|
|
* \return True if calibration was successful; otherwise false.
|
|
*/
|
|
uint8_t TSDCom_Calibrate(void)
|
|
{
|
|
volatile uint32_t i; /* to keep the tempo with gcc code optimisation */
|
|
int32_t slope1, slope2;
|
|
CalibrationPoint measuredPoint;
|
|
uint8_t xOk, yOk;
|
|
int32_t xDiff, yDiff;
|
|
|
|
/* Calibration setup */
|
|
LCDD_Fill(COLOR_WHITE);
|
|
LCDD_DrawString(30, 50, (uint8_t *)"LCD calibration", COLOR_BLACK);
|
|
LCDD_DrawString(1, 140, (uint8_t *)"Touch the dots to\ncalibrate the screen", COLOR_DARKBLUE);
|
|
|
|
/* Calibration points */
|
|
for (i=0; i < 4; i++) {
|
|
|
|
DrawCalibrationPoint(&calibrationPoints[i]);
|
|
|
|
/* Wait for touch & end of conversion */
|
|
TSD_WaitPenPressed();
|
|
TSD_GetRawMeasurement(calibrationPoints[i].data);
|
|
ClearCalibrationPoint(&calibrationPoints[i]);
|
|
|
|
/* Wait for contact loss */
|
|
TSD_WaitPenReleased();
|
|
}
|
|
|
|
/**
|
|
* Calculate slopes using the calibration data
|
|
* Theory behind those calculations:
|
|
* - We suppose the touchscreen measurements are linear, so the following equations are true (simple
|
|
* linear regression) for any two 'a' and 'b' points of the screen:
|
|
* dx = (a.data[0] - b.data[0]) / (a.x - b.x)
|
|
* dy = (a.data[1] - b.data[1]) / (a.y - b.y)
|
|
*
|
|
* - We calculate dx and dy (called xslope and yslope here) using the calibration points.
|
|
*
|
|
* - We can then use dx and dy to infer the position of a point 'p' given the measurements performed
|
|
* by the touchscreen ('c' is any of the calibration points):
|
|
* dx = (p.data[0] - c.data[0]) / (p.x - c.x)
|
|
* dy = (p.data[1] - c.data[1]) / (p.y - c.y)
|
|
* Thus:
|
|
* p.x = c.x - (p.data[0] - c.data[0]) / dx
|
|
* p.y = c.y - (p.data[1] - c.data[1]) / dy
|
|
*
|
|
* - Since there are four calibration points, dx and dy can be calculated twice, so we average
|
|
* the two values.
|
|
*/
|
|
slope1 = ((int32_t) calibrationPoints[0].data[0]) - ((int32_t) calibrationPoints[1].data[0]);
|
|
slope1 *= 1024;
|
|
slope1 /= ((int32_t) calibrationPoints[0].x) - ((int32_t) calibrationPoints[1].x);
|
|
slope2 = ((int32_t) calibrationPoints[2].data[0]) - ((int32_t) calibrationPoints[3].data[0]);
|
|
slope2 *= 1024;
|
|
slope2 /= ((int32_t) calibrationPoints[2].x) - ((int32_t) calibrationPoints[3].x);
|
|
xSlope = (slope1 + slope2) / 2;
|
|
|
|
slope1 = ((int32_t) calibrationPoints[0].data[1]) - ((int32_t) calibrationPoints[2].data[1]);
|
|
slope1 *= 1024;
|
|
slope1 /= ((int32_t) calibrationPoints[0].y) - ((int32_t) calibrationPoints[2].y);
|
|
slope2 = ((int32_t) calibrationPoints[1].data[1]) - ((int32_t) calibrationPoints[3].data[1]);
|
|
slope2 *= 1024;
|
|
slope2 /= ((int32_t) calibrationPoints[1].y) - ((int32_t) calibrationPoints[3].y);
|
|
ySlope = (slope1 + slope2) / 2;
|
|
|
|
/* Test point */
|
|
LCDD_Fill(0xFFFFFF);
|
|
LCDD_DrawString(30, 50, (uint8_t *)"LCD calibration", COLOR_BLACK);
|
|
LCDD_DrawString(1, 100, (uint8_t *)" Touch the point to\nvalidate calibration", COLOR_DARKBLUE);
|
|
DrawCalibrationPoint(&testPoint);
|
|
|
|
/* Wait for touch & end of conversion */
|
|
TSD_WaitPenPressed();
|
|
|
|
TSD_GetRawMeasurement(measuredPoint.data);
|
|
TSDCom_InterpolateMeasurement(measuredPoint.data, (uint32_t *) &measuredPoint);
|
|
DrawCalibrationPoint(&measuredPoint);
|
|
|
|
/* Check resulting x and y */
|
|
xDiff = (int32_t) measuredPoint.x - (int32_t) testPoint.x;
|
|
yDiff = (int32_t) measuredPoint.y - (int32_t) testPoint.y;
|
|
xOk = (xDiff >= -POINTS_MAX_ERROR) && (xDiff <= POINTS_MAX_ERROR);
|
|
yOk = (yDiff >= -POINTS_MAX_ERROR) && (yDiff <= POINTS_MAX_ERROR);
|
|
|
|
/* Wait for contact loss */
|
|
TSD_WaitPenReleased();
|
|
|
|
/* Check calibration result */
|
|
if (xOk && yOk) {
|
|
|
|
bCalibrationOk = 1;
|
|
LCDD_Fill(COLOR_WHITE);
|
|
LCDD_DrawString(30, 50, (uint8_t *)"LCD calibration", COLOR_BLACK);
|
|
LCDD_DrawString(80, 140, (uint8_t *)"Success !", COLOR_GREEN);
|
|
|
|
}
|
|
else {
|
|
|
|
bCalibrationOk = 0;
|
|
LCDD_Fill(COLOR_WHITE);
|
|
LCDD_DrawString(30, 50, (uint8_t *)"LCD calibration", COLOR_BLACK);
|
|
LCDD_DrawString(40, 140, (uint8_t *)"Error too big", COLOR_RED);
|
|
}
|
|
|
|
/* Slight delay */
|
|
for (i = 0; i < DELAY_RESULT_DISPLAY; i++);
|
|
|
|
return (xOk && yOk);
|
|
}
|
|
|
|
/**
|
|
* \brief Read calibrate data to buffer.
|
|
*
|
|
* \param pBuffer Data buffer.
|
|
* \param size Size of data buffer in bytes.
|
|
*/
|
|
void TSDCom_ReadCalibrateData(void *pBuffer, uint32_t size)
|
|
{
|
|
uint8_t *pDest = (uint8_t *)pBuffer;
|
|
|
|
assert( (sizeof(bCalibrationOk) + sizeof(xSlope) +
|
|
sizeof(ySlope) + sizeof(calibrationPoints[0].data)) < size ) ;
|
|
|
|
memcpy(pDest, (void const *)&bCalibrationOk, sizeof(bCalibrationOk));
|
|
pDest += sizeof(bCalibrationOk);
|
|
memcpy(pDest, &xSlope, sizeof(xSlope));
|
|
pDest += sizeof(xSlope);
|
|
memcpy(pDest, &ySlope, sizeof(ySlope));
|
|
pDest += sizeof(ySlope);
|
|
memcpy(pDest, &calibrationPoints[0].data, sizeof(calibrationPoints[0].data));
|
|
pDest += sizeof(calibrationPoints[0].data);
|
|
}
|
|
|
|
/**
|
|
* \brief Restore calibrate data with buffer data.
|
|
*
|
|
* \param pBuffer Data buffer.
|
|
* \param size Size of data buffer in bytes.
|
|
*/
|
|
void TSDCom_RestoreCalibrateData(void *pBuffer, uint32_t size)
|
|
{
|
|
uint8_t *pSrc = (uint8_t *)pBuffer;
|
|
|
|
assert( (sizeof(bCalibrationOk) + sizeof(xSlope) +
|
|
sizeof(ySlope) + sizeof(calibrationPoints[0].data)) < size ) ;
|
|
|
|
memcpy((void *)&bCalibrationOk, pSrc, sizeof(bCalibrationOk));
|
|
pSrc += sizeof(bCalibrationOk);
|
|
memcpy(&xSlope, pSrc, sizeof(xSlope));
|
|
pSrc += sizeof(xSlope);
|
|
memcpy(&ySlope, pSrc, sizeof(ySlope));
|
|
pSrc += sizeof(ySlope);
|
|
memcpy(&calibrationPoints[0].data, pSrc, sizeof(calibrationPoints[0].data));
|
|
pSrc += sizeof(calibrationPoints[0].data);
|
|
}
|