LVGLでLittleFSを使ってイメージボタンを使う

libraries\lvgl\examples\portingにあるlv_port_fs_templateを元に書き換えていく
```php:lv_port_littlefs.hpp
#ifndef LV_PORT_LITTLEFS_H
#define LV_PORT_LITTLEFS_H

/*********************
 *      INCLUDES
 *********************/
#include <lvgl.h>
#include <Arduino.h>
#include <FS.h>
#include<LittleFS.h>

/*********************
 *      DEFINES
 *********************/

/**********************
 *      TYPEDEFS
 **********************/

/**********************
 * GLOBAL PROTOTYPES
 **********************/
void lv_port_fs_init(void);

/**********************
 *      MACROS
 **********************/
#endif
```

同じくスケルトンコードを元に書き換えていく
```php:lv_port_littlefs.cpp
#include "HardwareSerial.h"
#include "FS.h"
#if 1

#include "lv_port_littlefs.hpp"

static void fs_init(void);

static void * fs_open(lv_fs_drv_t * drv, const char * path, lv_fs_mode_t mode);
static lv_fs_res_t fs_close(lv_fs_drv_t * drv, void * file_p);
static lv_fs_res_t fs_read(lv_fs_drv_t * drv, void * file_p, void * buf, uint32_t btr, uint32_t * br);
static lv_fs_res_t fs_write(lv_fs_drv_t * drv, void * file_p, const void * buf, uint32_t btw, uint32_t * bw);
static lv_fs_res_t fs_seek(lv_fs_drv_t * drv, void * file_p, uint32_t pos, lv_fs_whence_t whence);
static lv_fs_res_t fs_size(lv_fs_drv_t * drv, void * file_p, uint32_t * size_p);
static lv_fs_res_t fs_tell(lv_fs_drv_t * drv, void * file_p, uint32_t * pos_p);

static void * fs_dir_open(lv_fs_drv_t * drv, const char * path);
static lv_fs_res_t fs_dir_read(lv_fs_drv_t * drv, void * rddir_p, char * fn);
static lv_fs_res_t fs_dir_close(lv_fs_drv_t * drv, void * rddir_p);

void lv_port_fs_init(void)
{
    /*----------------------------------------------------
     * Initialize your storage device and File System
     * -------------------------------------------------*/
    fs_init();

    /*---------------------------------------------------
     * Register the file system interface in LVGL
     *--------------------------------------------------*/

    /*Add a simple drive to open images*/
    static lv_fs_drv_t fs_drv;
    lv_fs_drv_init(&fs_drv);

    /*Set up fields...*/
    fs_drv.letter = 'P';
    fs_drv.open_cb = fs_open;
    fs_drv.close_cb = fs_close;
    fs_drv.read_cb = fs_read;
    fs_drv.write_cb = fs_write;
    fs_drv.seek_cb = fs_seek;
    fs_drv.tell_cb = fs_tell;

    fs_drv.dir_close_cb = fs_dir_close;
    fs_drv.dir_open_cb = fs_dir_open;
    fs_drv.dir_read_cb = fs_dir_read;

    lv_fs_drv_register(&fs_drv);
}

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

/*Initialize your Storage device and File system.*/
static void fs_init(void)
{
    /*E.g. for FatFS initialize the SD card and FatFS itself*/

    /*You code here*/
    LittleFS.begin();
}

/**
 * Open a file
 * @param drv       pointer to a driver where this function belongs
 * @param path      path to the file beginning with the driver letter (e.g. S:/folder/file.txt)
 * @param mode      read: FS_MODE_RD, write: FS_MODE_WR, both: FS_MODE_RD | FS_MODE_WR
 * @return          a file descriptor or NULL on error
 */
static void * fs_open(lv_fs_drv_t * drv, const char * path, lv_fs_mode_t mode)
{
  LV_UNUSED(drv);

  const char* flag = "";  //読み書きフラグ

  //モードフラグ  
  if (mode == LV_FS_MODE_WR) {
    flag = FILE_WRITE;
  } else if (mode == LV_FS_MODE_RD) {
    flag = FILE_READ;
  }else if (mode == (LV_FS_MODE_WR | LV_FS_MODE_RD)) {
    flag = FILE_WRITE;
  }

  //ファイルオープン
  File f = LittleFS.open(path, flag);
  if (!f) {
    Serial.println("lvgl File System Open error");
    return NULL;
  }
    Serial.println("fopen");

//  LittleFile* lf = new LittleFile{f};
    File* f_p = new File(f);
//  return (void*)lf;
    return (void*)f_p;
}

/**
 * Close an opened file
 * @param drv       pointer to a driver where this function belongs
 * @param file_p    pointer to a file_t variable. (opened with fs_open)
 * @return          LV_FS_RES_OK: no error or  any error from @lv_fs_res_t enum
 */
static lv_fs_res_t fs_close(lv_fs_drv_t * drv, void * file_p)
{
  Serial.println("fclose");
  LV_UNUSED(drv);
//  LittleFile* lf = (LittleFile*)file_p;

//  lf->file.close();

//  delete lf;
  File* f_p = (File*)file_p;

  f_p->close(); //ファイルクローズ

  return LV_FS_RES_OK;
}

/**
 * Read data from an opened file
 * @param drv       pointer to a driver where this function belongs
 * @param file_p    pointer to a file_t variable.
 * @param buf       pointer to a memory block where to store the read data
 * @param btr       number of Bytes To Read
 * @param br        the real number of read bytes (Byte Read)
 * @return          LV_FS_RES_OK: no error or  any error from @lv_fs_res_t enum
 */
static lv_fs_res_t fs_read(lv_fs_drv_t * drv, void * file_p, void * buf, uint32_t btr, uint32_t * br)
{
  Serial.println("fread");
  LV_UNUSED(drv);
//  LittleFile* lf = (LittleFile*)file_p;

//  *br = lf->file.read((uint8_t*)buf, btr);
  File* f_p = (File*)file_p;

  *br = f_p->read((uint8_t*)buf, btr);  //読み取り

  return (int32_t)(*br) < 0 ? LV_FS_RES_UNKNOWN : LV_FS_RES_OK;
}

/**
 * Write into a file
 * @param drv       pointer to a driver where this function belongs
 * @param file_p    pointer to a file_t variable
 * @param buf       pointer to a buffer with the bytes to write
 * @param btw       Bytes To Write
 * @param bw        the number of real written bytes (Bytes Written). NULL if unused.
 * @return          LV_FS_RES_OK: no error or  any error from @lv_fs_res_t enum
 */
static lv_fs_res_t fs_write(lv_fs_drv_t * drv, void * file_p, const void * buf, uint32_t btw, uint32_t * bw)
{
  Serial.println("fwrite");
  LV_UNUSED(drv);

//  LittleFile* lf = (LittleFile*)file_p;
//  *bw = lf->file.write((uint8_t*)buf, btw);
  File* f_p = (File*)file_p;
  *bw = f_p->write((uint8_t*)buf, btw); //書き込み

  return (int32_t)(*bw) < 0 ? LV_FS_RES_UNKNOWN : LV_FS_RES_OK;
}

/**
 * Set the read write pointer. Also expand the file size if necessary.
 * @param drv       pointer to a driver where this function belongs
 * @param file_p    pointer to a file_t variable. (opened with fs_open )
 * @param pos       the new position of read write pointer
 * @param whence    tells from where to interpret the `pos`. See @lv_fs_whence_t
 * @return          LV_FS_RES_OK: no error or  any error from @lv_fs_res_t enum
 */
static lv_fs_res_t fs_seek(lv_fs_drv_t * drv, void * file_p, uint32_t pos, lv_fs_whence_t whence)
{
  Serial.println("fseek");
  LV_UNUSED(drv);

  //シークモード位置
  SeekMode mode;
  if (whence == LV_FS_SEEK_SET) {
    mode = SeekSet;
  } else if (whence == LV_FS_SEEK_CUR) {
    mode = SeekCur;
  } else if (whence == LV_FS_SEEK_END) {
    mode = SeekEnd;
  }

//  LittleFile* lf = (LittleFile*)file_p;
//  lf->file.seek(pos, mode);
  File* f_p = (File*)file_p;
  f_p->seek(pos,mode);  //位置移動

  return LV_FS_RES_OK;
}
/**
 * Give the position of the read write pointer
 * @param drv       pointer to a driver where this function belongs
 * @param file_p    pointer to a file_t variable.
 * @param pos_p     pointer to to store the result
 * @return          LV_FS_RES_OK: no error or  any error from @lv_fs_res_t enum
 */
static lv_fs_res_t fs_tell(lv_fs_drv_t * drv, void * file_p, uint32_t * pos_p)
{
    lv_fs_res_t res = LV_FS_RES_NOT_IMP;

    /*Add your code here*/

    return res;
}

/**
 * Initialize a 'lv_fs_dir_t' variable for directory reading
 * @param drv       pointer to a driver where this function belongs
 * @param path      path to a directory
 * @return          pointer to the directory read descriptor or NULL on error
 */
static void * fs_dir_open(lv_fs_drv_t * drv, const char * path)
{
    void * dir = NULL;
    /*Add your code here*/
    //dir = ...           /*Add your code here*/
          return dir;
}

/**
 * Read the next filename form a directory.
 * The name of the directories will begin with '/'
 * @param drv       pointer to a driver where this function belongs
 * @param rddir_p   pointer to an initialized 'lv_fs_dir_t' variable
 * @param fn        pointer to a buffer to store the filename
 * @return          LV_FS_RES_OK: no error or  any error from @lv_fs_res_t enum
 */
static lv_fs_res_t fs_dir_read(lv_fs_drv_t * drv, void * rddir_p, char * fn)
{
    lv_fs_res_t res = LV_FS_RES_NOT_IMP;

    /*Add your code here*/

    return res;
}

/**
 * Close the directory reading
 * @param drv       pointer to a driver where this function belongs
 * @param rddir_p   pointer to an initialized 'lv_fs_dir_t' variable
 * @return          LV_FS_RES_OK: no error or  any error from @lv_fs_res_t enum
 */
static lv_fs_res_t fs_dir_close(lv_fs_drv_t * drv, void * rddir_p)
{
    lv_fs_res_t res = LV_FS_RES_NOT_IMP;

    /*Add your code here*/

    return res;
}




#else /*Enable this file at the top*/

/*This dummy typedef exists purely to silence -Wpedantic.*/
typedef int keep_pedantic_happy;
#endif
```

