add error checking and initial backlight state to char lcd

This commit is contained in:
2026-09-29 23:54:27 -05:00
parent 8d635d41c6
commit ef79b2a835
6 changed files with 135 additions and 98 deletions
+1 -1
View File
@@ -16,7 +16,7 @@ void init_blk_box(BlkBoxInitConfig cfg) {
init_main_i2c(); init_main_i2c();
init_expander(); init_expander();
init_leds(); init_leds();
init_lcd(); init_lcd(cfg.lcd_backlight);
init_ssegs(); init_ssegs();
init_tft(); init_tft();
+22 -12
View File
@@ -5,6 +5,7 @@
#include <freertos/FreeRTOS.h> #include <freertos/FreeRTOS.h>
#include <freertos/semphr.h> #include <freertos/semphr.h>
#include <esp_log.h> #include <esp_log.h>
#include <esp_err.h>
// mutex is for all these vars // mutex is for all these vars
SemaphoreHandle_t lcd_mutex; SemaphoreHandle_t lcd_mutex;
@@ -21,6 +22,12 @@ static bool is_header_enabled = false;
static const char *TAG = "char_lcd"; static const char *TAG = "char_lcd";
static const char* EMPTY_ROW = " "; static const char* EMPTY_ROW = " ";
static void log_lcd_error(const char* operation, esp_err_t err) {
if (err != ESP_OK) {
ESP_LOGE(TAG, "LCD %s failed: %s", operation, esp_err_to_name(err));
}
}
// TODO: move this to power.cpp // TODO: move this to power.cpp
// static void monitor_battery_task(void* _arg) { // static void monitor_battery_task(void* _arg) {
// (void) _arg; // (void) _arg;
@@ -91,14 +98,17 @@ static const char* EMPTY_ROW = " ";
// return true; // return true;
// } // }
void init_lcd() { void init_lcd(bool initial_backlight) {
ESP_LOGI(TAG, "Initializing LCD..."); ESP_LOGI(TAG, "Initializing LCD...");
lcd_mutex = xSemaphoreCreateRecursiveMutex(); lcd_mutex = xSemaphoreCreateRecursiveMutex();
assert(lcd_mutex != NULL); assert(lcd_mutex != NULL);
lcd = LCD2004I2C(); lcd = LCD2004I2C();
lcd.init(LCD_ADDR); esp_err_t err = lcd.init(LCD_ADDR, initial_backlight);
if (err != ESP_OK) {
ESP_LOGE(TAG, "LCD initialization failed: %s", esp_err_to_name(err));
}
// register_replay_fn(replay_handler); // register_replay_fn(replay_handler);
@@ -111,7 +121,7 @@ void LCDController::clear() {
xSemaphoreTakeRecursive(lcd_mutex, portMAX_DELAY); xSemaphoreTakeRecursive(lcd_mutex, portMAX_DELAY);
if (!is_header_enabled) { if (!is_header_enabled) {
lcd.clear(); log_lcd_error("clear", lcd.clear());
// if (is_state_tracking()) { // if (is_state_tracking()) {
// event_occured("LCD_CLEAR", NULL); // event_occured("LCD_CLEAR", NULL);
@@ -134,7 +144,7 @@ bool LCDController::get_backlight() {
void LCDController::set_backlight(bool backlight) { void LCDController::set_backlight(bool backlight) {
xSemaphoreTakeRecursive(lcd_mutex, portMAX_DELAY); xSemaphoreTakeRecursive(lcd_mutex, portMAX_DELAY);
lcd.set_backlight(backlight); log_lcd_error("set backlight", lcd.set_backlight(backlight));
xSemaphoreGiveRecursive(lcd_mutex); xSemaphoreGiveRecursive(lcd_mutex);
// if (is_state_tracking()) { // if (is_state_tracking()) {
@@ -145,7 +155,7 @@ void LCDController::set_backlight(bool backlight) {
void LCDController::set_display_show(bool show_display) { void LCDController::set_display_show(bool show_display) {
xSemaphoreTakeRecursive(lcd_mutex, portMAX_DELAY); xSemaphoreTakeRecursive(lcd_mutex, portMAX_DELAY);
lcd.show_hide(show_display); log_lcd_error("set display", lcd.show_hide(show_display));
xSemaphoreGiveRecursive(lcd_mutex); xSemaphoreGiveRecursive(lcd_mutex);
} }
@@ -159,10 +169,10 @@ bool LCDController::get_display_show() {
/// Changes the cursor display mode to the given mode. /// Changes the cursor display mode to the given mode.
static void change_cursor_display(CursorMode cursor_display_mode) { static void change_cursor_display(CursorMode cursor_display_mode) {
xSemaphoreTakeRecursive(lcd_mutex, portMAX_DELAY); xSemaphoreTakeRecursive(lcd_mutex, portMAX_DELAY);
lcd.show_blink_cursor( log_lcd_error("set cursor display", lcd.show_blink_cursor(
cursor_display_mode != CursorMode::Hide, cursor_display_mode != CursorMode::Hide,
cursor_display_mode == CursorMode::Blink cursor_display_mode == CursorMode::Blink
); ));
xSemaphoreGiveRecursive(lcd_mutex); xSemaphoreGiveRecursive(lcd_mutex);
} }
@@ -178,7 +188,7 @@ void LCDController::set_resting_cursor_pos(uint8_t row, uint8_t col) {
(resting_cursor_row != row || resting_cursor_col != col) && (resting_cursor_row != row || resting_cursor_col != col) &&
cursor_resting_mode != CursorMode::Hide cursor_resting_mode != CursorMode::Hide
) { ) {
lcd.move_cursor(row, col); log_lcd_error("move cursor", lcd.move_cursor(row, col));
} }
resting_cursor_row = row; resting_cursor_row = row;
@@ -243,7 +253,7 @@ void LCDController::create_custom_char(uint8_t location, const uint8_t charmap[]
if (location == 8) location = 0; if (location == 8) location = 0;
xSemaphoreTakeRecursive(lcd_mutex, portMAX_DELAY); xSemaphoreTakeRecursive(lcd_mutex, portMAX_DELAY);
lcd.create_custom_char(location, charmap); log_lcd_error("create custom character", lcd.create_custom_char(location, charmap));
xSemaphoreGiveRecursive(lcd_mutex); xSemaphoreGiveRecursive(lcd_mutex);
// if (is_state_tracking()) { // if (is_state_tracking()) {
@@ -260,12 +270,12 @@ void LCDController::create_custom_char(uint8_t location, const uint8_t charmap[]
/// Do not print across lines, as that leads to goofy behavior. /// Do not print across lines, as that leads to goofy behavior.
void LCDController::print(uint8_t row, uint8_t col, const char* str) { void LCDController::print(uint8_t row, uint8_t col, const char* str) {
xSemaphoreTakeRecursive(lcd_mutex, portMAX_DELAY); xSemaphoreTakeRecursive(lcd_mutex, portMAX_DELAY);
lcd.move_cursor(row, col); log_lcd_error("move cursor", lcd.move_cursor(row, col));
change_cursor_display(cursor_print_mode); change_cursor_display(cursor_print_mode);
lcd.write_str(str); log_lcd_error("write string", lcd.write_str(str));
if (cursor_resting_mode != CursorMode::Hide) { if (cursor_resting_mode != CursorMode::Hide) {
lcd.move_cursor(resting_cursor_row, resting_cursor_col); log_lcd_error("restore cursor", lcd.move_cursor(resting_cursor_row, resting_cursor_col));
} }
if (cursor_resting_mode != cursor_print_mode) { if (cursor_resting_mode != cursor_print_mode) {
change_cursor_display(cursor_resting_mode); change_cursor_display(cursor_resting_mode);
+83 -59
View File
@@ -49,7 +49,8 @@ LCD2004I2C::LCD2004I2C() {
entry_mode = 0; entry_mode = 0;
} }
void LCD2004I2C::init(uint8_t addr) { esp_err_t LCD2004I2C::init(uint8_t addr, bool initial_backlight) {
if (initialized) return ESP_ERR_INVALID_STATE;
i2c_device_config_t dev_config = { i2c_device_config_t dev_config = {
.dev_addr_length = I2C_ADDR_BIT_LEN_7, .dev_addr_length = I2C_ADDR_BIT_LEN_7,
.device_address = addr, .device_address = addr,
@@ -60,42 +61,52 @@ void LCD2004I2C::init(uint8_t addr) {
} }
}; };
// TODO: replace all these ESP_ERROR_CHECK with proper error handling that doesn't just crash the program esp_err_t err = i2c_master_bus_add_device(i2c_main_bus_handle, &dev_config, &lcd_device_handle);
ESP_ERROR_CHECK(i2c_master_bus_add_device(i2c_main_bus_handle, &dev_config, &lcd_device_handle)); if (err != ESP_OK) return err;
ESP_LOGD(TAG, "LCD2004 device added to bus"); ESP_LOGD(TAG, "LCD2004 device added to bus");
backlight = initial_backlight ? BACKLIGHT_MASK : 0;
// Initialize the LCD // Initialize the LCD
// set to 8-bit mode to bring it to a known state // set to 8-bit mode to bring it to a known state
for (int i = 0; i < 3; i++) { for (int i = 0; i < 3; i++) {
send4_cmd(CMD_FUNCTION_SET | FUNCTION_SET_DL); err = send4_cmd(CMD_FUNCTION_SET | FUNCTION_SET_DL);
if (err != ESP_OK) return err;
vTaskDelay(pdMS_TO_TICKS(5)); vTaskDelay(pdMS_TO_TICKS(5));
} }
// set to 4-bit mode, while in 8 bit mode // set to 4-bit mode, while in 8 bit mode
send4_cmd(CMD_FUNCTION_SET); err = send4_cmd(CMD_FUNCTION_SET);
if (err != ESP_OK) return err;
// use all 4 rows // use all 4 rows
send_cmd(CMD_FUNCTION_SET | FUNCTION_SET_N); err = send_cmd(CMD_FUNCTION_SET | FUNCTION_SET_N);
if (err != ESP_OK) return err;
// display, set cursor visible // display, set cursor visible
send_cmd(CMD_DISPLAY_CONTROL | DISPLAY_CONTROL_SHOW); err = send_cmd(CMD_DISPLAY_CONTROL | DISPLAY_CONTROL_SHOW);
if (err != ESP_OK) return err;
// clear display // clear display
send_cmd(CMD_CLEAR_DISPLAY); err = send_cmd(CMD_CLEAR_DISPLAY);
if (err != ESP_OK) return err;
esp_rom_delay_us(1600);
// set cursor to increment to the right // set cursor to increment to the right
send_cmd(CMD_ENTRY_MODE_SET | ENTRY_MODE_INC_DEC); err = send_cmd(CMD_ENTRY_MODE_SET | ENTRY_MODE_INC_DEC);
if (err != ESP_OK) return err;
display_control = DISPLAY_CONTROL_SHOW; display_control = DISPLAY_CONTROL_SHOW;
entry_mode = ENTRY_MODE_INC_DEC; entry_mode = ENTRY_MODE_INC_DEC;
initialized = true;
ESP_LOGI(TAG, "LCD2004 initialized!"); ESP_LOGI(TAG, "LCD2004 initialized!");
return ESP_OK;
} }
// i2c wrappers // i2c wrappers
/// Sends `cmd` to the device as a command. /// Sends `cmd` to the device as a command.
void LCD2004I2C::send_cmd(uint8_t cmd) { esp_err_t LCD2004I2C::send_cmd(uint8_t cmd) {
uint8_t control_bits = backlight; uint8_t control_bits = backlight;
uint8_t high = control_bits | (cmd & 0xF0); uint8_t high = control_bits | (cmd & 0xF0);
@@ -110,10 +121,10 @@ void LCD2004I2C::send_cmd(uint8_t cmd) {
low low
}; };
ESP_ERROR_CHECK(i2c_master_transmit(lcd_device_handle, i2c_data, sizeof(i2c_data), I2C_MASTER_TIMEOUT_MS)); return i2c_master_transmit(lcd_device_handle, i2c_data, sizeof(i2c_data), I2C_MASTER_TIMEOUT_MS);
} }
void LCD2004I2C::send_data(uint8_t data) { esp_err_t LCD2004I2C::send_data(uint8_t data) {
uint8_t control_bits = DATA_MASK | backlight; uint8_t control_bits = DATA_MASK | backlight;
uint8_t high = control_bits | (data & 0xF0); uint8_t high = control_bits | (data & 0xF0);
@@ -129,11 +140,11 @@ void LCD2004I2C::send_data(uint8_t data) {
low low
}; };
ESP_ERROR_CHECK(i2c_master_transmit(lcd_device_handle, i2c_data, sizeof(i2c_data), I2C_MASTER_TIMEOUT_MS)); return i2c_master_transmit(lcd_device_handle, i2c_data, sizeof(i2c_data), I2C_MASTER_TIMEOUT_MS);
} }
/// Sends the ***HIGH*** 4 bits of `cmd` as a command. /// Sends the ***HIGH*** 4 bits of `cmd` as a command.
void LCD2004I2C::send4_cmd(uint8_t cmd) { esp_err_t LCD2004I2C::send4_cmd(uint8_t cmd) {
uint8_t control_bits = backlight; uint8_t control_bits = backlight;
uint8_t high = control_bits | (cmd & 0xF0); uint8_t high = control_bits | (cmd & 0xF0);
@@ -145,7 +156,7 @@ void LCD2004I2C::send4_cmd(uint8_t cmd) {
high high
}; };
ESP_ERROR_CHECK(i2c_master_transmit(lcd_device_handle, i2c_data, sizeof(i2c_data), I2C_MASTER_TIMEOUT_MS)); return i2c_master_transmit(lcd_device_handle, i2c_data, sizeof(i2c_data), I2C_MASTER_TIMEOUT_MS);
} }
// LCD2004 class implementations // LCD2004 class implementations
@@ -154,35 +165,41 @@ bool LCD2004I2C::get_backlight() {
return backlight != 0; return backlight != 0;
} }
void LCD2004I2C::set_backlight(bool backlight) { esp_err_t LCD2004I2C::set_backlight(bool backlight) {
if (get_backlight() == backlight) { if (get_backlight() == backlight) {
return; return ESP_OK;
} }
this->backlight = backlight ? BACKLIGHT_MASK : 0; uint8_t data = backlight ? BACKLIGHT_MASK : 0;
uint8_t data = this->backlight; esp_err_t err = i2c_master_transmit(lcd_device_handle, &data, 1, I2C_MASTER_TIMEOUT_MS);
ESP_ERROR_CHECK(i2c_master_transmit(lcd_device_handle, &data, 1, I2C_MASTER_TIMEOUT_MS)); if (err == ESP_OK) {
this->backlight = data;
}
return err;
} }
void LCD2004I2C::clear() { esp_err_t LCD2004I2C::clear() {
send_cmd(CMD_CLEAR_DISPLAY); esp_err_t err = send_cmd(CMD_CLEAR_DISPLAY);
if (err != ESP_OK) return err;
esp_rom_delay_us(1600); esp_rom_delay_us(1600);
entry_mode |= ENTRY_MODE_INC_DEC; entry_mode |= ENTRY_MODE_INC_DEC;
return ESP_OK;
} }
void LCD2004I2C::move_cursor(uint8_t row, uint8_t col) { esp_err_t LCD2004I2C::move_cursor(uint8_t row, uint8_t col) {
const uint8_t ROW_OFFSETS[4] = {0x00, 0x40, 0x14, 0x54}; const uint8_t ROW_OFFSETS[4] = {0x00, 0x40, 0x14, 0x54};
if (row >= LCD2004_ROWS || col >= LCD2004_COLS) return ESP_ERR_INVALID_ARG;
uint8_t addr = ROW_OFFSETS[row] + col; uint8_t addr = ROW_OFFSETS[row] + col;
send_cmd(CMD_SET_DDRAM_ADDRESS | addr); return send_cmd(CMD_SET_DDRAM_ADDRESS | addr);
} }
bool LCD2004I2C::get_show_hide() { bool LCD2004I2C::get_show_hide() {
return (display_control & DISPLAY_CONTROL_SHOW) != 0; return (display_control & DISPLAY_CONTROL_SHOW) != 0;
} }
void LCD2004I2C::show_hide(bool show) { esp_err_t LCD2004I2C::show_hide(bool show) {
if (get_show_hide() == show) { if (get_show_hide() == show) {
return; return ESP_OK;
} }
if (show) { if (show) {
@@ -190,16 +207,16 @@ void LCD2004I2C::show_hide(bool show) {
} else { } else {
display_control &= ~DISPLAY_CONTROL_SHOW; display_control &= ~DISPLAY_CONTROL_SHOW;
} }
send_cmd(CMD_DISPLAY_CONTROL | display_control); return send_cmd(CMD_DISPLAY_CONTROL | display_control);
} }
bool LCD2004I2C::get_show_cursor() { bool LCD2004I2C::get_show_cursor() {
return (display_control & DISPLAY_CONTROL_CURSOR) != 0; return (display_control & DISPLAY_CONTROL_CURSOR) != 0;
} }
void LCD2004I2C::show_cursor(bool show_cursor) { esp_err_t LCD2004I2C::show_cursor(bool show_cursor) {
if (get_show_cursor() == show_cursor) { if (get_show_cursor() == show_cursor) {
return; return ESP_OK;
} }
if (show_cursor) { if (show_cursor) {
@@ -207,16 +224,16 @@ void LCD2004I2C::show_cursor(bool show_cursor) {
} else { } else {
display_control &= ~DISPLAY_CONTROL_CURSOR; display_control &= ~DISPLAY_CONTROL_CURSOR;
} }
send_cmd(CMD_DISPLAY_CONTROL | display_control); return send_cmd(CMD_DISPLAY_CONTROL | display_control);
} }
bool LCD2004I2C::get_blink_cursor() { bool LCD2004I2C::get_blink_cursor() {
return (display_control & DISPLAY_CONTROL_BLINK) != 0; return (display_control & DISPLAY_CONTROL_BLINK) != 0;
} }
void LCD2004I2C::blink_cursor(bool blink_cursor) { esp_err_t LCD2004I2C::blink_cursor(bool blink_cursor) {
if (get_blink_cursor() == blink_cursor) { if (get_blink_cursor() == blink_cursor) {
return; return ESP_OK;
} }
if (blink_cursor) { if (blink_cursor) {
@@ -224,12 +241,12 @@ void LCD2004I2C::blink_cursor(bool blink_cursor) {
} else { } else {
display_control &= ~DISPLAY_CONTROL_BLINK; display_control &= ~DISPLAY_CONTROL_BLINK;
} }
send_cmd(CMD_DISPLAY_CONTROL | display_control); return send_cmd(CMD_DISPLAY_CONTROL | display_control);
} }
void LCD2004I2C::show_blink_cursor(bool show_cursor, bool blink_cursor) { esp_err_t LCD2004I2C::show_blink_cursor(bool show_cursor, bool blink_cursor) {
if (get_show_cursor() == show_cursor && get_blink_cursor() == blink_cursor) { if (get_show_cursor() == show_cursor && get_blink_cursor() == blink_cursor) {
return; return ESP_OK;
} }
if (blink_cursor) { if (blink_cursor) {
@@ -242,16 +259,16 @@ void LCD2004I2C::show_blink_cursor(bool show_cursor, bool blink_cursor) {
} else { } else {
display_control &= ~DISPLAY_CONTROL_CURSOR; display_control &= ~DISPLAY_CONTROL_CURSOR;
} }
send_cmd(CMD_DISPLAY_CONTROL | display_control); return send_cmd(CMD_DISPLAY_CONTROL | display_control);
} }
bool LCD2004I2C::get_scroll_direction() { bool LCD2004I2C::get_scroll_direction() {
return (entry_mode & ENTRY_MODE_INC_DEC) != 0; return (entry_mode & ENTRY_MODE_INC_DEC) != 0;
} }
void LCD2004I2C::scroll_direction(bool left_to_right) { esp_err_t LCD2004I2C::scroll_direction(bool left_to_right) {
if (get_scroll_direction() == left_to_right) { if (get_scroll_direction() == left_to_right) {
return; return ESP_OK;
} }
if (left_to_right) { if (left_to_right) {
@@ -259,16 +276,16 @@ void LCD2004I2C::scroll_direction(bool left_to_right) {
} else { } else {
entry_mode &= ~ENTRY_MODE_INC_DEC; entry_mode &= ~ENTRY_MODE_INC_DEC;
} }
send_cmd(CMD_ENTRY_MODE_SET | entry_mode); return send_cmd(CMD_ENTRY_MODE_SET | entry_mode);
} }
bool LCD2004I2C::get_display_shift() { bool LCD2004I2C::get_display_shift() {
return (entry_mode & ENTRY_MODE_SHIFT) != 0; return (entry_mode & ENTRY_MODE_SHIFT) != 0;
} }
void LCD2004I2C::shift_display(bool shift_display) { esp_err_t LCD2004I2C::shift_display(bool shift_display) {
if (get_display_shift() == shift_display) { if (get_display_shift() == shift_display) {
return; return ESP_OK;
} }
if (shift_display) { if (shift_display) {
@@ -276,53 +293,60 @@ void LCD2004I2C::shift_display(bool shift_display) {
} else { } else {
entry_mode &= ~ENTRY_MODE_SHIFT; entry_mode &= ~ENTRY_MODE_SHIFT;
} }
send_cmd(CMD_ENTRY_MODE_SET | entry_mode); return send_cmd(CMD_ENTRY_MODE_SET | entry_mode);
} }
void LCD2004I2C::shift_cursor_left() { esp_err_t LCD2004I2C::shift_cursor_left() {
send_cmd(CMD_CURSOR_OR_DISPLAY_SHIFT); return send_cmd(CMD_CURSOR_OR_DISPLAY_SHIFT);
} }
void LCD2004I2C::shift_cursor_right() { esp_err_t LCD2004I2C::shift_cursor_right() {
send_cmd(CMD_CURSOR_OR_DISPLAY_SHIFT | CURSOR_OR_DISPLAY_SHIFT_RL); return send_cmd(CMD_CURSOR_OR_DISPLAY_SHIFT | CURSOR_OR_DISPLAY_SHIFT_RL);
} }
void LCD2004I2C::shift_display_left() { esp_err_t LCD2004I2C::shift_display_left() {
send_cmd(CMD_CURSOR_OR_DISPLAY_SHIFT | CURSOR_OR_DISPLAY_SHIFT_SC); return send_cmd(CMD_CURSOR_OR_DISPLAY_SHIFT | CURSOR_OR_DISPLAY_SHIFT_SC);
} }
void LCD2004I2C::shift_display_right() { esp_err_t LCD2004I2C::shift_display_right() {
send_cmd(CMD_CURSOR_OR_DISPLAY_SHIFT | CURSOR_OR_DISPLAY_SHIFT_SC | CURSOR_OR_DISPLAY_SHIFT_RL); return send_cmd(CMD_CURSOR_OR_DISPLAY_SHIFT | CURSOR_OR_DISPLAY_SHIFT_SC | CURSOR_OR_DISPLAY_SHIFT_RL);
} }
void LCD2004I2C::create_custom_char(uint8_t location, const uint8_t char_map[8]) { esp_err_t LCD2004I2C::create_custom_char(uint8_t location, const uint8_t char_map[8]) {
if (char_map == nullptr) return ESP_ERR_INVALID_ARG;
uint8_t loc = location % 8; uint8_t loc = location % 8;
send_cmd(CMD_SET_CGRAM_ADDRESS | (loc << 3)); esp_err_t err = send_cmd(CMD_SET_CGRAM_ADDRESS | (loc << 3));
if (err != ESP_OK) return err;
for (int i = 0; i < 8; i++) { for (int i = 0; i < 8; i++) {
send_data(char_map[i]); err = send_data(char_map[i]);
if (err != ESP_OK) return err;
} }
return ESP_OK;
} }
void LCD2004I2C::print_char(char c) { esp_err_t LCD2004I2C::print_char(char c) {
if (c == '\x08') { if (c == '\x08') {
// custom char 0 is represented by \x08 since \x00 is a null terminator // custom char 0 is represented by \x08 since \x00 is a null terminator
c = 0; c = 0;
} }
send_data(static_cast<uint8_t>(c)); return send_data(static_cast<uint8_t>(c));
} }
void LCD2004I2C::print_u8(uint8_t b) { esp_err_t LCD2004I2C::print_u8(uint8_t b) {
if (b == 0x08) { if (b == 0x08) {
// custom char 0 is represented by \x08 since \x00 is a null terminator // custom char 0 is represented by \x08 since \x00 is a null terminator
b = 0; b = 0;
} }
send_data(b); return send_data(b);
} }
void LCD2004I2C::write_str(const char* s) { esp_err_t LCD2004I2C::write_str(const char* s) {
// TODO: replace this with a single I2C transmission. // TODO: replace this with a single I2C transmission.
if (s == nullptr) return ESP_ERR_INVALID_ARG;
while (*s) { while (*s) {
print_char(*s); esp_err_t err = print_char(*s);
if (err != ESP_OK) return err;
s++; s++;
} }
return ESP_OK;
} }
+26 -22
View File
@@ -2,15 +2,19 @@
#define LCD2004_HPP #define LCD2004_HPP
#include "driver/i2c_master.h" #include "driver/i2c_master.h"
#include "esp_err.h"
#include <stdint.h> #include <stdint.h>
#define LCD2004_CLK_SPEED_HZ 100000 #define LCD2004_CLK_SPEED_HZ 100000
#define I2C_MASTER_TIMEOUT_MS 1000 #define I2C_MASTER_TIMEOUT_MS 1000
#define LCD2004_ROWS 4
#define LCD2004_COLS 20
class LCD2004I2C { class LCD2004I2C {
private: private:
i2c_master_dev_handle_t lcd_device_handle; i2c_master_dev_handle_t lcd_device_handle = nullptr;
bool initialized = false;
/// Weather or not the backlight is on. /// Weather or not the backlight is on.
/// `BACKLIGHT_MASK` if backlight is on, /// `BACKLIGHT_MASK` if backlight is on,
/// `0` if backlight is off. /// `0` if backlight is off.
@@ -19,9 +23,9 @@ private:
uint8_t display_control; uint8_t display_control;
uint8_t entry_mode; uint8_t entry_mode;
void send_cmd(uint8_t cmd); esp_err_t send_cmd(uint8_t cmd);
void send_data(uint8_t data); esp_err_t send_data(uint8_t data);
void send4_cmd(uint8_t cmd); esp_err_t send4_cmd(uint8_t cmd);
public: public:
/// Constructs a new LCD2004 device. /// Constructs a new LCD2004 device.
@@ -30,31 +34,31 @@ public:
/// Initializes the LCD2004 device. Must be called before any other methods. /// Initializes the LCD2004 device. Must be called before any other methods.
/// ///
/// The address is usually `0x27`. /// The address is usually `0x27`.
void init(uint8_t addr); esp_err_t init(uint8_t addr, bool initial_backlight);
/// Gets the state of the backlight of the module. /// Gets the state of the backlight of the module.
bool get_backlight(); bool get_backlight();
/// Sets the backlight of the module to be on or off. /// Sets the backlight of the module to be on or off.
void set_backlight(bool backlight); esp_err_t set_backlight(bool backlight);
/// Clears the display, and resets the cursor to /// Clears the display, and resets the cursor to
void clear(); esp_err_t clear();
/// Moves the cursor to `row` and `col`. /// Moves the cursor to `row` and `col`.
void move_cursor(uint8_t row, uint8_t col); esp_err_t move_cursor(uint8_t row, uint8_t col);
/// Returns `true` iff the display is showing. /// Returns `true` iff the display is showing.
bool get_show_hide(); bool get_show_hide();
/// Shows or hides the display. /// Shows or hides the display.
void show_hide(bool show); esp_err_t show_hide(bool show);
/// Returns `true` iff the cursor display is showing. /// Returns `true` iff the cursor display is showing.
bool get_show_cursor(); bool get_show_cursor();
/// Shows or hides the cursor. /// Shows or hides the cursor.
void show_cursor(bool show_cursor); esp_err_t show_cursor(bool show_cursor);
/// Returns `true` iff the cursor is blinking. /// Returns `true` iff the cursor is blinking.
/// ///
@@ -62,16 +66,16 @@ public:
bool get_blink_cursor(); bool get_blink_cursor();
/// Blinks or stops blinking the cursor. /// Blinks or stops blinking the cursor.
void blink_cursor(bool blink_cursor); esp_err_t blink_cursor(bool blink_cursor);
/// Sets the cursor show state and blink state. /// Sets the cursor show state and blink state.
void show_blink_cursor(bool show_cursor, bool blink_cursor); esp_err_t show_blink_cursor(bool show_cursor, bool blink_cursor);
/// Returns `true` iff the display scrolls left to right. /// Returns `true` iff the display scrolls left to right.
bool get_scroll_direction(); bool get_scroll_direction();
/// Sets the scroll direction for the display. /// Sets the scroll direction for the display.
void scroll_direction(bool left_to_right); esp_err_t scroll_direction(bool left_to_right);
/// Returns `true` iff the display is shifting with the cursor. /// Returns `true` iff the display is shifting with the cursor.
bool get_display_shift(); bool get_display_shift();
@@ -79,34 +83,34 @@ public:
/// Sets the display to shift with the cursor. /// Sets the display to shift with the cursor.
/// ///
/// This is like autoscrolling. /// This is like autoscrolling.
void shift_display(bool shift_display); esp_err_t shift_display(bool shift_display);
/// Shifts the cursor left 1 /// Shifts the cursor left 1
void shift_cursor_left(); esp_err_t shift_cursor_left();
/// Shifts the cursor right 1 /// Shifts the cursor right 1
void shift_cursor_right(); esp_err_t shift_cursor_right();
/// Shifts the display left 1 /// Shifts the display left 1
void shift_display_left(); esp_err_t shift_display_left();
/// Shifts the display right 1 /// Shifts the display right 1
void shift_display_right(); esp_err_t shift_display_right();
/// Sets the character map for a custom character. /// Sets the character map for a custom character.
/// ///
/// There are 8 locations (0..=7), for 8 characters. /// There are 8 locations (0..=7), for 8 characters.
/// You can print these characters by sending '\x00' - '\x07'. /// You can print these characters by sending '\x00' - '\x07'.
void create_custom_char(uint8_t location, const uint8_t char_map[8]); esp_err_t create_custom_char(uint8_t location, const uint8_t char_map[8]);
/// Prints a single character to the display. /// Prints a single character to the display.
void print_char(char c); esp_err_t print_char(char c);
/// Prints a single byte to the display. /// Prints a single byte to the display.
void print_u8(uint8_t b); esp_err_t print_u8(uint8_t b);
/// Writes a string to the display. /// Writes a string to the display.
void write_str(const char* s); esp_err_t write_str(const char* s);
}; };
#endif // LCD2004_HPP #endif // LCD2004_HPP
+2 -3
View File
@@ -2,11 +2,10 @@
#define BLK_BOX_H #define BLK_BOX_H
struct BlkBoxInitConfig { struct BlkBoxInitConfig {
// nothing for now... /// Initial character LCD backlight state.
bool lcd_backlight = true;
}; };
void init_blk_box(BlkBoxInitConfig cfg); void init_blk_box(BlkBoxInitConfig cfg);
#endif // BLK_BOX_H #endif // BLK_BOX_H
+1 -1
View File
@@ -18,7 +18,7 @@ enum class CursorMode: uint8_t {
}; };
/// Initializes the 2004 Character LCD /// Initializes the 2004 Character LCD
void init_lcd(); void init_lcd(bool initial_backlight);
class LCDController { class LCDController {
public: public: