318 lines
9.7 KiB
C++
318 lines
9.7 KiB
C++
#include "blk_box_drivers/char_lcd.hpp"
|
|
|
|
#include "lcd2004.hpp"
|
|
|
|
#include <freertos/FreeRTOS.h>
|
|
#include <freertos/semphr.h>
|
|
#include <esp_log.h>
|
|
|
|
// mutex is for all these vars
|
|
SemaphoreHandle_t lcd_mutex;
|
|
|
|
LCD2004I2C lcd;
|
|
|
|
static CursorMode cursor_resting_mode = CursorMode::Hide;
|
|
static CursorMode cursor_print_mode = CursorMode::Hide;
|
|
static uint8_t resting_cursor_row = 0;
|
|
static uint8_t resting_cursor_col = 0;
|
|
|
|
static bool is_header_enabled = false;
|
|
|
|
static const char *TAG = "char_lcd";
|
|
static const char* EMPTY_ROW = " ";
|
|
|
|
// TODO: move this to power.cpp
|
|
// static void monitor_battery_task(void* _arg) {
|
|
// (void) _arg;
|
|
|
|
// while (true) {
|
|
// vTaskDelay(pdMS_TO_TICKS(1'000));
|
|
// lcd_print_header_bat();
|
|
// }
|
|
// }
|
|
|
|
// static bool replay_handler(const char* event, char* arg) {
|
|
// if (strcmp(event, "LCD_CLEAR") == 0) {
|
|
// lcd_clear();
|
|
// }
|
|
// else if (strcmp(event, "LCD_SET_DISPLAY") == 0) {
|
|
// lcd_set_display(strcmp(arg, "true") == 0);
|
|
// }
|
|
// else if (strcmp(event, "LCD_CURSOR_VIS") == 0) {
|
|
// lcd_set_cursor_vis(strcmp(arg, "true") == 0);
|
|
// }
|
|
// else if (strcmp(event, "LCD_CURSOR_BLINK") == 0) {
|
|
// lcd_set_cursor_blink(strcmp(arg, "true") == 0);
|
|
// }
|
|
// else if (strcmp(event, "LCD_SCROLL_DISPLAY_LEFT") == 0) {
|
|
// lcd_scroll_display_left();
|
|
// }
|
|
// else if (strcmp(event, "LCD_SCROLL_DISPLAY_RIGHT") == 0) {
|
|
// lcd_scroll_display_right();
|
|
// }
|
|
// else if (strcmp(event, "LCD_LEFT_TO_RIGHT") == 0) {
|
|
// lcd_left_to_right();
|
|
// }
|
|
// else if (strcmp(event, "LCD_RIGHT_TO_LEFT") == 0) {
|
|
// lcd_right_to_left();
|
|
// }
|
|
// else if (strcmp(event, "LCD_AUTOSCROLL") == 0) {
|
|
// lcd_set_autoscroll(strcmp(arg, "true") == 0);
|
|
// }
|
|
// else if (strcmp(event, "LCD_BACKLIGHT") == 0) {
|
|
// lcd_set_backlight(strcmp(arg, "true") == 0);
|
|
// }
|
|
// else if (strcmp(event, "LCD_CREATE_CHAR") == 0) {
|
|
// char* location_str = strtok(arg, ",");
|
|
// uint8_t location = atoi(location_str);
|
|
|
|
// uint8_t charmap[8];
|
|
// for (int i = 0; i < 8; i++) {
|
|
// char* str = strtok(NULL, ",");
|
|
// charmap[i] = atoi(str);
|
|
// }
|
|
|
|
// lcd_create_char(location, charmap);
|
|
// }
|
|
// else if (strcmp(event, "LCD_PRINT") == 0) {
|
|
// char* str = strtok(arg, ",");
|
|
// uint8_t row = atoi(str);
|
|
// str = strtok(NULL, ",");
|
|
// uint8_t col = atoi(str);
|
|
// // get remaining part of string.
|
|
// str = strtok(NULL, "");
|
|
|
|
// // TODO: handle \r and \n
|
|
// lcd_print(row, col, str);
|
|
// } else {
|
|
// return false;
|
|
// }
|
|
|
|
// return true;
|
|
// }
|
|
|
|
void init_lcd() {
|
|
ESP_LOGI(TAG, "Initializing LCD...");
|
|
|
|
lcd_mutex = xSemaphoreCreateRecursiveMutex();
|
|
assert(lcd_mutex != NULL);
|
|
|
|
lcd = LCD2004I2C();
|
|
lcd.init(LCD_ADDR);
|
|
|
|
// register_replay_fn(replay_handler);
|
|
|
|
// xTaskCreate(monitor_battery_task, "bat_monitor", 1024*2, nullptr, 0, nullptr);
|
|
|
|
ESP_LOGI(TAG, "LCD initialized!");
|
|
}
|
|
|
|
void LCDController::clear() {
|
|
xSemaphoreTakeRecursive(lcd_mutex, portMAX_DELAY);
|
|
|
|
if (!is_header_enabled) {
|
|
lcd.clear();
|
|
|
|
// if (is_state_tracking()) {
|
|
// event_occured("LCD_CLEAR", NULL);
|
|
// }
|
|
} else {
|
|
print(1, 0, EMPTY_ROW);
|
|
print(2, 0, EMPTY_ROW);
|
|
print(3, 0, EMPTY_ROW);
|
|
}
|
|
|
|
xSemaphoreGiveRecursive(lcd_mutex);
|
|
}
|
|
|
|
bool LCDController::get_backlight() {
|
|
xSemaphoreTakeRecursive(lcd_mutex, portMAX_DELAY);
|
|
bool backlight = lcd.get_backlight();
|
|
xSemaphoreGiveRecursive(lcd_mutex);
|
|
return backlight;
|
|
}
|
|
|
|
void LCDController::set_backlight(bool backlight) {
|
|
xSemaphoreTakeRecursive(lcd_mutex, portMAX_DELAY);
|
|
lcd.set_backlight(backlight);
|
|
xSemaphoreGiveRecursive(lcd_mutex);
|
|
|
|
// if (is_state_tracking()) {
|
|
// sprintf(buf, "%d", backlight);
|
|
// event_occured("LCD_BACKLIGHT", backlight ? "true" : "false");
|
|
// }
|
|
}
|
|
|
|
void LCDController::set_display_show(bool show_display) {
|
|
xSemaphoreTakeRecursive(lcd_mutex, portMAX_DELAY);
|
|
lcd.show_hide(show_display);
|
|
xSemaphoreGiveRecursive(lcd_mutex);
|
|
}
|
|
|
|
bool LCDController::get_display_show() {
|
|
xSemaphoreTakeRecursive(lcd_mutex, portMAX_DELAY);
|
|
bool show_display = lcd.get_show_hide();
|
|
xSemaphoreGiveRecursive(lcd_mutex);
|
|
return show_display;
|
|
}
|
|
|
|
/// Changes the cursor display mode to the given mode.
|
|
static void change_cursor_display(CursorMode cursor_display_mode) {
|
|
xSemaphoreTakeRecursive(lcd_mutex, portMAX_DELAY);
|
|
lcd.show_blink_cursor(
|
|
cursor_display_mode != CursorMode::Hide,
|
|
cursor_display_mode == CursorMode::Blink
|
|
);
|
|
xSemaphoreGiveRecursive(lcd_mutex);
|
|
}
|
|
|
|
/// Moves the position of the resting cursor.
|
|
///
|
|
/// If the resting cursor mode is `Hide`, then this position has no effect on the display, but is still stored
|
|
/// for when it is put into resting cursor mode.
|
|
void LCDController::set_resting_cursor_pos(uint8_t row, uint8_t col) {
|
|
xSemaphoreTakeRecursive(lcd_mutex, portMAX_DELAY);
|
|
|
|
// update pos if we're not hiding the resting cursor
|
|
if (
|
|
(resting_cursor_row != row || resting_cursor_col != col) &&
|
|
cursor_resting_mode != CursorMode::Hide
|
|
) {
|
|
lcd.move_cursor(row, col);
|
|
}
|
|
|
|
resting_cursor_row = row;
|
|
resting_cursor_col = col;
|
|
xSemaphoreGiveRecursive(lcd_mutex);
|
|
}
|
|
|
|
/// Gets the position of the resting cursor.
|
|
///
|
|
/// This will return the value of the resting cursor position even if the resting cursor mode is `Hide`
|
|
/// even though the values are not meaningful during that time.
|
|
void LCDController::get_cursor_resting_position(uint8_t* row, uint8_t* col) {
|
|
xSemaphoreTakeRecursive(lcd_mutex, portMAX_DELAY);
|
|
if (row) *row = resting_cursor_row;
|
|
if (col) *col = resting_cursor_col;
|
|
xSemaphoreGiveRecursive(lcd_mutex);
|
|
}
|
|
|
|
/// This puts the display in and out of resting cursor mode.
|
|
///
|
|
/// If the resting mode is not `Hide`, then the cursor will be displayed in the resting position when not printing.
|
|
///
|
|
/// The cursor mode will change to the "cursor print mode"
|
|
/// during prints, then return to it's resting location and
|
|
/// switch back to the "cursor resting mode".
|
|
void LCDController::set_resting_cursor_mode(CursorMode new_mode) {
|
|
xSemaphoreTakeRecursive(lcd_mutex, portMAX_DELAY);
|
|
if (cursor_resting_mode != new_mode) {
|
|
cursor_resting_mode = new_mode;
|
|
change_cursor_display(cursor_resting_mode);
|
|
if (cursor_resting_mode != CursorMode::Hide) {
|
|
lcd.move_cursor(resting_cursor_row, resting_cursor_col);
|
|
}
|
|
}
|
|
xSemaphoreGiveRecursive(lcd_mutex);
|
|
}
|
|
|
|
/// Gets the display mode of the cursor when it is resting.
|
|
CursorMode LCDController::get_resting_cursor_mode() {
|
|
xSemaphoreTakeRecursive(lcd_mutex, portMAX_DELAY);
|
|
CursorMode mode = cursor_resting_mode;
|
|
xSemaphoreGiveRecursive(lcd_mutex);
|
|
return mode;
|
|
}
|
|
|
|
/// Sets the display mode of the cursor during printing.
|
|
void LCDController::set_cursor_print_mode(CursorMode new_mode) {
|
|
xSemaphoreTakeRecursive(lcd_mutex, portMAX_DELAY);
|
|
cursor_print_mode = new_mode;
|
|
xSemaphoreGiveRecursive(lcd_mutex);
|
|
}
|
|
|
|
/// Gets the display mode of the cursor during printing.
|
|
CursorMode LCDController::get_cursor_print_mode() {
|
|
xSemaphoreTakeRecursive(lcd_mutex, portMAX_DELAY);
|
|
CursorMode mode = cursor_print_mode;
|
|
xSemaphoreGiveRecursive(lcd_mutex);
|
|
return mode;
|
|
}
|
|
|
|
void LCDController::create_custom_char(uint8_t location, const uint8_t charmap[]) {
|
|
if (location == 8) location = 0;
|
|
|
|
xSemaphoreTakeRecursive(lcd_mutex, portMAX_DELAY);
|
|
lcd.create_custom_char(location, charmap);
|
|
xSemaphoreGiveRecursive(lcd_mutex);
|
|
|
|
// if (is_state_tracking()) {
|
|
// snprintf(buf, sizeof(buf),
|
|
// "%d,%d,%d,%d,%d,%d,%d,%d,%d", location,
|
|
// charmap[0], charmap[1], charmap[2], charmap[3], charmap[4], charmap[5], charmap[6], charmap[7]
|
|
// );
|
|
// event_occured("LCD_CREATE_CHAR", buf);
|
|
// }
|
|
}
|
|
|
|
/// Prints a string to the given row and column.
|
|
///
|
|
/// Do not print across lines, as that leads to goofy behavior.
|
|
void LCDController::print(uint8_t row, uint8_t col, const char* str) {
|
|
xSemaphoreTakeRecursive(lcd_mutex, portMAX_DELAY);
|
|
lcd.move_cursor(row, col);
|
|
change_cursor_display(cursor_print_mode);
|
|
lcd.write_str(str);
|
|
|
|
if (cursor_resting_mode != CursorMode::Hide) {
|
|
lcd.move_cursor(resting_cursor_row, resting_cursor_col);
|
|
}
|
|
if (cursor_resting_mode != cursor_print_mode) {
|
|
change_cursor_display(cursor_resting_mode);
|
|
}
|
|
|
|
xSemaphoreGiveRecursive(lcd_mutex);
|
|
|
|
// if (is_state_tracking()) {
|
|
// // TODO: handle \r and \n and others
|
|
// snprintf(buf, sizeof(buf), "%d,%d,%s", row, col, str);
|
|
// event_occured("LCD_PRINT", buf);
|
|
// }
|
|
}
|
|
|
|
void LCDController::set_lcd_header_enabled(bool enable) {
|
|
xSemaphoreTakeRecursive(lcd_mutex, portMAX_DELAY);
|
|
bool old_header_enabled = is_header_enabled;
|
|
is_header_enabled = enable;
|
|
|
|
// print the header in response to enabling/disabling it
|
|
if (enable && !old_header_enabled) {
|
|
print_header();
|
|
} else if (!enable && old_header_enabled) {
|
|
print(0, 0, EMPTY_ROW);
|
|
}
|
|
xSemaphoreGiveRecursive(lcd_mutex);
|
|
}
|
|
|
|
bool LCDController::header_enabled() {
|
|
xSemaphoreTakeRecursive(lcd_mutex, portMAX_DELAY);
|
|
bool enabled = is_header_enabled;
|
|
xSemaphoreGiveRecursive(lcd_mutex);
|
|
return enabled;
|
|
}
|
|
|
|
bool LCDController::lock(uint32_t ticks_to_wait) {
|
|
return xSemaphoreTakeRecursive(lcd_mutex, ticks_to_wait);
|
|
}
|
|
|
|
void LCDController::unlock() {
|
|
xSemaphoreGiveRecursive(lcd_mutex);
|
|
}
|
|
|
|
void LCDController::print_header() {
|
|
// TODO:
|
|
// lcd_print_header_star_code();
|
|
// lcd_print_header_step();
|
|
// lcd_print_header_bat();
|
|
}
|