#include "mbed.h"
#include "DisplayBace.h"
#include "rtos.h"
#include "LCD_shield_config_4_3inch.h"
#include "RGA.h"
#include "BinaryImage_RZ_A1H.h"
#include "recognition_proc.h"

/*! Frame buffer stride: Frame buffer stride should be set to a multiple of 32 or 128
    in accordance with the frame buffer burst transfer mode. */
/* TOUCH BUFFER Parameter GRAPHICS_LAYER_2 */
#define TOUCH_BUFFER_BYTE_PER_PIXEL     (4u)
#define TOUCH_BUFFER_STRIDE             (((LCD_PIXEL_WIDTH * TOUCH_BUFFER_BYTE_PER_PIXEL) + 31u) & ~31u)

/* Disp mode */
#define DISP_MODE_NORMAL                (0)
#define DISP_MODE_SETTING_1             (1)
#define DISP_MODE_SETTING_2             (2)
#define DISP_MODE_SETTING_3             (3)

/* Setting range  */
#define THRESHOLD_MIN                   (1)
#define THRESHOLD_MAX                   (1000)
#define SIZE_RANGE_MIN                  (20)
#define SIZE_RANGE_MAX                  (1000)
#define POSE_MIN                        (0)
#define POSE_MAX                        (2)
#define ANGLE_MIN                       (0)
#define ANGLE_MAX                       (1)

/* slide bar */
#define POS_SLIDE_BAR_X                 (185)
#define SLIDE_BAR_LENGTH                (200)
#define POS_PROGRESS_0_X                (POS_SLIDE_BAR_X + 15)

/* func_code */
#define TOUCH_KEY_CLOSE                 (1)
#define TOUCH_KEY_SETTING_1             (2)
#define TOUCH_KEY_SETTING_2             (3)
#define TOUCH_KEY_SETTING_3             (4)
#define TOUCH_KEY_REGISTRATION          (5)
#define TOUCH_KEY_THRESHOLD_BODY        (6)
#define TOUCH_KEY_THRESHOLD_FACE        (7)
#define TOUCH_KEY_THRESHOLD_RECO        (8)
#define TOUCH_KEY_RANGE_BODY_MIN        (9)
#define TOUCH_KEY_RANGE_BODY_MAX        (10)
#define TOUCH_KEY_RANGE_FACE_MIN        (11)
#define TOUCH_KEY_RANGE_FACE_MAX        (12)
#define TOUCH_KEY_FACE_POSE             (13)
#define TOUCH_KEY_FACE_ANGLE            (14)
#define TOUCH_KEY_BODY_DETECTION        (15)
#define TOUCH_KEY_FACE_DETECTION        (16)
#define TOUCH_KEY_AGE_ESTIMATION        (17)
#define TOUCH_KEY_GENDER_ESTIMATION     (18)
#define TOUCH_KEY_EXPRESSION_ESTIMATION (19)
#define TOUCH_KEY_SETTING_LAST          (20)
#define TOUCH_KEY_RESET_SETTING         (21)

typedef struct {
    uint32_t pic_pos_x;             /* X position of the key picture. */
    uint32_t pic_pos_y;             /* Y position of the key picture. */
    uint32_t pic_width;             /* Width of the key picture. */
    uint32_t pic_height;            /* Height of the key picture. */
    uint32_t func_code;             /* func code of the key picture. */
} key_pic_info_t;

static const key_pic_info_t touch_key_tbl_normal[] = {
    /*                X      Y    Width  Height   Func code                      */
    {                330,    10,   140,    36,    TOUCH_KEY_BODY_DETECTION        },
    {                330,    56,   140,    36,    TOUCH_KEY_FACE_DETECTION        },
    {                330,   102,   140,    36,    TOUCH_KEY_AGE_ESTIMATION        },
    {                330,   148,   140,    36,    TOUCH_KEY_GENDER_ESTIMATION     },
    {                330,   194,   140,    36,    TOUCH_KEY_EXPRESSION_ESTIMATION },
    {                448,   240,    32,    32,    TOUCH_KEY_SETTING_LAST          },
    {                  0,     0,   320,   240,    TOUCH_KEY_REGISTRATION          },
    {                  0,     0,     0,     0,    0                               } /* table end */
};

