GithubHelp home page GithubHelp logo

How to using xpt2046CalibData? about lv_drv HOT 3 OPEN

SinglWolf avatar SinglWolf commented on August 21, 2024
How to using xpt2046CalibData?

from lv_drv.

Comments (3)

Boldie avatar Boldie commented on August 21, 2024 1

I no longer use a 9 point calibration, 4 are enough for my kind of display. The placement is easy, just move them as far from each other as possible, so a point near to the corners of the screen will work best for it. Otherwise the algorithm starts with extrapolating which may result in some weird results.

From the library, you have to set it to raw mode on start:

  xpt2046_setRawMode(true);

Then you have to show the 4 points on the screen and gather the coordinates from the driver and finally let the driver calculate the calibration.

  xpt2046_setRawMode(false);
  CalibPoint points[4];
  for (int i = 0; i < 4; ++i) {
    points[i].raw.x = pointRaw[i].x;
    points[i].raw.y = pointRaw[i].y;
    points[i].screen.x = pointScreen[i].x;
    points[i].screen.y = pointScreen[i].y;
  }

  if (xpt2046_calculateCalibration(points, 4)) {
    sprintf(buf, "New calibration was set.\nPlease reboot.");
  } else {
    sprintf(buf, "Error while calibration.\nPlease reboot and retry.");
  }

Maybe you can adapt this code to your use case:

/**
 * @file tpcal.c
 *
 * TOUCHPAD CALIBRATION
 * ---------------------
 *
 * This application creates a GUI and instruct the user
 * to click the four corners to get data for touchpad calibration.
 *
 * - You display driver should have two functions: `xxx_read` and `xxx_set_cal_data`.
 * - At first run run the touchpad is not calibrated therefore your `xxx_read` function should provide raw data.
 * - When the user touched all four corners you should call the `xxx_set_cal_data` function in
 * ` TP_CAL_STATE_WAIT_LEAVE` state. As arguments you should pass `point[0]`, `point[1]`, `point[2]` and `point[3]`
 *   which are the coordinates read on corner pressing.
 * - `xxx_set_cal_data` should mark the display as calibrated, save the raw coordinates
 *    and use them in the upcoming calls of `xxx_read` to adjust the coordinates.
 * - A simple equation to adjust the coordinates: x_cal = ((x_act - x1_saved) * lcd_hor_res) / (x2_saved - x1_saved);
 *      - x_cal: the calibrated X coordinate
 *      - x_act: the currently measured X coordinate
 *      - x1_saved, x2_saved: The raw X coordinates saved as calibration data
 */

/*********************
 *      INCLUDES
 *********************/
#include "tpcal.h"

#include "esp_log.h"

#include "GUI.h"
#include "lvgl/lvgl.h"

#include "xpt2046.h"

#include <stdio.h>

/*********************
 *      DEFINES
 *********************/
#define CIRCLE_SIZE      20
#define CIRCLE_OFFSET    20
#define TP_MAX_VALUE     5000
#define TOUCH_NUMBER     3

/**********************
 *      TYPEDEFS
 **********************/
typedef enum {
    TP_CAL_STATE_INIT,
    TP_CAL_STATE_WAIT_TOP_LEFT,
    TP_CAL_STATE_WAIT_TOP_RIGHT,
    TP_CAL_STATE_WAIT_BOTTOM_RIGHT,
    TP_CAL_STATE_WAIT_BOTTOM_LEFT,
    TP_CAL_STATE_WAIT_LEAVE,
    TP_CAL_STATE_READY,
} tp_cal_state_t;

/**********************
 *  STATIC PROTOTYPES
 **********************/
static void get_avr_value(lv_point_t * p);
static void btn_event_cb(lv_obj_t * scr, lv_event_t event);

/**********************
 *  STATIC VARIABLES
 **********************/
