lcd.cpp 22 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000
  1. //menu.cpp
  2. #include "lcd.h"
  3. #include <stdio.h>
  4. #include <stdarg.h>
  5. #include <avr/pgmspace.h>
  6. #include <util/delay.h>
  7. #include "Timer.h"
  8. #include "Configuration.h"
  9. #include "pins.h"
  10. #include <binary.h>
  11. #include <Arduino.h>
  12. #include "Marlin.h"
  13. #include "fastio.h"
  14. //-//
  15. #include "sound.h"
  16. #define LCD_DEFAULT_DELAY 100
  17. #if (defined(LCD_PINS_D0) && defined(LCD_PINS_D1) && defined(LCD_PINS_D2) && defined(LCD_PINS_D3))
  18. #define LCD_8BIT
  19. #endif
  20. // #define VT100
  21. // commands
  22. #define LCD_CLEARDISPLAY 0x01
  23. #define LCD_RETURNHOME 0x02
  24. #define LCD_ENTRYMODESET 0x04
  25. #define LCD_DISPLAYCONTROL 0x08
  26. #define LCD_CURSORSHIFT 0x10
  27. #define LCD_FUNCTIONSET 0x20
  28. #define LCD_SETCGRAMADDR 0x40
  29. #define LCD_SETDDRAMADDR 0x80
  30. // flags for display entry mode
  31. #define LCD_ENTRYRIGHT 0x00
  32. #define LCD_ENTRYLEFT 0x02
  33. #define LCD_ENTRYSHIFTINCREMENT 0x01
  34. #define LCD_ENTRYSHIFTDECREMENT 0x00
  35. // flags for display on/off control
  36. #define LCD_DISPLAYON 0x04
  37. #define LCD_DISPLAYOFF 0x00
  38. #define LCD_CURSORON 0x02
  39. #define LCD_CURSOROFF 0x00
  40. #define LCD_BLINKON 0x01
  41. #define LCD_BLINKOFF 0x00
  42. // flags for display/cursor shift
  43. #define LCD_DISPLAYMOVE 0x08
  44. #define LCD_CURSORMOVE 0x00
  45. #define LCD_MOVERIGHT 0x04
  46. #define LCD_MOVELEFT 0x00
  47. // flags for function set
  48. #define LCD_8BITMODE 0x10
  49. #define LCD_4BITMODE 0x00
  50. #define LCD_2LINE 0x08
  51. #define LCD_1LINE 0x00
  52. #define LCD_5x10DOTS 0x04
  53. #define LCD_5x8DOTS 0x00
  54. // bitmasks for flag argument settings
  55. #define LCD_RS_FLAG 0x01
  56. #define LCD_HALF_FLAG 0x02
  57. FILE _lcdout; // = {0}; Global variable is always zero initialized, no need to explicitly state that.
  58. uint8_t lcd_displayfunction = 0;
  59. uint8_t lcd_displaycontrol = 0;
  60. uint8_t lcd_displaymode = 0;
  61. uint8_t lcd_currline;
  62. #ifdef VT100
  63. uint8_t lcd_escape[8];
  64. #endif
  65. static void lcd_display(void);
  66. #if 0
  67. static void lcd_no_display(void);
  68. static void lcd_no_cursor(void);
  69. static void lcd_cursor(void);
  70. static void lcd_no_blink(void);
  71. static void lcd_blink(void);
  72. static void lcd_scrollDisplayLeft(void);
  73. static void lcd_scrollDisplayRight(void);
  74. static void lcd_leftToRight(void);
  75. static void lcd_rightToLeft(void);
  76. static void lcd_autoscroll(void);
  77. static void lcd_no_autoscroll(void);
  78. #endif
  79. #ifdef VT100
  80. void lcd_escape_write(uint8_t chr);
  81. #endif
  82. static void lcd_pulseEnable(void)
  83. {
  84. WRITE(LCD_PINS_ENABLE,HIGH);
  85. _delay_us(1); // enable pulse must be >450ns
  86. WRITE(LCD_PINS_ENABLE,LOW);
  87. }
  88. static void lcd_writebits(uint8_t value)
  89. {
  90. #ifdef LCD_8BIT
  91. WRITE(LCD_PINS_D0, value & 0x01);
  92. WRITE(LCD_PINS_D1, value & 0x02);
  93. WRITE(LCD_PINS_D2, value & 0x04);
  94. WRITE(LCD_PINS_D3, value & 0x08);
  95. #endif
  96. WRITE(LCD_PINS_D4, value & 0x10);
  97. WRITE(LCD_PINS_D5, value & 0x20);
  98. WRITE(LCD_PINS_D6, value & 0x40);
  99. WRITE(LCD_PINS_D7, value & 0x80);
  100. lcd_pulseEnable();
  101. }
  102. static void lcd_send(uint8_t data, uint8_t flags, uint16_t duration = LCD_DEFAULT_DELAY)
  103. {
  104. WRITE(LCD_PINS_RS,flags&LCD_RS_FLAG);
  105. _delay_us(5);
  106. lcd_writebits(data);
  107. #ifndef LCD_8BIT
  108. if (!(flags & LCD_HALF_FLAG))
  109. {
  110. _delay_us(LCD_DEFAULT_DELAY);
  111. lcd_writebits(data<<4);
  112. }
  113. #endif
  114. delayMicroseconds(duration);
  115. }
  116. static void lcd_command(uint8_t value, uint16_t delayExtra = 0)
  117. {
  118. lcd_send(value, LOW, LCD_DEFAULT_DELAY + delayExtra);
  119. }
  120. static void lcd_write(uint8_t value)
  121. {
  122. if (value == '\n' || value == '\r')
  123. {
  124. if (lcd_currline > 3) lcd_currline = -1;
  125. lcd_set_cursor(0, lcd_currline + 1); // LF
  126. return;
  127. }
  128. #ifdef VT100
  129. if (lcd_escape[0] || (value == 0x1b)){
  130. lcd_escape_write(value);
  131. return;
  132. }
  133. #endif
  134. lcd_send(value, HIGH);
  135. }
  136. static void lcd_begin(uint8_t clear)
  137. {
  138. lcd_currline = 0;
  139. lcd_send(LCD_FUNCTIONSET | LCD_8BITMODE, LOW | LCD_HALF_FLAG, 4500); // wait min 4.1ms
  140. // second try
  141. lcd_send(LCD_FUNCTIONSET | LCD_8BITMODE, LOW | LCD_HALF_FLAG, 150);
  142. // third go!
  143. lcd_send(LCD_FUNCTIONSET | LCD_8BITMODE, LOW | LCD_HALF_FLAG, 150);
  144. #ifndef LCD_8BIT
  145. // set to 4-bit interface
  146. lcd_send(LCD_FUNCTIONSET | LCD_4BITMODE, LOW | LCD_HALF_FLAG, 150);
  147. #endif
  148. // finally, set # lines, font size, etc.0
  149. lcd_command(LCD_FUNCTIONSET | lcd_displayfunction);
  150. // turn the display on with no cursor or blinking default
  151. lcd_displaycontrol = LCD_CURSOROFF | LCD_BLINKOFF;
  152. lcd_display();
  153. // clear it off
  154. if (clear) lcd_clear();
  155. // Initialize to default text direction (for romance languages)
  156. lcd_displaymode = LCD_ENTRYLEFT | LCD_ENTRYSHIFTDECREMENT;
  157. // set the entry mode
  158. lcd_command(LCD_ENTRYMODESET | lcd_displaymode);
  159. #ifdef VT100
  160. lcd_escape[0] = 0;
  161. #endif
  162. }
  163. static void lcd_putchar(char c, FILE *)
  164. {
  165. lcd_write(c);
  166. }
  167. void lcd_init(void)
  168. {
  169. WRITE(LCD_PINS_ENABLE,LOW);
  170. SET_OUTPUT(LCD_PINS_RS);
  171. SET_OUTPUT(LCD_PINS_ENABLE);
  172. #ifdef LCD_8BIT
  173. SET_OUTPUT(LCD_PINS_D0);
  174. SET_OUTPUT(LCD_PINS_D1);
  175. SET_OUTPUT(LCD_PINS_D2);
  176. SET_OUTPUT(LCD_PINS_D3);
  177. #endif
  178. SET_OUTPUT(LCD_PINS_D4);
  179. SET_OUTPUT(LCD_PINS_D5);
  180. SET_OUTPUT(LCD_PINS_D6);
  181. SET_OUTPUT(LCD_PINS_D7);
  182. #ifdef LCD_8BIT
  183. lcd_displayfunction |= LCD_8BITMODE;
  184. #endif
  185. lcd_displayfunction |= LCD_2LINE;
  186. _delay_us(50000);
  187. lcd_begin(1); //first time init
  188. fdev_setup_stream(lcdout, lcd_putchar, NULL, _FDEV_SETUP_WRITE); //setup lcdout stream
  189. }
  190. void lcd_refresh(void)
  191. {
  192. lcd_begin(1);
  193. lcd_set_custom_characters();
  194. }
  195. void lcd_refresh_noclear(void)
  196. {
  197. lcd_begin(0);
  198. lcd_set_custom_characters();
  199. }
  200. void lcd_clear(void)
  201. {
  202. lcd_command(LCD_CLEARDISPLAY, 1600); // clear display, set cursor position to zero
  203. lcd_currline = 0;
  204. }
  205. void lcd_home(void)
  206. {
  207. lcd_command(LCD_RETURNHOME, 1600); // set cursor position to zero
  208. lcd_currline = 0;
  209. }
  210. // Turn the display on/off (quickly)
  211. void lcd_display(void)
  212. {
  213. lcd_displaycontrol |= LCD_DISPLAYON;
  214. lcd_command(LCD_DISPLAYCONTROL | lcd_displaycontrol);
  215. }
  216. #if 0
  217. void lcd_no_display(void)
  218. {
  219. lcd_displaycontrol &= ~LCD_DISPLAYON;
  220. lcd_command(LCD_DISPLAYCONTROL | lcd_displaycontrol);
  221. }
  222. // Turns the underline cursor on/off
  223. void lcd_no_cursor(void)
  224. {
  225. lcd_displaycontrol &= ~LCD_CURSORON;
  226. lcd_command(LCD_DISPLAYCONTROL | lcd_displaycontrol);
  227. }
  228. void lcd_cursor(void)
  229. {
  230. lcd_displaycontrol |= LCD_CURSORON;
  231. lcd_command(LCD_DISPLAYCONTROL | lcd_displaycontrol);
  232. }
  233. // Turn on and off the blinking cursor
  234. void lcd_no_blink(void)
  235. {
  236. lcd_displaycontrol &= ~LCD_BLINKON;
  237. lcd_command(LCD_DISPLAYCONTROL | lcd_displaycontrol);
  238. }
  239. void lcd_blink(void)
  240. {
  241. lcd_displaycontrol |= LCD_BLINKON;
  242. lcd_command(LCD_DISPLAYCONTROL | lcd_displaycontrol);
  243. }
  244. // These commands scroll the display without changing the RAM
  245. void lcd_scrollDisplayLeft(void)
  246. {
  247. lcd_command(LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVELEFT);
  248. }
  249. void lcd_scrollDisplayRight(void)
  250. {
  251. lcd_command(LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVERIGHT);
  252. }
  253. // This is for text that flows Left to Right
  254. void lcd_leftToRight(void)
  255. {
  256. lcd_displaymode |= LCD_ENTRYLEFT;
  257. lcd_command(LCD_ENTRYMODESET | lcd_displaymode);
  258. }
  259. // This is for text that flows Right to Left
  260. void lcd_rightToLeft(void)
  261. {
  262. lcd_displaymode &= ~LCD_ENTRYLEFT;
  263. lcd_command(LCD_ENTRYMODESET | lcd_displaymode);
  264. }
  265. // This will 'right justify' text from the cursor
  266. void lcd_autoscroll(void)
  267. {
  268. lcd_displaymode |= LCD_ENTRYSHIFTINCREMENT;
  269. lcd_command(LCD_ENTRYMODESET | lcd_displaymode);
  270. }
  271. // This will 'left justify' text from the cursor
  272. void lcd_no_autoscroll(void)
  273. {
  274. lcd_displaymode &= ~LCD_ENTRYSHIFTINCREMENT;
  275. lcd_command(LCD_ENTRYMODESET | lcd_displaymode);
  276. }
  277. #endif
  278. void lcd_set_cursor(uint8_t col, uint8_t row)
  279. {
  280. int row_offsets[] = { 0x00, 0x40, 0x14, 0x54 };
  281. if (row >= LCD_HEIGHT)
  282. row = LCD_HEIGHT - 1; // we count rows starting w/0
  283. lcd_currline = row;
  284. lcd_command(LCD_SETDDRAMADDR | (col + row_offsets[row]));
  285. }
  286. // Allows us to fill the first 8 CGRAM locations
  287. // with custom characters
  288. void lcd_createChar_P(uint8_t location, const uint8_t* charmap)
  289. {
  290. location &= 0x7; // we only have 8 locations 0-7
  291. lcd_command(LCD_SETCGRAMADDR | (location << 3));
  292. for (int i=0; i<8; i++)
  293. lcd_send(pgm_read_byte(&charmap[i]), HIGH);
  294. }
  295. #ifdef VT100
  296. //Supported VT100 escape codes:
  297. //EraseScreen "\x1b[2J"
  298. //CursorHome "\x1b[%d;%dH"
  299. //CursorShow "\x1b[?25h"
  300. //CursorHide "\x1b[?25l"
  301. void lcd_escape_write(uint8_t chr)
  302. {
  303. #define escape_cnt (lcd_escape[0]) //escape character counter
  304. #define is_num_msk (lcd_escape[1]) //numeric character bit mask
  305. #define chr_is_num (is_num_msk & 0x01) //current character is numeric
  306. #define e_2_is_num (is_num_msk & 0x04) //escape char 2 is numeric
  307. #define e_3_is_num (is_num_msk & 0x08) //...
  308. #define e_4_is_num (is_num_msk & 0x10)
  309. #define e_5_is_num (is_num_msk & 0x20)
  310. #define e_6_is_num (is_num_msk & 0x40)
  311. #define e_7_is_num (is_num_msk & 0x80)
  312. #define e2_num (lcd_escape[2] - '0') //number from character 2
  313. #define e3_num (lcd_escape[3] - '0') //number from character 3
  314. #define e23_num (10*e2_num+e3_num) //number from characters 2 and 3
  315. #define e4_num (lcd_escape[4] - '0') //number from character 4
  316. #define e5_num (lcd_escape[5] - '0') //number from character 5
  317. #define e45_num (10*e4_num+e5_num) //number from characters 4 and 5
  318. #define e6_num (lcd_escape[6] - '0') //number from character 6
  319. #define e56_num (10*e5_num+e6_num) //number from characters 5 and 6
  320. if (escape_cnt > 1) // escape length > 1 = "\x1b["
  321. {
  322. lcd_escape[escape_cnt] = chr; // store current char
  323. if ((chr >= '0') && (chr <= '9')) // char is numeric
  324. is_num_msk |= (1 | (1 << escape_cnt)); //set mask
  325. else
  326. is_num_msk &= ~1; //clear mask
  327. }
  328. switch (escape_cnt++)
  329. {
  330. case 0:
  331. if (chr == 0x1b) return; // escape = "\x1b"
  332. break;
  333. case 1:
  334. is_num_msk = 0x00; // reset 'is number' bit mask
  335. if (chr == '[') return; // escape = "\x1b["
  336. break;
  337. case 2:
  338. switch (chr)
  339. {
  340. case '2': return; // escape = "\x1b[2"
  341. case '?': return; // escape = "\x1b[?"
  342. default:
  343. if (chr_is_num) return; // escape = "\x1b[%1d"
  344. }
  345. break;
  346. case 3:
  347. switch (lcd_escape[2])
  348. {
  349. case '?': // escape = "\x1b[?"
  350. if (chr == '2') return; // escape = "\x1b[?2"
  351. break;
  352. case '2':
  353. if (chr == 'J') // escape = "\x1b[2J"
  354. { lcd_clear(); lcd_currline = 0; break; } // EraseScreen
  355. default:
  356. if (e_2_is_num && // escape = "\x1b[%1d"
  357. ((chr == ';') || // escape = "\x1b[%1d;"
  358. chr_is_num)) // escape = "\x1b[%2d"
  359. return;
  360. }
  361. break;
  362. case 4:
  363. switch (lcd_escape[2])
  364. {
  365. case '?': // "\x1b[?"
  366. if ((lcd_escape[3] == '2') && (chr == '5')) return; // escape = "\x1b[?25"
  367. break;
  368. default:
  369. if (e_2_is_num) // escape = "\x1b[%1d"
  370. {
  371. if ((lcd_escape[3] == ';') && chr_is_num) return; // escape = "\x1b[%1d;%1d"
  372. else if (e_3_is_num && (chr == ';')) return; // escape = "\x1b[%2d;"
  373. }
  374. }
  375. break;
  376. case 5:
  377. switch (lcd_escape[2])
  378. {
  379. case '?':
  380. if ((lcd_escape[3] == '2') && (lcd_escape[4] == '5')) // escape = "\x1b[?25"
  381. switch (chr)
  382. {
  383. case 'h': // escape = "\x1b[?25h"
  384. lcd_cursor(); // CursorShow
  385. break;
  386. case 'l': // escape = "\x1b[?25l"
  387. lcd_no_cursor(); // CursorHide
  388. break;
  389. }
  390. break;
  391. default:
  392. if (e_2_is_num) // escape = "\x1b[%1d"
  393. {
  394. if ((lcd_escape[3] == ';') && e_4_is_num) // escape = "\x1b%1d;%1dH"
  395. {
  396. if (chr == 'H') // escape = "\x1b%1d;%1dH"
  397. lcd_set_cursor(e4_num, e2_num); // CursorHome
  398. else if (chr_is_num)
  399. return; // escape = "\x1b%1d;%2d"
  400. }
  401. else if (e_3_is_num && (lcd_escape[4] == ';') && chr_is_num)
  402. return; // escape = "\x1b%2d;%1d"
  403. }
  404. }
  405. break;
  406. case 6:
  407. if (e_2_is_num) // escape = "\x1b[%1d"
  408. {
  409. if ((lcd_escape[3] == ';') && e_4_is_num && e_5_is_num && (chr == 'H')) // escape = "\x1b%1d;%2dH"
  410. lcd_set_cursor(e45_num, e2_num); // CursorHome
  411. else if (e_3_is_num && (lcd_escape[4] == ';') && e_5_is_num) // escape = "\x1b%2d;%1d"
  412. {
  413. if (chr == 'H') // escape = "\x1b%2d;%1dH"
  414. lcd_set_cursor(e5_num, e23_num); // CursorHome
  415. else if (chr_is_num) // "\x1b%2d;%2d"
  416. return;
  417. }
  418. }
  419. break;
  420. case 7:
  421. if (e_2_is_num && e_3_is_num && (lcd_escape[4] == ';')) // "\x1b[%2d;"
  422. if (e_5_is_num && e_6_is_num && (chr == 'H')) // "\x1b[%2d;%2dH"
  423. lcd_set_cursor(e56_num, e23_num); // CursorHome
  424. break;
  425. }
  426. escape_cnt = 0; // reset escape
  427. }
  428. #endif //VT100
  429. int lcd_putc(int c)
  430. {
  431. return fputc(c, lcdout);
  432. }
  433. int lcd_puts_P(const char* str)
  434. {
  435. return fputs_P(str, lcdout);
  436. }
  437. int lcd_puts_at_P(uint8_t c, uint8_t r, const char* str)
  438. {
  439. lcd_set_cursor(c, r);
  440. return fputs_P(str, lcdout);
  441. }
  442. int lcd_printf_P(const char* format, ...)
  443. {
  444. va_list args;
  445. va_start(args, format);
  446. int ret = vfprintf_P(lcdout, format, args);
  447. va_end(args);
  448. return ret;
  449. }
  450. void lcd_space(uint8_t n)
  451. {
  452. while (n--) lcd_putc(' ');
  453. }
  454. void lcd_print(const char* s)
  455. {
  456. while (*s) lcd_write(*(s++));
  457. }
  458. void lcd_print(char c, int base)
  459. {
  460. lcd_print((long) c, base);
  461. }
  462. void lcd_print(unsigned char b, int base)
  463. {
  464. lcd_print((unsigned long) b, base);
  465. }
  466. void lcd_print(int n, int base)
  467. {
  468. lcd_print((long) n, base);
  469. }
  470. void lcd_print(unsigned int n, int base)
  471. {
  472. lcd_print((unsigned long) n, base);
  473. }
  474. void lcd_print(long n, int base)
  475. {
  476. if (base == 0)
  477. lcd_write(n);
  478. else if (base == 10)
  479. {
  480. if (n < 0)
  481. {
  482. lcd_print('-');
  483. n = -n;
  484. }
  485. lcd_printNumber(n, 10);
  486. }
  487. else
  488. lcd_printNumber(n, base);
  489. }
  490. void lcd_print(unsigned long n, int base)
  491. {
  492. if (base == 0)
  493. lcd_write(n);
  494. else
  495. lcd_printNumber(n, base);
  496. }
  497. void lcd_print(double n, int digits)
  498. {
  499. lcd_printFloat(n, digits);
  500. }
  501. void lcd_printNumber(unsigned long n, uint8_t base)
  502. {
  503. unsigned char buf[8 * sizeof(long)]; // Assumes 8-bit chars.
  504. unsigned long i = 0;
  505. if (n == 0)
  506. {
  507. lcd_print('0');
  508. return;
  509. }
  510. while (n > 0)
  511. {
  512. buf[i++] = n % base;
  513. n /= base;
  514. }
  515. for (; i > 0; i--)
  516. lcd_print((char) (buf[i - 1] < 10 ? '0' + buf[i - 1] : 'A' + buf[i - 1] - 10));
  517. }
  518. void lcd_printFloat(double number, uint8_t digits)
  519. {
  520. // Handle negative numbers
  521. if (number < 0.0)
  522. {
  523. lcd_print('-');
  524. number = -number;
  525. }
  526. // Round correctly so that print(1.999, 2) prints as "2.00"
  527. double rounding = 0.5;
  528. for (uint8_t i=0; i<digits; ++i)
  529. rounding /= 10.0;
  530. number += rounding;
  531. // Extract the integer part of the number and print it
  532. unsigned long int_part = (unsigned long)number;
  533. double remainder = number - (double)int_part;
  534. lcd_print(int_part);
  535. // Print the decimal point, but only if there are digits beyond
  536. if (digits > 0)
  537. lcd_print('.');
  538. // Extract digits from the remainder one at a time
  539. while (digits-- > 0)
  540. {
  541. remainder *= 10.0;
  542. int toPrint = int(remainder);
  543. lcd_print(toPrint);
  544. remainder -= toPrint;
  545. }
  546. }
  547. uint8_t lcd_draw_update = 2;
  548. int32_t lcd_encoder = 0;
  549. uint8_t lcd_encoder_bits = 0;
  550. int8_t lcd_encoder_diff = 0;
  551. uint8_t lcd_buttons = 0;
  552. uint8_t lcd_button_pressed = 0;
  553. uint8_t lcd_update_enabled = 1;
  554. uint32_t lcd_next_update_millis = 0;
  555. uint8_t lcd_status_update_delay = 0;
  556. lcd_longpress_func_t lcd_longpress_func = 0;
  557. lcd_charsetup_func_t lcd_charsetup_func = 0;
  558. lcd_lcdupdate_func_t lcd_lcdupdate_func = 0;
  559. static ShortTimer buttonBlanking;
  560. ShortTimer longPressTimer;
  561. LongTimer lcd_timeoutToStatus;
  562. //! @brief Was button clicked?
  563. //!
  564. //! Consume click event, following call would return 0.
  565. //! See #LCD_CLICKED macro for version not consuming the event.
  566. //!
  567. //! Generally is used in modal dialogs.
  568. //!
  569. //! @retval 0 not clicked
  570. //! @retval nonzero clicked
  571. uint8_t lcd_clicked(void)
  572. {
  573. bool clicked = LCD_CLICKED;
  574. if(clicked)
  575. {
  576. lcd_consume_click();
  577. }
  578. return clicked;
  579. }
  580. void lcd_beeper_quick_feedback(void)
  581. {
  582. //-//
  583. Sound_MakeSound(e_SOUND_TYPE_ButtonEcho);
  584. /*
  585. for(int8_t i = 0; i < 10; i++)
  586. {
  587. Sound_MakeCustom(100,0,false);
  588. _delay_us(100);
  589. }
  590. */
  591. }
  592. void lcd_quick_feedback(void)
  593. {
  594. lcd_draw_update = 2;
  595. lcd_button_pressed = false;
  596. lcd_beeper_quick_feedback();
  597. }
  598. void lcd_update(uint8_t lcdDrawUpdateOverride)
  599. {
  600. if (lcd_draw_update < lcdDrawUpdateOverride)
  601. lcd_draw_update = lcdDrawUpdateOverride;
  602. if (!lcd_update_enabled)
  603. return;
  604. if (lcd_lcdupdate_func)
  605. lcd_lcdupdate_func();
  606. }
  607. void lcd_update_enable(uint8_t enabled)
  608. {
  609. if (lcd_update_enabled != enabled)
  610. {
  611. lcd_update_enabled = enabled;
  612. if (enabled)
  613. { // Reset encoder position. This is equivalent to re-entering a menu.
  614. lcd_encoder = 0;
  615. lcd_encoder_diff = 0;
  616. // Enabling the normal LCD update procedure.
  617. // Reset the timeout interval.
  618. lcd_timeoutToStatus.start();
  619. // Force the keypad update now.
  620. lcd_next_update_millis = _millis() - 1;
  621. // Full update.
  622. lcd_clear();
  623. if (lcd_charsetup_func)
  624. lcd_charsetup_func();
  625. lcd_update(2);
  626. } else
  627. {
  628. // Clear the LCD always, or let it to the caller?
  629. }
  630. }
  631. }
  632. void lcd_buttons_update(void)
  633. {
  634. static uint8_t lcd_long_press_active = 0;
  635. uint8_t newbutton = 0;
  636. if (READ(BTN_EN1) == 0) newbutton |= EN_A;
  637. if (READ(BTN_EN2) == 0) newbutton |= EN_B;
  638. if (READ(BTN_ENC) == 0)
  639. { //button is pressed
  640. lcd_timeoutToStatus.start();
  641. if (!buttonBlanking.running() || buttonBlanking.expired(BUTTON_BLANKING_TIME)) {
  642. buttonBlanking.start();
  643. safetyTimer.start();
  644. if ((lcd_button_pressed == 0) && (lcd_long_press_active == 0))
  645. {
  646. longPressTimer.start();
  647. lcd_button_pressed = 1;
  648. }
  649. else if (longPressTimer.expired(LONG_PRESS_TIME))
  650. {
  651. lcd_long_press_active = 1;
  652. //long press is not possible in modal mode
  653. if (lcd_longpress_func && lcd_update_enabled)
  654. lcd_longpress_func();
  655. }
  656. }
  657. }
  658. else
  659. { //button not pressed
  660. if (lcd_button_pressed)
  661. { //button was released
  662. buttonBlanking.start();
  663. if (lcd_long_press_active == 0)
  664. { //button released before long press gets activated
  665. newbutton |= EN_C;
  666. }
  667. //else if (menu_menu == lcd_move_z) lcd_quick_feedback();
  668. //lcd_button_pressed is set back to false via lcd_quick_feedback function
  669. }
  670. else
  671. lcd_long_press_active = 0;
  672. }
  673. lcd_buttons = newbutton;
  674. //manage encoder rotation
  675. uint8_t enc = 0;
  676. if (lcd_buttons & EN_A) enc |= B01;
  677. if (lcd_buttons & EN_B) enc |= B10;
  678. if (enc != lcd_encoder_bits)
  679. {
  680. switch (enc)
  681. {
  682. case encrot0:
  683. if (lcd_encoder_bits == encrot3)
  684. lcd_encoder_diff++;
  685. else if (lcd_encoder_bits == encrot1)
  686. lcd_encoder_diff--;
  687. break;
  688. case encrot1:
  689. if (lcd_encoder_bits == encrot0)
  690. lcd_encoder_diff++;
  691. else if (lcd_encoder_bits == encrot2)
  692. lcd_encoder_diff--;
  693. break;
  694. case encrot2:
  695. if (lcd_encoder_bits == encrot1)
  696. lcd_encoder_diff++;
  697. else if (lcd_encoder_bits == encrot3)
  698. lcd_encoder_diff--;
  699. break;
  700. case encrot3:
  701. if (lcd_encoder_bits == encrot2)
  702. lcd_encoder_diff++;
  703. else if (lcd_encoder_bits == encrot0)
  704. lcd_encoder_diff--;
  705. break;
  706. }
  707. }
  708. lcd_encoder_bits = enc;
  709. }
  710. ////////////////////////////////////////////////////////////////////////////////
  711. // Custom character data
  712. const uint8_t lcd_chardata_bedTemp[8] PROGMEM = {
  713. B00000,
  714. B11111,
  715. B10101,
  716. B10001,
  717. B10101,
  718. B11111,
  719. B00000,
  720. B00000}; //thanks Sonny Mounicou
  721. const uint8_t lcd_chardata_degree[8] PROGMEM = {
  722. B01100,
  723. B10010,
  724. B10010,
  725. B01100,
  726. B00000,
  727. B00000,
  728. B00000,
  729. B00000};
  730. const uint8_t lcd_chardata_thermometer[8] PROGMEM = {
  731. B00100,
  732. B01010,
  733. B01010,
  734. B01010,
  735. B01010,
  736. B10001,
  737. B10001,
  738. B01110};
  739. const uint8_t lcd_chardata_uplevel[8] PROGMEM = {
  740. B00100,
  741. B01110,
  742. B11111,
  743. B00100,
  744. B11100,
  745. B00000,
  746. B00000,
  747. B00000}; //thanks joris
  748. const uint8_t lcd_chardata_refresh[8] PROGMEM = {
  749. B00000,
  750. B00110,
  751. B11001,
  752. B11000,
  753. B00011,
  754. B10011,
  755. B01100,
  756. B00000}; //thanks joris
  757. const uint8_t lcd_chardata_folder[8] PROGMEM = {
  758. B00000,
  759. B11100,
  760. B11111,
  761. B10001,
  762. B10001,
  763. B11111,
  764. B00000,
  765. B00000}; //thanks joris
  766. /*const uint8_t lcd_chardata_feedrate[8] PROGMEM = {
  767. B11100,
  768. B10000,
  769. B11000,
  770. B10111,
  771. B00101,
  772. B00110,
  773. B00101,
  774. B00000};*/ //thanks Sonny Mounicou
  775. /*const uint8_t lcd_chardata_feedrate[8] PROGMEM = {
  776. B11100,
  777. B10100,
  778. B11000,
  779. B10100,
  780. B00000,
  781. B00111,
  782. B00010,
  783. B00010};*/
  784. /*const uint8_t lcd_chardata_feedrate[8] PROGMEM = {
  785. B01100,
  786. B10011,
  787. B00000,
  788. B01100,
  789. B10011,
  790. B00000,
  791. B01100,
  792. B10011};*/
  793. const uint8_t lcd_chardata_feedrate[8] PROGMEM = {
  794. B00000,
  795. B00100,
  796. B10010,
  797. B01001,
  798. B10010,
  799. B00100,
  800. B00000,
  801. B00000};
  802. const uint8_t lcd_chardata_clock[8] PROGMEM = {
  803. B00000,
  804. B01110,
  805. B10011,
  806. B10101,
  807. B10001,
  808. B01110,
  809. B00000,
  810. B00000}; //thanks Sonny Mounicou
  811. const uint8_t lcd_chardata_arrup[8] PROGMEM = {
  812. B00100,
  813. B01110,
  814. B11111,
  815. B00000,
  816. B00000,
  817. B00000,
  818. B00000,
  819. B00000};
  820. const uint8_t lcd_chardata_arrdown[8] PROGMEM = {
  821. B00000,
  822. B00000,
  823. B00000,
  824. B00000,
  825. B00000,
  826. B10001,
  827. B01010,
  828. B00100};
  829. void lcd_set_custom_characters(void)
  830. {
  831. lcd_createChar_P(LCD_STR_BEDTEMP[0], lcd_chardata_bedTemp);
  832. lcd_createChar_P(LCD_STR_DEGREE[0], lcd_chardata_degree);
  833. lcd_createChar_P(LCD_STR_THERMOMETER[0], lcd_chardata_thermometer);
  834. lcd_createChar_P(LCD_STR_UPLEVEL[0], lcd_chardata_uplevel);
  835. lcd_createChar_P(LCD_STR_REFRESH[0], lcd_chardata_refresh);
  836. lcd_createChar_P(LCD_STR_FOLDER[0], lcd_chardata_folder);
  837. lcd_createChar_P(LCD_STR_FEEDRATE[0], lcd_chardata_feedrate);
  838. lcd_createChar_P(LCD_STR_CLOCK[0], lcd_chardata_clock);
  839. //lcd_createChar_P(LCD_STR_ARROW_UP[0], lcd_chardata_arrup);
  840. //lcd_createChar_P(LCD_STR_ARROW_DOWN[0], lcd_chardata_arrdown);
  841. }
  842. void lcd_set_custom_characters_arrows(void)
  843. {
  844. lcd_createChar_P(1, lcd_chardata_arrdown);
  845. }
  846. const uint8_t lcd_chardata_progress[8] PROGMEM = {
  847. B11111,
  848. B11111,
  849. B11111,
  850. B11111,
  851. B11111,
  852. B11111,
  853. B11111,
  854. B11111};
  855. void lcd_set_custom_characters_progress(void)
  856. {
  857. lcd_createChar_P(1, lcd_chardata_progress);
  858. }
  859. const uint8_t lcd_chardata_arr2down[8] PROGMEM = {
  860. B00000,
  861. B00000,
  862. B10001,
  863. B01010,
  864. B00100,
  865. B10001,
  866. B01010,
  867. B00100};
  868. const uint8_t lcd_chardata_confirm[8] PROGMEM = {
  869. B00000,
  870. B00001,
  871. B00011,
  872. B10110,
  873. B11100,
  874. B01000,
  875. B00000};
  876. void lcd_set_custom_characters_nextpage(void)
  877. {
  878. lcd_createChar_P(1, lcd_chardata_arr2down);
  879. lcd_createChar_P(2, lcd_chardata_confirm);
  880. }
  881. void lcd_set_custom_characters_degree(void)
  882. {
  883. lcd_createChar_P(1, lcd_chardata_degree);
  884. }