Git Product home page Git Product logo

diy-esp32-epub-reader's Introduction

build status

ESP32 Based ePub Reader

3 supported environments Above the 3 supported environments. You can watch a video of the build here

Here it is running on a LilyGo board:

LilyGo

And here it is running on the M5Paper:

M5Paper

What is it? It's a DIY ePub reader for the ESP32.

It will parse ePub files that can be downloaded from places such as Project Gutenberg.

It has limited support for formating - the CSS content of the ePub file is not parsed, so we just use the standard HTML tags such as <h1>,<h2> etc.. and <b> and <i>.

I've only included 4 font styles - regular, bold, italic and bold-italic. I've also only generated glyphs for Latin characters and punctuation.

Building and Flashing

This project uses PlatformIO to build and flash. You will need VSCode with the PlatformIO extension installed.

There are several environments configured in platformio.ini. If you click on the PlatformIO logo in the left hand navigation of VSCode, you will see a list of Project Tasks - you can pick the environment you want and then Upload.

Select Environment

Why did you build it?

It seemed like a nice challenge - ePub files are not the most friendly format to process on an embedded device. Making it work in a constrained environment is good fun.

Can you contribute/help?

Yes - please try the project out on any e-paper boards that you have and open up pull requests if you get it working with any fixes.

And if you find bugs, feel free to report (or better yet, fix!) them :)

How to get it?

Make sure you clone recursively - the code uses git submodules.

git clone --recursive [email protected]:atomic14/esp32-ereader.git

What boards does it work on?

The code should work with M5-Paper and other EPDiy based parallel e-Papers such as the LilyGo EPD47.

  • PSRAM - parsing the ePub files needs a fair amount of memory
  • 3 Buttons - these buttons can be active high or low
    • UP - moves up in the list of ePubs or to the previous page when reading
    • DOWN - moves down in the list of ePubs or to the next page when reading
    • SELECT - opens the ePub currently selected ePub file or goes back to the ePub list from reading mode
  • An SD Card - you can jury rig an SPI sd card using the instructions here:
    • You can use SPIFFS instead of an SD Card, but you won't be able to fit many books on it.
  • [Optional] A battery if you want it to be portable

SPIFFS support

To use SPIFFS instead of an SD Card add a preprocessor define to plaformio.ini -DUSE_SPIFFS.

To upload the filesystem do:

pio run -t uploadfs

There some issues with SPIFFS which cause some problems - particularly with persisting the state of the display when going into deep sleep - if you can get an SD Card attached these problems don't exist.

Porting to other boards

To add a new board to the project you need to:

Create a new board class in src/boards this should implement the methods from the Board.h class.

This may or may not be necessary - if you are using an EPDIY board then everything is taken care of with preprocessor directives and you just need to define BOARD_TYPE_EPDIY in platformio.ini build flags.

If you have a completely new board then at a minimum you need to return a Renderer object that will draw to your display and a GPIOButtonControls to control navigation. Have a look at M5Paper.h for inspiration. Add your new board type to the factory method of Board.

