#include "blk_box_drivers/char_lcd.hpp" #include "lcd2004.hpp" #include #include #include // 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(); }