diff --git a/eink.hpp b/eink.hpp index fcf7ffa..b62ad9a 100644 --- a/eink.hpp +++ b/eink.hpp @@ -2,6 +2,7 @@ #include #include +#include #include #include @@ -23,6 +24,17 @@ class Eink { static io::Pin m_rst; static io::Pin m_busy; + template + static T pgm_load(const T &object) + { + auto buffer = T{}; + auto rawBuffer = reinterpret_cast(&buffer); + for (auto i = std::size_t{0}; i < sizeof(T); ++i) { + rawBuffer[i] = static_cast(pgm_read_byte(&reinterpret_cast(&object)[i])); + } + return buffer; + } + public: enum class Cmd : std::uint8_t { DRIVER_OUTPUT_CONTROL = 0x01, @@ -41,6 +53,22 @@ class Eink { SET_RAM_Y_ADDR = 0x4F, }; + enum class Color : std::uint8_t { + BLACK, + WHITE, + RED, + }; + + enum class RamDirection : std::uint8_t { + DECREMENT = 0, + INCREMENT = 1, + }; + + enum class FastestMovingIndex : std::uint8_t { + X = 0, + Y = 1, + }; + static void init() { m_rst.dir(io::Dir::OUT); @@ -49,28 +77,16 @@ class Eink { Spi::init(); reset(); - - waitUntilIdle(); - sendCommand(Cmd::SW_RESET); - waitUntilIdle(); + softReset(); sendCommand(Cmd::DRIVER_OUTPUT_CONTROL); sendData(0xC7); sendData(0x00); sendData(0x01); - sendCommand(Cmd::DATA_ENTRY_MODE); - sendData(0x02); + setDataEntryMode(RamDirection::DECREMENT, RamDirection::INCREMENT, FastestMovingIndex::X); - sendCommand(Cmd::SET_RAM_X_ADDR_POSITIONS); - sendData(Width / 8 - 1); - sendData(0x00); - - sendCommand(Cmd::SET_RAM_Y_ADDR_POSITIONS); - sendData(0x00); - sendData(0x00); - sendData(Height - 1); - sendData(0x00); + setRamRange({Width / 8 - 1, 0}, {0, Height - 1}); sendCommand(Cmd::BORDER_WAVEFORM_CONTROL); sendData(0x05); @@ -78,12 +94,8 @@ class Eink { sendCommand(Cmd::READ_TEMPERATURE_SENSOR); sendData(0x80); - sendCommand(Cmd::SET_RAM_X_ADDR); - sendData(Width / 8 - 1); - - sendCommand(Cmd::SET_RAM_Y_ADDR); - sendData(0x00); - sendData(0x00); + setRamXPos(Width / 8 - 1); + setRamYPos(0); waitUntilIdle(); } @@ -125,22 +137,19 @@ class Eink { _delay_ms(10); m_rst = true; _delay_ms(200); + waitUntilIdle(); + } + + static void softReset() + { + sendCommand(Cmd::SW_RESET); + waitUntilIdle(); } template static void draw(const RleImage &rleImage) { - constexpr auto pgm_load = [](const auto &object) { - using object_t = std::remove_cvref_t; - auto buffer = object_t{}; - auto rawBuffer = reinterpret_cast(&buffer); - for (auto i = std::size_t{0}; i < sizeof(object_t); ++i) { - rawBuffer[i] = static_cast(pgm_read_byte(&reinterpret_cast(&object)[i])); - } - return buffer; - }; - - constexpr auto sendImageChannel = [pgm_load](const auto command, const auto &image) { + constexpr auto sendImageChannel = [](const auto command, const auto &image) { sendCommand(command); for (auto j = std::size_t{0}; j < image.size(); ++j) { const auto [count, data] = pgm_load(image[j]); @@ -163,15 +172,29 @@ class Eink { waitUntilIdle(); } - static void clear() + static void clear(const Color color = Color::WHITE) { + constexpr auto getFillData = [](const auto &color) -> std::pair { + switch (color) { + case Color::WHITE: + return {0xFF, 0x00}; + case Color::BLACK: + return {0x00, 0x00}; + case Color::RED: + return {0xFF, 0xFF}; + } + return {0xFF, 0x00}; + }; + + const auto fillData = getFillData(color); + sendCommand(Cmd::WRITE_RAM_BLACK); for (auto i = std::uint16_t{0}; i < Width * Height / 8; i++) { - sendData(0xff); + sendData(fillData.first); } sendCommand(Cmd::WRITE_RAM_RED); for (auto i = std::uint16_t{0}; i < Width * Height / 8; i++) { - sendData(0x00); + sendData(fillData.second); } sendCommand(Cmd::DISPLAY_UPDATE_CONTROL_2); @@ -202,6 +225,45 @@ class Eink { waitUntilIdle(); } + static void setDataEntryMode(const RamDirection &xDir = RamDirection::INCREMENT, + const RamDirection &yDir = RamDirection::INCREMENT, + const FastestMovingIndex &fastestMovingIndex = FastestMovingIndex::X) + { + auto setting = static_cast(xDir) << 0; + setting |= static_cast(yDir) << 1; + setting |= static_cast(fastestMovingIndex) << 2; + + sendCommand(Cmd::DATA_ENTRY_MODE); + sendData(setting); + } + + static void setRamRange(const std::pair &xrange, + const std::pair &yrange) + { + sendCommand(Cmd::SET_RAM_X_ADDR_POSITIONS); + sendData(xrange.first & 0b00111111); + sendData(xrange.second & 0b00111111); + + sendCommand(Cmd::SET_RAM_Y_ADDR_POSITIONS); + sendData(yrange.first & 0xFF); + sendData((yrange.first >> 8) & 0b1); + sendData(yrange.second & 0xFF); + sendData((yrange.second >> 8) & 0b1); + } + + static void setRamXPos(const std::uint8_t pos) + { + sendCommand(Cmd::SET_RAM_X_ADDR); + sendData(pos & 0b00111111); + } + + static void setRamYPos(const std::uint16_t pos) + { + sendCommand(Cmd::SET_RAM_Y_ADDR); + sendData(pos & 0xFF); + sendData((pos >> 8) & 0b1); + } + static void sleep() { sendCommand(Cmd::DEEP_SLEEP_MODE);