メインのコード
```php:main.ino
#include <lvgl.h>

//LovyanGFX関係
#include "my_LovyanGFX_setting.h"

#include <Arduino.h>
#include "FS.h"
#include <LittleFS.h>
//#include<ArduinoJson.h>
#define FORMAT_LITTLEFS_IF_FAILED true

//Json関係
#include "myUtilJson.h"

///ここから定数関係
#define BACKLIGHTPOWER 127  //バックライトの明るさ(最大255)
#define MAXDISPICONNUM 5  //1画面の最大ボタン数
#define MAXJSONSIZE 1000  //Jsonファイルの最大サイズ（多分）
#define MAXFUNCTIONNAME 20  //関数名の最大文字数(Dicfunction)

//json内の関数名との紐づけ用
#define EV_CLICK_SENDBUTTON "ev_click_sendbutton" //コマンド送信系ボタンクリックイベント関数名
///ここまで定数関係
//グローバル変数
char currentdirectory[32] = "/";  //カレントディレクトリ


#include "lv_port_littlefs.hpp"


//LovyanGFXのインスタンスを作成します。
LGFX tft;

/*Change to your screen resolution*/
static const uint16_t screenWidth  = 320;
static const uint16_t screenHeight = 280;
static lv_disp_draw_buf_t draw_buf;
static lv_color_t buf[ screenWidth * 10 ];

/* Display flushing */
void my_disp_flush( lv_disp_drv_t *disp, const lv_area_t *area, lv_color_t *color_p )
{
    uint32_t w = ( area->x2 - area->x1 + 1 );
    uint32_t h = ( area->y2 - area->y1 + 1 );

    tft.startWrite();
    tft.setAddrWindow( area->x1, area->y1, w, h );
    //tft.pushColors( ( uint16_t * )&color_p->full, w * h, true );
    tft.writePixels((lgfx::rgb565_t *)&color_p->full, w * h );
    tft.endWrite();

    lv_disp_flush_ready( disp );
}

/*Read the touchpad*/
void my_touchpad_read( lv_indev_drv_t * indev_driver, lv_indev_data_t * data )
{
    uint16_t touchX, touchY;
    bool touched = tft.getTouch( &touchX, &touchY);

    if( !touched )
    {
        data->state = LV_INDEV_STATE_REL;
    }
    else
    {
        data->state = LV_INDEV_STATE_PR;

        /*Set the coordinates*/
        data->point.x = touchX;
        data->point.y = touchY;

        Serial.print( "Data x " );
        Serial.println( touchX );

        Serial.print( "Data y " );
        Serial.println( touchY );
    }
}


//ボタンクリックイベント(コマンド送信)
void ev_click_sendbutton(lv_event_t *e)
{
  lv_event_code_t code = lv_event_get_code(e);
  lv_obj_t * btn = lv_event_get_target(e);
  if(code == LV_EVENT_CLICKED)
  {
    Serial.println("func1");
    char *userdata = (char *)lv_event_get_user_data(e); //ユーザーデータの取り出し(文字列)
    MyUtilJson utiljson;  //json操作クラス
//    StaticJsonDocument<MAXJSONSIZE> doc;
    DynamicJsonDocument doc(MAXJSONSIZE);
    char filefullpath[32];  //commandファイルパス格納用

    sprintf(filefullpath,"%s%s",currentdirectory,userdata); //相対パスをフルパスに変換

    utiljson.readJson(LittleFS,filefullpath,doc);  //送信コマンドjsonファイル読み込み

    //送信用コマンドを1文ずつ取り出す
    for(int i=0;i<doc["command"].size();i++)
    {
      SendUDP((char *)((const char *)(doc["command"][i]))); //UDPでコマンドを送信
    }    
  }
}

void func2(lv_event_t *e)
{
  lv_event_code_t code = lv_event_get_code(e);
  lv_obj_t * btn = lv_event_get_target(e);
  if(code == LV_EVENT_CLICKED) {
    Serial.println("func2");
  }
}

//辞書配列っぽく使う予定
typedef struct Dicfunction {
  char name[MAXFUNCTIONNAME];
  void (*funcp)(lv_event_t * e);
} dicfunction;
//グローバル変数
//dicfuncにGUIで使うコールバック関数を追加していく。jsonファイルの関数名(func)と実際の関数を紐づけ
dicfunction dicfunc[] ={
  //↓例
  // {
  //   "jsonファイル内のfunc項目の文字列",プログラム上の関数へのポインタ
  // },
  {
    EV_CLICK_SENDBUTTON,ev_click_sendbutton
  },
  {
    "functionB",func2
  }
};

//文字列から対象の関数を探して返す(辞書配列っぽく使う用)
void (*searchfunction(const char *str))(lv_event_t *)
{
  for(int i=0;i<(sizeof(dicfunc)/sizeof(dicfunc[0]));i++)
  {
    if(strcmp(str,dicfunc[i].name) == 0)
    {
      return dicfunc[i].funcp;
    }
  }

  return 0;  
}

//lvglやlovyangfxの初期化
void initDrivers()
{
  tft.begin();          /* TFT init */
  tft.setRotation( 3 ); /* Landscape orientation, flipped */
  tft.setBrightness(BACKLIGHTPOWER); //液晶のバックライトを最大の明るさにする    
  uint16_t calData[] = { 267, 3671, 267, 180, 3843, 3717, 3846, 143 };  //事前に調べたキャリブレーション値
  tft.setTouchCalibrate( calData ); //キャリブレーション値の設定

  lv_init();
  lv_disp_draw_buf_init( &draw_buf, buf, NULL, screenWidth * 10 );

  /*Initialize the display*/
  static lv_disp_drv_t disp_drv;
  lv_disp_drv_init( &disp_drv );
  /*Change the following line to your display resolution*/
  disp_drv.hor_res = screenWidth;
  disp_drv.ver_res = screenHeight;
  disp_drv.flush_cb = my_disp_flush;
  disp_drv.draw_buf = &draw_buf;
  lv_disp_drv_register( &disp_drv );

  /*Initialize the (dummy) input device driver*/
  static lv_indev_drv_t indev_drv;
  lv_indev_drv_init( &indev_drv );
  indev_drv.type = LV_INDEV_TYPE_POINTER;
  indev_drv.read_cb = my_touchpad_read;
  lv_indev_drv_register( &indev_drv );

  lv_port_fs_init();  //lvglファイルシステムの初期化

}

void setup()
{
  Serial.begin( 115200 ); /* prepare for possible serial debug */

  ///ここからUDP関係///
  initUDP();
  openUDP();
  //Serial.println(WiFi.localIP());
  ///ここまでUDP関係///

  initDrivers();  //ドライバ関係の初期化(lvgl,lovyanGFX)

  //ここから画面構成呼び出し系
  //LittleFS初期化
  /*
  if(!LittleFS.begin(FORMAT_LITTLEFS_IF_FAILED)){
      Serial.println("LittleFS Mount Failed");
      return;
  }
  */
  my_load_disp(LittleFS,"/test.json");  //
  //ここまで画面構成呼び出し系
  listDir(LittleFS, "/", 3);




/*
lv_obj_t * img1 = lv_imgbtn_create(lv_scr_act());
lv_imgbtn_set_src(img1, LV_IMGBTN_STATE_RELEASED,  "P:/img.bin", 0, 0); //画像の設定(押されていないとき)
lv_imgbtn_set_src(img1, LV_IMGBTN_STATE_PRESSED,  "P:/img.bin", 0, 0);  //画像の設定(押されているとき)
lv_obj_set_pos(img1, 100, 100);
lv_obj_set_size(img1,64,64);  //サイズWidth,Height
static lv_style_t style;
lv_style_init(&style);
lv_style_set_outline_width(&style,2); //アウトラインの太さ
lv_style_set_outline_color(&style,lv_color_black());  //アウトラインの色
lv_obj_add_style(img1, &style,LV_STATE_PRESSED);  //イメージボタンの押されているときのスタイルにアウトラインのスタイルを設定
*/
//lv_img_cache_set_size(12);
/*
lv_obj_t * img1 = lv_imgbtn_create(lv_scr_act());
lv_imgbtn_set_src(img1, LV_IMGBTN_STATE_RELEASED,  "P:/img.bin", 0, 0); //画像の設定(押されていないとき)
lv_obj_set_pos(img1, 0, 0);
lv_obj_set_size(img1,64,64);  //サイズWidth,Height

lv_obj_t * img2 = lv_imgbtn_create(lv_scr_act());
lv_imgbtn_set_src(img2, LV_IMGBTN_STATE_RELEASED,  "P:/img.bin", 0, 0); //画像の設定(押されていないとき)
lv_obj_set_pos(img2, 64, 60);
lv_obj_set_size(img2,64,64);  //サイズWidth,Height
lv_obj_t * img3 = lv_imgbtn_create(lv_scr_act());
lv_imgbtn_set_src(img3, LV_IMGBTN_STATE_RELEASED,  "P:/img.bin", 0, 0); //画像の設定(押されていないとき)
lv_obj_set_pos(img3, 128, 0);
lv_obj_set_size(img3,64,64);  //サイズWidth,Height
lv_obj_t * img4 = lv_imgbtn_create(lv_scr_act());
lv_imgbtn_set_src(img4, LV_IMGBTN_STATE_RELEASED,  "P:/img.bin", 0, 0); //画像の設定(押されていないとき)
lv_obj_set_pos(img4, 192, 0);
lv_obj_set_size(img4,64,64);  //サイズWidth,Height
lv_obj_t * img5 = lv_imgbtn_create(lv_scr_act());
lv_imgbtn_set_src(img5, LV_IMGBTN_STATE_RELEASED,  "P:/img.bin", 0, 0); //画像の設定(押されていないとき)
lv_obj_set_pos(img5, 0, 64);
lv_obj_set_size(img5,64,64);  //サイズWidth,Height
lv_obj_t * img6 = lv_imgbtn_create(lv_scr_act());
lv_imgbtn_set_src(img6, LV_IMGBTN_STATE_RELEASED,  "P:/img.bin", 0, 0); //画像の設定(押されていないとき)
lv_obj_set_pos(img6, 0, 128);
lv_obj_set_size(img6,64,64);  //サイズWidth,Height
lv_obj_t * img7 = lv_imgbtn_create(lv_scr_act());
lv_imgbtn_set_src(img7, LV_IMGBTN_STATE_RELEASED,  "P:/img.bin", 0, 0); //画像の設定(押されていないとき)
lv_obj_set_pos(img7, 0, 192);
lv_obj_set_size(img7,64,64);  //サイズWidth,Height
/*
lv_obj_t * img8 = lv_imgbtn_create(lv_scr_act());
lv_imgbtn_set_src(img8, LV_IMGBTN_STATE_RELEASED,  "P:/img.bin", 0, 0); //画像の設定(押されていないとき)
lv_obj_set_pos(img8, 0, 230);
lv_obj_set_size(img8,64,64);  //サイズWidth,Height
*/
}

void loop()
{
  lv_timer_handler(); /* let the GUI do its work */
  delay( 5 );
}

//ここから画面構成呼び出し系
void my_load_disp(fs::FS &fs,const char *path)
{
Serial.println("mydisp");

  MyUtilJson utiljson;  //json操作クラス
  //StaticJsonDocument<MAXJSONSIZE> doc;
  DynamicJsonDocument doc(MAXJSONSIZE);
  utiljson.readJson(fs,"/test.json",doc);
Serial.println("readjson");

  static char userdata[MAXDISPICONNUM][20]; //ボタンに渡すユーザーデータ格納用
  static char imgfilepath[MAXDISPICONNUM][32];  //イメージボタンのファイルパス格納用!!!メモリ無駄使用しない配列の場所あり
  static lv_style_t style[MAXDISPICONNUM];  //イメージボタン用スタイル格納用!!!メモリ無駄使用しない配列の場所あり
  //UI種別による分岐
  for(int i=0;i<doc["items"].size();i++)
  {
    if(strcmp(doc["items"][i]["type"],"btn") == 0)
    {
      //ボタンの場合
      lv_obj_t * btn = lv_btn_create(lv_scr_act());
      lv_obj_set_pos(btn, (int)(doc["items"][i]["x"]), (int)(doc["items"][i]["y"]));
      lv_obj_set_size(btn, (int)(doc["items"][i]["width"]), (int)(doc["items"][i]["height"]));
      const char* commandfilepath=doc["items"][i]["filepath"]; //jsonからコマンドファイルのパス取得(ユーザーデータ)
      strcpy(userdata[i],commandfilepath); //jsonからの値をユーザーデータにコピー
      lv_obj_add_event_cb(btn, searchfunction(doc["items"][i]["func"]), LV_EVENT_ALL, &userdata[i]); //コールバックイベント登録とユーザーデータ付属

      lv_obj_t * label = lv_label_create(btn);
      lv_label_set_text(label, "ButtonJson");
      //lv_obj_add_flag(label, LV_OBJ_FLAG_HIDDEN); //非表示にする
      //lv_obj_clear_flag(label,LV_OBJ_FLAG_HIDDEN);  //表示にする
      lv_obj_center(label);
    } else if(strcmp(doc["items"][i]["type"],"imgbtn") == 0)
    {      
      //イメージボタンの場合
      lv_obj_t * imgbtn = lv_imgbtn_create(lv_scr_act());
      sprintf(imgfilepath[i],"P:%s",(const char *)doc["items"][i]["img"]); //jsonからイメージファイルのパス取得
      lv_imgbtn_set_src(imgbtn, LV_IMGBTN_STATE_RELEASED,  imgfilepath[i], 0, 0); //画像の設定(押されていないとき)
      lv_imgbtn_set_src(imgbtn, LV_IMGBTN_STATE_PRESSED,  imgfilepath[i], 0, 0);  //画像の設定(押されているとき)
      lv_obj_set_pos(imgbtn, (int)(doc["items"][i]["x"]), (int)(doc["items"][i]["y"]));
      lv_obj_set_size(imgbtn, (int)(doc["items"][i]["width"]), (int)(doc["items"][i]["height"]));
      const char* commandfilepath=doc["items"][i]["filepath"]; //jsonからコマンドファイルのパス取得(ユーザーデータ)
      strcpy(userdata[i],commandfilepath); //jsonからの値をユーザーデータにコピー
      lv_obj_add_event_cb(imgbtn, searchfunction(doc["items"][i]["func"]), LV_EVENT_ALL, &userdata[i]); //コールバックイベント登録とユーザーデータ付属

      //押された時の見た目変更用
      lv_style_init(&style[i]);
      lv_style_set_outline_width(&style[i],2); //アウトラインの太さ
      lv_style_set_outline_color(&style[i],lv_color_black());  //アウトラインの色
      lv_obj_add_style(imgbtn, &style[i],LV_STATE_PRESSED);  //イメージボタンの押されているときのスタイルにアウトラインのスタイルを設定      
    }
  }  
}




/*
//ファイルの読み込み
void readFile(fs::FS &fs, const char * path,char *buf)
{
  File file = fs.open(path);
  if(!file || file.isDirectory()){
      Serial.println("- failed to open file for reading");
      return;
  }

  int i=0;
  while(file.available())
  {
    *(buf+i) = file.read();
    i++;
  }
  *(buf+i) = '\0';
Serial.println(buf);
  file.close();
}
*/
//ここまで画面構成呼び出し系

/*
static void btn_event_cb(lv_event_t * e)
{
  lv_event_code_t code = lv_event_get_code(e);
  lv_obj_t * btn = lv_event_get_target(e);
  if(code == LV_EVENT_CLICKED) {
    char *userdata = (char *)lv_event_get_user_data(e); //ユーザーデータの取り出し(文字列)
Serial.println(userdata);
    static uint8_t cnt = 0;
    cnt++;


    lv_obj_t * label = lv_obj_get_child(btn, 0);
    lv_label_set_text_fmt(label, "Button: %d", cnt);
    
    lv_obj_clean(lv_scr_act()); //現在のスクリーンをクリア
    lv_obj_t * btn = lv_btn_create(lv_scr_act());    
    lv_obj_set_pos(btn, 50, 50);                        
    //lv_obj_align(btn3,LV_ALIGN_CENTER,0,0);
    lv_obj_set_size(btn, 120, 50);                        
    lv_obj_add_event_cb(btn, btn_event_cb, LV_EVENT_ALL, NULL);       

    lv_obj_t * label2 = lv_label_create(btn);        
    lv_label_set_text(label2, "NewButton");               
    lv_obj_center(label2);

    ///ここからUDP関係///
    //SendUDP("test1");
    ///ここまでUDP関係///
  }
}
*/
/**
 * Create a button with a label and react on click event.
 */
 /*
void lv_example_get_started_1(void)
{
    lv_obj_t * btn = lv_btn_create(lv_scr_act());  
    //lv_obj_set_pos(btn, 10, 10);                      
    lv_obj_align(btn,LV_ALIGN_CENTER,0,0);
    lv_obj_set_size(btn, 120, 50);                     
    lv_obj_add_event_cb(btn, btn_event_cb, LV_EVENT_ALL, NULL);         

    lv_obj_t * label = lv_label_create(btn);          
    lv_label_set_text(label, "Button");                    
    lv_obj_center(label);
}
*/


void listDir(fs::FS &fs, const char * dirname, uint8_t levels){
    Serial.printf("Listing directory: %s\r\n", dirname);

    File root = fs.open(dirname);
    if(!root){
        Serial.println("- failed to open directory");
        return;
    }
    if(!root.isDirectory()){
        Serial.println(" - not a directory");
        return;
    }

    File file = root.openNextFile();
    while(file){
        if(file.isDirectory()){
            Serial.print("  DIR : ");
            Serial.println(file.name());
            if(levels){
                listDir(fs, file.path(), levels -1);
            }
        } else {
            Serial.print("  FILE: ");
            Serial.print(file.name());
            Serial.print("\tSIZE: ");
            Serial.println(file.size());
        }
        file = root.openNextFile();
    }
}
```

動作が重いのはEEEPROMなので仕方がないのかな？
画面がスクロールするような構成で使うとスクロールのたびに再描画がかかり重すぎてどうにもならない。
なにか方法があるかよくわからない