M5Stack Core2でLVGLを使いたい

# 結論

- `lv_conf.h`を設定する。
    - https://docs.lvgl.io/master/get-started/platforms/arduino.html
- arduino向けのサンプルは`LVGL/examples/arduino/LVGL_Ardino/LVGL_Arduino.ino`にある。
- ディスプレイとタッチパネルの実装を行う必要がある。
    - ディスプレイの実装テンプレは`LVGL/examples/porting/lv_port_disp_template.{h,c}`にある。
    - 入力デバイスの実装テンプレは`LVGL/examples/porting/lv_port_indev_template.{h,c}`にある。

# 前提条件

- 使用するデバイスはM5Stack Core2
- 開発環境はPlatformIO (Windows10)
- 使用するライブラリは以下のふたつ
    - LovyanGFX
        - https://github.com/lovyan03/LovyanGFX
    - LVGL
        - https://lvgl.io/

# 実装結果

githubに置きました。LVGLのサンプルコード由来の部分はもとのMITライセンスに準拠します。
追加実装部分はPDにしますのでご自由にお使いいただけます。

https://github.com/hyaguchi947d/M5Core2LVGL

# 解説

M5Stack Core2のディスプレイを有効活用したい。
LVGLという組み込み向けのライブラリがあるため、これを試してみたが、
対応させるための手順がそこそこあり、またそのための情報が断片的であったため試した結果を記していく。

## 公式ドキュメントの読解

Arduino開発の際の手順は以下のページにある。

https://docs.lvgl.io/master/get-started/platforms/arduino.html

まずは`lv_conf.h`の作成を行う。

Arduino向けのサンプルはexamolesの下にあり、
`LVGL/examples/arduino/LVGL_Ardino/LVGL_Arduino.ino`
となる。

が、そのままでは動かない。
ディスプレイの設定と入力デバイスの実装が必要になる。

そのための設定は以下のページにある。

https://docs.lvgl.io/master/porting/index.html

## 実はテンプレートがある

よく読むと"Further Reading"にテンプレの場所が書いてある。
`LVGL/examples/porting`の下にいくつかファイルがある。
`lv_port_disp_template.{h,c}`がディスプレイ、
`lv_port_indev_template.{h,c}`が入力デバイスとなる。

## ディスプレイの実装

`MY_DISP_{HOR,VER}_RES`という定数が求められる箇所があるため宣言する。

`lv_port_disp_init()`の中で"Example for 1)"みたいな箇所があるが、
どれか一つだけにして残りはコメントアウトする。

`disp_init()`と`disp_flush()`が自分で書く部分。
LovyanGFXを使うと以下のように書ける。
(lcdは事前に宣言しておくこと)

```
/*Initialize your display and the required peripherals.*/
static void disp_init(void)
{
    /*You code here*/
    lcd.init();
    lcd.setBrightness(128);
    lcd.setColorDepth(24);
}

/*Flush the content of the internal buffer the specific area on the display
 *You can use DMA or any hardware acceleration to do this operation in the background but
 *'lv_disp_flush_ready()' has to be called when finished.*/
static void disp_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p)
{
    int32_t width = area->x2 - area->x1 + 1;
    int32_t height = area->y2 - area->y1 + 1;
    lcd.setAddrWindow(area->x1, area->y1,
                      width, height);
    lcd.pushPixels((uint16_t*)color_p, width * height, true);
  
    /*IMPORTANT!!!
     *Inform the graphics library that you are ready with the flushing*/
    lv_disp_flush_ready(disp_drv);
}
```

## タッチパネルの実装

入力デバイスのうち、今回はタッチパネルだけ実装する。
ボタンもできると思うが一旦後回し。

テンプレートからタッチパネルに関連する以外のものを消しておく。

自分で書く部分は`touchpad_init()`と`touchpad_is_pressed()`と`touchpad_get_xy()`。
だが、M5Stackの場合`M5.begin()`で初期化されるためinitは空にしておく。

残りの実装は以下のように書ける。

```
/*Return true is the touchpad is pressed*/
static bool touchpad_is_pressed(void)
{
    /*Your code comes here*/

    return M5.Touch.ispressed();
}

/*Get the x and y coordinates if the touchpad is pressed*/
static void touchpad_get_xy(lv_coord_t * x, lv_coord_t * y)
{
    /*Your code comes here*/

    TouchPoint_t coordinate;
    coordinate = M5.Touch.getPressPoint();

    (*x) = coordinate.x;
    (*y) = coordinate.y;
}
```

# 課題

汎用的に使えるライブラリ化を検討したが、主に理解不足により以下のような部分で躓いている。

`lv_conf.h`をLVGLのライブラリの外におく方法が今のところわからない。
`LV_CONF_INCLUDE_SIMPLE`をdefineせよ、と書いてあるが意図した挙動になっていない。

portingテンプレートも別ファイルにしたいが、
グローバル領域に置いてある変数があり、
ファイル分割できちんとスコープが通るかどうかがあやしく、現状できていない。

また、LVGLのデモコードを試していたが今の所動かせていない。
`void*`を他の構造体にキャストするなど結構怖い部分があり、platformioでは弾かれている。
`extern "c"`をつければいけるか？