# Driver for IT8951 E-Paper display

The driver uses the embedded_hal traits as hardware abstraction layer.
This driver can be used with the embedded graphics trait, currently only supporing Gray4 (16bit grayscale).

## Details
- IT8951 has a image load engine which can convert pixel data before storing it in the local frame  buffer.
- It is possible to read and write the memory directly without using the image load engine
- **Important** Data must be always aligned to 16bit words!
- The crates uses the alloc feature to allocate memory on the heap:
    - Firmware and LUT version string read from the controller
    - Staging buffers to write pixel to the controller. The buffers are allocated as needed, but only one buffer at a time and with up to `Config::max_buffer_size`, which is 1kByte per default.

## Supported devices

It should support all waveshare devices using the IT8951 controller over SPI.
These e-ink screens are known to be working

* [7.8 inch, 1872×1404 pixels, 4-bit grayscale](https://www.waveshare.com/wiki/7.8inch_e-Paper_HAT)
* [10.3 inch, 1872×1404 pixels, 4-bit grayscale](https://www.waveshare.com/wiki/10.3inch_e-Paper_HAT) **Important** This screen needs to be initialized with origin of `TopRight` to be working correctly

## Performance Considerations
Always prefer the embedded_graphics `fill_solid` and `fill_contiguous` functions over `draw_iter`.
`draw_iter` writes every single pixel to the display, which has a significant overhead.

### Improve Drawing Speed e.g. for Fonts
If you embedded_graphics UI uses a lot of `draw_iter` calls, e.g. for font rendering, please consider using the textbox locally.
A suitable crate is [embedded-graphics-framebuf](https://crates.io/crates/embedded-graphics-framebuf). 
An example can be found in the `test_eink` example.
The idea is to create a local framebuffer to render into, with only the required dimensions e.g. 100x20px on an 1000x800px display.
The local framebuffer can be written sparsely using `draw_iter`. 
Afterwards the full local framebuffer is written to the display using `fill_contiguous`.
On an 200x30px sized Text as used in the example the speed-up is roughly 10x.

### Allocation details
The general approach of this crate is to dynamically allocate buffers with the smallest possible size.
Meaning the required heap is minimized, but new allocations & releases may happen more often.

We are currently discussing approaches without alloc. If you have any opinion on this please get in touch. 

## TODOs
- Support Gray2 and Gray8 with embedded-graphics
- Support display engine fill area
- Support display engine 1 bit per pixel mode
- Support static buffer allocations

## Changelog

### 0.5.1
- Reset pin is optional
- VCOM during init is optional

### 0.5.0
- Add optional defmt support
- Add display origin support (fixes mirroring on certain devices)
- Allow setting memory buffer address

### 0.4.2
- add display rotation support
- Exponential backoff for `wait_while_busy`

### 0.4.1
- fix divide by zero in fill_solid for zero sized area
- fill_solid correctly skip limit areas to the display bounds

### 0.4.0
- **Public API** `new` expects a `Config` parameter to set timeout and buffer size. Default is implemented with timeouts of 15s and buffer size is 1024 Bytes.    
- Buffer data type changed from u16 to u8
    - **Public API**: `load_image_area`, `load_image`, and `memory_burst_write` functions are now using u8 as buffer type
    - Memory usage is reduced by half (1kByte max. instead of 2kByte)
- **Behavior** Calling `init` no longer clears the eink display. Instead call `reset` directly.
