]> git.sur5r.net Git - freertos/blob - FreeRTOS/Demo/CORTEX_A5_SAMA5D3x_Xplained_IAR/AtmelFiles/libboard_sama5d3x-ek/source/tsd_com.c
commit 9f316c246baafa15c542a5aea81a94f26e3d6507
[freertos] / FreeRTOS / Demo / CORTEX_A5_SAMA5D3x_Xplained_IAR / AtmelFiles / libboard_sama5d3x-ek / source / tsd_com.c
1 /* ----------------------------------------------------------------------------\r
2  *         SAM Software Package License \r
3  * ----------------------------------------------------------------------------\r
4  * Copyright (c) 2011, Atmel Corporation\r
5  *\r
6  * All rights reserved.\r
7  *\r
8  * Redistribution and use in source and binary forms, with or without\r
9  * modification, are permitted provided that the following conditions are met:\r
10  *\r
11  * - Redistributions of source code must retain the above copyright notice,\r
12  * this list of conditions and the disclaimer below.\r
13  *\r
14  * Atmel's name may not be used to endorse or promote products derived from\r
15  * this software without specific prior written permission.\r
16  *\r
17  * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR\r
18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
19  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE\r
20  * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,\r
21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\r
22  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,\r
23  * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\r
24  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\r
25  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,\r
26  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
27  * ----------------------------------------------------------------------------\r
28  */\r
29  \r
30 /** \file */\r
31 \r
32 /*----------------------------------------------------------------------------\r
33  *        Headers\r
34  *----------------------------------------------------------------------------*/\r
35 \r
36 /** \addtogroup tsd_module\r
37  *@{\r
38  */\r
39      \r
40 \r
41 #include <board.h>\r
42 #include <string.h>\r
43 \r
44 /*----------------------------------------------------------------------------\r
45  *        Local definitions\r
46  *----------------------------------------------------------------------------*/\r
47 \r
48 /** Size in pixels of calibration points. */\r
49 #define POINTS_SIZE         4\r
50 /** Maximum difference in pixels between the test point and the measured point.\r
51  */\r
52 #define POINTS_MAX_XERROR   10\r
53 /** Maximum difference in pixels between the test point and the measured point.\r
54  */\r
55 #define POINTS_MAX_YERROR   8\r
56 \r
57 /** Delay at the end of calibartion for result display (positive or negative) */\r
58 #define DELAY_RESULT_DISPLAY 4000000\r
59 \r
60 /** Clear Strings on LCD */\r
61 #if 1\r
62 #define CLEAR_STRING()  LCDD_Fill(COLOR_WHITE)\r
63 #else\r
64 #define CLEAR_STRING()  \\r
65     LCDD_DrawFilledRectangle(strX -  3*strW, strY, \\r
66                              strX + 20*strW, strY + 6*strH, COLOR_WHITE)\r
67 #endif\r
68 \r
69 /*----------------------------------------------------------------------------\r
70  *         Local types\r
71  *----------------------------------------------------------------------------*/\r
72 \r
73 /**\r
74  * Point used during the touchscreen calibration process.\r
75  */\r
76 typedef struct _CalibrationPoint {\r
77 \r
78     /** Coordinate of point along the X-axis of the screen. */\r
79     uint32_t x;\r
80     /** Coordinate of point along the Y-axis of the screen. */\r
81     uint32_t y;\r
82     /** Calibration data of point. */\r
83     uint32_t data[2];\r
84 \r
85 } CalibrationPoint;\r
86 \r
87 /*----------------------------------------------------------------------------\r
88  *         Local variables\r
89  *----------------------------------------------------------------------------*/\r
90 \r
91 /** Calibration display title */\r
92 static const char* strTitle = "LCD Calibration";\r
93 \r
94 /** indicates if the touch screen has been calibrated.\r
95     If not, Callback functions are not called */\r
96 static volatile uint8_t bCalibrationOk = 0;\r
97 /** Slope for interpoling touchscreen measurements along the X-axis. */\r
98 static int32_t xSlope;\r
99 /** Slope for interpoling touchscreen measurements along the Y-axis. */\r
100 static int32_t ySlope;\r
101 \r
102 /** Calibration points */\r
103 static CalibrationPoint calibrationPoints[] = {\r
104 \r
105     /* Top-left corner calibration point */\r
106     {\r
107         BOARD_LCD_WIDTH / 10,\r
108         BOARD_LCD_HEIGHT / 10,\r
109         {0, 0}\r
110     },\r
111     /* Top-right corner calibration point */\r
112     {\r
113         BOARD_LCD_WIDTH - BOARD_LCD_WIDTH / 10,\r
114         BOARD_LCD_HEIGHT / 10,\r
115         {0, 0}\r
116     },\r
117     /* Bottom-right corner calibration point */\r
118     {\r
119         BOARD_LCD_WIDTH - BOARD_LCD_WIDTH / 10,\r
120         BOARD_LCD_HEIGHT - BOARD_LCD_HEIGHT / 10,\r
121         {0, 0}\r
122     },\r
123     /* Bottom-left corner calibration point */\r
124     {\r
125         BOARD_LCD_WIDTH / 10,\r
126         BOARD_LCD_HEIGHT - BOARD_LCD_HEIGHT / 10,\r
127         {0, 0}\r
128     }\r
129 };\r
130 \r
131 /** Test point */\r
132 static const CalibrationPoint testPoint = {\r
133     BOARD_LCD_WIDTH / 2,\r
134     BOARD_LCD_HEIGHT / 2,\r
135     {0, 0}\r
136 };\r
137 \r
138 /*----------------------------------------------------------------------------\r
139  *         External functions\r
140  *----------------------------------------------------------------------------*/\r
141 \r
142 /*----------------------------------------------------------------------------\r
143  *         Local functions\r
144  *----------------------------------------------------------------------------*/\r
145 \r
146 /**\r
147  * Display a calibration point on the given buffer.\r
148  * \param pPoint  Calibration point to display.\r
149  */\r
150 static void DrawCalibrationPoint(\r
151     const CalibrationPoint *pPoint)\r
152 {\r
153     LCDD_DrawFilledRectangle(pPoint->x - POINTS_SIZE / 2,\r
154                              pPoint->y - POINTS_SIZE / 2,\r
155                              pPoint->x + POINTS_SIZE,\r
156                              pPoint->y + POINTS_SIZE,\r
157                              COLOR_RED);\r
158 }\r
159 \r
160 /**\r
161  * Clears a calibration point from the given buffer.\r
162  * \param pLcdBuffer  LCD buffer to draw on.\r
163  * \param pPoint  Calibration point to clear.\r
164  */\r
165 static void ClearCalibrationPoint(\r
166     const CalibrationPoint *pPoint)\r
167 {\r
168     LCDD_DrawFilledRectangle(pPoint->x - POINTS_SIZE,\r
169                              pPoint->y - POINTS_SIZE,\r
170                              pPoint->x + POINTS_SIZE,\r
171                              pPoint->y + POINTS_SIZE,\r
172                              COLOR_WHITE);\r
173 }\r
174 \r
175 /*----------------------------------------------------------------------------\r
176  *        Exported functions\r
177  *----------------------------------------------------------------------------*/\r
178 \r
179 /**\r
180  * Indicates if the calibration of the touch screen is Ok\r
181  * \return 1 calibration Ok, 0 if not\r
182  */\r
183 uint8_t TSDCom_IsCalibrationOk(void)\r
184 {\r
185     return bCalibrationOk;\r
186 }\r
187 \r
188 /**\r
189  * Interpolates the provided raw measurements using the previously calculated\r
190  * slope. The resulting x and y coordinates are stored in an array.\r
191  * \param pData  Raw measurement data, as returned by TSD_GetRawMeasurement().\r
192  * \param pPoint  Array in which x and y will be stored.\r
193  */\r
194 void TSDCom_InterpolateMeasurement(const uint32_t *pData, uint32_t *pPoint)\r
195 {\r
196     pPoint[0] = calibrationPoints[0].x\r
197                 - (((int32_t) calibrationPoints[0].data[0] - (int32_t) pData[0]) * 1024)\r
198                 / xSlope;\r
199 \r
200     pPoint[1] = calibrationPoints[0].y\r
201                 - (((int32_t) calibrationPoints[0].data[1] - (int32_t) pData[1]) * 1024)\r
202                 / ySlope;\r
203     /* Is pPoint[0] negative ? */\r
204     if(pPoint[0] & 0x80000000)        pPoint[0] = 0;\r
205     /* Is pPoint[0] bigger than the LCD width ? */\r
206     if(pPoint[0] > BOARD_LCD_WIDTH)   pPoint[0] = BOARD_LCD_WIDTH;\r
207     /* Is pPoint[1] negative ? */\r
208     if(pPoint[1] & 0x80000000)        pPoint[1] = 0;\r
209     /* Is pPoint[1] bigger than the LCD width ? */\r
210     if(pPoint[1] > BOARD_LCD_HEIGHT)  pPoint[1] = BOARD_LCD_HEIGHT;\r
211 }\r
212 \r
213 /**\r
214  * Performs the calibration process using the provided buffer to display\r
215  * information.\r
216  * \param pLcdBuffer  LCD buffer to display.\r
217  * \return True if calibration was successful; otherwise false.\r
218  */\r
219 uint8_t TSDCom_Calibrate(void)\r
220 {\r
221     uint32_t i; // to keep the tempo with gcc code optimisation\r
222     int32_t slope1, slope2;\r
223     CalibrationPoint measuredPoint;\r
224     uint8_t xOk, yOk;\r
225     int32_t xDiff, yDiff;\r
226     uint32_t strX = BOARD_LCD_WIDTH / 2 - 75, strY = 60;\r
227     uint32_t strW, strH;\r
228 \r
229     LCDD_GetStringSize("P", &strW, &strH);\r
230     /* Calibration setup */\r
231     LCDD_Fill(COLOR_WHITE);\r
232     LCDD_Flush_CurrentCanvas();\r
233     LCDD_DrawString(strX, strY, strTitle, COLOR_BLACK);\r
234     LCDD_Flush_CurrentCanvas();\r
235     LCDD_DrawString(strX - 2*strW, strY + 3*strH,\r
236         " Touch the dots to\ncalibrate the screen", COLOR_DARKBLUE);\r
237     LCDD_Flush_CurrentCanvas();\r
238     /* Calibration points */\r
239     for (i = 0; i < 4; i++) {\r
240 \r
241         DrawCalibrationPoint(&calibrationPoints[i]);\r
242         LCDD_Flush_CurrentCanvas();\r
243         /* Wait for touch & end of conversion */\r
244         TSD_WaitPenPressed();\r
245         TSD_GetRawMeasurement(calibrationPoints[i].data);\r
246         ClearCalibrationPoint(&calibrationPoints[i]);\r
247         LCDD_Flush_CurrentCanvas();\r
248         /* Wait for contact loss */\r
249         TSD_WaitPenReleased();\r
250         printf("P%d: (%d,%d)\n\r", (unsigned int)i, (unsigned int)calibrationPoints[i].data[0], (unsigned int)calibrationPoints[i].data[1]);\r
251     }\r
252 \r
253     /* Calculate slopes using the calibration data\r
254      * Theory behind those calculations:\r
255      *   - We suppose the touchscreen measurements are linear, so the following equations are true (simple\r
256      *     linear regression) for any two 'a' and 'b' points of the screen:\r
257      *       dx = (a.data[0] - b.data[0]) / (a.x - b.x)\r
258      *       dy = (a.data[1] - b.data[1]) / (a.y - b.y)\r
259      *\r
260      *   - We calculate dx and dy (called xslope and yslope here) using the calibration points.\r
261      *\r
262      *   - We can then use dx and dy to infer the position of a point 'p' given the measurements performed\r
263      *     by the touchscreen ('c' is any of the calibration points):\r
264      *       dx = (p.data[0] - c.data[0]) / (p.x - c.x)\r
265      *       dy = (p.data[1] - c.data[1]) / (p.y - c.y)\r
266      *     Thus:\r
267      *       p.x = c.x - (p.data[0] - c.data[0]) / dx\r
268      *       p.y = c.y - (p.data[1] - c.data[1]) / dy\r
269      *\r
270      *   - Since there are four calibration points, dx and dy can be calculated twice, so we average\r
271      *     the two values.\r
272      */\r
273     slope1 = ((int32_t) calibrationPoints[0].data[0]) - ((int32_t) calibrationPoints[1].data[0]);\r
274     slope1 *= 1024;\r
275     slope1 /= ((int32_t) calibrationPoints[0].x) - ((int32_t) calibrationPoints[1].x);\r
276     slope2 = ((int32_t) calibrationPoints[2].data[0]) - ((int32_t) calibrationPoints[3].data[0]);\r
277     slope2 *= 1024;\r
278     slope2 /= ((int32_t) calibrationPoints[2].x) - ((int32_t) calibrationPoints[3].x);\r
279     xSlope = (slope1 + slope2) / 2;\r
280 \r
281     slope1 = ((int32_t) calibrationPoints[0].data[1]) - ((int32_t) calibrationPoints[2].data[1]);\r
282     slope1 *= 1024;\r
283     slope1 /= ((int32_t) calibrationPoints[0].y) - ((int32_t) calibrationPoints[2].y);\r
284     slope2 = ((int32_t) calibrationPoints[1].data[1]) - ((int32_t) calibrationPoints[3].data[1]);\r
285     slope2 *= 1024;\r
286     slope2 /= ((int32_t) calibrationPoints[1].y) - ((int32_t) calibrationPoints[3].y);\r
287     ySlope = (slope1 + slope2) / 2;\r
288 \r
289     printf("Slope: %d, %d\n\r", (unsigned int)xSlope, (unsigned int)ySlope);\r
290 \r
291     /* Test point */\r
292     CLEAR_STRING();\r
293     LCDD_DrawString(strX, strY, strTitle, COLOR_BLACK);\r
294     LCDD_DrawString(strX - 2*strW, strY + 3*strH,\r
295         " Touch the point to\nvalidate calibration", COLOR_DARKBLUE);\r
296     LCDD_Flush_CurrentCanvas();\r
297     DrawCalibrationPoint(&testPoint);\r
298     LCDD_Flush_CurrentCanvas();\r
299     /* Wait for touch & end of conversion */\r
300     TSD_WaitPenPressed();\r
301 \r
302     TSD_GetRawMeasurement(measuredPoint.data);\r
303     TSDCom_InterpolateMeasurement(measuredPoint.data, (uint32_t *) &measuredPoint);\r
304     DrawCalibrationPoint(&measuredPoint);\r
305     LCDD_Flush_CurrentCanvas();\r
306     /* Check resulting x and y */\r
307     xDiff = (int32_t) measuredPoint.x - (int32_t) testPoint.x;\r
308     yDiff = (int32_t) measuredPoint.y - (int32_t) testPoint.y;\r
309     xOk = (xDiff >= -POINTS_MAX_XERROR) && (xDiff <= POINTS_MAX_XERROR);\r
310     yOk = (yDiff >= -POINTS_MAX_YERROR) && (yDiff <= POINTS_MAX_YERROR);\r
311 \r
312     /* Wait for contact loss */\r
313     TSD_WaitPenReleased();\r
314 \r
315     printf("TP: %d, %d -> %d, %d\n\r",\r
316         (unsigned int)measuredPoint.data[0], (unsigned int)measuredPoint.data[1],\r
317         (unsigned int)measuredPoint.x, (unsigned int)measuredPoint.y);\r
318 \r
319     /* Check calibration result */\r
320     if (xOk && yOk) {\r
321 \r
322         bCalibrationOk = 1;\r
323         CLEAR_STRING();\r
324         LCDD_DrawString(strX, strY, strTitle, COLOR_BLACK);\r
325         LCDD_DrawString(strX + 3*strW, strY + 2*strH, "Success !", COLOR_GREEN);\r
326         LCDD_Flush_CurrentCanvas();\r
327     }\r
328     else {\r
329 \r
330         bCalibrationOk = 0;\r
331         CLEAR_STRING();\r
332         LCDD_DrawString(strX, strY, strTitle, COLOR_BLACK);\r
333         LCDD_DrawString(strX + strW, strY + 2*strH, "Error too big", COLOR_RED);\r
334         LCDD_Flush_CurrentCanvas();\r
335         TRACE_WARNING("X %u, Y %u; Diff %d, %d\n\r",\r
336             (unsigned int)(measuredPoint.x), (unsigned int)(measuredPoint.y), (unsigned int)xDiff, (unsigned int)yDiff);\r
337     }\r
338 \r
339     /* Slight delay */\r
340     for (i = 0; i < DELAY_RESULT_DISPLAY; i++);\r
341     LCDD_Flush_CurrentCanvas();\r
342     return (xOk && yOk);\r
343 }\r
344 \r
345 /**\r
346  * Read calibrate data to buffer.\r
347  * \param pBuffer  Data buffer.\r
348  * \param size     Size of data buffer in bytes.\r
349  */\r
350 void TSDCom_ReadCalibrateData(void *pBuffer, uint32_t size)\r
351 {\r
352     uint8_t *pDest = (uint8_t *)pBuffer;\r
353     \r
354     memcpy(pDest, (void const *)&bCalibrationOk, sizeof(bCalibrationOk));\r
355     pDest += sizeof(bCalibrationOk);\r
356     memcpy(pDest, &xSlope, sizeof(xSlope));\r
357     pDest += sizeof(xSlope);\r
358     memcpy(pDest, &ySlope, sizeof(ySlope));\r
359     pDest += sizeof(ySlope);\r
360     memcpy(pDest, &calibrationPoints[0].data, sizeof(calibrationPoints[0].data));\r
361     pDest += sizeof(calibrationPoints[0].data);\r
362 }\r
363 \r
364 /**\r
365  * Restore calibrate data with buffer data.\r
366  * \param pBuffer  Data buffer.\r
367  * \param size     Size of data buffer in bytes.\r
368  */\r
369 void TSDCom_RestoreCalibrateData(void *pBuffer, uint32_t size)\r
370 {\r
371     uint8_t *pSrc = (uint8_t *)pBuffer;\r
372 \r
373     memcpy((void *)&bCalibrationOk, pSrc, sizeof(bCalibrationOk));\r
374     pSrc += sizeof(bCalibrationOk);\r
375     memcpy(&xSlope, pSrc, sizeof(xSlope));\r
376     pSrc += sizeof(xSlope);\r
377     memcpy(&ySlope, pSrc, sizeof(ySlope));\r
378     pSrc += sizeof(ySlope);\r
379     memcpy(&calibrationPoints[0].data, pSrc, sizeof(calibrationPoints[0].data));\r
380     pSrc += sizeof(calibrationPoints[0].data);\r
381 }\r
382 \r
383 /**@}*/\r
384 \r