#![no_std]
#[cfg(feature = "heap_buffer")]
extern crate alloc;
#[cfg(feature = "std")]
extern crate std;
#[cfg(feature = "heap_buffer")]
use alloc::boxed::Box;
mod command;
pub mod error;
use command::*;
use error::Error;
use embedded_graphics::{
draw_target::DrawTarget, geometry::OriginDimensions, geometry::Size, pixelcolor::BinaryColor,
Pixel,
};
use embedded_hal::digital::{InputPin, OutputPin};
#[cfg(feature = "async")]
use embedded_hal_async::{spi::SpiDevice, digital::Wait};
#[cfg(feature = "async")]
use embedded_hal_async::delay::DelayNs;
#[cfg(not(feature = "async"))]
use embedded_hal::spi::SpiDevice;
#[cfg(not(feature = "async"))]
use embedded_hal::delay::DelayNs;
pub struct GDEH0154D67<SPI, DC, RST, BSY, DLY, S> {
interface: SPI,
#[cfg(feature = "heap_buffer")]
buffer: Box<Buffer>,
#[cfg(not(feature = "heap_buffer"))]
buffer: Buffer,
dc: DC,
reset: RST,
busy: BSY,
delay: DLY,
#[allow(dead_code)]
state: S,
}
pub struct Initialized;
pub struct NotInitialized;
const PIXELS_X: usize = 200;
const PIXELS_Y: usize = 200;
struct Buffer {
pixels: [u8; PIXELS_X*PIXELS_Y/8],
flags: [u8; PIXELS_X*PIXELS_Y/8],
}
impl<SPI, DC, RST, BSY, DLY> GDEH0154D67<SPI, DC, RST, BSY, DLY, NotInitialized>
where
SPI: SpiDevice,
DC: OutputPin,
RST: OutputPin,
BSY: InputPin,
DLY: DelayNs,
{
pub fn new(interface: SPI, dc: DC, reset: RST, busy: BSY, delay: DLY) -> Result<Self, Error> {
Ok(Self {
interface,
#[cfg(feature = "heap_buffer")]
buffer: Box::new(Buffer {
pixels: [0; PIXELS_X*PIXELS_Y/8],
flags: [0; PIXELS_X*PIXELS_Y/8],
}),
#[cfg(not(feature = "heap_buffer"))]
buffer: Buffer {
pixels: [0; PIXELS_X*PIXELS_Y/8],
flags: [0; PIXELS_X*PIXELS_Y/8],
},
dc,
reset,
busy,
delay,
state: NotInitialized,
})
}
pub fn release(self) -> Result<(SPI, DC, RST, BSY), Error> {
Ok((self.interface, self.dc, self.reset, self.busy))
}
}
#[cfg(not(feature = "async"))]
mod blocking {
use super::*;
use embedded_hal::spi::SpiDevice;
impl<SPI, DC, RST, BSY, DLY> GDEH0154D67<SPI, DC, RST, BSY, DLY, NotInitialized>
where
SPI: SpiDevice,
DC: OutputPin,
RST: OutputPin,
BSY: InputPin,
DLY: DelayNs,
{
pub fn init(mut self) -> Result<GDEH0154D67<SPI, DC, RST, BSY, DLY, Initialized>, Error> {
self.reset()?;
DriverOutputControl([0xc7, 0x00, 0b000])
.send(&mut self.interface, &mut self.dc)
.unwrap();
DataEntryModeSetting([0b011])
.send(&mut self.interface, &mut self.dc)
.unwrap();
SetRamXAddressStartEndPosition([0x00, 0x18])
.send(&mut self.interface, &mut self.dc)
.unwrap();
SetRamYAddressStartEndPosition([0x00, 0x00, 0xc7, 0x00])
.send(&mut self.interface, &mut self.dc)
.unwrap();
TemperatureSensorWrite([0x43, 0x20])
.send(&mut self.interface, &mut self.dc)
.unwrap();
DisplayUpdateControl2([0xb1])
.send(&mut self.interface, &mut self.dc)
.unwrap();
MasterActivation
.send(&mut self.interface, &mut self.dc)
.unwrap();
self.busy_block().unwrap();
Ok(GDEH0154D67 {
interface: self.interface,
buffer: self.buffer,
dc: self.dc,
reset: self.reset,
busy: self.busy,
delay: self.delay,
state: Initialized,
})
}
}
impl<SPI, DC, RST, BSY, DLY> GDEH0154D67<SPI, DC, RST, BSY, DLY, Initialized>
where
SPI: SpiDevice,
DC: OutputPin,
RST: OutputPin,
BSY: InputPin,
DLY: DelayNs,
{
pub fn partial_update(&mut self) -> Result<(), Error> {
for (idx, val) in self
.buffer
.flags
.chunks_mut(1)
.enumerate()
.filter(|(_, val)| val[0] != 0)
{
let idx = idx as usize;
let (x, y) = index2address(idx);
SetRamXAddressPosition([x])
.send(&mut self.interface, &mut self.dc)
.unwrap();
SetRamYAddressPosition([y, 0x00])
.send(&mut self.interface, &mut self.dc)
.unwrap();
let raw_data = self.buffer.pixels;
WriteRam(&[raw_data[idx]])
.send(&mut self.interface, &mut self.dc)
.unwrap();
val[0] = 0;
}
DisplayUpdateControl2([0xc7])
.send(&mut self.interface, &mut self.dc)
.unwrap();
MasterActivation
.send(&mut self.interface, &mut self.dc)
.unwrap();
self.busy_block()
}
pub fn full_update(&mut self) -> Result<(), Error> {
SetRamXAddressPosition([0x00])
.send(&mut self.interface, &mut self.dc)
.unwrap();
SetRamYAddressPosition([0x00, 0x00])
.send(&mut self.interface, &mut self.dc)
.unwrap();
WriteRam(&self.buffer.pixels)
.send(&mut self.interface, &mut self.dc)
.unwrap();
DisplayUpdateControl2([0xc7])
.send(&mut self.interface, &mut self.dc)
.unwrap();
MasterActivation
.send(&mut self.interface, &mut self.dc)
.unwrap();
self.busy_block()
}
pub fn release(self) -> Result<(SPI, DC, RST, BSY), Error> {
let display = self.turn_off().unwrap();
Ok((display.interface, display.dc, display.reset, display.busy))
}
}
impl<SPI, DC, RST, BSY, DLY, S> GDEH0154D67<SPI, DC, RST, BSY, DLY, S>
where
SPI: SpiDevice,
DC: OutputPin,
RST: OutputPin,
BSY: InputPin,
DLY: DelayNs,
{
pub fn turn_off(mut self) -> Result<GDEH0154D67<SPI, DC, RST, BSY, DLY, NotInitialized>, Error> {
DeepSleepMode([0x1])
.send(&mut self.interface, &mut self.dc)
.unwrap();
Ok(GDEH0154D67 {
interface: self.interface,
buffer: self.buffer,
dc: self.dc,
reset: self.reset,
busy: self.busy,
delay: self.delay,
state: NotInitialized,
})
}
fn reset(&mut self) -> Result<(), Error> {
self.reset.set_low().unwrap();
DelayNs::delay_ms(&mut self.delay, 10);
self.reset.set_high().unwrap();
DelayNs::delay_ms(&mut self.delay, 10);
SwReset.send(&mut self.interface, &mut self.dc).unwrap();
self.busy_block()
}
fn busy_block(&mut self) -> Result<(), Error> {
while self.busy.is_high().unwrap() {
DelayNs::delay_ms(&mut self.delay, 10);
}
Ok(())
}
}
}
#[cfg(feature = "async")]
mod asynchronous {
use super::*;
impl<SPI, DC, RST, BSY, DLY> GDEH0154D67<SPI, DC, RST, BSY, DLY, NotInitialized>
where
SPI: SpiDevice,
DC: OutputPin,
RST: OutputPin,
BSY: InputPin + Wait,
DLY: DelayNs,
{
pub async fn init(mut self) -> Result<GDEH0154D67<SPI, DC, RST, BSY, DLY, Initialized>, Error> {
self.reset().await?;
DriverOutputControl([0xc7, 0x00, 0b000])
.send(&mut self.interface, &mut self.dc)
.await?;
DataEntryModeSetting([0b011])
.send(&mut self.interface, &mut self.dc)
.await?;
SetRamXAddressStartEndPosition([0x00, 0x18])
.send(&mut self.interface, &mut self.dc)
.await?;
SetRamYAddressStartEndPosition([0x00, 0x00, 0xc7, 0x00])
.send(&mut self.interface, &mut self.dc)
.await?;
TemperatureSensorWrite([0x43, 0x20])
.send(&mut self.interface, &mut self.dc)
.await?;
DisplayUpdateControl2([0xb1])
.send(&mut self.interface, &mut self.dc)
.await?;
MasterActivation
.send(&mut self.interface, &mut self.dc)
.await?;
self.busy_block().await?;
Ok(GDEH0154D67 {
interface: self.interface,
buffer: self.buffer,
dc: self.dc,
reset: self.reset,
busy: self.busy,
delay: self.delay,
state: Initialized,
})
}
}
impl<SPI, DC, RST, BSY, DLY> GDEH0154D67<SPI, DC, RST, BSY, DLY, Initialized>
where
SPI: SpiDevice,
DC: OutputPin,
RST: OutputPin,
BSY: InputPin + Wait,
DLY: DelayNs,
{
pub async fn partial_update(&mut self) -> Result<(), Error> {
for (idx, val) in self
.buffer
.flags
.chunks_mut(1)
.enumerate()
.filter(|(_, val)| val[0] != 0)
{
let idx = idx as usize;
let (x, y) = index2address(idx);
SetRamXAddressPosition([x])
.send(&mut self.interface, &mut self.dc)
.await?;
SetRamYAddressPosition([y, 0x00])
.send(&mut self.interface, &mut self.dc)
.await?;
let raw_data = self.buffer.pixels;
WriteRam(&[raw_data[idx]])
.send(&mut self.interface, &mut self.dc)
.await?;
val[0] = 0;
}
DisplayUpdateControl2([0xc7])
.send(&mut self.interface, &mut self.dc)
.await?;
MasterActivation
.send(&mut self.interface, &mut self.dc)
.await?;
self.busy_block().await
}
pub async fn full_update(&mut self) -> Result<(), Error> {
SetRamXAddressPosition([0x00])
.send(&mut self.interface, &mut self.dc)
.await?;
SetRamYAddressPosition([0x00, 0x00])
.send(&mut self.interface, &mut self.dc)
.await?;
WriteRam(&self.buffer.pixels)
.send(&mut self.interface, &mut self.dc)
.await?;
DisplayUpdateControl2([0xc7])
.send(&mut self.interface, &mut self.dc)
.await?;
MasterActivation
.send(&mut self.interface, &mut self.dc)
.await?;
self.busy_block().await
}
pub async fn release(self) -> Result<(SPI, DC, RST, BSY), Error> {
let display = self.turn_off().await?;
Ok((display.interface, display.dc, display.reset, display.busy))
}
}
impl<SPI, DC, RST, BSY, DLY, S> GDEH0154D67<SPI, DC, RST, BSY, DLY, S>
where
SPI: SpiDevice,
DC: OutputPin,
RST: OutputPin,
BSY: InputPin + Wait,
DLY: DelayNs,
{
pub async fn turn_off(mut self) -> Result<GDEH0154D67<SPI, DC, RST, BSY, DLY, NotInitialized>, Error> {
DeepSleepMode([0x1])
.send(&mut self.interface, &mut self.dc)
.await.unwrap();
Ok(GDEH0154D67 {
interface: self.interface,
buffer: self.buffer,
dc: self.dc,
reset: self.reset,
busy: self.busy,
delay: self.delay,
state: NotInitialized,
})
}
async fn reset(&mut self) -> Result<(), Error> {
self.reset.set_low().unwrap();
DelayNs::delay_ms(&mut self.delay, 10).await;
self.reset.set_high().unwrap();
DelayNs::delay_ms(&mut self.delay, 10).await;
SwReset.send(&mut self.interface, &mut self.dc).await?;
self.busy_block().await
}
async fn busy_block(&mut self) -> Result<(), Error> {
self.busy.wait_for_low().await.unwrap();
Ok(())
}
}
}
impl<SPI, DC, RST, BSY, DLY> DrawTarget for GDEH0154D67<SPI, DC, RST, BSY, DLY, Initialized>
where
SPI: SpiDevice,
DC: OutputPin,
RST: OutputPin,
BSY: InputPin,
DLY: DelayNs,
{
type Color = BinaryColor;
type Error = Error;
fn draw_iter<I>(&mut self, pixels: I) -> Result<(), Self::Error>
where
I: IntoIterator<Item = Pixel<Self::Color>>,
{
for Pixel(coord, color) in pixels.into_iter() {
const MAX_X_IDX: u32 = PIXELS_X as u32 - 1;
const MAX_Y_IDX: u32 = PIXELS_Y as u32 - 1;
if let Ok((x @ 0..=MAX_X_IDX, y @ 0..=MAX_Y_IDX)) = coord.try_into() {
let index = pixel2buffer(x, y);
let bit_index = index%8;
let mask = 0b10000000 >> bit_index;
let byte_index = index/8;
let color_val_u8 = u8::from(color.is_on()) << 7;
self.buffer.pixels[byte_index] = (self.buffer.pixels[byte_index] & !mask) | color_val_u8 >> bit_index;
self.buffer.flags[byte_index] = (self.buffer.flags[byte_index] & !mask) | 0b10000000 >> bit_index;
}
}
Ok(())
}
}
impl<SPI, DC, RST, BSY, DLY> OriginDimensions for GDEH0154D67<SPI, DC, RST, BSY, DLY, Initialized> {
fn size(&self) -> Size {
Size::new(PIXELS_X as u32, PIXELS_Y as u32)
}
}
fn pixel2buffer(x: u32, y: u32) -> usize {
(x + y * PIXELS_X as u32).try_into().unwrap()
}
fn index2address(i: usize) -> (u8, u8) {
((i % (PIXELS_Y/8)).try_into().unwrap(), (i / (PIXELS_Y/8)).try_into().unwrap())
}