static const key_pic_info_t touch_key_tbl_setting_1[] = {
    /*                X      Y    Width  Height   Func code                      */
    {                127,   220,    80,    34,    TOUCH_KEY_RESET_SETTING         },
    {                273,   220,    80,    34,    TOUCH_KEY_CLOSE                 },
    {                 21,    20,   146,    34,    TOUCH_KEY_SETTING_1             },
    {                167,    20,   146,    34,    TOUCH_KEY_SETTING_2             },
    {                313,    20,   146,    34,    TOUCH_KEY_SETTING_3             },
    { POS_SLIDE_BAR_X-20,  80-8,   281,    30,    TOUCH_KEY_THRESHOLD_BODY        },
    { POS_SLIDE_BAR_X-20, 120-8,   281,    30,    TOUCH_KEY_THRESHOLD_FACE        },
    { POS_SLIDE_BAR_X-20, 160-8,   281,    30,    TOUCH_KEY_THRESHOLD_RECO        },
    {                  0,     0,     0,     0,    0                               } /* table end */
};

static const key_pic_info_t touch_key_tbl_setting_2[] = {
    /*                X      Y    Width  Height   Func code                      */
    {                127,   220,    80,    34,    TOUCH_KEY_RESET_SETTING         },
    {                273,   220,    80,    34,    TOUCH_KEY_CLOSE                 },
    {                 21,    20,   146,    34,    TOUCH_KEY_SETTING_1             },
    {                167,    20,   146,    34,    TOUCH_KEY_SETTING_2             },
    {                313,    20,   146,    34,    TOUCH_KEY_SETTING_3             },
    { POS_SLIDE_BAR_X-20,  80-8,   281,    30,    TOUCH_KEY_RANGE_BODY_MIN        },
    { POS_SLIDE_BAR_X-20, 110-8,   281,    30,    TOUCH_KEY_RANGE_BODY_MAX        },
    { POS_SLIDE_BAR_X-20, 150-8,   281,    30,    TOUCH_KEY_RANGE_FACE_MIN        },
    { POS_SLIDE_BAR_X-20, 180-8,   281,    30,    TOUCH_KEY_RANGE_FACE_MAX        },
    {                  0,     0,     0,     0,    0                               } /* table end */
};

static const key_pic_info_t touch_key_tbl_setting_3[] = {
    /*                X      Y    Width  Height   Func code                      */
    {                127,   220,    80,    34,    TOUCH_KEY_RESET_SETTING         },
    {                273,   220,    80,    34,    TOUCH_KEY_CLOSE                 },
    {                 21,    20,   146,    34,    TOUCH_KEY_SETTING_1             },
    {                167,    20,   146,    34,    TOUCH_KEY_SETTING_2             },
    {                313,    20,   146,    34,    TOUCH_KEY_SETTING_3             },
    { POS_SLIDE_BAR_X-20,  80-8,   281,    30,    TOUCH_KEY_FACE_POSE             },
    { POS_SLIDE_BAR_X-20, 120-8,   281,    30,    TOUCH_KEY_FACE_ANGLE            },
    {                  0,     0,     0,     0,    0                               } /* table end */
};

static const key_pic_info_t * p_touch_key_tbl[] = {
    touch_key_tbl_normal,           /* DISP_MODE_NORMAL    */
    touch_key_tbl_setting_1,        /* DISP_MODE_SETTING_1 */
    touch_key_tbl_setting_2,        /* DISP_MODE_SETTING_2 */
    touch_key_tbl_setting_3,        /* DISP_MODE_SETTING_3 */
    NULL
};

static TouckKey_LCD_shield touch(P4_0, P2_13, I2C_SDA, I2C_SCL);
static Semaphore   sem_touch_int(0);

#if defined(__ICCARM__)
/* 32 bytes aligned */
#pragma data_alignment=32
static uint8_t user_frame_buffer_touch0[TOUCH_BUFFER_STRIDE * LCD_PIXEL_HEIGHT];
#pragma data_alignment=32
static uint8_t user_frame_buffer_touch1[TOUCH_BUFFER_STRIDE * LCD_PIXEL_HEIGHT];
#else
/* 32 bytes aligned */
static uint8_t user_frame_buffer_touch0[TOUCH_BUFFER_STRIDE * LCD_PIXEL_HEIGHT]__attribute((aligned(32)));
static uint8_t user_frame_buffer_touch1[TOUCH_BUFFER_STRIDE * LCD_PIXEL_HEIGHT]__attribute((aligned(32)));
#endif

static volatile int32_t vsync_count = 0;
static recognition_setting_t * p_setting;
static int disp_mode;

