No Description
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

lcd.cpp 9.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340
  1. #include <Arduino.h>
  2. #include "config.h"
  3. #include "config_pins.h"
  4. #include "lcd.h"
  5. #if (defined(USE_20X4_TEXT_LCD) && defined(USE_FULL_GRAPHIC_LCD)) || (!defined(USE_20X4_TEXT_LCD) && !defined(USE_FULL_GRAPHIC_LCD))
  6. #error define one of USE_20X4_TEXT_LCD or USE_FULL_GRAPHIC_LCD
  7. #endif
  8. #ifdef USE_20X4_TEXT_LCD
  9. #include <LiquidCrystal.h>
  10. #define LCD_HEADING_LINES 1
  11. #define LCD_HEADING_WIDTH 20
  12. #define LCD_TEXT_LINES 3
  13. #define LCD_TEXT_WIDTH 20
  14. LiquidCrystal lcd(LCD_PINS_RS, LCD_PINS_ENABLE, LCD_PINS_D4, LCD_PINS_D5, LCD_PINS_D6, LCD_PINS_D7);
  15. #endif // USE_20X4_TEXT_LCD
  16. #ifdef USE_FULL_GRAPHIC_LCD
  17. #include <U8g2lib.h>
  18. #define ENABLE_DYNAMIC_SCROLLING
  19. #define LCD_HEADING_LINES 1
  20. #define LCD_HEADING_WIDTH 15
  21. #define LCD_TEXT_LINES 5
  22. #define LCD_TEXT_WIDTH 25
  23. #define LCD_HEADING_FONT u8g2_font_torussansbold8_8r
  24. #define LCD_TEXT_FONT u8g2_font_5x7_tr
  25. #define LCD_HEADING_TEXT_OFFSET 3
  26. #define LCD_HEADING_HEIGHT 8
  27. #define LCD_TEXT_HEIGHT 9
  28. U8G2_ST7920_128X64_1_SW_SPI lcd(U8G2_R0, LCD_PINS_SCK, LCD_PINS_MOSI, LCD_PINS_CS);
  29. #endif // USE_FULL_GRAPHIC_LCD
  30. String heading[LCD_HEADING_LINES];
  31. String text[LCD_TEXT_LINES];
  32. String heading_pre, heading_post;
  33. String text_pre, text_post;
  34. int heading_direction, text_direction;
  35. String menu_pre[LCD_TEXT_LINES], menu_post[LCD_TEXT_LINES];
  36. int menu_dir[LCD_TEXT_LINES];
  37. int scroll_offset = 0;
  38. boolean redraw = false;
  39. enum lcd_text_mode {
  40. lcd_mode_none,
  41. lcd_mode_multiline,
  42. lcd_mode_menu
  43. };
  44. enum lcd_text_mode text_mode = lcd_mode_none;
  45. #define SCROLL_DELAY 1000
  46. unsigned long last_scroll_time = 0;
  47. #define IS_TEXT_CHAR(x) (((x >= 'a') && (x <= 'z')) || ((x >= 'A') && (x <= 'Z')))
  48. void lcd_shorten_multiline(String s[], int n, int w, String *remainder) {
  49. String for_next_line = "";
  50. for (int i = 0; i < n; i++) {
  51. // take previously stored string and put in front of line
  52. s[i] = for_next_line + s[i];
  53. for_next_line = "";
  54. // if a line is longer then w, take end off and store
  55. if (s[i].length() > w) {
  56. for_next_line += s[i].substring(w);
  57. s[i] = s[i].substring(0, w);
  58. }
  59. // if a newline is in this line, end the text there and split it
  60. for (int j = 0; j < s[i].length(); j++) {
  61. if (s[i][j] == '\n') {
  62. for_next_line = s[i].substring(j + 1) + for_next_line;
  63. s[i] = s[i].substring(0, j);
  64. break;
  65. }
  66. }
  67. // if the last char of this line and the first char of for_next_line
  68. // exist and are both upper/lowercase characters, check if one of the
  69. // previous 5 chars is a space, and instead split there
  70. if ((n > 1) && (for_next_line.length() > 0) && IS_TEXT_CHAR(s[i][s[i].length() - 1]) && IS_TEXT_CHAR(for_next_line[0])) {
  71. for (int j = s[i].length() - 2; (j >= 0) && (j >= s[i].length() - 2 - 5); j--) {
  72. if (s[i][j] == ' ') {
  73. for_next_line = s[i].substring(j + 1) + for_next_line;
  74. s[i] = s[i].substring(0, j + 1);
  75. break;
  76. }
  77. }
  78. }
  79. }
  80. // if something remains at end, store remainder, if given, otherwise leave at last line
  81. if (remainder != NULL) {
  82. *remainder = for_next_line;
  83. } else {
  84. s[n - 1] = s[n - 1] + for_next_line;
  85. }
  86. last_scroll_time = millis();
  87. }
  88. #ifdef ENABLE_DYNAMIC_SCROLLING
  89. void lcd_scroll_multiline(String s[], int n, int w, String &pre, String &post, int &dir) {
  90. if (dir == 0) {
  91. // switch directions if done scrolling in current direction
  92. if (post.length() == 0) {
  93. dir = 1;
  94. return;
  95. }
  96. // take first char of first line, append to pre
  97. pre = pre + s[0][scroll_offset];
  98. s[0] = s[0].substring(0, scroll_offset) + s[0].substring(scroll_offset + 1);
  99. // shift now empty spot to the left through lines
  100. for (int i = 1; i < n; i++) {
  101. s[i - 1] = s[i - 1] + s[i][scroll_offset];
  102. s[i] = s[i].substring(0, scroll_offset) + s[i].substring(scroll_offset + 1);
  103. }
  104. // fill empty spot at end of last line with first char of post
  105. s[n - 1] = s[n - 1] + post[0];
  106. post = post.substring(1);
  107. } else {
  108. // switch directions if done scrolling in current direction
  109. if (pre.length() == 0) {
  110. dir = 0;
  111. return;
  112. }
  113. // take last char of last line, prepend to post
  114. post = s[n - 1][s[n - 1].length() - 1] + post;
  115. s[n - 1] = s[n - 1].substring(0, s[n - 1].length() - 1);
  116. // shift now empty sport to the right through lines
  117. for (int i = n - 1; i >= 1; i--) {
  118. s[i] = s[i].substring(0, scroll_offset) + s[i - 1][s[i - 1].length() - 1] + s[i].substring(scroll_offset);
  119. s[i - 1] = s[i - 1].substring(0, s[i - 1].length() - 1);
  120. }
  121. // fill empty spot at beginning with last char of pre
  122. s[0] = s[0].substring(0, scroll_offset) + pre[pre.length() - 1] + s[0].substring(scroll_offset);
  123. pre = pre.substring(0, pre.length() - 1);
  124. }
  125. redraw = true;
  126. }
  127. void lcd_scrolling(void) {
  128. if (text_mode != lcd_mode_none) {
  129. if ((heading_pre.length() > 0) || (heading_post.length() > 0)) {
  130. lcd_scroll_multiline(heading, LCD_HEADING_LINES, LCD_HEADING_WIDTH,
  131. heading_pre, heading_post, heading_direction);
  132. }
  133. }
  134. if (text_mode == lcd_mode_multiline) {
  135. if ((text_pre.length() > 0) || (text_post.length() > 0)) {
  136. lcd_scroll_multiline(text, LCD_TEXT_LINES, LCD_TEXT_WIDTH,
  137. text_pre, text_post, text_direction);
  138. }
  139. } else if (text_mode == lcd_mode_menu) {
  140. for (int i = 0; i < LCD_TEXT_LINES; i++) {
  141. if ((menu_pre[i].length() > 0) || (menu_post[i].length() > 0)) {
  142. lcd_scroll_multiline(text + i, 1, LCD_TEXT_WIDTH,
  143. menu_pre[i], menu_post[i], menu_dir[i]);
  144. }
  145. }
  146. }
  147. }
  148. #endif // ENABLE_DYNAMIC_SCROLLING
  149. int lcd_text_lines(void) {
  150. return LCD_TEXT_LINES;
  151. }
  152. void lcd_init(void) {
  153. #ifdef USE_20X4_TEXT_LCD
  154. lcd.begin(20, 4);
  155. lcd.clear();
  156. lcd.print(F(" Fuellfix v2 "));
  157. lcd.print(F(" Initializing.... "));
  158. lcd.print(F("Software Version "));
  159. lcd.print(F(FIRMWARE_VERSION));
  160. lcd.print(F("made by: xythobuz.de"));
  161. #endif // USE_20X4_TEXT_LCD
  162. #ifdef USE_FULL_GRAPHIC_LCD
  163. lcd.begin();
  164. lcd.firstPage();
  165. do {
  166. lcd.setFont(u8g2_font_luBS12_tr);
  167. String s = F("Fuellfix v2");
  168. lcd.drawStr(0, 14 * 1, s.c_str());
  169. s = F("Initializing");
  170. lcd.drawStr(0, 14 * 2, s.c_str());
  171. lcd.setFont(u8g2_font_t0_12b_tr);
  172. s = F("Software Version " FIRMWARE_VERSION);
  173. lcd.drawStr(0, 14 * 2 + 8 + 12 * 1, s.c_str());
  174. s = F("made by: xythobuz.de");
  175. lcd.drawStr(0, 14 * 2 + 8 + 12 * 2, s.c_str());
  176. } while (lcd.nextPage());
  177. #endif // USE_FULL_GRAPHIC_LCD
  178. }
  179. void lcd_loop(void) {
  180. #ifdef ENABLE_DYNAMIC_SCROLLING
  181. if ((millis() - last_scroll_time) >= SCROLL_DELAY) {
  182. last_scroll_time = millis();
  183. lcd_scrolling();
  184. }
  185. #endif // ENABLE_DYNAMIC_SCROLLING
  186. #ifdef USE_FULL_GRAPHIC_LCD
  187. if (redraw) {
  188. lcd.firstPage();
  189. do {
  190. lcd.setFont(LCD_HEADING_FONT);
  191. for (int i = 0; i < LCD_HEADING_LINES; i++) {
  192. lcd.drawStr(0, LCD_HEADING_HEIGHT * (i + 1), heading[i].c_str());
  193. }
  194. lcd.setFont(LCD_TEXT_FONT);
  195. for (int i = 0; i < LCD_TEXT_LINES; i++) {
  196. lcd.drawStr(0, LCD_HEADING_HEIGHT * LCD_HEADING_LINES + LCD_HEADING_TEXT_OFFSET + LCD_TEXT_HEIGHT * (i + 1), text[i].c_str());
  197. }
  198. } while (lcd.nextPage());
  199. redraw = false;
  200. }
  201. #endif // USE_FULL_GRAPHIC_LCD
  202. }
  203. void lcd_clear(void) {
  204. //Serial.println();
  205. text_mode = lcd_mode_none;
  206. #ifdef USE_20X4_TEXT_LCD
  207. lcd.clear();
  208. #endif // USE_20X4_TEXT_LCD
  209. #ifdef USE_FULL_GRAPHIC_LCD
  210. for (int i = 0; i < LCD_HEADING_LINES; i++) {
  211. heading[i] = "";
  212. }
  213. for (int i = 0; i < LCD_TEXT_LINES; i++) {
  214. text[i] = "";
  215. }
  216. redraw = true;
  217. #endif // USE_FULL_GRAPHIC_LCD
  218. }
  219. void lcd_set_heading(const char *h) {
  220. Serial.println(h);
  221. #ifdef USE_20X4_TEXT_LCD
  222. lcd.setCursor(0, 0);
  223. lcd.print(h);
  224. #endif // USE_20X4_TEXT_LCD
  225. #ifdef USE_FULL_GRAPHIC_LCD
  226. heading[0] = h;
  227. heading_pre = "";
  228. heading_direction = 0;
  229. lcd_shorten_multiline(heading, LCD_HEADING_LINES, LCD_HEADING_WIDTH, &heading_post);
  230. redraw = true;
  231. #endif // USE_FULL_GRAPHIC_LCD
  232. }
  233. void lcd_set_text(const char *t) {
  234. Serial.println(t);
  235. text_mode = lcd_mode_multiline;
  236. scroll_offset = 0;
  237. #ifdef USE_20X4_TEXT_LCD
  238. lcd.setCursor(0, LCD_HEADING_LINES);
  239. lcd.print(t);
  240. #endif // USE_20X4_TEXT_LCD
  241. #ifdef USE_FULL_GRAPHIC_LCD
  242. text[0] = t;
  243. text_pre = "";
  244. text_direction = 0;
  245. lcd_shorten_multiline(text, LCD_TEXT_LINES, LCD_TEXT_WIDTH, &text_post);
  246. redraw = true;
  247. #endif // USE_FULL_GRAPHIC_LCD
  248. }
  249. void lcd_set_menu_text(int line, const char *t, int scroll_off) {
  250. if ((line < 0) || (line >= LCD_TEXT_LINES)) {
  251. Serial.print(F("Invalid lcd line no: "));
  252. Serial.println(line);
  253. return;
  254. }
  255. //Serial.print(line);
  256. //Serial.print(F(": "));
  257. Serial.println(t);
  258. text_mode = lcd_mode_menu;
  259. scroll_offset = scroll_off;
  260. #ifdef USE_20X4_TEXT_LCD
  261. lcd.setCursor(0, LCD_HEADING_LINES + line);
  262. lcd.print(t);
  263. #endif // USE_20X4_TEXT_LCD
  264. #ifdef USE_FULL_GRAPHIC_LCD
  265. text[line] = t;
  266. menu_pre[line] = "";
  267. menu_dir[line] = 0;
  268. lcd_shorten_multiline(text + line, 1, LCD_TEXT_WIDTH, menu_post + line);
  269. redraw = true;
  270. #endif // USE_FULL_GRAPHIC_LCD
  271. }