static lv_point_t pointRaw[4]; /*Calibration points: [0]: top-left; [1]: top-right, [2]: bottom-right, [3]: bottom-left */
static lv_point_t pointScreen[4]; /*Calibration points: [0]: top-left; [1]: top-right, [2]: bottom-right, [3]: bottom-left */
static lv_point_t avr[TOUCH_NUMBER]; /*Storage point to calculate average*/

static tp_cal_state_t state;
static lv_obj_t * prev_scr;
static lv_obj_t * big_btn;
static lv_obj_t * label_main;
static lv_obj_t * circ_area;

static const char* TAG = "tpcal";

/**********************
 *      MACROS
 **********************/

/**********************
 *   GLOBAL FUNCTIONS
 **********************/

/**
 * Create a touch pad calibration screen
 */
void tpcal_create(void)
{
  GUI::lock_guard lg( GUI::getInstance().getMutex() );

  state = TP_CAL_STATE_INIT;

  prev_scr = lv_disp_get_scr_act(NULL);

  lv_obj_t * scr = lv_obj_create(NULL, NULL);
  lv_obj_set_size(scr, TP_MAX_VALUE, TP_MAX_VALUE);
  lv_disp_load_scr(scr);

  /*Create a big transparent button screen to receive clicks*/
  big_btn = lv_btn_create(lv_disp_get_scr_act(NULL), NULL);
  lv_obj_set_size(big_btn, TP_MAX_VALUE, TP_MAX_VALUE);
  // lv_btn_set_style(big_btn, LV_BTN_STYLE_REL, &lv_style_transp);
  // lv_btn_set_style(big_btn, LV_BTN_STYLE_PR, &lv_style_transp);
  lv_obj_set_event_cb(big_btn, btn_event_cb);
  lv_btn_set_layout(big_btn, LV_LAYOUT_OFF);

  label_main = lv_label_create(lv_disp_get_scr_act(NULL), NULL);
  char buf[64];
  sprintf(buf, "Click the circle in\n"
          "upper left-hand corner\n"
          "%u left",
          TOUCH_NUMBER);
  lv_label_set_text(label_main, buf);
  lv_label_set_align(label_main, LV_LABEL_ALIGN_CENTER);

  lv_coord_t hres = lv_disp_get_hor_res(NULL);
  lv_coord_t vres = lv_disp_get_ver_res(NULL);

  lv_obj_set_pos(label_main, (hres - lv_obj_get_width(label_main)) / 2,
                 (vres - lv_obj_get_height(label_main)) / 2);

  // static lv_style_t style_circ;
  // lv_style_copy(&style_circ, &lv_style_pretty_color);
  // style_circ.body.radius = LV_RADIUS_CIRCLE;

  circ_area = lv_obj_create(lv_disp_get_scr_act(NULL), NULL);
  lv_obj_set_size(circ_area, CIRCLE_SIZE, CIRCLE_SIZE);
  // lv_obj_set_style(circ_area, &style_circ);
  lv_obj_set_click(circ_area, false);

#if LV_USE_ANIMATION
  lv_anim_t a;
  lv_anim_init(&a);

  a.var = circ_area;
  a.start = hres / 2;
  a.end = CIRCLE_OFFSET;
  a.exec_cb = (lv_anim_exec_xcb_t) lv_obj_set_x;
  a.path.user_data = nullptr;
  a.path.cb = lv_anim_path_linear;
  a.ready_cb = NULL;
  a.act_time = -500;
  a.time = 200;
  a.playback_time = 0;
  a.playback_delay = 0;
  a.repeat_cnt = 0;
  a.repeat_delay = 0;
  lv_anim_start(&a);

  a.start = vres / 2;
  a.end = CIRCLE_OFFSET;
  a.exec_cb = (lv_anim_exec_xcb_t) lv_obj_set_y;
  a.ready_cb = NULL;
  a.time = 200;
  lv_anim_start(&a);
#else
  lv_obj_set_pos(circ_area, CIRCLE_OFFSET, CIRCLE_OFFSET);
#endif
  pointScreen[0].x = CIRCLE_OFFSET;
  pointScreen[0].y = CIRCLE_OFFSET;

  state = TP_CAL_STATE_WAIT_TOP_LEFT;
  xpt2046_setRawMode(true);
}

