GR-PEACH Digital Signage sample for DISPLAY SHIELD. USB edition.

Dependencies:   GR-PEACH_video GraphicsFramework R_BSP USBHost mbed scan_folder

概要

USBメモリ内のJPEGファイルを読み出し、ディスプレイに表示します。
USBマウスを接続することで、次ファイル遷移、前ファイル遷移、マウスポインタ表示、ファイル表示時間変更などの操作ができます。
一定時間表示(時間の変更可)する、USBマウスを接続し左クリックを行う、または、USER_BUTTON0が押されると次のJPEGファイルを表示します。
JPEGファイルはディスプレイに出力する画像解像度にあわせて拡大/縮小されます。そのため、JPEGファイルはディスプレイ出力に近い解像度の方が元データに近い画質で表示されます。
JPEGファイルの表示順はディレクトリ解析順です。表示したい順にJPEGファイルを1ファイルずつUSBメモリに書き込んでください。

Information

micro SDカードを使用する場合はこちらのサンプルをご利用ください。
https://developer.mbed.org/users/dkato/code/GR-PEACH_Digital_Signage_display_shield/

表示可能なJPEGファイル

ファイル位置フォルダの深さはルートフォルダを含め8階層まで。
ファイル名半角英数字 (全角には対応していません)
拡張子".jpg" , ".JPG"
解像度制限上限1280 x 800 ピクセル。MCU単位のサイズ。
サイズ上限450Kbyte
フォーマットJPEGベースラインに準拠 (最適化、および、プログレッシブには対応していません)


構成

GR-PEACH、USBメモリ、USBマウス(マウス操作を行わない場合は不要)、USB HUB(USBマウス使用時)、DISPLAY SHIELD、ディスプレイ、DVI-Dケーブル。
本サンプルを使用する際は、GR-PEACHのJP3、JP8、JP9、JP10、JP11をショートする必要があります。
Jumper位置についてはこちらを参照ください。
https://developer.mbed.org/teams/Renesas/wiki/Jumper-settings-of-GR-PEACH

/media/uploads/RyoheiHagimoto/usb.jpg

機能設定

下記のマクロを変更することで、一部機能を変更できます。

main.cpp

/**** User Selection *********/
#define WAIT_TIME                           (10000) /* wait time (ms) */
#define DISSOLVE_STEP_NUM                   (16)    /* minimum 1 */
#define SCROLL_STEP_NUM                     (8)     /* minimum 1 */
#define SCROLL_DIRECTION                    (-1)    /* Select 1(left to right) or -1(right to left) */
#define LCD_SIZE                            HD_720p /* Select SVGA, XGA, or HD_720p */
/*****************************/


WAIT_TIME一つのJPEGファイルを表示する時間を設定します。単位はmsです。
DISSOLVE_STEP_NUM時間経過によって表示が変わる際のDISSOLVEエフェクトの長さを設定します。設定可能な最小値は1です。
SCROLL_STEP_NUMUSER_BUTTON0によって表示が変わる際のSCROLLエフェクトの長さを設定します。設定可能な最小値は1です。
SCROLL_DIRECTIONUSER_BUTTON0によって表示が変わる際のSCROLLエフェクトのスクロール方向を設定します。1を設定すると右へスクロール、-1を設定すると左へスクロールします。
LCD_SIZEディスプレイに出力する画面解像度を設定します。SVGA(800 x 600)、XGA(1024 x 768)、HD_720p(1280 x 720)より選択できます。


マウス操作

USBマウスを接続することで、以下の操作が可能です。

操作動作
左クリック次のJPEGファイルを表示します。
右クリック一つ前のJPEGファイルを表示します。
センタークリック
(センターホイール押し込み)
マウスポインタ表示。マウスポインタ表示中は時間経過による次ファイル遷移は行いません。
センターホイールマウスポインタ表示中にセンターホイールを回転させると、JPEGファイルの表示する時間を変更できます。

一部使用できないUSBマウスがあります。使用可能なUSBマウスは下記サンプルで動作するデバイスのみです。
https://developer.mbed.org/handbook/USBHostMouse

GIMPを使ったJPEGベースラインに準拠 したJPEGファイルの作成例