/****** Touch panel ******/
static uint32_t Scan_Key(const key_pic_info_t * key_tbl, const uint32_t pos_x, const uint32_t pos_y) {
    uint32_t ret = 0;

    while (ret == 0) {
        if (key_tbl->func_code == 0) {
            break;
        }
        /* Check the range of the X position */
        if ((pos_x >= key_tbl->pic_pos_x) && (pos_x <= (key_tbl->pic_pos_x + key_tbl->pic_width))) {
            /* Check the range of the Y position */
            if ((pos_y >= key_tbl->pic_pos_y) && (pos_y <= (key_tbl->pic_pos_y + key_tbl->pic_height))) {
                /* Decide the func code. */
                ret = key_tbl->func_code;
            }
        }
        key_tbl++;
    }

    return ret;
}

static void draw_button(Canvas2D_ContextClass * p_canvas2d) {
    const graphics_image_t* p_wk;

    /* Draw background */
    p_canvas2d->drawImage(background, 320, 0);

    /* Draw "HUMAN BODY" button */
    if ((p_setting->execFlag & HVC_ACTIV_BODY_DETECTION) == 0) {
        p_wk = button_off;
    } else {
        p_wk = button_on;
    }
    p_canvas2d->drawImage(p_wk, 330, 10);
    p_canvas2d->drawImage(str_human_body, 330 + 19, 10 + 11);

    /* Draw "FACE" or "RECOGNITION" button */
    if ((p_setting->execFlag & HVC_ACTIV_FACE_RECOGNITION) == 0) {
        if ((p_setting->execFlag & HVC_ACTIV_FACE_DETECTION) == 0) {
            p_wk = button_off;
        } else {
            p_wk = button_on;
        }
        p_canvas2d->drawImage(p_wk, 330, 56);
        p_canvas2d->drawImage(str_face, 330 + 51, 56 + 11);
    } else {
        p_canvas2d->drawImage(button_on2, 330, 56);
        p_canvas2d->drawImage(str_recognition, 330 + 19, 56 + 11);
    }

    /* Draw "AGE" button */
    if ((p_setting->execFlag & HVC_ACTIV_FACE_DETECTION) == 0) {
        p_wk = button_inv;
    } else if ((p_setting->execFlag & HVC_ACTIV_AGE_ESTIMATION) == 0) {
        p_wk = button_off;
    } else {
        p_wk = button_on;
    }
    p_canvas2d->drawImage(p_wk, 330, 102);
    p_canvas2d->drawImage(str_age, 330 + 54, 102 + 11);

    /* Draw "GENDER" button */
    if ((p_setting->execFlag & HVC_ACTIV_FACE_DETECTION) == 0) {
        p_wk = button_inv;
    } else if ((p_setting->execFlag & HVC_ACTIV_GENDER_ESTIMATION) == 0) {
        p_wk = button_off;
    } else {
        p_wk = button_on;
    }
    p_canvas2d->drawImage(p_wk, 330, 148);
    p_canvas2d->drawImage(str_gender, 330 + 39, 148 + 11);

    /* Draw "EXPRESSION" button */
    if ((p_setting->execFlag & HVC_ACTIV_FACE_DETECTION) == 0) {
        p_wk = button_inv;
    } else if ((p_setting->execFlag & HVC_ACTIV_EXPRESSION_ESTIMATION) == 0) {
        p_wk = button_off;
    } else {
        p_wk = button_on;
    }
    p_canvas2d->drawImage(p_wk, 330, 194);
    p_canvas2d->drawImage(str_expression, 330 + 23, 194 + 11);

    /* Draw setting icon */
    p_canvas2d->drawImage(icon_setting, LCD_PIXEL_WIDTH - 32, LCD_PIXEL_HEIGHT - 32);
}

static void draw_number(Canvas2D_ContextClass * p_canvas2d, int x, int y, int number) {
    int wk_num;
    bool disp_flg = false;
    const graphics_image_t * p_num_tbl[] = {
        char_0, char_1, char_2, char_3, char_4, char_5, char_6, char_7, char_8, char_9
    };

    wk_num = (number / 1000) % 10;
    if ((wk_num != 0) || (disp_flg != false)) {
        p_canvas2d->drawImage(p_num_tbl[wk_num], x + 9 * 0, y);
        R_OSPL_CLEAR_ERROR();
        disp_flg = true;
    }
    wk_num = (number / 100) % 10;
    if ((wk_num != 0) || (disp_flg != false)) {
        p_canvas2d->drawImage(p_num_tbl[wk_num], x + 9 * 1, y);
        R_OSPL_CLEAR_ERROR();
        disp_flg = true;
    }
    wk_num = (number / 10) % 10;
    if ((wk_num != 0) || (disp_flg != false)) {
        p_canvas2d->drawImage(p_num_tbl[wk_num], x + 9 * 2, y);
        R_OSPL_CLEAR_ERROR();
    }
    wk_num = number % 10;
    p_canvas2d->drawImage(p_num_tbl[wk_num], x + 9 * 3, y);
    R_OSPL_CLEAR_ERROR();
}