/**********************
 *   STATIC FUNCTIONS
 **********************/

static void get_avr_value(lv_point_t * p)
{
  int32_t x_sum = 0;
  int32_t y_sum = 0;
  uint8_t i = 0;
  for (; i < TOUCH_NUMBER; i++) {
    x_sum += avr[i].x;
    y_sum += avr[i].y;
  }
  p->x = x_sum / TOUCH_NUMBER;
  p->y = y_sum / TOUCH_NUMBER;
}

static void btn_event_cb(lv_obj_t * scr, lv_event_t event)
{
  (void) scr; /*Unused*/

  // Maybe this is not needed, because call will come from lv task itself,
  // but sure is sure.
  GUI::lock_guard lg( GUI::getInstance().getMutex() );

  if (event != LV_EVENT_CLICKED)
    return;

  lv_disp_t * disp = lv_obj_get_disp(prev_scr);
  lv_coord_t hres = lv_disp_get_hor_res(disp);
  lv_coord_t vres = lv_disp_get_ver_res(disp);

  static uint8_t touch_nb = TOUCH_NUMBER;

  if (state == TP_CAL_STATE_WAIT_TOP_LEFT) {
    char buf[64];
    touch_nb--;
    lv_indev_t * indev = lv_indev_get_act();
    lv_indev_get_point(indev, &avr[touch_nb]);

    if (!touch_nb) {
      touch_nb = TOUCH_NUMBER;
      get_avr_value(&pointRaw[0]);
      sprintf(buf, "x: %d\ny: %d", pointRaw[0].x, pointRaw[0].y);
      lv_obj_t * label_coord = lv_label_create(lv_disp_get_scr_act(disp), NULL);
      lv_label_set_text(label_coord, buf);
      sprintf(buf, "Click the circle in\n"
              "upper right-hand corner\n"
              " %u Left",
              TOUCH_NUMBER);
#if LV_USE_ANIMATION
      lv_anim_t a;
      lv_anim_init(&a);

      a.var = circ_area;
      a.start = CIRCLE_OFFSET;
      a.end = hres - CIRCLE_SIZE - CIRCLE_OFFSET;
      a.exec_cb = (lv_anim_exec_xcb_t) lv_obj_set_x;
      a.path.user_data = nullptr;
      a.path.cb = lv_anim_path_linear;
      a.ready_cb = NULL;
      a.act_time = 0;
      a.time = 200;
      a.playback_time = 0;
      a.playback_delay = 0;
      a.repeat_cnt = 0;
      a.repeat_delay = 0;
      lv_anim_start(&a);

      a.start = CIRCLE_OFFSET;
      a.end = CIRCLE_OFFSET;
      a.exec_cb = (lv_anim_exec_xcb_t) lv_obj_set_y;
      a.ready_cb = NULL;
      a.time = 200;
      lv_anim_start(&a);
#else
      lv_obj_set_pos(circ_area, LV_HOR_RES - CIRCLE_SIZE - CIRCLE_OFFSET, CIRCLE_OFFSET);
#endif
      pointScreen[1].x = LV_HOR_RES - CIRCLE_OFFSET;
      pointScreen[1].y = CIRCLE_OFFSET;

      state = TP_CAL_STATE_WAIT_TOP_RIGHT;
    } else {
      sprintf(buf, "Click the circle in\n"
              "upper left-hand corner\n"
              " %u Left",
              touch_nb);
    }
    lv_label_set_text(label_main, buf);
    lv_obj_set_pos(label_main, (hres - lv_obj_get_width(label_main)) / 2,
                   (vres - lv_obj_get_height(label_main)) / 2);

  } else if (state == TP_CAL_STATE_WAIT_TOP_RIGHT) {
    char buf[64];
    touch_nb--;
    lv_indev_t * indev = lv_indev_get_act();
    lv_indev_get_point(indev, &avr[touch_nb]);

    if (!touch_nb) {
      touch_nb = TOUCH_NUMBER;
      get_avr_value(&pointRaw[1]);
      sprintf(buf, "x: %d\ny: %d", pointRaw[1].x, pointRaw[1].y);
      lv_obj_t * label_coord = lv_label_create(lv_disp_get_scr_act(disp), NULL);
      lv_label_set_text(label_coord, buf);
      lv_obj_set_pos(label_coord, hres - lv_obj_get_width(label_coord), 0);
      sprintf(buf, "Click the circle in\n"
              "lower right-hand corner\n"
              " %u Left",
              TOUCH_NUMBER);
#if LV_USE_ANIMATION
      lv_anim_t a;
      lv_anim_init(&a);

      a.var = circ_area;
      a.start = hres - CIRCLE_SIZE - CIRCLE_OFFSET;
      a.end = hres - CIRCLE_SIZE - CIRCLE_OFFSET;
      a.exec_cb = (lv_anim_exec_xcb_t) lv_obj_set_x;
      a.path.user_data = nullptr;
      a.path.cb = lv_anim_path_linear;
      a.ready_cb = NULL;
      a.act_time = 0;
      a.time = 200;
      a.playback_time = 0;
      a.playback_delay = 0;
      a.repeat_cnt = 0;
      a.repeat_delay = 0;
      lv_anim_start(&a);

      a.start = CIRCLE_OFFSET;
      a.end = vres - CIRCLE_SIZE - CIRCLE_OFFSET;
      a.exec_cb = (lv_anim_exec_xcb_t) lv_obj_set_y;
      a.ready_cb = NULL;
      a.time = 200;
      lv_anim_start(&a);
#else
      lv_obj_set_pos(circ_area, hres - CIRCLE_SIZE - CIRCLE_OFFSET, vres - CIRCLE_SIZE - CIRCLE_OFFSET);
#endif
      pointScreen[2].x = hres - CIRCLE_OFFSET;
      pointScreen[2].y = vres - CIRCLE_OFFSET;

      state = TP_CAL_STATE_WAIT_BOTTOM_RIGHT;
    } else {
      sprintf(buf, "Click the circle in\n"
              "upper right-hand corner\n"
              " %u Left",
              touch_nb);
    }
    lv_label_set_text(label_main, buf);
    lv_obj_set_pos(label_main, (hres - lv_obj_get_width(label_main)) / 2,
                   (vres - lv_obj_get_height(label_main)) / 2);

  } else if (state == TP_CAL_STATE_WAIT_BOTTOM_RIGHT) {
    char buf[64];
    touch_nb--;
    lv_indev_t * indev = lv_indev_get_act();
    lv_indev_get_point(indev, &avr[touch_nb]);

    if (!touch_nb) {
      touch_nb = TOUCH_NUMBER;
      get_avr_value(&pointRaw[2]);
      sprintf(buf, "x: %d\ny: %d", pointRaw[2].x, pointRaw[2].y);
      lv_obj_t * label_coord = lv_label_create(scr, NULL);
      lv_label_set_text(label_coord, buf);
      sprintf(buf, "Click the circle in\n"
              "lower left-hand corner\n"
              " %u Left",
              TOUCH_NUMBER);
      lv_obj_set_pos(label_coord, hres - lv_obj_get_width(label_coord),
                     vres - lv_obj_get_height(label_coord));
#if LV_USE_ANIMATION
      lv_anim_t a;
      lv_anim_init(&a);

      a.var = circ_area;
      a.start = hres - CIRCLE_SIZE - CIRCLE_OFFSET;
      a.end = CIRCLE_OFFSET;
      a.exec_cb = (lv_anim_exec_xcb_t) lv_obj_set_x;
      a.path.user_data = nullptr;
      a.path.cb = lv_anim_path_linear;
      a.ready_cb = NULL;
      a.act_time = 0;
      a.time = 200;
      a.playback_time = 0;
      a.playback_delay = 0;
      a.repeat_cnt = 0;
      a.repeat_delay = 0;
      lv_anim_start(&a);

      a.start = vres - CIRCLE_SIZE - CIRCLE_OFFSET;
      a.end = vres - CIRCLE_SIZE - CIRCLE_OFFSET;
      a.exec_cb = (lv_anim_exec_xcb_t) lv_obj_set_y;
      a.ready_cb = NULL;
      a.time = 200;
      lv_anim_start(&a);
#else
      lv_obj_set_pos(circ_area, CIRCLE_OFFSET, LV_VER_RES - CIRCLE_SIZE - CIRCLE_OFFSET);
#endif
      pointScreen[3].x = CIRCLE_OFFSET;
      pointScreen[3].y = LV_VER_RES - CIRCLE_OFFSET;

      state = TP_CAL_STATE_WAIT_BOTTOM_LEFT;
    } else {
      sprintf(buf, "Click the circle in\n"
              "lower right-hand corner\n"
              " %u Left",
              touch_nb);
    }
    lv_label_set_text(label_main, buf);
    lv_obj_set_pos(label_main, (hres - lv_obj_get_width(label_main)) / 2,
                   (vres - lv_obj_get_height(label_main)) / 2);
  } else if (state == TP_CAL_STATE_WAIT_BOTTOM_LEFT) {
    char buf[64];
    touch_nb--;
    lv_indev_t * indev = lv_indev_get_act();
    lv_indev_get_point(indev, &avr[touch_nb]);

    if (!touch_nb) {
      touch_nb = TOUCH_NUMBER;
      get_avr_value(&pointRaw[3]);
      sprintf(buf, "x: %d\ny: %d", pointRaw[3].x, pointRaw[3].y);
      lv_obj_t * label_coord = lv_label_create(scr, NULL);
      lv_label_set_text(label_coord, buf);
      lv_obj_set_pos(label_coord, 0, vres - lv_obj_get_height(label_coord));
      lv_obj_del(circ_area);

      // Make calibration now ...
      for (int i = 0; i < 4; ++i) {
        ESP_LOGI(TAG, "P[%i]: Raw(%d,%d), Screen(%d, %d)", i, pointRaw[i].x,
                 pointRaw[i].y, pointScreen[i].x, pointScreen[i].y);
      }

      xpt2046_setRawMode(false);
      CalibPoint points[4];
      for (int i = 0; i < 4; ++i) {
        points[i].raw.x = pointRaw[i].x;
        points[i].raw.y = pointRaw[i].y;
        points[i].screen.x = pointScreen[i].x;
        points[i].screen.y = pointScreen[i].y;
      }

      if (xpt2046_calculateCalibration(points, 4)) {
        sprintf(buf, "New calibration was set.\nPlease reboot.");
      } else {
        sprintf(buf, "Error while calibration.\nPlease reboot and retry.");
      }

      state = TP_CAL_STATE_WAIT_LEAVE;
    } else {
      sprintf(buf, "Click the circle in\n"
              "lower left-hand corner\n"
              " %u Left",
              touch_nb);
    }
    lv_label_set_text(label_main, buf);
    lv_obj_set_pos(label_main, (hres - lv_obj_get_width(label_main)) / 2,
                   (vres - lv_obj_get_height(label_main)) / 2);
  } else if (state == TP_CAL_STATE_WAIT_LEAVE) {
    // lv_disp_load_scr(prev_scr);
    state = TP_CAL_STATE_READY;

  } else if (state == TP_CAL_STATE_READY) {
  }
}

from lv_drv.

SinglWolf avatar SinglWolf commented on August 21, 2024

Thanks! This is what I was looking for! For which version of LVGL is this code? I'm asking because I can't start working on my project right now.

from lv_drv.

Boldie avatar Boldie commented on August 21, 2024

Good question, I do not know. This code was written to the current version of the lib 2 years ago.

from lv_drv.

Related Issues (1)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.