#include "LCDDisplay.hpp" #include #include #include #include #include #include #include #include /* lcd size hardcoded to 4x40 idgaf */ LCDDisplay::LCDDisplay(const std::string& dev, const uint32_t baud) { this->dev = dev; this->baud = baud; } LCDDisplay::~LCDDisplay() { this->close(); } int LCDDisplay::Init() { if (const int ret = this->open(); ret < 0) { this->close(); return -1; } struct termios term{}; // Setup the serial port 8 data bits, no parity, 1 stopbit, no flow control term.c_cflag = baud | CS8 | CSTOPB | CLOCAL | CREAD; term.c_iflag = 0; term.c_oflag = 0; term.c_lflag = 0; tcflush(lcd, TCIFLUSH); tcsetattr(lcd, TCSANOW, &term); // init linebuf to spaces this->clearBuf(); // disable underline and block cursor constexpr uint8_t cmdbuf[] = {254, 75, 254, 84}; ::write(lcd, &cmdbuf, sizeof(cmdbuf)); // clear display and set cursor home this->clear(); return 0; } int LCDDisplay::open(const bool reopen) { applog(LOG::INF, "Opening serial port at \"{}\"", dev); if (lcd < 0 || reopen) lcd = ::open(dev.c_str(), O_RDWR | O_NOCTTY | O_NONBLOCK); // ::open calls the global open() instead of LCDDisplay::open() if (lcd < 0) { applog(LOG::ERR, "Error opening serial port \"{}\"", dev); // err return -1; } return 0; } void LCDDisplay::close() { if (lcd >= 0) { ::close(lcd); applog(LOG::INF, "LCD port closed"); } lcd = -1; } void LCDDisplay::write(const uint8_t* cmdbuf, const uint8_t len) { if (::write(lcd, cmdbuf, len) != len) { applog(LOG::ERR, "failed to execute ::write, lost access to port?"); this->open(true); } } void LCDDisplay::clear() { constexpr uint8_t cmdbuf[] = {254, 88}; this->write(cmdbuf, sizeof(cmdbuf)); } void LCDDisplay::setContrast(const uint8_t contrast) { applog(LOG::INF, "Set contrast to {}", contrast); const uint8_t cmdbuf[] = {254, 80, contrast}; this->write(cmdbuf, sizeof(cmdbuf)); } void LCDDisplay::setBacklight(const bool enabled) { applog(LOG::INF, "Set backlight to {}", enabled); const uint8_t cmdbuf[] = {254, static_cast(enabled ? 66 : 70), 255}; this->write(cmdbuf, enabled ? 3 : 2); } /* still doesnt work? */ void LCDDisplay::setBacklight(const uint8_t brightness) { applog(LOG::INF, "Set backlight brightness to {}", brightness); const uint8_t cmdbuf[] = {254, static_cast(brightness ? 66 : 70), 255, brightness}; // 3rd char is timer, 4th is brightness this->write(cmdbuf, brightness ? 4 : 2); } void LCDDisplay::setCursor(const uint8_t row, const uint8_t col) { const uint8_t cmdbuf[] = {254, 71, static_cast(col + 1), static_cast(row + 1)}; this->write(cmdbuf, sizeof(cmdbuf)); } /* reconsider so im not writing every time. prepend custom chars to the write buffer? */ void LCDDisplay::setCustomChar(const uint8_t index, const std::array cchar) { uint8_t cmdbuf[] = {254, 78, index, 0, 0, 0, 0, 0, 0, 0, 0}; std::memcpy(&cmdbuf[3], &cchar, sizeof(cchar)); this->write(cmdbuf, sizeof(cmdbuf)); } /* immediately writes string to the lcd at current cursor pos */ void LCDDisplay::writeStr(const std::string& str) { this->write(reinterpret_cast(str.c_str()), str.size()); } /* immediately writes string to the lcd at given cursor pos */ void LCDDisplay::writeStr(const uint8_t row, const uint8_t col, const std::string& str) { this->setCursor(row, col); this->write(reinterpret_cast(str.c_str()), str.size()); } /* writes string to write buffer at calculated pos */ void LCDDisplay::writeBuf(const uint8_t row, const uint8_t col, const std::string& str) { const size_t len = std::min(str.size(), writebuf.size() - col); uint8_t pos = 4 + col + (LCD_COLS * (row % 2)); // skip 4 bytes to leave room for set cursor command if (row >= 2) pos += 2 * LCD_COLS + 4; // if we're writing to disp2, skip another 4 bytes for set cursor command and 2*40 bytes of disp 1 std::memcpy(&writebuf[pos], str.c_str(), len); } /* initializes the write buffer to spaces */ void LCDDisplay::clearBuf() { std::memset(writebuf.data(), ' ', writebuf.size()); } /* flushes writebuffer to lcd, hyperoptmized, flushes buffer and commands in a single write operation */ void LCDDisplay::flushBuf() { constexpr uint8_t setDisp[] = {254, 71, 1, 1}; // set cursor to char 1, line 1 std::memcpy(&writebuf[0], setDisp, 4); std::memcpy(&writebuf[2 * LCD_COLS + 4], setDisp, 4); writebuf[2 * LCD_COLS + 7] = 3; // overwrite set cursor c1 l1 to c1 l3 this->write(reinterpret_cast(writebuf.data()), writebuf.size()); } // i have a whole flushbuf func to avoid too many writes, but im writing on every bar, need to rethink this. // we could have a separate pre-char buffer and put all the setCustomChar commands to that? char LCDDisplay::bar(const uint8_t char_id, const double value) { std::array b{}; b.fill(0b01110); for (uint8_t i = 0; i < (1.0 - value) * 8; i++) b[i] = 0; this->setCustomChar(char_id, b); return cc(char_id); }