static void draw_slide_bar(Canvas2D_ContextClass * p_canvas2d, int y, INT32 data, int min, int max) {
    p_canvas2d->globalAlpha = 0.7f;
    p_canvas2d->fillStyle = "#D9C3E6";
    p_canvas2d->fillRect(POS_PROGRESS_0_X, y + 6, SLIDE_BAR_LENGTH + 10, 2);
    p_canvas2d->globalAlpha = 1.0f;
    p_canvas2d->drawImage(char_left, POS_SLIDE_BAR_X, y);
    p_canvas2d->drawImage(char_rigth, POS_PROGRESS_0_X + SLIDE_BAR_LENGTH + 10 + 1, y);
    p_canvas2d->fillStyle = "#5B9BD5";
    p_canvas2d->fillRect(POS_PROGRESS_0_X + (int)(SLIDE_BAR_LENGTH * ((float)(data - min) / (max - min))), y, 10, 14);
}

static void draw_setting_menu(Canvas2D_ContextClass * p_canvas2d) {
    if (disp_mode == DISP_MODE_NORMAL) {
        return;
    }

    p_canvas2d->globalAlpha = 0.95f;
    p_canvas2d->drawImage(background_setting, 0, 0);

    /* Tab */
    if (disp_mode == DISP_MODE_SETTING_1) {
        p_canvas2d->globalAlpha = 0.9f;
        p_canvas2d->fillStyle = "#5B9BD5";
        p_canvas2d->fillRect(21, 20, 146, 34);
        p_canvas2d->globalAlpha = 1.0f;
    } else {
        p_canvas2d->globalAlpha = 0.3f;
    }
    p_canvas2d->drawImage(str_threshold_value, 23, 30);

    if (disp_mode == DISP_MODE_SETTING_2) {
        p_canvas2d->globalAlpha = 0.9f;
        p_canvas2d->fillStyle = "#5B9BD5";
        p_canvas2d->fillRect(167, 20, 146, 34);
        p_canvas2d->globalAlpha = 1.0f;
    } else {
        p_canvas2d->globalAlpha = 0.3f;
    }
    p_canvas2d->drawImage(str_detection_size, 181, 30);

    if (disp_mode == DISP_MODE_SETTING_3) {
        p_canvas2d->globalAlpha = 0.9f;
        p_canvas2d->fillStyle = "#5B9BD5";
        p_canvas2d->fillRect(313, 20, 146, 34);
        p_canvas2d->globalAlpha = 1.0f;
    } else {
        p_canvas2d->globalAlpha = 0.3f;
    }
    p_canvas2d->drawImage(str_face, 342, 30);
    p_canvas2d->drawImage(str_angle, 383, 30);

    /* Setting */
    p_canvas2d->globalAlpha = 1.0f;
    if (disp_mode == DISP_MODE_SETTING_1) {
        p_canvas2d->drawImage(str_human_body, 30, 80);
        p_canvas2d->drawImage(str_face, 30, 120);
        p_canvas2d->drawImage(str_recognition, 30, 160);

        draw_slide_bar(p_canvas2d,  80, p_setting->threshold.bdThreshold, THRESHOLD_MIN, THRESHOLD_MAX);
        draw_slide_bar(p_canvas2d, 120, p_setting->threshold.dtThreshold, THRESHOLD_MIN, THRESHOLD_MAX);
        draw_slide_bar(p_canvas2d, 160, p_setting->threshold.rsThreshold, THRESHOLD_MIN, THRESHOLD_MAX);

        draw_number(p_canvas2d, 430,  80, p_setting->threshold.bdThreshold);
        draw_number(p_canvas2d, 430, 120, p_setting->threshold.dtThreshold);
        draw_number(p_canvas2d, 430, 160, p_setting->threshold.rsThreshold);
    } else if (disp_mode == DISP_MODE_SETTING_2) {
        p_canvas2d->drawImage(str_human_body, 30, 80);
        p_canvas2d->drawImage(str_min, 140, 80);
        p_canvas2d->drawImage(str_max, 140, 110);
        p_canvas2d->drawImage(str_face, 30, 150);
        p_canvas2d->drawImage(str_min, 140, 150);
        p_canvas2d->drawImage(str_max, 140, 180);

        draw_slide_bar(p_canvas2d,  80, p_setting->sizeRange.bdMinSize, SIZE_RANGE_MIN, SIZE_RANGE_MAX);
        draw_slide_bar(p_canvas2d, 110, p_setting->sizeRange.bdMaxSize, SIZE_RANGE_MIN, SIZE_RANGE_MAX);
        draw_slide_bar(p_canvas2d, 150, p_setting->sizeRange.dtMinSize, SIZE_RANGE_MIN, SIZE_RANGE_MAX);
        draw_slide_bar(p_canvas2d, 180, p_setting->sizeRange.dtMaxSize, SIZE_RANGE_MIN, SIZE_RANGE_MAX);

        draw_number(p_canvas2d, 430,  80, p_setting->sizeRange.bdMinSize);
        draw_number(p_canvas2d, 430, 110, p_setting->sizeRange.bdMaxSize);
        draw_number(p_canvas2d, 430, 150, p_setting->sizeRange.dtMinSize);
        draw_number(p_canvas2d, 430, 180, p_setting->sizeRange.dtMaxSize);
    } else {
        int wk_data;

        p_canvas2d->drawImage(str_yaw, 30, 80);
        p_canvas2d->drawImage(str_angle, 30 + 41, 80);
        p_canvas2d->drawImage(str_roll, 30, 120);
        p_canvas2d->drawImage(str_angle, 30 + 42, 120);

        if (p_setting->pose == 0) {
            wk_data = 30;
        } else if (p_setting->pose == 1) {
            wk_data = 60;
        } else {
            wk_data = 90;
        }
        draw_slide_bar(p_canvas2d,  80, p_setting->pose, POSE_MIN , POSE_MAX);
        p_canvas2d->drawImage(char_plus_minus, 426, 80);
        draw_number(p_canvas2d, 420,  80, wk_data); /* 30 60 90 */
        p_canvas2d->drawImage(char_angle, 457, 80);

        if (p_setting->angle == 0) {
            wk_data = 15;
        } else {
            wk_data = 45;
        }
        draw_slide_bar(p_canvas2d, 120, p_setting->angle, ANGLE_MIN, ANGLE_MAX);
        p_canvas2d->drawImage(char_plus_minus, 426, 120);
        draw_number(p_canvas2d, 420, 120, wk_data); /* 15 45 */
        p_canvas2d->drawImage(char_angle, 457, 120);
    }
    p_canvas2d->drawImage(str_reset, 144, 230);
    p_canvas2d->drawImage(str_close, 290, 230);
}