Add a new environment to `platformio.ini

The majority of the configuration is in platformio.ini using pre-processor directives. If you do add a new board then please create a new section in platofmrio.ini with the appropriate pre-processor directives for your board and open a pull request to add it to the project - I'm happy to answer any questions on this.

The important settings are the following:

The first two settings come from the vroland/epdiy library and defined the ePaper display that is being used.

; Setup display format and model via build flags
-DCONFIG_EPD_DISPLAY_TYPE_ED047TC1
-DCONFIG_EPD_BOARD_REVISION_LILYGO_T5_47

There is also a setting to tell the code if the buttons are active high or low.

; buttons are low when pressed
-DBUTONS_ACTIVE_LEVEL=0

We have the pins for the SD card. I've got a video on how to hack an SD Card and connect it as a SPI device here

; setup the pins for the SDCard
-DSD_CARD_PIN_NUM_MISO=GPIO_NUM_14
-DSD_CARD_PIN_NUM_MOSI=GPIO_NUM_13
-DSD_CARD_PIN_NUM_CLK=GPIO_NUM_15
-DSD_CARD_PIN_NUM_CS=GPIO_NUM_12

Optional L58 Touch interface (Defaults to Lilygo EPD47)

  ; Touch configuration
  -D CONFIG_TOUCH_SDA=15
  -D CONFIG_TOUCH_SDL=14
  -D CONFIG_TOUCH_INT=13
  -D CONFIG_I2C_MASTER_FREQUENCY=50000
  -D CONFIG_FT6X36_DEBUG=0
  ; Uncomment USE_L58_TOUCH define to activate it
  -USE_L58_TOUCH

And finally we have the ADC channel that the battery voltage divider is connected to:

; the adc channel that is connected to the battery voltage divider - this is GPIO_NUM_35
-DBATTERY_ADC_CHANNEL=ADC1_CHANNEL_0

To enable the use of SPIFFS

; enable the use of SPIFFS
-DUSE_SPIFFS

How does it work?

Epub files are a bit of a pain to parse. Despite the file extension epub, they are actually zip archives containing multiple files. To read the file I'm using a nice zip library from here: lbernstrone/miniz. This library has been modified to work on the ESP32 with PSRAM. Miniz is actually built into the ESP32 ROM, but support for multifile archives is disabled.

Parsing the ePub file

I've encapsulated the needed ZIP function in a small wrapper class which can be found here: ZipFile

The most interesting file in the epub archive is the OEBPS/content.opf file. This file contains the list of files in the epub archive. The OEBPS/content.opf file is a simple XML file so we need an XML parser to parse it.

To do the heavy lifting of parsing the XML we're using TinyXML2. This library is a very small and simple XML parser. The content.opf contains three sections, metadata, manifest and spine. The metadata section contains the title of the book, the author and the cover image. The manifest section contains the list of files in the epub archive. The spine section tells you what order to read the files in.

The parsing of the epub file and reading in the contents is done by the Epub class. This uses the ZipFile class and the TinyXML2 library to parse the epub file and read the contents.

Parsing the ePub contents

Each logical section of the book (typically chapters) is one HTML file in the zip archive.

These are all XHTML files - this means that once again we can parse them using the TinyXML2 library.

I've limited our parsing to a set of minimum tags that are enough to give us the basic structure of the book without making things too complicated.

  • Block tags <div>, <p>, <h1>, <h2> etc...
  • Inline tags <b>, <i>
  • Images <img>
  • Line breaks <br>

You can see the details in the RubbishHtmlParser code.

For each block tag we extract the text and add the block to a list of blocks. For inline tags we add these to the current block along with any style information (e.g. bold, italic).

Whenever we hit a new block tag we start a new block.

Image tags are also treated as blocks.

After parsing the HTML we end up with a list of blocks containing either text or an image. For header tags, we just set the style of the block to bold. You could get more sophisticated here with multiple fonts and different sizes if you wanted to.

Laying out a section of the book

With the blocks extracted, we can now layout the blocks of the section onto individual pages.

Image blocks are easy - we just need to read the width and height of the image and scale it to fit on the screen. This gives us the height the image will be when it is rendered.

For text blocks we need to calculate the height of the text once it has been split over multiple lines. To do this we measure the width of each word in the block and then use some dynamic programming to break the words up into lines - you can watch a great video from MIT here on how this algorithm works: 20. Dynamic Programming II: Text Justification, Blackjack.

I copied the solution for this problem from here with minor modifications. This implementation will work for most cases but could be improved considerably.

With the heights of the blocks all computed and the text blocks broken up into lines, we can now assign the content to pages.

We create a page and then start adding content to it - either images or lines of text. Everytime we run out of space we create a new page.

Rendering

Rendering each page is trivial - we know the y position of each element on the page.

Images are simply drawn at the correct y position centred on the screen.

Text is drawn word by word and a side effect of the text justification and line-breaking is that we have already computed the x position of each word on a line.

Deep sleep

The code will go to sleep after 30 seconds of inactivity. The current state of the ePaper display is saved to the SD Card - this is needed so that the display updates correctly. Other state is held in RTC memory.

For wake up there are two options, ULP for buttons that are active low and EXT1 for buttons that are active high. I've got a good video on deep sleep here if you are interested in this kind of thing: ESP32 Deep Dive into Deep Sleep

Fonts

You can generate different fonts by modifying the code in scripts/generate_fonts.sh this is a slightly modified script from the epdiy repository that lets you output the font data in only two colors which lets us update the screen considerably faster.

How well does it work?

Surprisingly, it works pretty well. Layout is reasonable, but there are a lot of improvements that could be made. The code makes no attempt to break pages at suitable places - there are hints that can be extracted from the XHTML files and there are also CSS files that could be used.

Depending on the images that have been used for the book covers displaying the list of ePub files on the SD Card can take a few sections and moving through the pages of ePub files can be a bit slow. Rendering the actual pages is pretty reasonable, even when they have images on them.

Improvements:

There's a lot of room for improvement. This is a very basic e-reader and I'm more than happy for people to contribute to this project.

Check aditional notes and research in our esp-32 epub reader Wiki. Here you can find the DIY-ePUB reader project in Hackaday and the public chat-room.

diy-esp32-epub-reader's People

Contributors

cgreening avatar hpsaturn avatar martinberlin avatar slord6 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

diy-esp32-epub-reader's Issues

Opening certain part of TOC crashes - heavy xhtml (>280 Kb)

To reproduce open Chapter VIII of Blade Runner "Future noir" book.

I (27829) EREADER: go to section:15
I (28129) EPUB: toc path: OEBPS/9780062852892_toc.ncx

I (28289) EREADER: Parse and render section 15
I (28289) EREADER: item OEBPS/text/9780062852892_Chapter_8.xhtml

abort() was called at PC 0x40112937 on core 1
TRACE relevant parts show: 
Looks if there is some problem with the itemSize parsing the XML. Previous chapters before 8 open just fine...

  #15 0x4014568f:0x3ffd0010 in tinyxml2::MemPoolT<52>::ItemSize() const at .pio/libdeps/epdiy/tinyxml2/tinyxml2.h:370
  #16 0x40145607:0x3ffd0030 in tinyxml2::XMLText::Accept(tinyxml2::XMLVisitor*) const at .pio/libdeps/epdiy/tinyxml2/tinyxml2.cpp:1251
  #17 0x400e538d:0x3ffd0050 in RubbishHtmlParser::parse(char const*, int) at lib/Epub/RubbishHtmlParser/RubbishHtmlParser.cpp:179


      (inlined by) RubbishHtmlParser::RubbishHtmlParser(char const*, int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) at lib/Epub/RubbishHtmlParser/RubbishHtmlParser.cpp:58
  #19 0x400e3a41:0x3ffd0260 in EpubReader::parse_and_layout_current_section() at lib/Epub/EpubList/EpubReader.cpp:55 (discriminator 3)
  #20 0x400e3b27:0x3ffd02c0 in EpubReader::set_state_section(unsigned short) at lib/Epub/EpubList/EpubReader.cpp:104
  #21 0x400d3b5a:0x3ffd02e0 in handleEpub(Renderer*, UIAction) at src/main.cpp:83

@cgreening book to reproduce this is here: https://sync.luckycloud.de/d/a04070e242b841f7b784/

It seems to be a specific problem with this Chapter, others seem to work well, and open as expected. It will be nice to research why it hangs on this one since it might happen also with other books.

Port to TFT displays

At the moment the rendering is fairly generic but only ePaper displays are supported - it would be cool to add support for TFT displays and show color ebooks.

m5paper compile error

Hi, I was trying to compile and test your project on my m5paper, but I can't get it to work.
After cloning it, I selected the correct env task for m5paper, but it gave me a lot of compilation errors:

In file included from src/boards/Lilygo_t5_47.cpp:2:
lib/Fonts/regular_font.h:2:10: fatal error: epd_driver.h: No such file or directory

********************************************************************
* Looking for epd_driver.h dependency? Check our library registry!
*
* CLI  > platformio lib search "header:epd_driver.h"
* Web  > https://platformio.org/lib/search?query=header:epd_driver.h
*
********************************************************************

 #include "epd_driver.h"
          ^~~~~~~~~~~~~~
compilation terminated.
Compiling .pio/build/m5_paper/src/boards/controls/EpdiyV6ButtonControls.o
*** [.pio/build/m5_paper/src/boards/Lilygo_t5_47.o] Error 1
Compiling .pio/build/m5_paper/src/boards/controls/GPIOButtonControls.o
In file included from src/boards/controls/EpdiyV6ButtonControls.cpp:1:
src/boards/controls/EpdiyV6ButtonControls.h:2:10: fatal error: pca9555.h: No such file or directory

*****************************************************************
* Looking for pca9555.h dependency? Check our library registry!
*
* CLI  > platformio lib search "header:pca9555.h"
* Web  > https://platformio.org/lib/search?query=header:pca9555.h
*
*****************************************************************

 #include "pca9555.h"
          ^~~~~~~~~~~
compilation terminated.
*** [.pio/build/m5_paper/src/boards/controls/EpdiyV6ButtonControls.o] Error 1
In file included from lib/Epub/Renderer/M5PaperRenderer.h:6,
                 from src/boards/M5Paper.cpp:2:
lib/Epub/Renderer/EpdiyFrameBufferRenderer.h:3:10: fatal error: epd_driver.h: No such file or directory

********************************************************************
* Looking for epd_driver.h dependency? Check our library registry!
*
* CLI  > platformio lib search "header:epd_driver.h"
* Web  > https://platformio.org/lib/search?query=header:epd_driver.h
*
********************************************************************

 #include <epd_driver.h>
          ^~~~~~~~~~~~~~
compilation terminated.
*** [.pio/build/m5_paper/src/boards/M5Paper.o] Error 1
In file included from lib/Epub/EpubList/EpubIndex.h:13,
                 from src/main.cpp:9:
/Users/sn0wst0rm/.platformio/packages/toolchain-xtensa-esp32/xtensa-esp32-elf/sys-include/dirent.h:53:6: error: conflicting declaration of 'DIR* opendir(const char*)' with 'C' linkage
 DIR *opendir(const char *);
      ^~~~~~~
In file included from /Users/sn0wst0rm/.platformio/packages/toolchain-xtensa-esp32/xtensa-esp32-elf/sys-include/dirent.h:39,
                 from lib/Epub/EpubList/EpubIndex.h:13,
                 from src/main.cpp:9:
/Users/sn0wst0rm/.platformio/packages/framework-espidf/components/newlib/platform_include/sys/dirent.h:53:6: note: previous declaration with 'C++' linkage
 DIR* opendir(const char* name);
      ^~~~~~~
In file included from lib/Epub/EpubList/EpubIndex.h:13,
                 from src/main.cpp:9:
/Users/sn0wst0rm/.platformio/packages/toolchain-xtensa-esp32/xtensa-esp32-elf/sys-include/dirent.h:56:3: error: conflicting declaration of 'dirent* readdir(DIR*)' with 'C' linkage
   readdir(DIR *);
   ^~~~~~~
In file included from /Users/sn0wst0rm/.platformio/packages/toolchain-xtensa-esp32/xtensa-esp32-elf/sys-include/dirent.h:39,
                 from lib/Epub/EpubList/EpubIndex.h:13,
                 from src/main.cpp:9:
/Users/sn0wst0rm/.platformio/packages/framework-espidf/components/newlib/platform_include/sys/dirent.h:54:16: note: previous declaration with 'C++' linkage
 struct dirent* readdir(DIR* pdir);
                ^~~~~~~
In file included from lib/Epub/EpubList/EpubIndex.h:13,
                 from src/main.cpp:9:
/Users/sn0wst0rm/.platformio/packages/toolchain-xtensa-esp32/xtensa-esp32-elf/sys-include/dirent.h:58:6: error: conflicting declaration of 'int readdir_r(DIR*, dirent*, dirent**)' with 'C' linkage
 int  readdir_r(DIR *__restrict, struct dirent *__restrict,
      ^~~~~~~~~
In file included from /Users/sn0wst0rm/.platformio/packages/toolchain-xtensa-esp32/xtensa-esp32-elf/sys-include/dirent.h:39,
                 from lib/Epub/EpubList/EpubIndex.h:13,
                 from src/main.cpp:9:
/Users/sn0wst0rm/.platformio/packages/framework-espidf/components/newlib/platform_include/sys/dirent.h:59:5: note: previous declaration with 'C++' linkage
 int readdir_r(DIR* pdir, struct dirent* entry, struct dirent** out_dirent);
     ^~~~~~~~~
In file included from lib/Epub/EpubList/EpubIndex.h:13,
                 from src/main.cpp:9:
/Users/sn0wst0rm/.platformio/packages/toolchain-xtensa-esp32/xtensa-esp32-elf/sys-include/dirent.h:61:7: error: conflicting declaration of 'void rewinddir(DIR*)' with 'C' linkage
 void  rewinddir(DIR *);
       ^~~~~~~~~
In file included from /Users/sn0wst0rm/.platformio/packages/toolchain-xtensa-esp32/xtensa-esp32-elf/sys-include/dirent.h:39,
                 from lib/Epub/EpubList/EpubIndex.h:13,
                 from src/main.cpp:9:
/Users/sn0wst0rm/.platformio/packages/framework-espidf/components/newlib/platform_include/sys/dirent.h:57:6: note: previous declaration with 'C++' linkage
 void rewinddir(DIR* pdir);
      ^~~~~~~~~
In file included from lib/Epub/EpubList/EpubIndex.h:13,
                 from src/main.cpp:9:
/Users/sn0wst0rm/.platformio/packages/toolchain-xtensa-esp32/xtensa-esp32-elf/sys-include/dirent.h:72:7: error: conflicting declaration of 'void seekdir(DIR*, long int)' with 'C' linkage
 void  seekdir(DIR *, long);
       ^~~~~~~
In file included from /Users/sn0wst0rm/.platformio/packages/toolchain-xtensa-esp32/xtensa-esp32-elf/sys-include/dirent.h:39,
                 from lib/Epub/EpubList/EpubIndex.h:13,
                 from src/main.cpp:9:
/Users/sn0wst0rm/.platformio/packages/framework-espidf/components/newlib/platform_include/sys/dirent.h:56:6: note: previous declaration with 'C++' linkage
 void seekdir(DIR* pdir, long loc);
      ^~~~~~~
In file included from lib/Epub/EpubList/EpubIndex.h:13,
                 from src/main.cpp:9:
/Users/sn0wst0rm/.platformio/packages/toolchain-xtensa-esp32/xtensa-esp32-elf/sys-include/dirent.h:73:7: error: conflicting declaration of 'long int telldir(DIR*)' with 'C' linkage
 long  telldir(DIR *);
       ^~~~~~~
In file included from /Users/sn0wst0rm/.platformio/packages/toolchain-xtensa-esp32/xtensa-esp32-elf/sys-include/dirent.h:39,
                 from lib/Epub/EpubList/EpubIndex.h:13,
                 from src/main.cpp:9:
/Users/sn0wst0rm/.platformio/packages/framework-espidf/components/newlib/platform_include/sys/dirent.h:55:6: note: previous declaration with 'C++' linkage
 long telldir(DIR* pdir);
      ^~~~~~~
In file included from lib/Epub/EpubList/EpubIndex.h:13,
                 from src/main.cpp:9:
/Users/sn0wst0rm/.platformio/packages/toolchain-xtensa-esp32/xtensa-esp32-elf/sys-include/dirent.h:76:6: error: conflicting declaration of 'int closedir(DIR*)' with 'C' linkage
 int  closedir(DIR *);
      ^~~~~~~~
In file included from /Users/sn0wst0rm/.platformio/packages/toolchain-xtensa-esp32/xtensa-esp32-elf/sys-include/dirent.h:39,
                 from lib/Epub/EpubList/EpubIndex.h:13,
                 from src/main.cpp:9:
/Users/sn0wst0rm/.platformio/packages/framework-espidf/components/newlib/platform_include/sys/dirent.h:58:5: note: previous declaration with 'C++' linkage
 int closedir(DIR* pdir);
     ^~~~~~~~
*** [.pio/build/m5_paper/src/main.o] Error 1
================================================================================== [FAILED] Took 6.32 seconds ==================================================================================

Environment    Status    Duration
-------------  --------  ------------
m5_paper       FAILED    00:00:06.320

I noticed that in platform.ini config file, in the m5paper env section, there was not specified anywhere the m5stack/M5EPD library. I tried adding it as a dependency but as I thought it did not work because it is written to be built against the Arduino framework, while you use espidf.

Can you please tell me how you did get it to compile? It would be really appreciated!

Restart loop: Button pressed continuously

The ePub reader is continuously looping from start list Screen to open book and first page.
And then resetting in an eternal loop.
The strange part is that it's like if the button will be stuck on pressed state, but it's certainly not.

Serial output:

I (679045) PUBLIST: Rendering item 1
I (679255) EPUB: Reading item OEBPS/Images/cover.jpg
I (679685) JPG: JPEG Decoded - size 600,900, scale = 0.640000, 0.644444, 2
I (680495) PUBLIST: Rendering item 2
I (680685) EPUB: Reading item OEBPS/@public@vhost@g@gutenberg@html@files@43@43-h@[email protected]
I (681035) JPG: JPEG Decoded - size 500,862, scale = 0.768000, 0.672854, 2
I (683755) main: Selected epub /fs/el_aleph.epub
E (684635) task_wdt: Task watchdog got triggered. The following tasks did not reset the watchdog in time:
E (684635) task_wdt:  - IDLE (CPU 1)
E (684635) task_wdt: Tasks currently running:
E (684635) task_wdt: CPU 0: epd_fetch
E (684635) task_wdt: CPU 1: IDLE
E (684635) task_wdt: Print CPU 0 (current core) backtrace


Backtrace:0x40116FCB:0x3FFB0840 0x40084209:0x3FFB0860 0x4000BFED:0x3FFBAC30 0x40090CD5:0x3FFBAC40 0x4008E909:0x3FFBAC60 0x40082D5D:0x3FFBACA0 0x40090A21:0x3FFBB0D0 
  #0  0x40116FCB:0x3FFB0840 in task_wdt_isr at /home/martin/.platformio/packages/framework-espidf/components/esp_common/src/task_wdt.c:189
  #1  0x40084209:0x3FFB0860 in _xt_lowint1 at /home/martin/.platformio/packages/framework-espidf/components/freertos/port/xtensa/xtensa_vectors.S:1105
  #2  0x4000BFED:0x3FFBAC30 in ?? ??:0
  #3  0x40090CD5:0x3FFBAC40 in vPortExitCritical at /home/martin/.platformio/packages/framework-espidf/components/freertos/port/xtensa/port.c:472
  #4  0x4008E909:0x3FFBAC60 in xQueueGenericSend at /home/martin/.platformio/packages/framework-espidf/components/freertos/queue.c:954
  #5  0x40082D5D:0x3FFBACA0 in provide_out at lib/epdiy/epdiy/src/epd_driver/lut.c:427 

Continuous hour glass

I loaded the project via M5Burner and put the recommended epub file on the micro SD card. However, despite restarts/etc all I get is the hour glass, even after waiting a while. Is this user error, in which case can you provide a pointer? Thanks.

Display Margins

Currently, the words in the book go all the way to the edge of the display which doesn't look very nice. It would be nice if there was a small margin on either side.

SPIFFS reset loop

I (923) main: Controls configured
I (933) EPD: Full clear
E (2513) ZIP: mz_zip_reader_init_file() failed!

E (2513) ZIP: Error file open failed

E (2513) EPUB: Could not find META-INF/container.xml
Guru Meditation Error: Core  1 panic'ed (LoadProhibited). Exception was unhandled.

Help in adding a language.

Hello. Help please. I'm from Russia. And it turned out that this program does not support Cyrillic. Please add a language. Or please tell me how to add. I attach the book to the attachment for the test
80072670.zip
.

Error when using EPDiy PCB and a supported epaper

Maybe it's simply a conflict with I2C since EPDiy also uses this interface. Error in log shows the following:

I (536) cpu_start: Starting scheduler on PRO CPU.
I (0) cpu_start: Starting scheduler on APP CPU.
I (541) spiram: Reserving pool of 32K of internal memory for DMA/internal allocations
E (551) i2c: i2c_master_cmd_begin(1164): i2c driver not installed
ESP_ERROR_CHECK failed: esp_err_t 0x103 (ESP_ERR_INVALID_STATE) at 0x4008c860
file: "lib/epdiy/config_reg_v6.h" line 86
func: push_cfg
expression: pca9555_set_value(reg->port, value, 1)
abort() was called at PC 0x4008c863 on core 1  --> Continuous reboot

V6 uses concretely I2C in pca9555.c that is a GPIO expander. The temporal solution might be to instantiate current L58 touch only if the display is LilyGo EPD47.
But still it should be possible to instantiate somehow another I2C interface in case we use another touch overlay.

Setup:
EPDiy V6

Not all HTML entities are being parsed

We get some out of the box functionality from the XML parser, but the majority of HTML entities are ignore and come out as is:

e.g.

&nbspc;

There is a list of all valid entities in the file lib/Epub/RubbishHtmlParser/htmlEntities.h

It would be good to also handle unicode escapes. e.g:

&#x20AC;

This could be done at parsing time or it could be done during text measurement and drawing. Probably easier to do at parse time when the text is being collected.

Parse the `application/x-dtbncx+xml` file and generate a table of contents

This would be one very interesting option if it can be done. And it's what in another ePub readers comes as "Content". My best guess is that the manifest is listed:

<manifest>
    <item href="Text/Introduccion.xhtml" id="Introduccion.xhtml" media-type="application/xhtml+xml"/>
    <item href="Text/Capitulo1.xhtml" id="Capitulo1.xhtml" media-type="application/xhtml+xml"/>
    <item href="Text/Capitulo2.xhtml" id="Capitulo2.xhtml" media-type="application/xhtml+xml"/>
    <item href="Text/Capitulo3.xhtml" id="Capitulo3.xhtml" media-type="application/xhtml+xml"/>
</manifest>

The tricky part is that the title is not there. So I guess the xhtml should be read in order to extract is. As a result it should render:

Introduction
Title of chapter 1, etc.

And same as in the book index, going up and down will draw a selected rectangle, and on SELECT should go directly open that html so you can go to a section directly.
This will improve usability a lot since you should not start always from the beginning. But I know is a pretty tricky one to get working.

Additionally to this I'm happy about #28 but not entirely satisfied with it. This page state should be saved in a non volatile storage. Even a key value store in the NVS will do a much better job than saving it like this since it's lost on every reset.

epdiy version: Add a way to read 2 buttons from PCA9555 IO expander

The problem with V6 is that I would like to add the microSD card reader and I don't have enough GPIOs for everything.
Luckily Valentin though about this and added an IO expander. So my idea to solve in this ticket and future PR is to read < and > buttons using I2C.
So the only one that will be read the standard way when using V6 is the SELECT one (And the only that will serve to wake-up)
pca9555

After checking the datasheet I see that I need to add a external pull-up to this two IOs and then there is a function already written here:
https://github.com/vroland/epdiy/blob/8b4302a6a650a5c228520c100b862aba60978c2c/src/epd_driver/config_reg_v6.h#L36
Basically if I understand good how to do it, I need to call this function in a loop, and it will return the IO that is turned LOW.

So the button will just put the IO to ground and I have to scan this.

@cgreening another thing that I detected on V6 is that when using the BUTONS_ACTIVE_LEVEL=1 when pressed, the debounce is not working properly and everytime I make a click the button is pressed at least two times.
From the ugly hacks department, I'm thinking to make a copy of ButtonControls.h to ButtonControlsEpdiy.h and control this two buttons reading I2C that I have no idea if it will work like expected.

But if it does then I will have enough pins to add the SD via SPI and even one more to control Frontlight PWM intensity.

Research links:
Calling xTaskCreate on C++ member function?

Touch thoughts

I've done a bit of refactoring on the touch code - not sure if it's really correct yet.

A couple of thoughts I had.

It's quite hard to hit the buttons - we could:

When reading a book, go to the next page by tapping the right of the screen and go left by tapping the left of the screen. Get back to the main menu by tapping near the top of the screen.

When selecting books got up and down by tapping the top and bottom of the screen and select by tapping in the centre - not sure how intuitive that is though...

Is it possible with the touch library to detect a "touch up" ie the end of the touch interaction when the finger is removed from the screen? That would be a good point to kick off the interaction.

I need to pull a lot of the code out of the main function so that it's a bit easier to drive the UI from controls. I'll make a start on that next.

Possibility to use SPIFFs as MicroSD reader alternative

I will get a new SD card of 2GB since I've only one and it's on the 3D-printer.
But I was thinking maybe you can add also the option to use SPIFFS file system on the ESP32. I guess there will be space for a few books there and it makes the whole thing more portable since you don't need to carry around that monstrosity of hanging SPI cables ;)
Just a suggestion since I think only thing that changes is initialization, then it's just another File System to be read.
Then you can have a define constant of FS_TYPE and select between 2 systems.

Page memory per book

Mission: To have the Epub reader to conserve the page number for each book, when you switch between Epub list mode and read mode. So you can read different books at the same time without the need to press the next page a zillion of times to get to the last page you read.
Would be complicated to store a key-> value table in NVS to add this feature?

Characters that are missing and replaced by ?

... Page 18 of the poetry book
¯ No idea if it's exacly this char but it's called "macron" and it's like the _ but in the center.

in a book I also saw an html space entity:

&nbsp;

not being parsed. This is now addressed in #34

Related to #36

Maybe we can detect more and make a special character, for example the 3 dots could be text replaced by 3 real dots, that's a no brainer. And then for the exceptions we replace by " " space that will be in my opinion the safest way to go.

Finally we can address in this Issue also a layout issue. How to reproduce: Poetry book, where in one page is full of text and in the other just a title. Then this is what happens (image)
2CCD7BE8-A315-4BA3-8F83-52B877D43D3B

Add touch gestures Swipe and double Tap

First I will have to add this in my component, so the blocker is this issue in Focal Tech repository
The basic idea is to add first Swipe left and right gestures provided it does not affect Tap detection.
Then here I will add this Event as UP or DOWN so you can pass the pages of the book swaping the finger in the screen.

Touch issue on Lilygo environment

@cgreening can you tell me if you also experience this:

-D CONFIG_FT6X36_DEBUG=1

With the touch serial output activated it works. When I turn this to 0 it keeps on working but not like before.
For example if you go to the new table of contents, it works for the first 2 and then it just stops. Very strange like if having the Serial output makes it work better.

LilyGo_T5_47 upload the code enter reboot cycle

After upload the code lilygo enter reboot cycle. The log is below.

Rebooting...
ets Jul 29 2019 12:21:46

rst:0xc (SW_CPU_RESET),boot:0x33 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:2
load:0x3fff0030,len:4996
load:0x40078000,len:14436
load:0x40080400,len:3240
entry 0x40080610
I (481) psram: This chip is ESP32-D0WD
I (482) spiram: Found 64MBit SPI RAM device
I (482) spiram: SPI RAM mode: flash 80m sram 80m
I (484) spiram: PSRAM initialized, cache is in low/high (2-core) mode.
I (492) cpu_start: Pro cpu up.
I (495) cpu_start: Starting app cpu, entry point is 0x400840c0
I (489) cpu_start: App cpu up.
I (517) cpu_start: Pro cpu start user code
I (517) cpu_start: cpu freq: 240000000
I (517) cpu_start: Application information:
I (522) cpu_start: Project name: epub-reader
I (527) cpu_start: App version: e849c1e-dirty
I (533) cpu_start: Compile time: Jan 3 2022 18:07:48
I (539) cpu_start: ELF file SHA256: bf1bf981faa088a8...
I (545) cpu_start: ESP-IDF: 4.3.1
I (550) heap_init: Initializing. RAM available for dynamic allocation:
I (557) heap_init: At 3FFAE6E0 len 00001920 (6 KiB): DRAM
I (563) heap_init: At 3FFB80E0 len 00027F20 (159 KiB): DRAM
I (569) heap_init: At 3FFE0440 len 00003AE0 (14 KiB): D/IRAM
I (575) heap_init: At 3FFE4350 len 0001BCB0 (111 KiB): D/IRAM
I (582) heap_init: At 40095C2C len 0000A3D4 (40 KiB): IRAM
I (588) spiram: Adding pool of 4096K of external SPI memory to heap allocator
I (596) spi_flash: detected chip: generic
I (600) spi_flash: flash io: dio
I (610) cpu_start: Starting scheduler on PRO CPU.
I (0) cpu_start: Starting scheduler on APP CPU.
I (615) spiram: Reserving pool of 32K of internal memory for DMA/internal allocations
I (625) main: epub list state num_epubs=0
I (625) main: epub list state is_loaded=0
I (635) main: epub list state selected_item=0
I (635) main: Memory before main task start 4413491
I (645) main: Powering up the board
I (645) main: Creating renderer
I (715) main: Starting file system
I (715) main: Using SPIFFS
I (715) SPIFFS: Initializing SPIFFS
I (935) main: Starting battery monitor
I (935) main: Setting up controls
i2c_driver started correctly
I (935) gpio: GPIO[13]| InputEn: 1| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:1
E (945) gpio: gpio_install_isr_service(460): GPIO isr service already installed
ISR trigger install response: 0x103
I (955) main: Controls configured
I (955) EPD: Full clear

abort() was called at PC 0x400851c7 on core 0

Backtrace:0x4008ed8e:0x3ffbe860 0x4008f509:0x3ffbe880 0x40094862:0x3ffbe8a0 0x400851c7:0x3ffbe910 0x40085325:0x3ffbe940 0x400853c1:0x3ffbe960 0x4012eaed:0x3ffbe990 0x40125f13:0x3ffbec50 0x40125d36:0x3ffbeca0 0x40092307:0x3ffbecd0 0x4008fdcf:0x3ffbed00 0x4008307d:0x3ffbed40 0x4009213d:0x3ffbf170
#0 0x4008ed8e:0x3ffbe860 in panic_abort at C:\Users\ddj1.platformio\packages\framework-espidf\components\esp_system/panic.c:368
#1 0x4008f509:0x3ffbe880 in esp_system_abort at C:\Users\ddj1.platformio\packages\framework-espidf\components\esp_system/system_api.c:112
#2 0x40094862:0x3ffbe8a0 in abort at C:\Users\ddj1.platformio\packages\framework-espidf\components\newlib/abort.c:46
#3 0x400851c7:0x3ffbe910 in lock_acquire_generic at C:\Users\ddj1.platformio\packages\framework-espidf\components\newlib/locks.c:139
#4 0x40085325:0x3ffbe940 in _lock_acquire_recursive at C:\Users\ddj1.platformio\packages\framework-espidf\components\newlib/locks.c:167 #5 0x400853c1:0x3ffbe960 in __retarget_lock_acquire_recursive at C:\Users\ddj1.platformio\packages\framework-espidf\components\newlib/locks.c:323
#6 0x4012eaed:0x3ffbe990 in _vfiprintf_r at /builds/idf/crosstool-NG/.build/HOST-x86_64-w64-mingw32/xtensa-esp32-elf/src/newlib/newlib/libc/stdio/vfprintf.c:853 (discriminator 2)
#7 0x40125f13:0x3ffbec50 in fiprintf at /builds/idf/crosstool-NG/.build/HOST-x86_64-w64-mingw32/xtensa-esp32-elf/src/newlib/newlib/libc/stdio/fiprintf.c:48
#8 0x40125d36:0x3ffbeca0 in __assert_func at /builds/idf/crosstool-NG/.build/HOST-x86_64-w64-mingw32/xtensa-esp32-elf/src/newlib/newlib/libc/stdlib/assert.c:58 (discriminator 8)
#9 0x40092307:0x3ffbecd0 in spinlock_acquire at C:\Users\ddj1.platformio\packages\framework-espidf\components\esp_hw_support\include/soc/spinlock.h:122
(inlined by) vPortCPUAcquireMutex at C:\Users\ddj1.platformio\packages\framework-espidf\components\freertos\port\xtensa\include/freertos/portmacro.h:158
(inlined by) vPortEnterCritical at C:\Users\ddj1.platformio\packages\framework-espidf\components\freertos\port\xtensa/port.c:448
#10 0x4008fdcf:0x3ffbed00 in xQueueGenericSend at C:\Users\ddj1.platformio\packages\framework-espidf\components\freertos/queue.c:790
#11 0x4008307d:0x3ffbed40 in provide_out at lib/epdiy/lut.c:427
#12 0x4009213d:0x3ffbf170 in vPortTaskWrapper at C:\Users\ddj1.platformio\packages\framework-espidf\components\freertos\port\xtensa/port.c:168

ELF file SHA256: bf1bf981faa088a8

Update to latest epdiy restarts

If you do a: git submodules update --remote then epiy get's last update:

epdiy @ 8b4302a

Currently is:
epdiy @ 07925dc -> Works

Updating to the latest generates this backtrace:

Backtrace:0x400dda2a:0x3ffcc550 0x400d281f:0x3ffcc5a0 0x400e03d9:0x3ffcc5f0 0x400dfa85:0x3ffcc6a0 0x400d29e6:0x3ffcc720 0x400d2a9c:0x3ffcc740 0x400d2d66:0x3ffcc760 0x40090a21:0x3ffcc7c0
  #0  0x400dda2a:0x3ffcc550 in utf8_len at lib/epdiy/epdiy/src/epd_driver/font.c:46
      (inlined by) next_cp at lib/epdiy/epdiy/src/epd_driver/font.c:62
      (inlined by) epd_get_text_bounds at lib/epdiy/epdiy/src/epd_driver/font.c:248

Transparent background PNG shown as black

This can be tested on the poetry book from Pizarnik. On this books this EPublibre logo comes with transparent background:
03CA4331-F9CA-4CDA-A78E-4D26102E988F

@cgreening is there a way to detect when there is transparent background and render it as white instead of black?

I remember EPDiy had a function called

441 | static void draw_rotated_transparent_image(EpdRect image_area, const uint8_t *image_buffer, uint8_t *framebuffer, uint8_t *transparent_color)

But I really don’t have any idea about PNG since I never worked with this image format. Only thing I know is that supports transparent backgrounds just as gif.

Restart loop when a file is not found in ePub

Hi Chris,
I found this using this book that I you can download here "El Aleph":
https://freeditorial.com/es/books/el-aleph

In Serial I see the following output:

I (804) Controls: ULP Wakeup
I (2164) main: Creating epub list
E (3234) ZIP: Could not find file OEBPS/content.opf
E (3234) EPUB: Error parsing content.opf - XML_ERROR_EMPTY_DOCUMENT
Guru Meditation Error: Core  1 panic'ed (LoadProhibited). Exception was unhandled.

In my opinion it should not restart when it does not find a related file. Note that I got this restart loop at start when it's making the list, not when opening the book.

Update: With most of the books of freeditorial it does not work. It seems they are missing something but they do open in another ePub readers (iPad and Android)

Add support for sup and sub html tags

We'll need to check how much room we have for more fonts - I'm wondering if the epdiy library could be modified to support scaling of existing fonts. That might give us an easy way of drawing fonts at half size for the super and subscript text.

Build instructions and first issues

Hi Chris,
trying to compile this using PlatformIO and wanted to report first problems, so we can build proper build instructions.

  1. First found, in order to hit the Build button and start with the right environment this should be added to platformio.ini
[platformio]
default_envs = lilygo_t5_47 

So it selects that env by default.

  1. got this error when building after the default_envs setting
1/7] Generating esp32.ulp.ld
[2/7] Generating main.ulp.S
[3/7] Building ASM object CMakeFiles/ulp_main.dir/main.ulp.S.obj
[4/7] Linking ASM executable ulp_main
FAILED: ulp_main 
: && esp32ulp-elf-ld                                   -A elf32-esp32ulp -nostdlib CMakeFiles/ulp_main.dir/main.ulp.S.obj -o ulp_main  -T/home/martin/esp/projects/diy-esp32-epub-reader/.pio/build/lilygo_t5_47/esp-idf/src/ulp_main/esp32.ulp.ld  -Map=/home/martin/esp/projects/diy-esp32-epub-reader/.pio/build/lilygo_t5_47/esp-idf/src/ulp_main/ulp_main.map && :
esp32ulp-elf-ld: ulp_main section `.text' will not fit in region `ram'
esp32ulp-elf-ld: region `ram' overflowed by 140 bytes
ninja: build stopped: subcommand failed.
Compiling .pio/build/lilygo_t5_47/bootloader_support/src/bootloader_clock.o
Compiling .pio/build/lilygo_t5_47/bootloader_support/src/bootloader_common.o
Compiling .pio/build/lilygo_t5_47/bootloader_support/src/bootloader_flash.o
Compiling .pio/build/lilygo_t5_47/bootloader_support/src/bootloader_mem.o
Compiling .pio/build/lilygo_t5_47/bootloader_support/src/bootloader_random.o
Compiling .pio/build/lilygo_t5_47/bootloader_support/src/bootloader_random_esp32.o
Compiling .pio/build/lilygo_t5_47/bootloader_support/src/bootloader_utility.o
*** [.pio/build/lilygo_t5_47/esp-idf/src/ulp_main/ulp_main.h] Error 1

Additional Info:

PACKAGES: 
 - framework-espidf 3.40200.210118 (4.2.0) 
 - tool-cmake 3.16.4 
 - tool-esptoolpy 1.30000.201119 (3.0.0) 
 - tool-ninja 1.7.1 
 - toolchain-esp32ulp 1.22851.191205 (2.28.51) 
 - toolchain-xtensa32 2.80400.210211 (8.4.0)

@cgreening can you understand where is the problem with the missing ULP here? According to this post it should be already solved in this IDF version.

Additionally I would like to know what will be the minimum ESP-IDF framework version required and if it will be possible to compile this on command line using idf.py build (I guess no, since some lib dependences are managed by platformio)

UPDATE: Using esp-idf 4.3.0 it compiles further ( It requires then version >= 4.3? )

Next error hit is:

*** [.pio/build/lilygo_t5_47/bootloader/soc/src/cpu_util.o] 
Source `/home/martin/.platformio/packages/framework-espidf/components/soc/src/cpu_util.c' not found, needed by target `.pio/build/lilygo_t5_47/bootloader/soc/src/cpu_util.o'.