このサンプルでは、JPEGベースラインに準拠したJPEGファイルのみ表示可能です。
表示できないJPEGファイルがある場合は以下の手順をお試しください。

  1. 画像編集ツールGIMPをインストールする
  2. GIMPで画像ファイルを開く
    1. 画像ファイル上で右クリック
    2. Edit with GIMPを選択
  3. 画像サイズを変更する
    1. 「画像」→「画像の拡大・縮小」を選んで、画像の拡大・縮小ダイアログをから変更する
  4. JPEG形式で保存
    1. 「ファイル」→「名前をつけてエクスポート」で保存ダイアログを表示
    2. 保存先フォルダを選択 (ファイルの拡張子は.jpg)
    3. 「エクスポート」をクリックし、エクスポートダイアログを表示
    4. 「+詳細設定」の「+」部分をクリックして詳細設定画面を表示
    5. 「最適化」と「プログレッシブ」のチェックを外す
    6. エクスポートボタンを押す (注意:出力サイズが450Kbyteを超える場合は、品質値を調整して下さい。)
Revision:
0:6627ec9d57e6
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Tue May 31 02:14:35 2016 +0000
@@ -0,0 +1,570 @@
+/*
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+ 
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+ 
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#include "mbed.h"
+#include "DisplayBace.h"
+#include "RGA.h"
+#include "rtos.h"
+#include "USBHostMSD.h"
+#include "USBHostMouse.h"
+#include "BinaryImage_RZ_A1H.h"
+#include "scan_folder.h"
+
+#define SVGA                                (0u)  /*  800x600@60  37.9kHz/60Hz */
+#define XGA                                 (1u)  /* 1024x768@60  48.4kHz/60Hz */
+#define HD_720p                             (2u)  /* 1280x720@60  45.0kHz/60Hz */
+
+/**** User Selection *********/
+#define WAIT_TIME                           (10000) /* wait time (ms) */
+#define DISSOLVE_STEP_NUM                   (16)    /* minimum 1 */
+#define SCROLL_STEP_NUM                     (8)     /* minimum 1 */
+#define SCROLL_DIRECTION                    (-1)    /* Select 1(left to right) or -1(right to left) */
+#define LCD_SIZE                            HD_720p /* Select SVGA, XGA, or HD_720p */
+/*****************************/
+
+#if (SCROLL_DIRECTION == -1)
+#define SCROLL_DIRECTION_NEXT               (-1)
+#define SCROLL_DIRECTION_PREV               (1)
+#else
+#define SCROLL_DIRECTION_NEXT               (1)
+#define SCROLL_DIRECTION_PREV               (-1)
+#endif
+
+/* LCD Parameter */
+#define LCD_INPUT_CLOCK                     (66.67)
+#if ( LCD_SIZE == SVGA )
+#define LCD_OUTPUT_CLOCK                    (40.0003)
+#define LCD_PIXEL_WIDTH                     (800u)
+#define LCD_PIXEL_HEIGHT                    (600u)
+#define LCD_H_BACK_PORCH                    (88u)
+#define LCD_H_FRONT_PORCH                   (40u)
+#define LCD_H_SYNC_WIDTH                    (128u)
+#define LCD_V_BACK_PORCH                    (23u)
+#define LCD_V_FRONT_PORCH                   (1u)
+#define LCD_V_SYNC_WIDTH                    (4u)
+#elif ( LCD_SIZE == XGA )
+#define LCD_OUTPUT_CLOCK                    (65.0002)
+#define LCD_PIXEL_WIDTH                     (1024u)
+#define LCD_PIXEL_HEIGHT                    (768u)
+#define LCD_H_BACK_PORCH                    (160u)
+#define LCD_H_FRONT_PORCH                   (24u)
+#define LCD_H_SYNC_WIDTH                    (136u)
+#define LCD_V_BACK_PORCH                    (29u)
+#define LCD_V_FRONT_PORCH                   (3u)
+#define LCD_V_SYNC_WIDTH                    (6u)
+#elif ( LCD_SIZE == HD_720p )
+#define LCD_OUTPUT_CLOCK                    (74.1800)
+#define LCD_PIXEL_WIDTH                     (1280u)
+#define LCD_PIXEL_HEIGHT                    (720u)
+#define LCD_H_BACK_PORCH                    (220u)
+#define LCD_H_FRONT_PORCH                   (70u)
+#define LCD_H_SYNC_WIDTH                    (80u)
+#define LCD_V_BACK_PORCH                    (20u)
+#define LCD_V_FRONT_PORCH                   (5u)
+#define LCD_V_SYNC_WIDTH                    (5u)
+#endif
+
+/* FRAME BUFFER Parameter */
+#define FRAME_BUFFER_BYTE_PER_PIXEL         (2)
+#define FRAME_BUFFER_STRIDE                 (((LCD_PIXEL_WIDTH * FRAME_BUFFER_BYTE_PER_PIXEL) + 31u) & ~31u)
+
+#define EVENT_NONE                          (0)
+#define EVENT_NEXT                          (1)
+#define EVENT_PREV                          (2)
+
+#define MAX_JPEG_SIZE                       (1024 * 450)
+#define MOUNT_NAME                          "usb"
+static const char_t * extension_tbl[] = {
+    ".jpg",
+    NULL
+};
+DigitalIn   button(USER_BUTTON0);
+I2C         i2c(I2C_SDA, I2C_SCL);
+DisplayBase Display;
+Canvas2D_ContextClass canvas2d;
+
+#if defined(__ICCARM__)
+#pragma data_alignment=32
+static uint8_t user_frame_buffer[FRAME_BUFFER_STRIDE * LCD_PIXEL_HEIGHT];
+static uint8_t user_frame_buffer2[FRAME_BUFFER_STRIDE * LCD_PIXEL_HEIGHT];
+#pragma data_alignment=8
+static uint8_t JpegBuffer[MAX_JPEG_SIZE]@ ".mirrorram";  //8 bytes aligned!;
+#pragma data_alignment=4
+#else
+static uint8_t user_frame_buffer[FRAME_BUFFER_STRIDE * LCD_PIXEL_HEIGHT]__attribute((aligned(32)));  /* 32 bytes aligned */
+static uint8_t user_frame_buffer2[FRAME_BUFFER_STRIDE * LCD_PIXEL_HEIGHT]__attribute((aligned(32))); /* 32 bytes aligned */
+static uint8_t JpegBuffer[MAX_JPEG_SIZE]__attribute((section("NC_BSS"),aligned(8)));  //8 bytes aligned!;
+#endif
+static frame_buffer_t frame_buffer_info;
+static volatile int32_t vsync_count = 0;
+static ScanFolder scan_foler;
+static int  mouse_pos_x = 0;
+static int  mouse_pos_y = 0;
+static bool mouse_pos = false;
+static bool mouse_view = false;
+static bool mouse_disp_time = false;
+static int event_req = EVENT_NONE;
+static int disp_time = WAIT_TIME;
+
+static void IntCallbackFunc_Vsync(DisplayBase::int_type_t int_type) {
+    /* Interrupt callback function for Vsync interruption */
+    if (vsync_count > 0) {
+        vsync_count--;
+    }
+}
+
+static void Wait_Vsync(const int32_t wait_count) {
+    /* Wait for the specified number of times Vsync occurs */
+    vsync_count = wait_count;
+    while (vsync_count > 0) {
+        /* Do nothing */
+    }
+}
+
+static void Init_LCD_Display(uint8_t* disp_buf) {
+    /* Create DisplayBase object */
+    DisplayBase::graphics_error_t error;
+    DisplayBase::rect_t rect;
+    DisplayBase::lcd_config_t lcd_config;
+    PinName lcd_pin[28] = {
+        /* data pin */
+        P11_15, P11_14, P11_13, P11_12, P5_7, P5_6, P5_5, P5_4, P5_3, P5_2, P5_1, P5_0,
+        P4_7, P4_6, P4_5, P4_4, P10_12, P10_13, P10_14, P10_15, P3_15, P3_14, P3_13,
+        P3_12, P3_11, P3_10, P3_9, P3_8
+    };
+
+    Thread::wait(100);
+
+    lcd_config.lcd_type             = DisplayBase::LCD_TYPE_PARALLEL_RGB;
+    lcd_config.intputClock          = LCD_INPUT_CLOCK;
+    lcd_config.outputClock          = LCD_OUTPUT_CLOCK;
+    lcd_config.lcd_outformat        = DisplayBase::LCD_OUTFORMAT_RGB888;
+    lcd_config.lcd_edge             = DisplayBase::EDGE_RISING;
+    lcd_config.h_toatal_period      = (LCD_PIXEL_WIDTH  + LCD_H_FRONT_PORCH + LCD_H_BACK_PORCH + LCD_H_SYNC_WIDTH);
+    lcd_config.v_toatal_period      = (LCD_PIXEL_HEIGHT + LCD_V_FRONT_PORCH + LCD_V_BACK_PORCH + LCD_V_SYNC_WIDTH);
+
+    lcd_config.h_disp_widht         = LCD_PIXEL_WIDTH;
+    lcd_config.v_disp_widht         = LCD_PIXEL_HEIGHT;
+    lcd_config.h_back_porch         = LCD_H_BACK_PORCH;
+    lcd_config.v_back_porch         = LCD_V_BACK_PORCH;
+
+    lcd_config.h_sync_port          = DisplayBase::LCD_TCON_PIN_1;
+    lcd_config.h_sync_port_polarity = DisplayBase::SIG_POL_NOT_INVERTED;
+    lcd_config.h_sync_width         = LCD_H_SYNC_WIDTH;
+
+    lcd_config.v_sync_port          = DisplayBase::LCD_TCON_PIN_2;
+    lcd_config.v_sync_port_polarity = DisplayBase::SIG_POL_NOT_INVERTED;
+    lcd_config.v_sync_width         = LCD_V_SYNC_WIDTH;
+
+    lcd_config.de_port              = DisplayBase::LCD_TCON_PIN_0;
+    lcd_config.de_port_polarity     = DisplayBase::SIG_POL_NOT_INVERTED;
+
+    /* Graphics initialization process */
+    error = Display.Graphics_init(&lcd_config);
+    if (error != DisplayBase::GRAPHICS_OK) {
+        printf("Line %d, error %d\n", __LINE__, error);
+        while (1);
+    }
+
+    /* Interrupt callback function setting (Vsync signal output from scaler 0) */
+    error = Display.Graphics_Irq_Handler_Set(DisplayBase::INT_TYPE_S0_LO_VSYNC, 0, IntCallbackFunc_Vsync);
+    if (error != DisplayBase::GRAPHICS_OK) {
+        printf("Line %d, error %d\n", __LINE__, error);
+        while (1);
+    }
+
+    Display.Graphics_Lcd_Port_Init(lcd_pin, 28);
+    rect.vs = 0;
+    rect.vw = LCD_PIXEL_HEIGHT;
+    rect.hs = 0;
+    rect.hw = LCD_PIXEL_WIDTH;
+
+    Display.Graphics_Read_Setting(
+        DisplayBase::GRAPHICS_LAYER_0,
+        (void *)disp_buf,
+        FRAME_BUFFER_STRIDE,
+        DisplayBase::GRAPHICS_FORMAT_RGB565,
+        DisplayBase::WR_RD_WRSWA_32_16BIT,
+        &rect
+    );
+}
+
+static void Start_LCD_Display(void) {
+    Display.Graphics_Start(DisplayBase::GRAPHICS_LAYER_0);
+}
+
+static void Update_LCD_Display(frame_buffer_t * frmbuf_info) {
+    Display.Graphics_Read_Change(DisplayBase::GRAPHICS_LAYER_0,
+     (void *)frmbuf_info->buffer_address[frmbuf_info->draw_buffer_index]);
+    Wait_Vsync(1);
+}
+
+static void Swap_FrameBuffer(frame_buffer_t * frmbuf_info) {
+    if (frmbuf_info->draw_buffer_index == 1) {
+        frmbuf_info->draw_buffer_index = 0;
+    } else {
+        frmbuf_info->draw_buffer_index = 1;
+    }
+}
+
+static void draw_mouse_pos(void) {
+    /* mouse pos */
+    if (mouse_pos != false) {
+        mouse_view = true;
+        /* Complete drawing */
+        R_GRAPHICS_Finish(canvas2d.c_LanguageContext);
+        /* Draw a image */
+        canvas2d.drawImage(mousu_pos_File, mouse_pos_x, mouse_pos_y);
+        R_OSPL_CLEAR_ERROR();
+
+        if (mouse_disp_time != false) {
+            const graphics_image_t * p_num;
+
+            /* Draw a image */
+            canvas2d.drawImage(disp_xsec_File, mouse_pos_x + 30, mouse_pos_y);
+            R_OSPL_CLEAR_ERROR();
+            switch (disp_time) {
+                case 0:       p_num = number0_File;    break;
+                case 1000:    p_num = number1_File;    break;
+                case 2000:    p_num = number2_File;    break;
+                case 3000:    p_num = number3_File;    break;
+                case 4000:    p_num = number4_File;    break;
+                case 5000:    p_num = number5_File;    break;
+                case 6000:    p_num = number6_File;    break;
+                case 7000:    p_num = number7_File;    break;
+                case 8000:    p_num = number8_File;    break;
+                case 9000:    p_num = number9_File;    break;
+                case 10000:   p_num = number10_File;   break;
+                case 11000:   p_num = number11_File;   break;
+                case 12000:   p_num = number12_File;   break;
+                case 13000:   p_num = number13_File;   break;
+                case 14000:   p_num = number14_File;   break;
+                case 15000:   p_num = number15_File;   break;
+                default:      p_num = NULL;            break;
+            }
+            if (p_num != NULL) {
+                /* Draw a image */
+                canvas2d.drawImage(p_num, mouse_pos_x + 136, mouse_pos_y);
+                R_OSPL_CLEAR_ERROR();
+            }
+        }
+    }
+}
+
+static void draw_image(frame_buffer_t* frmbuf_info, const graphics_image_t* image_new) {
+    Swap_FrameBuffer(frmbuf_info);
+    /* Clear */
+    canvas2d.clearRect(0, 0, frmbuf_info->width, frmbuf_info->height);
+    /* Draw a image */
+    canvas2d.globalAlpha = 1.0f;
+    canvas2d.drawImage((const graphics_image_t*)image_new, 0, 0, frmbuf_info->width, frmbuf_info->height);
+    R_OSPL_CLEAR_ERROR();
+    /* mouse pos */
+    draw_mouse_pos();
+    /* Complete drawing */
+    R_GRAPHICS_Finish(canvas2d.c_LanguageContext);
+    Update_LCD_Display(frmbuf_info);
+}
+
+static void draw_image_scroll(frame_buffer_t* frmbuf_info, const graphics_image_t* image_last,
+                              const graphics_image_t* image_new, float32_t scroll, int ditection) {
+    Swap_FrameBuffer(frmbuf_info);
+    /* Clear */
+    canvas2d.clearRect(0, 0, frmbuf_info->width, frmbuf_info->height);
+    /* Draw a image */
+    canvas2d.globalAlpha = 1.0f;
+    canvas2d.drawImage((const graphics_image_t*)image_last,
+                       (int_t)(frmbuf_info->width * scroll) * ditection, 0,
+                       frmbuf_info->width, frmbuf_info->height);
+    R_OSPL_CLEAR_ERROR();
+    canvas2d.globalAlpha = 1.0f;
+    canvas2d.drawImage((const graphics_image_t*)image_new,
+                       ((int_t)(frmbuf_info->width * scroll) - frmbuf_info->width) * ditection, 0,
+                       frmbuf_info->width, frmbuf_info->height);
+    R_OSPL_CLEAR_ERROR();
+    /* mouse pos */
+    draw_mouse_pos();
+    /* Complete drawing */
+    R_GRAPHICS_Finish(canvas2d.c_LanguageContext);
+    Update_LCD_Display(frmbuf_info);
+}
+
+static void draw_image_dissolve(frame_buffer_t* frmbuf_info, const graphics_image_t* image_last,
+                                const graphics_image_t* image_new, float32_t alpha) {
+    Swap_FrameBuffer(frmbuf_info);
+    /* Clear */
+    canvas2d.clearRect(0, 0, frmbuf_info->width, frmbuf_info->height);
+    /* Draw a image */
+    canvas2d.globalAlpha = 1.0f - alpha;
+    canvas2d.drawImage((const graphics_image_t*)image_last, 0, 0, frmbuf_info->width, frmbuf_info->height);
+    R_OSPL_CLEAR_ERROR();
+    canvas2d.globalAlpha = alpha;
+    canvas2d.drawImage((const graphics_image_t*)image_new, 0, 0, frmbuf_info->width, frmbuf_info->height);
+    R_OSPL_CLEAR_ERROR();
+    /* mouse pos */
+    draw_mouse_pos();
+    /* Complete drawing */
+    R_GRAPHICS_Finish(canvas2d.c_LanguageContext);
+    Update_LCD_Display(frmbuf_info);
+}
+
+static void next_file(uint32_t * file_id, uint32_t total_track) {
+    if (file_id == NULL) {
+        // do nothing
+    } else if (*file_id < (total_track - 1)) {
+        *file_id += 1;
+    } else {
+        *file_id = 0;
+    }
+}
+
+static void prev_file(uint32_t * file_id, uint32_t total_track) {
+    if (file_id == NULL) {
+        // do nothing
+    } else if (*file_id != 0) {
+        *file_id -= 1;
+    } else {
+        *file_id = total_track - 1;
+    }
+}
+
+void onMouseEvent(uint8_t buttons, int8_t x, int8_t y, int8_t z) {
+    int wk_pos;
+    int wk_disp_time;
+    static uint8_t last_buttons = 0;
+
+//    printf("buttons: %d, x: %d, y: %d, z: %d\r\n", buttons, x, y, z);
+
+    wk_pos = mouse_pos_x;
+    wk_pos += x;
+    if (wk_pos < 0) {
+        wk_pos = 0;
+    }
+    if (wk_pos > (LCD_PIXEL_WIDTH - 10)) {
+        wk_pos = LCD_PIXEL_WIDTH - 10;
+    }
+    mouse_pos_x = wk_pos;
+
+    wk_pos = mouse_pos_y;
+    wk_pos += y;
+    if (wk_pos < 0) {
+        wk_pos = 0;
+    }
+    if (wk_pos > (LCD_PIXEL_HEIGHT - 10)) {
+        wk_pos = (LCD_PIXEL_HEIGHT - 10);
+    }
+    mouse_pos_y = wk_pos;
+
+    // left
+    if (((buttons & 0x01) == 0) && ((last_buttons & 0x01) != 0)) {
+        if (mouse_disp_time != false) {
+            mouse_disp_time = false;
+        } else {
+            event_req = EVENT_NEXT;
+        }
+    }
+
+    // rigth
+    if (((buttons & 0x02) == 0) && ((last_buttons & 0x02) != 0)) {
+        if (mouse_disp_time != false) {
+            mouse_disp_time = false;
+        } else {
+            event_req = EVENT_PREV;
+        }
+    }
+
+    if (((buttons & 0x04) != 0) && ((last_buttons & 0x04) == 0)) {
+        mouse_pos = !mouse_pos;
+        if (mouse_pos == false) {
+            mouse_disp_time = false;
+        }
+    }
+
+    if (z != 0) {
+        if (mouse_pos != false) {
+            wk_disp_time = disp_time;
+            if (z > 0) {
+                wk_disp_time += 1000;
+                if (wk_disp_time > 15000) {
+                    wk_disp_time = 15000;
+                }
+            } else {
+                wk_disp_time -= 1000;
+                if (wk_disp_time < 0) {
+                    wk_disp_time = 0;
+                }
+            }
+            disp_time = wk_disp_time;
+            mouse_disp_time = true;
+        }
+    }
+
+    last_buttons = buttons;
+
+//    printf("pos_x: %d, pos_y: %d\n", mouse_pos_x, mouse_pos_y);
+}
+
+void mouse_task(void const *) {
+    USBHostMouse mouse;
+
+    while(1) {
+        // try to connect a USB mouse
+        while(!mouse.connect())
+            Thread::wait(500);
+
+        // when connected, attach handler called on mouse event
+        mouse.attachEvent(onMouseEvent);
+        
+        // wait until the mouse is disconnected
+        while(mouse.connected())
+            Thread::wait(500);
+    }
+}
+
+int main(void) {
+    errnum_t err;
+    Canvas2D_ContextConfigClass config;
+
+    memset(user_frame_buffer, 0, sizeof(user_frame_buffer));
+    memset(user_frame_buffer2, 0, sizeof(user_frame_buffer2));
+    frame_buffer_info.buffer_address[0] = user_frame_buffer;
+    frame_buffer_info.buffer_address[1] = user_frame_buffer2;
+    frame_buffer_info.buffer_count      = 2;
+    frame_buffer_info.show_buffer_index = 0;
+    frame_buffer_info.draw_buffer_index = 0;
+    frame_buffer_info.width             = LCD_PIXEL_WIDTH;
+    frame_buffer_info.byte_per_pixel    = FRAME_BUFFER_BYTE_PER_PIXEL;
+    frame_buffer_info.stride            = LCD_PIXEL_WIDTH * FRAME_BUFFER_BYTE_PER_PIXEL;
+    frame_buffer_info.height            = LCD_PIXEL_HEIGHT;
+    frame_buffer_info.pixel_format      = PIXEL_FORMAT_RGB565;
+    Init_LCD_Display(frame_buffer_info.buffer_address[0]);
+
+    config.frame_buffer = &frame_buffer_info;
+    canvas2d = R_RGA_New_Canvas2D_ContextClass(config);
+    err = R_OSPL_GetErrNum();
+    if (err != 0) {
+        printf("Line %d, error %d\n", __LINE__, err);
+        while (1);
+    }
+    Start_LCD_Display();
+
+    Thread::wait(100);  // wait sd mount
+    Thread mouseTask(mouse_task, NULL, osPriorityNormal, 1024);
+
+    USBHostMSD msd(MOUNT_NAME);
+    uint32_t now_file_id = 0xffffffff;
+    uint32_t req_file_id = 0;
+    int jpeg_toggle = 0;
+    size_t ret;
+    uint8_t * p_JpegBuffer[2];
+    int wait_time = 0;
+    uint32_t total_file = 0;
+
+    p_JpegBuffer[0] = JpegBuffer;
+    p_JpegBuffer[1] = new uint8_t[MAX_JPEG_SIZE];
+
+    while (1) {
+        bool key_press = false;
+
+        /* USB connect check */
+        while (!msd.connected()) {
+            if (!msd.connect()) {
+                Thread::wait(500);
+            } else {
+                scan_foler.scan("/"MOUNT_NAME, extension_tbl);
+                total_file = scan_foler.getTotalFile();
+            }
+        }
+
+        switch (event_req) {
+            case EVENT_NEXT:
+                next_file(&req_file_id, total_file);
+                key_press = true;
+                break;
+            case EVENT_PREV:
+                prev_file(&req_file_id, total_file);
+                key_press = true;
+                break;
+            case EVENT_NONE:
+            default:
+                if (button == 0) {
+                    next_file(&req_file_id, total_file);
+                    key_press = true;
+                } else if ((wait_time >= disp_time) && (mouse_pos == false)) {
+                    next_file(&req_file_id, total_file);
+                    wait_time = 0;
+                } else {
+                    // Do Nothing
+                }
+                break;
+        }
+        event_req = EVENT_NONE;
+
+        if (now_file_id != req_file_id) {
+            FILE * fp = scan_foler.open(req_file_id);
+            ret = fread(p_JpegBuffer[jpeg_toggle], sizeof(char), MAX_JPEG_SIZE, fp);
+            scan_foler.close(fp);
+            if (ret < MAX_JPEG_SIZE) {
+                if (now_file_id == 0xffffffff) {
+                    // Effect NONE
+                    draw_image(&frame_buffer_info, (const graphics_image_t*)p_JpegBuffer[jpeg_toggle]);
+                } else if (key_press == false) {
+                    // Effect DISSOLVE
+                    for (int i = 1; i <= DISSOLVE_STEP_NUM; i++) {
+                        draw_image_dissolve(&frame_buffer_info,
+                                            (const graphics_image_t*)p_JpegBuffer[!jpeg_toggle],
+                                            (const graphics_image_t*)p_JpegBuffer[jpeg_toggle],
+                                            (float32_t)i / (float32_t)DISSOLVE_STEP_NUM);
+                    }
+                } else {
+                    // Effect SCROLL
+                    int direction;
+                    if ((req_file_id == 0) && (now_file_id == (total_file - 1))) {
+                        direction = SCROLL_DIRECTION_NEXT;
+                    } else if ((now_file_id == 0) && (req_file_id == (total_file - 1))) {
+                        direction = SCROLL_DIRECTION_PREV;
+                    } else if (req_file_id > now_file_id) {
+                        direction = SCROLL_DIRECTION_NEXT;
+                    } else {
+                        direction = SCROLL_DIRECTION_PREV;
+                    }
+                    for (int i = 1; i <= SCROLL_STEP_NUM; i++) {
+                        draw_image_scroll(&frame_buffer_info,
+                                          (const graphics_image_t*)p_JpegBuffer[!jpeg_toggle],
+                                          (const graphics_image_t*)p_JpegBuffer[jpeg_toggle],
+                                          (float32_t)i / (float32_t)SCROLL_STEP_NUM, direction);
+                    }
+                }
+                jpeg_toggle = !jpeg_toggle;
+            }
+            now_file_id = req_file_id;
+            wait_time = 0;
+        } else {
+            if ((mouse_pos != false) || (mouse_view != false)) {
+                mouse_view = false;
+                draw_image(&frame_buffer_info, (const graphics_image_t*)p_JpegBuffer[!jpeg_toggle]);
+                wait_time = 0;
+            } else {
+                Thread::wait(100);
+                wait_time += 100;
+            }
+        }
+    }
+}