static void draw_touch_layer(DisplayBase * p_display, frame_buffer_t * frmbuf_info, Canvas2D_ContextClass * p_canvas2d) {
    while (vsync_count > 0) {
        Thread::wait(1);
    }

    /* Swap the frame buffer */
    if (frmbuf_info->draw_buffer_index == 1) {
        frmbuf_info->draw_buffer_index = 0;
    } else {
        frmbuf_info->draw_buffer_index = 1;
    }

    /* Clear */
    p_canvas2d->clearRect(0, 0, frmbuf_info->width, frmbuf_info->height);

    /* Draw button */
    draw_button(p_canvas2d);

    /* Draw setting menu */
    draw_setting_menu(p_canvas2d);

    /* Complete drawing */
    R_GRAPHICS_Finish(p_canvas2d->c_LanguageContext);
    p_display->Graphics_Read_Change(DisplayBase::GRAPHICS_LAYER_2,
     (void *)frmbuf_info->buffer_address[frmbuf_info->draw_buffer_index]);
    vsync_count = 1;
}

static void set_progress(int x, INT32 * p_data, int min, int max, bool * p_slide, int last_key) {
    int now_pos = POS_PROGRESS_0_X + (int)(SLIDE_BAR_LENGTH * (float)(*p_data - min) / (max - min));

    x -= 5;
    if ((last_key == 0) && (x > (now_pos - 10)) && (x < (now_pos + 20))) {
        *p_slide = true;
    }
    if (x < POS_PROGRESS_0_X) {
        x = POS_PROGRESS_0_X;
    }
    if (x > (POS_PROGRESS_0_X + SLIDE_BAR_LENGTH)) {
        x = (POS_PROGRESS_0_X + SLIDE_BAR_LENGTH);
    }
    if (*p_slide) {
        *p_data = ((float)(x - POS_PROGRESS_0_X) / (float)SLIDE_BAR_LENGTH * (float)(max - min)) + min;
    } else if ((x > now_pos) && (*p_data < max)) {
        *p_data += 1;
    } else if ((x < now_pos) && (*p_data > min)) {
        *p_data -= 1;
    } else {
        /* do nothing */
    }
}

