#include "i2c.h" #include "lcd.h" #include "globals.h" #include #include #include #define LCD_ENABLE 0x03 /* the 4x40 LCDs have two enable lines - 0x03 enables both at the same time */ #define LCD_DATA_RAM 128 /* display RAM, in the LCD ICs */ #define LCD_CG_RAM 64 /* custom character RAM, in the LCD ICs */ #define LCD_chars_total 160 char LCD_Data[LCD_rows][LCD_cols]; /* shadow copy of LCD display in local RAM, to minimize slow I2C writes */ /*** EndHeader */ static void break_up_string (char *in_string, int N, char **str1, char **str2, char **str3) { int i; gchar** words = g_strsplit(in_string, " ", -1); GString* rows[3]; for (i = 0; i<3; i++) { rows[i] = g_string_new(NULL); } int row = 0; int col = 0; gchar** word; for (word = words; *word != NULL; word++) { int wordlen = strlen(*word); if (wordlen > N) { // model numbers can be up to 64 chars int remainder = col + wordlen - N; if (row < 3) { g_string_append(rows[row], *word); col = 0; row++; } if (row < 3) { g_string_append(rows[row], *word + (wordlen - remainder)); col += remainder; } } else { if (col + wordlen > N) { col = 0; row++; } if (row < 3) { g_string_append(rows[row], *word); col += wordlen; } } if ((row < 3) && (col != 0) && (col < N)) { g_string_append(rows[row], " "); col++; } if (col >= N) { col = 0; row++; } } for (i = 0; i<3; i++) { g_string_truncate (rows[i], N); } *str1 = g_string_free(rows[0], FALSE); *str2 = g_string_free(rows[1], FALSE); *str3 = g_string_free(rows[2], FALSE); g_strfreev(words); } void LCD_clear() { int i; int j; I2C_Write(PCF8574A+LCD_Port, 0x00 | LCD_ENABLE); I2C_Write(PCF8574A+LCD_Port, 0x00); I2C_Write(PCF8574A+LCD_Port, 0x10 | LCD_ENABLE); I2C_Write(PCF8574A+LCD_Port, 0x10); /* wait 1.64ms */ g_usleep(1640); for (i=0; i<4; ++i) for (j=0; j<40; ++j) { LCD_Data[i][j]=0; } return; } static void LCD_RAM_write(int RAM_start,int row, int col, char *LCD_string) { /* rows: 0-3, cols: 0-39 */ #define data_level 0x04 int i; int cur_row, cur_col; int String_length; char char_out, enable_one_lcd; int ram_location; char last_op_a_write; if (!LCD_string) { return; } String_length=strlen(LCD_string); enable_one_lcd=0x02; last_op_a_write=0; cur_row=row; cur_col=col; if (cur_row<2) { enable_one_lcd=0x02; } else { enable_one_lcd=0x01; } /* write out the string */ for (i=0; i= LCD_rows) || (cur_col >= LCD_cols)) { break; } if (LCD_string[i]!=LCD_Data[cur_row][cur_col]) { if (!last_op_a_write) { /* move to new position */ ram_location = (cur_row & 1) * 64 + cur_col + RAM_start; char_out=ram_location & 0xf0; I2C_Write(PCF8574A+LCD_Port, char_out | enable_one_lcd); I2C_Write(PCF8574A+LCD_Port, char_out); char_out=ram_location << 4; I2C_Write(PCF8574A+LCD_Port, char_out | enable_one_lcd); I2C_Write(PCF8574A+LCD_Port, char_out); } LCD_Data[cur_row][cur_col]=LCD_string[i]; char_out=LCD_string[i] & 0xf0; I2C_Write(PCF8574A+LCD_Port, char_out | enable_one_lcd | data_level); I2C_Write(PCF8574A+LCD_Port, char_out | data_level); char_out=LCD_string[i] << 4; I2C_Write(PCF8574A+LCD_Port, char_out | enable_one_lcd | data_level); I2C_Write(PCF8574A+LCD_Port, char_out | data_level); last_op_a_write=1; } else { last_op_a_write=0; } ++cur_col; if (cur_col==40) { cur_col=0; ++cur_row; } } return; } void LCD_write(int row, int col, char *LCD_string) { LCD_RAM_write(LCD_DATA_RAM, row, col, LCD_string); } void LCD_write_padded_spaces(int row, int col, char *LCD_string, int width) { gchar *padded = NULL; int in_len = strlen (LCD_string); if (in_len > width) { padded = g_strdup (LCD_string); padded[width] = 0; } else { padded = g_strdup_printf ("%s%*s", LCD_string, width - in_len, ""); } LCD_write(row, col, padded); g_free (padded); } void LCD_write_padded_to_end_of_line(int row, int col, char *LCD_string) { LCD_write_padded_spaces (row, col, LCD_string, LCD_cols - col); } static void LCD_make_custom_chars() { /* define custom LCD characters 2 and 3 (up arrow and down arrow).*/ /* The up arrow is stored in one LCD controller (for rows 0 and 1) */ /* The down arrow is stored in the other LCD controller (for rows 2 and 3) */ LCD_RAM_write(LCD_CG_RAM,0,16,"\x4"); LCD_RAM_write(LCD_CG_RAM,0,17,"\xe"); LCD_RAM_write(LCD_CG_RAM,0,18,"\x15"); LCD_RAM_write(LCD_CG_RAM,0,19,"\x4"); LCD_RAM_write(LCD_CG_RAM,0,20,"\x4"); LCD_RAM_write(LCD_CG_RAM,0,21,"\x4"); LCD_RAM_write(LCD_CG_RAM,0,22,"\x4"); LCD_RAM_write(LCD_CG_RAM,0,23,"\x4"); LCD_RAM_write(LCD_CG_RAM,2,24,"\x4"); LCD_RAM_write(LCD_CG_RAM,2,25,"\x4"); LCD_RAM_write(LCD_CG_RAM,2,26,"\x4"); LCD_RAM_write(LCD_CG_RAM,2,27,"\x4"); LCD_RAM_write(LCD_CG_RAM,2,28,"\x4"); LCD_RAM_write(LCD_CG_RAM,2,29,"\x15"); LCD_RAM_write(LCD_CG_RAM,2,30,"\xe"); LCD_RAM_write(LCD_CG_RAM,2,31,"\x4"); // prove that it works - debug only // LCD_RAM_write(LCD_DATA_RAM,0,39,"\x2"); // LCD_RAM_write(LCD_DATA_RAM,3,39,"\x3"); return; } void LCD_initialize(void) { /* Wait 15ms */ g_usleep(15000); I2C_Write(PCF8574A+LCD_Port, 0x30 | LCD_ENABLE); I2C_Write(PCF8574A+LCD_Port, 0x30); /* wait 4.1ms */ g_usleep(4100); I2C_Write(PCF8574A+LCD_Port, 0x30 | LCD_ENABLE); I2C_Write(PCF8574A+LCD_Port, 0x30); /* wait 100us */ g_usleep(100); I2C_Write(PCF8574A+LCD_Port, 0x30 | LCD_ENABLE); I2C_Write(PCF8574A+LCD_Port, 0x30); /* wait 4.1ms */ g_usleep(4100); I2C_Write(PCF8574A+LCD_Port, 0x20 | LCD_ENABLE); I2C_Write(PCF8574A+LCD_Port, 0x20); /*wait 40us */ g_usleep(40); I2C_Write(PCF8574A+LCD_Port, 0x20 | LCD_ENABLE); I2C_Write(PCF8574A+LCD_Port, 0x20); I2C_Write(PCF8574A+LCD_Port, 0x80 | LCD_ENABLE); I2C_Write(PCF8574A+LCD_Port, 0x80); /* wait 40us */ g_usleep(40); LCD_clear(); I2C_Write(PCF8574A+LCD_Port, 0x00 | LCD_ENABLE); I2C_Write(PCF8574A+LCD_Port, 0x00); I2C_Write(PCF8574A+LCD_Port, 0x60 | LCD_ENABLE); I2C_Write(PCF8574A+LCD_Port, 0x60); /* wait 40us */ g_usleep(40); I2C_Write(PCF8574A+LCD_Port, 0x00 | LCD_ENABLE); I2C_Write(PCF8574A+LCD_Port, 0x00); I2C_Write(PCF8574A+LCD_Port, 0xc0 | LCD_ENABLE); I2C_Write(PCF8574A+LCD_Port, 0xc0); LCD_make_custom_chars(); return; } void LCD_display_extended_message(char *response, gboolean show_change_message, gboolean is_error_screen) { char *row0 = NULL; char *row1 = NULL; char *row2 = NULL; g_assert (response); if (is_error_screen) { globals.MenuStatus.Error_Screen = is_error_screen; } break_up_string (response, LCD_cols, &row0, &row1, &row2); LCD_clear(); LCD_write(0,0,row0); LCD_write(1,0,row1); LCD_write(2,0,row2); if (show_change_message) { LCD_write(3,0,Press_Change_Message); } g_free (row0); g_free (row1); g_free (row2); return; }