#include "LCDDisplay.hpp" #include #include #include #include #include #include #include #include /* lcd size hardcoded to 4x40 idgaf */ LCDDisplay::LCDDisplay(std::string dev, uint32_t baud) { _dev = dev; this->open(); // calls this (LCDDisplay) open() function, LCDDisplay::open() 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 uint8_t cmdbuf[] = {254, 75, 254, 84}; ::write(_lcd, &cmdbuf, 4); // clear display and set cursor home this->clear(); this->close(); } LCDDisplay::~LCDDisplay() { this->close(); } void LCDDisplay::open() { _lcd = ::open(_dev.c_str(), O_RDWR | O_NOCTTY | O_NONBLOCK); // ::open calls the global open() instead of LCDDisplay::open() if (_lcd < 0) { log(LOG::ERR, "LCDDisplay", "Error opening serial port \"{}\"", _dev); // err exit(_lcd); } // log(LOG::INF, "LCDDisplay", "Opened LCD at \"{}\"", _dev); } void LCDDisplay::close() { if (_lcd >= 0) ::close(_lcd); _lcd = -1; // log(LOG::INF, "LCDDisplay", "LCD port closed"); } void LCDDisplay::clear() { uint8_t cmdbuf[] = {254, 88}; ::write(_lcd, &cmdbuf, 2); } void LCDDisplay::setContrast(uint8_t contrast) { log(LOG::INF, "LCDDisplay::setContrast", "Set contrast to {}", contrast); uint8_t cmdbuf[] = {254, 80, contrast}; ::write(_lcd, &cmdbuf, 3); } void LCDDisplay::setBacklight(bool enabled) { log(LOG::INF, "LCDDisplay::setBacklight", "Set backlight to {}", enabled); uint8_t cmdbuf[] = {254, (uint8_t)(enabled ? 66 : 70), 255}; ::write(_lcd, &cmdbuf, enabled ? 3 : 2); } /* still doesnt work? */ void LCDDisplay::setBacklight(uint8_t brightness) { log(LOG::INF, "LCDDisplay::setBacklight", "Set backlight brightness to {}", brightness); uint8_t cmdbuf[] = {254, (uint8_t)(brightness ? 66 : 70), 255, brightness}; // 3rd char is timer, 4th is brightness ::write(_lcd, &cmdbuf, brightness ? 4 : 2); } void LCDDisplay::setCursor(uint8_t row, uint8_t col) { uint8_t cmdbuf[] = {254, 71, (uint8_t)(col + 1), (uint8_t)(row + 1)}; ::write(_lcd, &cmdbuf, 4); } void LCDDisplay::setCustomChar(uint8_t index, std::array cchar) { uint8_t cmdbuf[] = {254, 78, index, 0, 0, 0, 0, 0, 0, 0, 0}; std::memcpy(&cmdbuf[3], &cchar, cchar.size()); ::write(_lcd, &cmdbuf, 11); } /* immediately writes string to the lcd at current cursor pos */ void LCDDisplay::writeStr(std::string str) { ::write(_lcd, str.c_str(), str.size()); } /* immediately writes string to the lcd at given cursor pos */ void LCDDisplay::writeStr(uint8_t row, uint8_t col, std::string str) { this->setCursor(row, col); this->writeStr(str); } void LCDDisplay::writeLines(std::array lines) { for (auto& line : lines) { if (line.size() > LCD_COLS) { log(LOG::WRN, "LCDDisplay::writeLines", "Line {} too long! ({} chars)", line, line.size()); continue; } line.insert(line.end(), LCD_COLS - line.size(), ' '); } this->writeStr(0, 0, lines[0] + lines[1]); this->writeStr(2, 0, lines[2] + lines[3]); } /* writes string to write buffer at calculated pos */ void LCDDisplay::writeBuf(uint8_t row, uint8_t col, std::string str) { size_t len = std::min(str.size(), sizeof(writebuf) - 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, ' ', sizeof(writebuf)); } /* flushes writebuffer to lcd, hyperoptmized, flushes buffer and commands in a single write operation */ void LCDDisplay::flushBuf() { // we could skip all of this and set it in constructor if we were extra sure the lines wont ever exceed 40 chars 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->open(); ::write(_lcd, writebuf, sizeof(writebuf)); this->close(); } char LCDDisplay::bar(uint8_t char_id, 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); }