That is strange, there is no such a file in the .platformio/packages directory

martin@martin-IdeaPad:~$ ls /home/martin/.platformio/packages/framework-espidf/components/soc/
CMakeLists.txt  esp32c3  include    memory_layout_utils.c
component.mk    esp32s2  linker.lf  README.md
esp32           esp32s3  lldesc.c   soc_include_legacy_warn.c

Second error hit, seems related to this issue:

Library Manager: tinyxml2 @ 0.0.0+20211002104647.sha.a977397 has been installed!
Generating assembly for certificate bundle...
CMake Error at /home/martin/.platformio/packages/framework-espidf/tools/cmake/scripts/data_file_embed_asm.cmake:26 (file):
  file failed to open for reading (No such file or directory):

    /home/martin/esp/projects/diy-esp32-epub-reader/.pio/build/lilygo_t5_47/x509_crt_bundle

Headers should not be justified, should be centred or left aligned.

Currently, headers are treated just like paragraphs and end up justified which looks a bit odd. They should just be left-aligned or centred.

I think the easiest way to implement this is to pass a format flag to the text block that tells it how the text should be laid out - left-aligned, centred, justified, right-aligned.

The layout code can then look at this and decide what to do when it positions the words on a line. At the moment it takes all the spare space and places it between the words. We can change this so that for:

  • left-aligned - we just ignore the spare space and position the words from left to right
  • centred - we place half the spare space at the start of the line
  • right-aligned - we place the all the spare space at the start of the line
  • justified - behaves as it does not

