grovepi/Software/Cpp/grove_rgb_lcd/grove_rgb_lcd.cpp
2025-03-21 16:04:17 +01:00

128 lines
3.6 KiB
C++

#include "grove_rgb_lcd.h"
using GrovePi::LCD;
uint8_t LCD::DISPLAY_RGB_ADDR = 0x62;
uint8_t LCD::DISPLAY_TEXT_ADDR = 0x3e;
uint8_t LCD::CLEAR_DISPLAY = 0x01;
uint8_t LCD::DISPLAY_ON = 0x08;
uint8_t LCD::NO_CURSOR = 0x04;
uint8_t LCD::ENABLE_2ROWS = 0x28;
uint8_t LCD::PROGRAM_MODE = 0x80;
uint8_t LCD::NEW_ROW = 0xc0;
uint8_t LCD::DISPLAY_CHAR = 0x40;
uint8_t LCD::MAX_NO_CHARS = 32;
void LCD::connect()
{
// initializing with a random address
// it's just important to get the device file
this->DEVICE_FILE = initDevice(LCD::DISPLAY_TEXT_ADDR);
}
/**
* set rgb color
* if there are writes errors, then it throws exception
* @param red 8-bit
* @param green 8-bit
* @param blue 8-bit
*/
void LCD::setRGB(uint8_t red, uint8_t green, uint8_t blue)
{
this->selectSlave(LCD::DISPLAY_RGB_ADDR);
this->sendCommand(0x00, 0x00);
this->sendCommand(0x01, 0x00);
this->sendCommand(0x08, 0xaa);
this->sendCommand(0x04, red);
this->sendCommand(0x03, green);
this->sendCommand(0x02, blue);
}
/**
* Grove RGB LCD
*
* | Column
* ------------------------------------------------------
* Row | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
* ------------------------------------------------------
* 1 | x x x x x x x x x x x x x x x x
* 2 | x x x x x x x x x x x x x x x x
* ------------------------------------------------------
*
* Whatever text is sent to the LCD via the [str] variable
* Gets printed on the screen.
* The limit of text is determined by the amount of available
* Characters on the LCD screen.
*
* Every newline char ['\n'] takes the cursor onto the next line
* (aka on the row no. 2) and uses that space
* This means that if we have a text such "Hello\n World!",
* The first 5 characters of the word "Hello" get printed on the first line,
* whilst the rest of the string gets printed onto the 2nd line.
* So, if you use the newline char ['\n'] before the row ends,
* You will end up with less space to put the rest of the characters (aka the last line)
*
* If the text your putting occupies more than the LCD is capable of showing,
* Than the LCD will display only the first 16x2 characters.
*
* @param string of maximum 32 characters excluding the NULL character.
*/
void LCD::setText(const char *str)
{
this->selectSlave(LCD::DISPLAY_TEXT_ADDR);
this->sendCommand(LCD::PROGRAM_MODE, LCD::CLEAR_DISPLAY);
delay(50);
this->sendCommand(LCD::PROGRAM_MODE, LCD::DISPLAY_ON | LCD::NO_CURSOR);
this->sendCommand(LCD::PROGRAM_MODE, LCD::ENABLE_2ROWS);
delay(50);
int length = strlen(str);
bool already_had_newline = false;
for(int i = 0; i < length && i < LCD::MAX_NO_CHARS; i++)
{
if(i == 16 || str[i] == '\n')
{
if(!already_had_newline)
{
already_had_newline = true;
this->sendCommand(LCD::PROGRAM_MODE, LCD::NEW_ROW);
if(str[i] == '\n')
continue;
}
else if(str[i] == '\n')
break;
}
this->sendCommand(LCD::DISPLAY_CHAR, uint8_t(str[i]));
}
}
/**
* function for sending data to GrovePi RGB LCD
* @param mode see the constants defined up top
* @param command see the constants defined up top
*/
void LCD::sendCommand(uint8_t mode, uint8_t command)
{
int error = i2c_smbus_write_byte_data(this->DEVICE_FILE, mode, command);
if(error == -1)
throw I2CError("[I2CError writing data: check LCD wirings]\n");
}
/**
* the LCD has 2 slaves
* 1 for the RGB backlight color
* 1 for the actual text
* therefore there are 2 adresses
* @param slave 7-bit address
*/
void LCD::selectSlave(uint8_t slave)
{
int error = ioctl(this->DEVICE_FILE, I2C_SLAVE, slave);
if(error == -1)
throw I2CError("[I2CError selecting LCD address]\n");
}