static void init_touch_layer(DisplayBase * p_display, frame_buffer_t * frmbuf_info, Canvas2D_ContextClass * p_canvas2d) {
    errnum_t err;
    Canvas2D_ContextConfigClass config;
    DisplayBase::rect_t rect;

    /* The layer by which the buttons is drawn */
    memset(user_frame_buffer_touch0, 0, sizeof(user_frame_buffer_touch0));
    memset(user_frame_buffer_touch1, 0, sizeof(user_frame_buffer_touch1));
    frmbuf_info->buffer_address[0] = user_frame_buffer_touch0;
    frmbuf_info->buffer_address[1] = user_frame_buffer_touch1;
    frmbuf_info->buffer_count      = 2;
    frmbuf_info->show_buffer_index = 0;
    frmbuf_info->draw_buffer_index = 0;
    frmbuf_info->width             = LCD_PIXEL_WIDTH;
    frmbuf_info->byte_per_pixel    = TOUCH_BUFFER_BYTE_PER_PIXEL;
    frmbuf_info->stride            = TOUCH_BUFFER_STRIDE;
    frmbuf_info->height            = LCD_PIXEL_HEIGHT;
    frmbuf_info->pixel_format      = PIXEL_FORMAT_ARGB8888;

    rect.vs = 0;
    rect.vw = LCD_PIXEL_HEIGHT;
    rect.hs = 0;
    rect.hw = LCD_PIXEL_WIDTH;
    p_display->Graphics_Read_Setting(
        DisplayBase::GRAPHICS_LAYER_2,
        (void *)frmbuf_info->buffer_address[frmbuf_info->draw_buffer_index],
        TOUCH_BUFFER_STRIDE,
        DisplayBase::GRAPHICS_FORMAT_ARGB8888,
        DisplayBase::WR_RD_WRSWA_32BIT,
        &rect
    );
    p_display->Graphics_Start(DisplayBase::GRAPHICS_LAYER_2);

    /* Drawing buttons */
    config.frame_buffer = frmbuf_info;
    *p_canvas2d = R_RGA_New_Canvas2D_ContextClass(config);
    err = R_OSPL_GetErrNum();
    if (err != 0) {
        printf("Line %d, err %d\n", __LINE__, err);
        mbed_die();
    }
}

static void touch_int_callback(void) {
    sem_touch_int.release();
}

void touch_lcd_int(DisplayBase::int_type_t int_type) {
    /* Interrupt callback function for Vsync interruption */
    if (int_type == DisplayBase::INT_TYPE_S0_LO_VSYNC) {
        if (vsync_count > 0) {
            vsync_count--;
        }
    }
}