Wake up periodically to refresh the battery display

At the moment, you could go to sleep and never wake up as the battery would have died.

We should probably wake up every hour or so to refresh the battery display - maybe could get fancy and show a needs charging icon if the battery is very low.

Split the rendering of the display from the model objects

It would be good to move towards the MVC (Model View Controller) pattern for the UI to make the code a bit cleaner. At the moment classes like the EpubList and EpubReader have everything in them with some of the controller code in the main.cpp as well.

Ideally, we'd have a model class that contains the state, a controller class that responds to user events and updates the model and then a view class that renders the current state of the model.

User Event (touch, button_press) -> Controller -> Model Update -> View Rendered

This will be a fairly chunky refactor.

Top margin lost and touch becomes irresponsive

This happened to me after the nice refactoring from controls and touch. No idea if it’s something related or not but could not experience it before.
Also no clues from Serial. Touch events sometimes after browsing many pages disappears and touching the screen I can see any output in Serial. After that keeps on working with the buttons but top margin is kind of lost (see photo)
UPDATE: This bug is already solved! The freeze one is still under research and hard to reproduce.
EB8C55B3-A291-4063-8E09-43B408D9F722

after some more pagination it works again. This happened to me browsing Section0028 of the following poetry book: piedra_Pizarnik.EPub

