743 lines
22 KiB
C
743 lines
22 KiB
C
/**************************************************************************//**
|
|
* @copyright (C) 2020 Nuvoton Technology Corp. All rights reserved.
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*
|
|
* Change Logs:
|
|
* Date Author Notes
|
|
* 2021-04-20 Wayne First version
|
|
*
|
|
******************************************************************************/
|
|
|
|
#include <rtconfig.h>
|
|
|
|
#if defined(NU_PKG_USING_ADC_TOUCH)
|
|
|
|
#include "NuMicro.h"
|
|
#include <rtdevice.h>
|
|
#include <dfs_file.h>
|
|
#include <unistd.h>
|
|
#include <stdio.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/statfs.h>
|
|
//#include "drv_adc.h"
|
|
#include "adc_touch.h"
|
|
|
|
#if !defined(PATH_CALIBRATION_FILE)
|
|
#define PATH_CALIBRATION_FILE "/mnt/filesystem/ts_calibration"
|
|
#endif
|
|
|
|
rt_err_t nu_adc_touch_disable(void);
|
|
rt_err_t nu_adc_touch_enable(rt_touch_t psRtTouch);
|
|
void nu_adc_touch_detect(rt_bool_t bStartDetect);
|
|
int32_t nu_adc_touch_read_xyz(uint32_t *bufX, uint32_t *bufY, uint32_t *bufZ0, uint32_t *bufZ1, int32_t dataCnt);
|
|
|
|
typedef struct
|
|
{
|
|
struct rt_touch_device dev;
|
|
rt_uint32_t x_range;
|
|
rt_uint32_t y_range;
|
|
} nu_adc_touch;
|
|
typedef nu_adc_touch *nu_adc_touch_t;
|
|
|
|
static nu_adc_touch s_NuAdcTouch = {0};
|
|
|
|
/* User can define ADC touch calibration matrix in board_dev.c. */
|
|
rt_weak S_CALIBRATION_MATRIX g_sCalMat = { 1, 0, 0, 0, 1, 0, 1 };
|
|
static volatile uint32_t g_u32Calibrated = 0;
|
|
|
|
static int nu_adc_touch_readfile(void);
|
|
|
|
static const S_CALIBRATION_MATRIX g_sCalZero = { 1, 0, 0, 0, 1, 0, 1 };
|
|
|
|
static int nu_adc_cal_mat_get(const S_COORDINATE_POINT *psDispCP, S_COORDINATE_POINT *psADCCP, S_CALIBRATION_MATRIX *psCM)
|
|
{
|
|
#if (DEF_CAL_POINT_NUM==3)
|
|
|
|
psCM->div = ((psADCCP[0].x - psADCCP[2].x) * (psADCCP[1].y - psADCCP[2].y)) -
|
|
((psADCCP[1].x - psADCCP[2].x) * (psADCCP[0].y - psADCCP[2].y)) ;
|
|
|
|
if (psCM->div == 0)
|
|
{
|
|
return -1;
|
|
}
|
|
else
|
|
{
|
|
psCM->a = ((psDispCP[0].x - psDispCP[2].x) * (psADCCP[1].y - psADCCP[2].y)) -
|
|
((psDispCP[1].x - psDispCP[2].x) * (psADCCP[0].y - psADCCP[2].y)) ;
|
|
|
|
psCM->b = ((psADCCP[0].x - psADCCP[2].x) * (psDispCP[1].x - psDispCP[2].x)) -
|
|
((psDispCP[0].x - psDispCP[2].x) * (psADCCP[1].x - psADCCP[2].x)) ;
|
|
|
|
psCM->c = (psADCCP[2].x * psDispCP[1].x - psADCCP[1].x * psDispCP[2].x) * psADCCP[0].y +
|
|
(psADCCP[0].x * psDispCP[2].x - psADCCP[2].x * psDispCP[0].x) * psADCCP[1].y +
|
|
(psADCCP[1].x * psDispCP[0].x - psADCCP[0].x * psDispCP[1].x) * psADCCP[2].y ;
|
|
|
|
psCM->d = ((psDispCP[0].y - psDispCP[2].y) * (psADCCP[1].y - psADCCP[2].y)) -
|
|
((psDispCP[1].y - psDispCP[2].y) * (psADCCP[0].y - psADCCP[2].y)) ;
|
|
|
|
psCM->e = ((psADCCP[0].x - psADCCP[2].x) * (psDispCP[1].y - psDispCP[2].y)) -
|
|
((psDispCP[0].y - psDispCP[2].y) * (psADCCP[1].x - psADCCP[2].x)) ;
|
|
|
|
psCM->f = (psADCCP[2].x * psDispCP[1].y - psADCCP[1].x * psDispCP[2].y) * psADCCP[0].y +
|
|
(psADCCP[0].x * psDispCP[2].y - psADCCP[2].x * psDispCP[0].y) * psADCCP[1].y +
|
|
(psADCCP[1].x * psDispCP[0].y - psADCCP[0].x * psDispCP[1].y) * psADCCP[2].y ;
|
|
}
|
|
|
|
#elif (DEF_CAL_POINT_NUM==5)
|
|
|
|
int i;
|
|
float n, x, y, xx, yy, xy, z, zx, zy;
|
|
float a, b, c, d, e, f, g;
|
|
float scaling = 65536.0f;
|
|
|
|
n = x = y = xx = yy = xy = 0;
|
|
for (i = 0; i < DEF_CAL_POINT_NUM; i++)
|
|
{
|
|
n += (float)1.0;
|
|
x += (float)psADCCP[i].x;
|
|
y += (float)psADCCP[i].y;
|
|
xx += (float)psADCCP[i].x * psADCCP[i].x;
|
|
yy += (float)psADCCP[i].y * psADCCP[i].y;
|
|
xy += (float)psADCCP[i].x * psADCCP[i].y;
|
|
}
|
|
|
|
d = n * (xx * yy - xy * xy) + x * (xy * y - x * yy) + y * (x * xy - y * xx);
|
|
if (d < (float)0.1 && d > (float) -0.1)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
a = (xx * yy - xy * xy) / d;
|
|
b = (xy * y - x * yy) / d;
|
|
c = (x * xy - y * xx) / d;
|
|
e = (n * yy - y * y) / d;
|
|
f = (x * y - n * xy) / d;
|
|
g = (n * xx - x * x) / d;
|
|
|
|
z = zx = zy = 0;
|
|
for (i = 0; i < DEF_CAL_POINT_NUM; i++)
|
|
{
|
|
z += (float)psDispCP[i].x;
|
|
zx += (float)psDispCP[i].x * psADCCP[i].x;
|
|
zy += (float)psDispCP[i].x * psADCCP[i].y;
|
|
}
|
|
|
|
psCM->c = (int32_t)((a * z + b * zx + c * zy) * scaling);
|
|
psCM->a = (int32_t)((b * z + e * zx + f * zy) * scaling);
|
|
psCM->b = (int32_t)((c * z + f * zx + g * zy) * scaling);
|
|
|
|
z = zx = zy = 0;
|
|
for (i = 0; i < DEF_CAL_POINT_NUM; i++)
|
|
{
|
|
z += (float)psDispCP[i].y;
|
|
zx += (float)psDispCP[i].y * psADCCP[i].x;
|
|
zy += (float)psDispCP[i].y * psADCCP[i].y;
|
|
}
|
|
|
|
psCM->f = (int32_t)((a * z + b * zx + c * zy) * scaling);
|
|
psCM->d = (int32_t)((b * z + e * zx + f * zy) * scaling);
|
|
psCM->e = (int32_t)((c * z + f * zx + g * zy) * scaling);
|
|
|
|
psCM->div = (int32_t)scaling;
|
|
|
|
#else
|
|
#error "Not supported calibration method"
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
static void nu_adc_touch_cal(int32_t *sumx, int32_t *sumy)
|
|
{
|
|
int32_t xtemp, ytemp;
|
|
|
|
xtemp = *sumx;
|
|
ytemp = *sumy;
|
|
*sumx = (g_sCalMat.c +
|
|
g_sCalMat.a * xtemp +
|
|
g_sCalMat.b * ytemp) / g_sCalMat.div;
|
|
*sumy = (g_sCalMat.f +
|
|
g_sCalMat.d * xtemp +
|
|
g_sCalMat.e * ytemp) / g_sCalMat.div;
|
|
}
|
|
|
|
static rt_ssize_t nu_adc_touch_readpoint(struct rt_touch_device *device, void *buf, rt_size_t read_num)
|
|
{
|
|
static uint32_t last_report_x = 0, last_report_y = 0;
|
|
struct rt_touch_data *pPoint = (struct rt_touch_data *)buf;
|
|
nu_adc_touch_t psNuAdcTouch = (nu_adc_touch_t)device;
|
|
|
|
RT_ASSERT(device != RT_NULL);
|
|
RT_ASSERT(buf != RT_NULL);
|
|
|
|
int i;
|
|
|
|
for (i = 0; i < read_num; i++)
|
|
{
|
|
uint32_t bufZ0 = 0, bufZ1 = 0;
|
|
int32_t sumx = 0, sumy = 0;
|
|
pPoint[i].timestamp = rt_touch_get_ts();
|
|
pPoint[i].track_id = 0;
|
|
|
|
if (nu_adc_touch_read_xyz((uint32_t *)&sumx, (uint32_t *)&sumy, &bufZ0, &bufZ1, 1) != 1)
|
|
break;
|
|
|
|
if (bufZ0 == 0)
|
|
{
|
|
/* Workaround: In this case, x, y values are unstable. so, report last point's coordinate.*/
|
|
pPoint[i].event = RT_TOUCH_EVENT_UP;
|
|
pPoint[i].x_coordinate = (uint16_t)last_report_x;
|
|
pPoint[i].y_coordinate = (uint16_t)last_report_y;
|
|
}
|
|
else
|
|
{
|
|
if (g_u32Calibrated)
|
|
{
|
|
nu_adc_touch_cal(&sumx, &sumy);
|
|
}
|
|
last_report_x = sumx;
|
|
last_report_y = sumy;
|
|
|
|
pPoint[i].event = RT_TOUCH_EVENT_DOWN;
|
|
pPoint[i].x_coordinate = (uint16_t)sumx;
|
|
pPoint[i].y_coordinate = (uint16_t)sumy;
|
|
}
|
|
|
|
if (g_u32Calibrated)
|
|
{
|
|
bufZ0 = bufZ0 >> 3;
|
|
pPoint[i].width = (bufZ0 > 255) ? 255 : bufZ0;
|
|
|
|
//Limit max x, y coordinate if value is over its range.
|
|
pPoint[i].x_coordinate = (pPoint[i].x_coordinate > psNuAdcTouch->x_range) ? psNuAdcTouch->x_range : pPoint[i].x_coordinate;
|
|
pPoint[i].y_coordinate = (pPoint[i].y_coordinate > psNuAdcTouch->y_range) ? psNuAdcTouch->y_range : pPoint[i].y_coordinate;
|
|
}
|
|
}
|
|
return (rt_size_t)i;
|
|
}
|
|
|
|
static rt_err_t nu_adc_touch_control(struct rt_touch_device *device, int cmd, void *data)
|
|
{
|
|
nu_adc_touch_t psNuAdcTouch = (nu_adc_touch_t)device;
|
|
RT_ASSERT(psNuAdcTouch != RT_NULL);
|
|
|
|
switch (cmd)
|
|
{
|
|
case RT_TOUCH_CTRL_SET_X_RANGE: /* set x range */
|
|
psNuAdcTouch->x_range = *((rt_int32_t *)data);
|
|
break;
|
|
|
|
case RT_TOUCH_CTRL_SET_Y_RANGE: /* set y range */
|
|
psNuAdcTouch->y_range = *((rt_int32_t *)data);
|
|
break;
|
|
|
|
case RT_TOUCH_CTRL_ENABLE_INT: /* enable pen_down interrupt */
|
|
nu_adc_touch_detect(RT_TRUE);
|
|
break;
|
|
|
|
case RT_TOUCH_CTRL_DISABLE_INT: /* disable pen_down interrupt */
|
|
nu_adc_touch_detect(RT_FALSE);
|
|
break;
|
|
|
|
case RT_TOUCH_CTRL_POWER_ON: /* Touch Power On */
|
|
return nu_adc_touch_enable(device);
|
|
|
|
case RT_TOUCH_CTRL_POWER_OFF: /* Touch Power Off */
|
|
return nu_adc_touch_disable();
|
|
|
|
default:
|
|
return -RT_ERROR;
|
|
}
|
|
return RT_EOK;
|
|
}
|
|
|
|
static struct rt_touch_ops touch_ops =
|
|
{
|
|
.touch_readpoint = nu_adc_touch_readpoint,
|
|
.touch_control = nu_adc_touch_control,
|
|
};
|
|
|
|
static void nu_adc_touch_update_calmat(S_CALIBRATION_MATRIX *psNewCalMat)
|
|
{
|
|
if (psNewCalMat &&
|
|
psNewCalMat->div != 0)
|
|
{
|
|
rt_memcpy(&g_sCalMat, psNewCalMat, sizeof(S_CALIBRATION_MATRIX));
|
|
g_u32Calibrated = 1;
|
|
rt_kprintf("Applied calibration data: %d, %d, %d, %d, %d, %d, %d\n",
|
|
g_sCalMat.a,
|
|
g_sCalMat.b,
|
|
g_sCalMat.c,
|
|
g_sCalMat.d,
|
|
g_sCalMat.e,
|
|
g_sCalMat.f,
|
|
g_sCalMat.div);
|
|
|
|
}
|
|
}
|
|
|
|
static void nu_adc_touch_reset_calmat(void)
|
|
{
|
|
rt_memcpy(&g_sCalMat, &g_sCalZero, sizeof(S_CALIBRATION_MATRIX));
|
|
g_u32Calibrated = 0;
|
|
}
|
|
|
|
int rt_hw_adc_touch_init(void)
|
|
{
|
|
/* Register touch device */
|
|
s_NuAdcTouch.dev.info.type = RT_TOUCH_TYPE_RESISTANCE;
|
|
s_NuAdcTouch.dev.info.vendor = RT_TOUCH_VENDOR_UNKNOWN;
|
|
s_NuAdcTouch.dev.info.point_num = 1;
|
|
s_NuAdcTouch.dev.info.range_x = BSP_LCD_WIDTH;
|
|
s_NuAdcTouch.dev.info.range_y = BSP_LCD_HEIGHT;
|
|
|
|
s_NuAdcTouch.dev.ops = &touch_ops;
|
|
|
|
return (int)rt_hw_touch_register(&s_NuAdcTouch.dev, "adc_touch", RT_DEVICE_FLAG_INT_RX, RT_NULL);
|
|
}
|
|
INIT_DEVICE_EXPORT(rt_hw_adc_touch_init);
|
|
|
|
|
|
static rt_thread_t adc_touch_thread = RT_NULL;
|
|
static rt_sem_t adc_touch_sem = RT_NULL;
|
|
static int adc_touch_worker_run = 0;
|
|
|
|
static rt_err_t adc_touch_rx_callback(rt_device_t dev, rt_size_t size)
|
|
{
|
|
//rt_kprintf("[%s %d] %d\n", __func__, __LINE__, size);
|
|
return rt_sem_release(adc_touch_sem);
|
|
}
|
|
|
|
static rt_err_t adc_request_point(rt_device_t pdev, struct rt_touch_data *psTouchPoint)
|
|
{
|
|
rt_err_t ret = -RT_ERROR;
|
|
|
|
if ((ret = rt_sem_take(adc_touch_sem, rt_tick_from_millisecond(500))) == RT_EOK)
|
|
{
|
|
rt_memset(psTouchPoint, 0, sizeof(struct rt_touch_data));
|
|
|
|
if (rt_device_read(pdev, 0, psTouchPoint, s_NuAdcTouch.dev.info.point_num) == s_NuAdcTouch.dev.info.point_num)
|
|
{
|
|
ret = RT_EOK;
|
|
}
|
|
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
rt_weak void nu_touch_inputevent_cb(rt_int16_t x, rt_int16_t y, rt_uint8_t event)
|
|
{
|
|
}
|
|
|
|
static rt_device_t lcd_device = 0;
|
|
static struct rt_device_graphic_info info;
|
|
|
|
static void lcd_cleanscreen(void)
|
|
{
|
|
if (info.framebuffer != RT_NULL)
|
|
{
|
|
if (rt_device_control(lcd_device, RTGRAPHIC_CTRL_PAN_DISPLAY, (void *)info.framebuffer) == RT_EOK)
|
|
{
|
|
/* Sync-type LCD panel, will fill to VRAM directly. */
|
|
rt_memset(info.framebuffer, 0, (info.pitch * info.height));
|
|
}
|
|
else
|
|
{
|
|
/* MPU-type LCD panel, fill to shadow RAM, then flush. */
|
|
struct rt_device_rect_info rectinfo;
|
|
int filled_line_num = 0;
|
|
int i32LineBufNum = info.smem_len / info.pitch;
|
|
int i32RemainLineNum = info.height;
|
|
|
|
i32LineBufNum = (i32LineBufNum > info.height) ? info.height : i32LineBufNum;
|
|
|
|
while (i32RemainLineNum > 0)
|
|
{
|
|
int pixel_count;
|
|
rectinfo.x = 0;
|
|
rectinfo.y = filled_line_num;
|
|
rectinfo.width = info.width;
|
|
rectinfo.height = (i32RemainLineNum > i32LineBufNum) ? i32LineBufNum : i32RemainLineNum ;
|
|
|
|
pixel_count = info.width * rectinfo.height;
|
|
rt_uint16_t *pu16ShadowBuf = (rt_uint16_t *)info.framebuffer;
|
|
|
|
while (pixel_count > 0)
|
|
{
|
|
*pu16ShadowBuf++ = 0;
|
|
pixel_count--;
|
|
}
|
|
rt_device_control(lcd_device, RTGRAPHIC_CTRL_RECT_UPDATE, &rectinfo);
|
|
filled_line_num += i32LineBufNum;
|
|
i32RemainLineNum -= rectinfo.height;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// TODO
|
|
}
|
|
}
|
|
|
|
#define DEF_DOT_NUMBER 9
|
|
#define DOTS_NUMBER (DEF_DOT_NUMBER*DEF_DOT_NUMBER)
|
|
static void nu_draw_bots(int x, int y)
|
|
{
|
|
if (info.framebuffer != RT_NULL)
|
|
{
|
|
/* Rendering */
|
|
struct rt_device_rect_info rect;
|
|
int i, j;
|
|
int start_x = x - (DEF_DOT_NUMBER / 2);
|
|
int start_y = y - (DEF_DOT_NUMBER / 2);
|
|
rt_bool_t bDrawDirect;
|
|
|
|
if (rt_device_control(lcd_device, RTGRAPHIC_CTRL_PAN_DISPLAY, (void *)info.framebuffer) == RT_EOK)
|
|
{
|
|
/* Sync-type LCD panel, will draw to VRAM directly. */
|
|
bDrawDirect = RT_TRUE;
|
|
}
|
|
else
|
|
{
|
|
/* MPU-type LCD panel, draw to shadow RAM, then flush. */
|
|
bDrawDirect = RT_FALSE;
|
|
}
|
|
|
|
if (info.pixel_format == RTGRAPHIC_PIXEL_FORMAT_RGB565)
|
|
{
|
|
uint16_t *pu16Start = (bDrawDirect == RT_TRUE) ? (uint16_t *)((uint32_t)info.framebuffer + (start_y) * info.pitch + (start_x * 2)) : (uint16_t *)info.framebuffer;
|
|
for (i = 0; i < DEF_DOT_NUMBER; i++)
|
|
{
|
|
for (j = 0; j < DEF_DOT_NUMBER; j++)
|
|
{
|
|
*pu16Start = 0x07E0; //Green, RGB565
|
|
pu16Start++;
|
|
}
|
|
if (bDrawDirect)
|
|
pu16Start += (info.width - DEF_DOT_NUMBER);
|
|
}
|
|
}
|
|
else if (info.pixel_format == RTGRAPHIC_PIXEL_FORMAT_ARGB888)
|
|
{
|
|
uint32_t *pu32Start = (bDrawDirect == RT_TRUE) ? (uint32_t *)((uint32_t)info.framebuffer + (start_y) * info.pitch + (start_x * 4)) : (uint32_t *)info.framebuffer;
|
|
for (i = 0; i < DEF_DOT_NUMBER; i++)
|
|
{
|
|
for (j = 0; j < DEF_DOT_NUMBER; j++)
|
|
{
|
|
*pu32Start = 0xff00ff00; //Green, ARGB888
|
|
pu32Start++;
|
|
}
|
|
if (bDrawDirect)
|
|
pu32Start += (info.width - DEF_DOT_NUMBER);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//Not supported
|
|
return;
|
|
}
|
|
|
|
if (!bDrawDirect)
|
|
{
|
|
/* Region updating */
|
|
rect.x = start_x;
|
|
rect.y = start_y;
|
|
rect.width = DEF_DOT_NUMBER;
|
|
rect.height = DEF_DOT_NUMBER;
|
|
rt_device_control(lcd_device, RTGRAPHIC_CTRL_RECT_UPDATE, &rect);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// TODO
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
#if (DEF_CAL_POINT_NUM==3)
|
|
const S_COORDINATE_POINT sDispPoints[DEF_CAL_POINT_NUM] =
|
|
{
|
|
{BSP_LCD_WIDTH / 4, BSP_LCD_HEIGHT / 2},
|
|
{BSP_LCD_WIDTH - BSP_LCD_WIDTH / 4, BSP_LCD_HEIGHT / 4},
|
|
{BSP_LCD_WIDTH / 2, BSP_LCD_HEIGHT - BSP_LCD_HEIGHT / 4}
|
|
};
|
|
#elif (DEF_CAL_POINT_NUM==5)
|
|
const static S_COORDINATE_POINT sDispPoints[DEF_CAL_POINT_NUM] =
|
|
{
|
|
#define DEF_CUT_PIECES 8
|
|
{BSP_LCD_WIDTH / DEF_CUT_PIECES, BSP_LCD_HEIGHT / DEF_CUT_PIECES},
|
|
{BSP_LCD_WIDTH - BSP_LCD_WIDTH / DEF_CUT_PIECES, BSP_LCD_HEIGHT / DEF_CUT_PIECES},
|
|
{BSP_LCD_WIDTH - BSP_LCD_WIDTH / DEF_CUT_PIECES, BSP_LCD_HEIGHT - BSP_LCD_HEIGHT / DEF_CUT_PIECES},
|
|
{BSP_LCD_WIDTH / DEF_CUT_PIECES, BSP_LCD_HEIGHT - BSP_LCD_HEIGHT / DEF_CUT_PIECES},
|
|
|
|
{BSP_LCD_WIDTH / 2, BSP_LCD_HEIGHT / 2}
|
|
};
|
|
#endif
|
|
|
|
static int nu_adc_touch_readfile(void)
|
|
{
|
|
int fd;
|
|
|
|
S_CALIBRATION_MATRIX sCalMat;
|
|
|
|
if ((fd = open(PATH_CALIBRATION_FILE, O_RDONLY, 0)) < 0)
|
|
{
|
|
goto exit_nu_adc_touch_readfile;
|
|
}
|
|
else if (read(fd, &sCalMat, sizeof(S_CALIBRATION_MATRIX)) == sizeof(S_CALIBRATION_MATRIX))
|
|
{
|
|
rt_kprintf("[%s] %s\n", __func__, PATH_CALIBRATION_FILE);
|
|
}
|
|
|
|
close(fd);
|
|
|
|
nu_adc_touch_update_calmat(&sCalMat);
|
|
|
|
return 0;
|
|
|
|
exit_nu_adc_touch_readfile:
|
|
|
|
return -1;
|
|
}
|
|
|
|
static int nu_adc_touch_writefile(void *buf, int buf_len)
|
|
{
|
|
int fd;
|
|
|
|
if ((fd = open(PATH_CALIBRATION_FILE, O_WRONLY | O_CREAT, 0)) < 0)
|
|
{
|
|
goto exit_nu_adc_touch_writefile;
|
|
}
|
|
else if (write(fd, buf, buf_len) == buf_len)
|
|
{
|
|
rt_kprintf("[%s] %s\n", __func__, PATH_CALIBRATION_FILE);
|
|
}
|
|
|
|
close(fd);
|
|
|
|
return 0;
|
|
|
|
exit_nu_adc_touch_writefile:
|
|
|
|
return -1;
|
|
}
|
|
|
|
static void nu_touch_do_calibration(rt_device_t pdev)
|
|
{
|
|
int i;
|
|
rt_err_t result;
|
|
|
|
S_CALIBRATION_MATRIX sCalMat;
|
|
S_COORDINATE_POINT sADCPoints[DEF_CAL_POINT_NUM];
|
|
|
|
lcd_device = rt_device_find("lcd");
|
|
if (!lcd_device)
|
|
{
|
|
rt_kprintf("Not supported graphics ops\n");
|
|
return;
|
|
}
|
|
|
|
result = rt_device_control(lcd_device, RTGRAPHIC_CTRL_GET_INFO, &info);
|
|
if (result != RT_EOK)
|
|
{
|
|
rt_kprintf("error!");
|
|
return;
|
|
}
|
|
|
|
result = rt_device_open(lcd_device, 0);
|
|
if (result != RT_EOK)
|
|
{
|
|
rt_kprintf("opened?");
|
|
}
|
|
|
|
rt_device_control(lcd_device, RTGRAPHIC_CTRL_PAN_DISPLAY, info.framebuffer);
|
|
rt_device_control(lcd_device, RTGRAPHIC_CTRL_POWERON, RT_NULL);
|
|
|
|
for (i = 0; i < DEF_CAL_POINT_NUM; i++)
|
|
{
|
|
struct rt_touch_data sTouchPoint;
|
|
int count = 0;
|
|
|
|
lcd_cleanscreen();
|
|
|
|
/* Drain RX queue before doing calibrate. */
|
|
while (adc_request_point(pdev, &sTouchPoint) == RT_EOK);
|
|
|
|
rt_thread_mdelay(100);
|
|
|
|
/* Ready to calibrate */
|
|
nu_draw_bots(sDispPoints[i].x, sDispPoints[i].y);
|
|
|
|
#define DEF_MAX_GET_POINT_NUM 5
|
|
|
|
sADCPoints[i].x = 0;
|
|
sADCPoints[i].y = 0;
|
|
|
|
while (count < DEF_MAX_GET_POINT_NUM)
|
|
{
|
|
if (adc_request_point(pdev, &sTouchPoint) == RT_EOK)
|
|
{
|
|
sADCPoints[i].x += (int32_t)sTouchPoint.x_coordinate;
|
|
sADCPoints[i].y += (int32_t)sTouchPoint.y_coordinate;
|
|
rt_kprintf("[%d %d] - Disp:[%d, %d] -> ADC:[%d, %d]\n", i, count, sDispPoints[i].x, sDispPoints[i].y, sADCPoints[i].x, sADCPoints[i].y);
|
|
count++;
|
|
}
|
|
}
|
|
|
|
sADCPoints[i].x = (int32_t)((float)sADCPoints[i].x / DEF_MAX_GET_POINT_NUM);
|
|
sADCPoints[i].y = (int32_t)((float)sADCPoints[i].y / DEF_MAX_GET_POINT_NUM);
|
|
rt_kprintf("[%d] - Disp:[%d, %d], ADC:[%d, %d]\n", i, sDispPoints[i].x, sDispPoints[i].y, sADCPoints[i].x, sADCPoints[i].y);
|
|
|
|
rt_thread_mdelay(300);
|
|
}
|
|
|
|
lcd_cleanscreen();
|
|
|
|
/* Get calibration matrix. */
|
|
if (nu_adc_cal_mat_get(&sDispPoints[0], &sADCPoints[0], &sCalMat) == 0)
|
|
{
|
|
/* Finally, update calibration matrix to drivers. */
|
|
nu_adc_touch_update_calmat(&sCalMat);
|
|
|
|
nu_adc_touch_writefile(&sCalMat, sizeof(sCalMat));
|
|
|
|
for (i = 0; i < DEF_CAL_POINT_NUM; i++)
|
|
{
|
|
rt_kprintf("[%d] - Disp:[%d, %d], ADC:[%d, %d]\n", i, sDispPoints[i].x, sDispPoints[i].y, sADCPoints[i].x, sADCPoints[i].y);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
rt_kprintf("Failed to calibrate.\n");
|
|
}
|
|
|
|
rt_device_control(lcd_device, RTGRAPHIC_CTRL_POWEROFF, RT_NULL);
|
|
rt_device_close(lcd_device);
|
|
|
|
return;
|
|
}
|
|
|
|
static void adc_touch_entry(void *parameter)
|
|
{
|
|
struct rt_touch_data touch_point;
|
|
|
|
rt_err_t result;
|
|
rt_device_t pdev;
|
|
int max_range;
|
|
|
|
adc_touch_sem = rt_sem_create("adc_touch_sem", 0, RT_IPC_FLAG_FIFO);
|
|
RT_ASSERT(adc_touch_sem != RT_NULL);
|
|
|
|
pdev = rt_device_find("adc_touch");
|
|
if (!pdev)
|
|
{
|
|
rt_kprintf("Not found\n");
|
|
return ;
|
|
}
|
|
|
|
if (rt_memcmp((void *)&g_sCalMat, (void *)&g_sCalZero, sizeof(S_CALIBRATION_MATRIX)) != 0)
|
|
g_u32Calibrated = 1;
|
|
|
|
nu_adc_touch_readfile();
|
|
|
|
result = rt_device_open(pdev, RT_DEVICE_FLAG_INT_RX);
|
|
RT_ASSERT(result == RT_EOK);
|
|
|
|
result = rt_device_set_rx_indicate(pdev, adc_touch_rx_callback);
|
|
RT_ASSERT(result == RT_EOK);
|
|
|
|
max_range = BSP_LCD_WIDTH;
|
|
result = rt_device_control(pdev, RT_TOUCH_CTRL_SET_X_RANGE, (void *)&max_range);
|
|
RT_ASSERT(result == RT_EOK);
|
|
|
|
max_range = BSP_LCD_HEIGHT;
|
|
result = rt_device_control(pdev, RT_TOUCH_CTRL_SET_Y_RANGE, (void *)&max_range);
|
|
RT_ASSERT(result == RT_EOK);
|
|
|
|
result = rt_device_control(pdev, RT_TOUCH_CTRL_POWER_ON, RT_NULL);
|
|
RT_ASSERT(result == RT_EOK);
|
|
|
|
while (adc_touch_worker_run)
|
|
{
|
|
if (!g_u32Calibrated)
|
|
{
|
|
rt_kprintf("Start ADC touching calibration.\n");
|
|
nu_touch_do_calibration(pdev);
|
|
rt_kprintf("Stop ADC touching calibration.\n");
|
|
continue;
|
|
}
|
|
|
|
if (adc_request_point(pdev, &touch_point) == RT_EOK)
|
|
{
|
|
if (touch_point.event == RT_TOUCH_EVENT_DOWN
|
|
|| touch_point.event == RT_TOUCH_EVENT_UP
|
|
|| touch_point.event == RT_TOUCH_EVENT_MOVE)
|
|
{
|
|
nu_touch_inputevent_cb(touch_point.x_coordinate, touch_point.y_coordinate, touch_point.event);
|
|
|
|
rt_kprintf("x=%d y=%d event=%s%s%s\n",
|
|
touch_point.x_coordinate,
|
|
touch_point.y_coordinate,
|
|
(touch_point.event == RT_TOUCH_EVENT_DOWN) ? "DOWN" : "",
|
|
(touch_point.event == RT_TOUCH_EVENT_UP) ? "UP" : "",
|
|
(touch_point.event == RT_TOUCH_EVENT_MOVE) ? "MOVE" : "");
|
|
}
|
|
}
|
|
}
|
|
|
|
result = rt_device_control(pdev, RT_TOUCH_CTRL_POWER_OFF, RT_NULL);
|
|
RT_ASSERT(result == RT_EOK);
|
|
|
|
result = rt_device_close(pdev);
|
|
RT_ASSERT(result == RT_EOK);
|
|
}
|
|
|
|
|
|
/* Support "nu_touch_start" command line in msh mode */
|
|
static rt_err_t nu_touch_start(int argc, char **argv)
|
|
{
|
|
if (adc_touch_thread == RT_NULL)
|
|
{
|
|
adc_touch_thread = rt_thread_create("adc_touch_thread",
|
|
adc_touch_entry,
|
|
RT_NULL,
|
|
2048,
|
|
5,
|
|
5);
|
|
adc_touch_worker_run = 1;
|
|
if (adc_touch_thread != RT_NULL)
|
|
rt_thread_startup(adc_touch_thread);
|
|
}
|
|
return 0;
|
|
}
|
|
MSH_CMD_EXPORT(nu_touch_start, e.g: start adc touch);
|
|
|
|
/* Support "nu_touch_stop" command line in msh mode */
|
|
static rt_err_t nu_touch_stop(int argc, char **argv)
|
|
{
|
|
adc_touch_worker_run = 0;
|
|
adc_touch_thread = RT_NULL;
|
|
return 0;
|
|
}
|
|
MSH_CMD_EXPORT(nu_touch_stop, e.g: stop adc touch);
|
|
|
|
static int nu_touch_autostart(void)
|
|
{
|
|
return nu_touch_start(0, RT_NULL);
|
|
}
|
|
INIT_APP_EXPORT(nu_touch_autostart);
|
|
|
|
static rt_err_t nu_touch_calibration(int argc, char **argv)
|
|
{
|
|
/* Clean calibration matrix data for getting raw adc value. */
|
|
nu_adc_touch_reset_calmat();
|
|
|
|
return 0;
|
|
}
|
|
MSH_CMD_EXPORT(nu_touch_calibration, for adc touch);
|
|
|
|
#endif //#if defined(NU_PKG_USING_ADC_TOUCH)
|