void touch_task(DisplayBase * p_display) {
    frame_buffer_t frame_buffer_info;
    Canvas2D_ContextClass canvas2d;
    TouchKey::touch_pos_t touch_pos[1];
    int touch_num = 0;
    int touch_num_last = 0;
    bool key_rep = false;
    int func_code;
    int func_code_last = 0;
    bool slide = false;
    Timer key_time;
    int wait_time;
    int last_setting_mode = DISP_MODE_SETTING_1;

    p_setting = GetRecognitionSettingPointer();
    disp_mode = DISP_MODE_NORMAL;

    /* Initializing Touch layer */
    init_touch_layer(p_display, &frame_buffer_info, &canvas2d);
    draw_touch_layer(p_display, &frame_buffer_info, &canvas2d);

    /* Callback setting */
    touch.SetCallback(&touch_int_callback);

    /* Reset touch IC */
    touch.Reset();

    key_time.reset();
    key_time.start();

    while (1) {
        /* Wait touch event */
        sem_touch_int.wait();

        /* Get touch coordinates */
        touch_num = touch.GetCoordinates(1, touch_pos);

        if (slide) {
            wait_time = 80;
        } else {
            wait_time = 250;
        }
        if ((key_time.read_ms() > wait_time) || (touch_num != touch_num_last)) {
            key_time.reset();
            key_time.start();
            if ((touch_num != 0) && ((touch_num_last == 0) || (key_rep == true))) {
                key_rep = false;
                func_code = Scan_Key(p_touch_key_tbl[disp_mode], touch_pos[0].x, touch_pos[0].y);
                if (slide) {
                    func_code = func_code_last;
                }
                if (func_code != 0) {
                    switch (func_code) {
                        case TOUCH_KEY_SETTING_LAST:
                            disp_mode = last_setting_mode;
                            break;
                        case TOUCH_KEY_CLOSE:
                            disp_mode = DISP_MODE_NORMAL;
                            SetSettingReq();
                            break;
                        case TOUCH_KEY_SETTING_1:
                            disp_mode = DISP_MODE_SETTING_1;
                            last_setting_mode = DISP_MODE_SETTING_1;
                            break;
                        case TOUCH_KEY_SETTING_2:
                            disp_mode = DISP_MODE_SETTING_2;
                            last_setting_mode = DISP_MODE_SETTING_2;
                            break;
                        case TOUCH_KEY_SETTING_3:
                            disp_mode = DISP_MODE_SETTING_3;
                            last_setting_mode = DISP_MODE_SETTING_3;
                            break;
                        case TOUCH_KEY_REGISTRATION:
                            if ((p_setting->execFlag & HVC_ACTIV_FACE_RECOGNITION) != 0) {
                                SetRegistrationrReq();
                            }
                            break;
                        case TOUCH_KEY_THRESHOLD_BODY:
                            set_progress(touch_pos[0].x, &p_setting->threshold.bdThreshold,
                                         THRESHOLD_MIN, THRESHOLD_MAX, &slide, touch_num_last);
                            key_rep = true;
                            break;
                        case TOUCH_KEY_THRESHOLD_FACE:
                            set_progress(touch_pos[0].x, &p_setting->threshold.dtThreshold,
                                         THRESHOLD_MIN, THRESHOLD_MAX, &slide, touch_num_last);
                            key_rep = true;
                            break;
                        case TOUCH_KEY_THRESHOLD_RECO:
                            set_progress(touch_pos[0].x, &p_setting->threshold.rsThreshold,
                                         THRESHOLD_MIN, THRESHOLD_MAX, &slide, touch_num_last);
                            key_rep = true;
                            break;
                        case TOUCH_KEY_RANGE_BODY_MIN:
                            set_progress(touch_pos[0].x, &p_setting->sizeRange.bdMinSize,
                                         SIZE_RANGE_MIN, SIZE_RANGE_MAX, &slide, touch_num_last);
                            if (p_setting->sizeRange.bdMinSize > p_setting->sizeRange.bdMaxSize) {
                                p_setting->sizeRange.bdMaxSize = p_setting->sizeRange.bdMinSize;
                            }
                            key_rep = true;
                            break;
                        case TOUCH_KEY_RANGE_BODY_MAX:
                            set_progress(touch_pos[0].x, &p_setting->sizeRange.bdMaxSize,
                                         SIZE_RANGE_MIN, SIZE_RANGE_MAX, &slide, touch_num_last);
                            if (p_setting->sizeRange.bdMaxSize < p_setting->sizeRange.bdMinSize) {
                                p_setting->sizeRange.bdMinSize = p_setting->sizeRange.bdMaxSize;
                            }
                            key_rep = true;
                            break;
                        case TOUCH_KEY_RANGE_FACE_MIN:
                            set_progress(touch_pos[0].x, &p_setting->sizeRange.dtMinSize,
                                         SIZE_RANGE_MIN, SIZE_RANGE_MAX, &slide, touch_num_last);
                            if (p_setting->sizeRange.dtMinSize > p_setting->sizeRange.dtMaxSize) {
                                p_setting->sizeRange.dtMaxSize = p_setting->sizeRange.dtMinSize;
                            }
                            key_rep = true;
                            break;
                        case TOUCH_KEY_RANGE_FACE_MAX:
                            set_progress(touch_pos[0].x, &p_setting->sizeRange.dtMaxSize,
                                         SIZE_RANGE_MIN, SIZE_RANGE_MAX, &slide, touch_num_last);
                            if (p_setting->sizeRange.dtMaxSize < p_setting->sizeRange.dtMinSize) {
                                p_setting->sizeRange.dtMinSize = p_setting->sizeRange.dtMaxSize;
                            }
                            key_rep = true;
                            break;
                        case TOUCH_KEY_FACE_POSE:
                            set_progress(touch_pos[0].x, &p_setting->pose,
                                         POSE_MIN, POSE_MAX, &slide, touch_num_last);
                            if (slide) {
                                key_rep = true;
                            }
                            break;
                        case TOUCH_KEY_FACE_ANGLE:
                            set_progress(touch_pos[0].x, &p_setting->angle,
                                         ANGLE_MIN, ANGLE_MAX, &slide, touch_num_last);
                            if (slide) {
                                key_rep = true;
                            }
                            break;
                        case TOUCH_KEY_BODY_DETECTION:
                            if ((p_setting->execFlag & HVC_ACTIV_BODY_DETECTION) != 0) {
                                p_setting->execFlag &= ~HVC_ACTIV_BODY_DETECTION;
                            } else {
                                p_setting->execFlag |= HVC_ACTIV_BODY_DETECTION;
                            }
                            break;
                        case TOUCH_KEY_FACE_DETECTION:
                            if ((p_setting->execFlag & HVC_ACTIV_FACE_DETECTION) == 0) {
                                p_setting->execFlag |= HVC_ACTIV_FACE_DETECTION;
                            } else if ((p_setting->execFlag & HVC_ACTIV_FACE_RECOGNITION) == 0) {
                                p_setting->execFlag |= HVC_ACTIV_FACE_RECOGNITION;
                            } else {
                                p_setting->execFlag &= ~(HVC_ACTIV_FACE_DETECTION | HVC_ACTIV_FACE_RECOGNITION);
                            }
                            break;
                        case TOUCH_KEY_AGE_ESTIMATION:
                            if ((p_setting->execFlag & HVC_ACTIV_FACE_DETECTION) == 0) {
                                /* do nothing */
                            } else if ((p_setting->execFlag & HVC_ACTIV_AGE_ESTIMATION) != 0) {
                                p_setting->execFlag &= ~HVC_ACTIV_AGE_ESTIMATION;
                            } else {
                                p_setting->execFlag |= HVC_ACTIV_AGE_ESTIMATION;
                            }
                            break;
                        case TOUCH_KEY_GENDER_ESTIMATION:
                            if ((p_setting->execFlag & HVC_ACTIV_FACE_DETECTION) == 0) {
                                /* do nothing */
                            } else if ((p_setting->execFlag & HVC_ACTIV_GENDER_ESTIMATION) != 0) {
                                p_setting->execFlag &= ~HVC_ACTIV_GENDER_ESTIMATION;
                            } else {
                                p_setting->execFlag |= HVC_ACTIV_GENDER_ESTIMATION;
                            }
                            break;
                        case TOUCH_KEY_EXPRESSION_ESTIMATION:
                            if ((p_setting->execFlag & HVC_ACTIV_FACE_DETECTION) == 0) {
                                /* do nothing */
                            } else if ((p_setting->execFlag & HVC_ACTIV_EXPRESSION_ESTIMATION) != 0) {
                                p_setting->execFlag &= ~HVC_ACTIV_EXPRESSION_ESTIMATION;
                            } else {
                                p_setting->execFlag |= HVC_ACTIV_EXPRESSION_ESTIMATION;
                            }
                            break;
                        case TOUCH_KEY_RESET_SETTING:
                            if (disp_mode == DISP_MODE_SETTING_1) {
                                p_setting->threshold.bdThreshold = BODY_THRESHOLD_DEFAULT;
                                p_setting->threshold.hdThreshold = HAND_THRESHOLD_DEFAULT;
                                p_setting->threshold.dtThreshold = FACE_THRESHOLD_DEFAULT;
                                p_setting->threshold.rsThreshold = REC_THRESHOLD_DEFAULT;
                            } else if (disp_mode == DISP_MODE_SETTING_2) {
                                p_setting->sizeRange.bdMinSize = BODY_SIZE_RANGE_MIN_DEFAULT;
                                p_setting->sizeRange.bdMaxSize = BODY_SIZE_RANGE_MAX_DEFAULT;
                                p_setting->sizeRange.hdMinSize = HAND_SIZE_RANGE_MIN_DEFAULT;
                                p_setting->sizeRange.hdMaxSize = HAND_SIZE_RANGE_MAX_DEFAULT;
                                p_setting->sizeRange.dtMinSize = FACE_SIZE_RANGE_MIN_DEFAULT;
                                p_setting->sizeRange.dtMaxSize = FACE_SIZE_RANGE_MAX_DEFAULT;
                            } else if (disp_mode == DISP_MODE_SETTING_3) {
                                p_setting->pose  = FACE_POSE_DEFAULT;
                                p_setting->angle = FACE_ANGLE_DEFAULT;
                            } else {
                                /* do nothing */
                            }
                            break;
                        default:
                            break;
                    }
                    draw_touch_layer(p_display, &frame_buffer_info, &canvas2d);
                }
                func_code_last = func_code;
            } else {
                slide = false;
            }
        }
        touch_num_last = touch_num;
    }
}