Second glitch:
Same as before after navigating many pages doing a button SELECT, just displays the hourglass (Half printed) and hangs there. Will try to catch the Serial output for this one.

Third glitch:
Even with the new Waveform that it works much better as before, we should do a full refresh every 3 or 4 pages read. Reading the book added in last commit: data/el_aleph.epub
After some pages the old text mixes with the new one making further lecture almost impossible (See additional picture)
8FEE485B-0DA5-445A-BF50-A7D3114880C0

Note this is hard to reproduce and I still can read many pages clearly before hitting this issue. It does not come always and I'm not sure if it's a bug of EPDiy or it's because we need to just make a full epd_fullclear and refresh every now and then or there is something more.

Intermitent error after many deepsleep and wakeup

I'm experiencing this restart while debugging and waking up with the buttons:

I (279) main: Using SPIFFS
I (279) SPIFFS: Initializing SPIFFS
I (519) main: Memory after sdcard init: 3250087
I (519) Controls: ULP Wakeup
I (519) EPD: Hydrating EPD
I (519) EPD: Front buffer compressed size: 0
E (519) EPD: Failed to allocate memory for front buffer
I (629) EPD: Back buffer compressed size: 44237

Any idea why it fails allocating the Front buffer?

Detect touches on the epub items in the list view to navigate to the book

It would be nice in the epub list view to be able to tap on a book to open it. We could also page up and page down buttons to the top and bottom of the screen to navigate through the pages.

As an added bonus - we could have a page indicator in the top margin - maybe a set of circles with a filled circle indicating the currently active page?

Screenshot 2021-10-09 at 11 12 30

Improve wake up performance when reading a book

We "dehydrate" the state of the epub list so that when we come back from deep sleep it's quite fast to update.

When reading a book we need to redo the parsing and layout of the current section. Can we persist the state of reading as well?

EPDiy reading SPI microSD

  • Set the right IOs for SD card SPI
  • Correct ADC channel:to reflect GPIO 34

Updated the ADC channel:
; Adc channel that is connected to the battery voltage divider - this is GPIO_NUM_34 in EPDiy V6
-D BATTERY_ADC_CHANNEL=ADC1_CHANNEL_6

But still shows the battery empty. I was told the voltage divider was connected to IO 34. Got it there is a bridge I need to close in the PCB, will document it later in the Wiki.
schematic-v6.pdf

Related to #60

Adding experimental touch

Hi Chris,
started a fork here: https://github.com/martinberlin/diy-esp32-epub-reader-touch

with the mission to add touch (If I can, really experimental)
And I wanted to leave this topic to ask you about building an ESP-IDF project with Platformio since it's my first time and for sure I will make lot's of mistakes.
For example in this commit just added my touch component in lib folder.
But I'm still trying to guess how I tell Platformio to include this in the build process. In IDF I do that using CMakeLists in the component folder but here I'm a bit lost. Can you share your knowledge with me?
Thanks in advance

Optimization: Making the display flush faster and other ideas

Hi Chris, this is working already great but I have some ideas that I wanted to share with you.
First I'm suspecting that most of the pages are rendering with MODE_GC16 update mode that is not the faster if you need to render only black/white text.

Adding a Serial output here:

void flush_display()
  {
    printf("needs_gray:%d\n", needs_gray_flush);
    epd_hl_update_screen(&m_hl, needs_gray_flush ? MODE_GC16 : MODE_DU, 20);
    needs_gray_flush = false;
  }

You can see that even on pages where is pure text, needs_gray is always true. This should be corrected since it will make navigating pages much faster!

Another optimization tip can be to use a smaller hourglass (Maybe half the size) that will also help to be a bit faster. But mainly the MODE_GC16 should be only used on the pages that render images and need grayscale.

As a resume:

  • MODE_GC16 only on pages that require it
  • Smaller visual indicator when a button is pressed (optional)
    Showing a small visual indicator in the top bar is enough and it has the benefit that does not leave ghosting in the center of the screen as it is now.
  • Battery indicator is shown always full for me even if it's almost no power left (last wish, not important)

Book titles should break on spaces and not in the middle of words

At the moment the layout of the book titles is a bit rubbish - it just breaks the lines when it runs out of space. It would be nice to either:

  • Break on whitespace
  • Use the DP approach for line breaking

The first option is probably the simplest to implement and would be a massive improvement on the current display.

SDCard very flaky

SDCard usage seems to be extremely flaky on both the lilygo and the m5 paper. Not sure why as the code has not really changed in that area.

Make the busy indicator "nicer"

It's a bit big and not very nice at the moment.

Maybe we should move it to the header area when reading a book and when browsing the book list have a nicer icon?

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.