Browse Source

Added files missing from earlier commit.

Marcio Teixeira 7 years ago
parent
commit
f05bd7f082

+ 247
- 0
Marlin/src/lcd/dogm/ultralcd_impl_st7920_lite_status_screen.h View File

@@ -0,0 +1,247 @@
1
+/*
2
+ * Lightweight Status Screen for the RepRapDiscount Full
3
+ * Graphics Smart Controller (ST7920-based 128x64 LCD)
4
+ *
5
+ * (c) 2017 Aleph Objects, Inc.
6
+ *
7
+ * The code in this page is free software: you can
8
+ * redistribute it and/or modify it under the terms of the GNU
9
+ * General Public License (GNU GPL) as published by the Free Software
10
+ * Foundation, either version 3 of the License, or (at your option)
11
+ * any later version.  The code is distributed WITHOUT ANY WARRANTY;
12
+ * without even the implied warranty of MERCHANTABILITY or FITNESS
13
+ * FOR A PARTICULAR PURPOSE.  See the GNU GPL for more details.
14
+ *
15
+ */
16
+
17
+#ifndef ULTRALCD_ST7920_LITE_STATUS_H
18
+#define ULTRALCD_ST7920_LITE_STATUS_H
19
+
20
+class ST7920_Lite_Status_Screen {
21
+  private:
22
+    static struct st7920_state_t {
23
+      uint8_t synced   : 1; // Whether a sync has been sent
24
+      uint8_t cmd      : 1; // Whether the sync was cmd or data
25
+      uint8_t extended : 1;
26
+      uint8_t graphics : 1;
27
+      uint8_t sa       : 1;
28
+    } current_bits;
29
+
30
+    static void cs();
31
+    static void ncs();
32
+    static void sync_cmd();
33
+    static void sync_dat();
34
+    static void write_byte(uint8_t w);
35
+
36
+    static void cmd(uint8_t cmd);
37
+    static void begin_data();
38
+    static void write_word(uint16_t w);
39
+    static void write_str(const char *str);
40
+    static void write_str(const char *str, uint8_t len);
41
+    static void write_str_P(const char *str);
42
+    static void write_str(progmem_str str);
43
+    static void write_number(uint8_t value, uint8_t digits=3);
44
+
45
+    static void _extended_function_set(bool extended, bool graphics);
46
+    static void _scroll_or_addr_select(bool sa);
47
+    static void reset_state_from_unknown();
48
+
49
+    static void home();
50
+    static void display_status(bool display_on, bool cursor_on, bool blink_on);
51
+    static void extended_function_set(bool extended);
52
+    static void graphics(bool graphics);
53
+    static void entry_mode_select(bool ac_increase, bool shift);
54
+    static void scroll_or_addr_select(bool sa);
55
+    static void set_ddram_address(uint8_t addr);
56
+    static void set_cgram_address(uint8_t addr);
57
+    static void set_gdram_address(uint8_t x, uint8_t y);
58
+
59
+    static void clear();
60
+    static void clear_ddram();
61
+    static void clear_gdram();
62
+
63
+    static void load_cgram_icon(uint16_t addr, const void *data);
64
+    static void draw_gdram_icon(uint8_t x, uint8_t y, const void *data);
65
+
66
+    static uint8_t string_checksum(const char *str);
67
+
68
+  protected:
69
+    static void draw_static_elements();
70
+    static void draw_progress_bar(uint8_t value);
71
+    static void draw_fan_icon(bool whichIcon);
72
+    static void draw_heat_icon(bool whichIcon, bool heating);
73
+    static void draw_extruder_1_temp(uint8_t temp, uint8_t target);
74
+    static void draw_extruder_2_temp(uint8_t temp, uint8_t target);
75
+    static void draw_bed_temp(uint8_t temp, uint8_t target);
76
+    static void draw_fan_speed(uint8_t value);
77
+    static void draw_print_time(uint32_t elapsed);
78
+    static void draw_feedrate_percentage(uint8_t percentage);
79
+    static void draw_status_message(const unsigned char *str);
80
+    static void draw_position(const float x, const float y, const float z, bool position_known = true);
81
+
82
+    static bool indicators_changed();
83
+    static bool position_changed();
84
+    static bool blink_changed();
85
+    static bool status_changed();
86
+
87
+    static void update_indicators(bool forceUpdate);
88
+    static void update_position(bool forceUpdate, bool resetChecksum);
89
+    static void update_status_or_position(bool forceUpdate);
90
+    static void update_progress(bool forceUpdate);
91
+
92
+  public:
93
+    static void update(bool forceUpdate);
94
+    static void on_entry();
95
+    static void on_exit();
96
+    static void clear_text_buffer();
97
+};
98
+
99
+/************************** ICON DEFINITIONS *************************************/
100
+
101
+#define CGRAM_ICON_1_ADDR 0x00
102
+#define CGRAM_ICON_2_ADDR 0x10
103
+#define CGRAM_ICON_3_ADDR 0x20
104
+#define CGRAM_ICON_4_ADDR 0x30
105
+
106
+#define CGRAM_ICON_1_WORD 0x00
107
+#define CGRAM_ICON_2_WORD 0x02
108
+#define CGRAM_ICON_3_WORD 0x04
109
+#define CGRAM_ICON_4_WORD 0x06
110
+
111
+PROGMEM const uint16_t nozzle_icon[] = {
112
+  0b0000000000000000,
113
+  0b0000000000000000,
114
+  0b0000111111110000,
115
+  0b0001111111111000,
116
+  0b0001111111111000,
117
+  0b0001111111111000,
118
+  0b0000111111110000,
119
+  0b0000111111110000,
120
+  0b0001111111111000,
121
+  0b0001111111111000,
122
+  0b0001111111111000,
123
+  0b0000011111100000,
124
+  0b0000001111000000,
125
+  0b0000000110000000,
126
+  0b0000000000000000,
127
+  0b0000000000000000
128
+};
129
+
130
+PROGMEM const uint16_t bed_icon[] = {
131
+  0b0000000000000000,
132
+  0b0000000000000000,
133
+  0b0000000000000000,
134
+  0b0000000000000000,
135
+  0b0000000000000000,
136
+  0b0000000000000000,
137
+  0b0000000000000000,
138
+  0b0000000000000000,
139
+  0b0000000000000000,
140
+  0b0000000000000000,
141
+  0b0000000000000000,
142
+  0b0000000000000000,
143
+  0b0111111111111110,
144
+  0b0111111111111110,
145
+  0b0000000000000000,
146
+  0b0000000000000000
147
+};
148
+
149
+PROGMEM const uint16_t heat1_icon[] = {
150
+  0b0000000000000000,
151
+  0b0000000000000000,
152
+  0b0010001000100000,
153
+  0b0001000100010000,
154
+  0b0000100010001000,
155
+  0b0000100010001000,
156
+  0b0001000100010000,
157
+  0b0010001000100000,
158
+  0b0010001000100000,
159
+  0b0001000100010000,
160
+  0b0000100010001000,
161
+  0b0000000000000000,
162
+  0b0000000000000000,
163
+  0b0000000000000000,
164
+  0b0000000000000000,
165
+  0b0000000000000000
166
+};
167
+
168
+PROGMEM const uint16_t heat2_icon[] = {
169
+  0b0000000000000000,
170
+  0b0000000000000000,
171
+  0b0000100010001000,
172
+  0b0000100010001000,
173
+  0b0001000100010000,
174
+  0b0010001000100000,
175
+  0b0010001000100000,
176
+  0b0001000100010000,
177
+  0b0000100010001000,
178
+  0b0000100010001000,
179
+  0b0001000100010000,
180
+  0b0000000000000000,
181
+  0b0000000000000000,
182
+  0b0000000000000000,
183
+  0b0000000000000000,
184
+  0b0000000000000000
185
+};
186
+
187
+PROGMEM const uint16_t fan1_icon[] = {
188
+  0b0000000000000000,
189
+  0b0111111111111110,
190
+  0b0111000000001110,
191
+  0b0110001111000110,
192
+  0b0100001111000010,
193
+  0b0100000110000010,
194
+  0b0101100000011010,
195
+  0b0101110110111010,
196
+  0b0101100000011010,
197
+  0b0100000110000010,
198
+  0b0100001111000010,
199
+  0b0110001111000110,
200
+  0b0111000000001110,
201
+  0b0111111111111110,
202
+  0b0000000000000000,
203
+  0b0000000000000000
204
+};
205
+
206
+PROGMEM const uint16_t fan2_icon[] = {
207
+  0b0000000000000000,
208
+  0b0111111111111110,
209
+  0b0111000000001110,
210
+  0b0110010000100110,
211
+  0b0100111001110010,
212
+  0b0101111001111010,
213
+  0b0100110000110010,
214
+  0b0100000110000010,
215
+  0b0100110000110010,
216
+  0b0101111001111010,
217
+  0b0100111001110010,
218
+  0b0110010000100110,
219
+  0b0111000000001110,
220
+  0b0111111111111110,
221
+  0b0000000000000000,
222
+  0b0000000000000000
223
+};
224
+
225
+PROGMEM const uint16_t feedrate_icon[] = {
226
+  0b0000000000000000,
227
+  0b0111111000000000,
228
+  0b0100000000000000,
229
+  0b0100000000000000,
230
+  0b0100000000000000,
231
+  0b0111111011111000,
232
+  0b0100000010000100,
233
+  0b0100000010000100,
234
+  0b0100000010000100,
235
+  0b0100000011111000,
236
+  0b0000000010001000,
237
+  0b0000000010000100,
238
+  0b0000000010000100,
239
+  0b0000000010000010,
240
+  0b0000000000000000,
241
+  0b0000000000000000
242
+};
243
+
244
+static void lcd_implementation_status_screen();
245
+static void lcd_in_status(bool inStatus);
246
+
247
+#endif // ULTRALCD_ST7920_LITE_STATUS_H

+ 757
- 0
Marlin/src/lcd/dogm/ultralcd_impl_st7920_lite_status_screen_impl.h View File

@@ -0,0 +1,757 @@
1
+/*
2
+ * Lightweight Status Screen for the RepRapDiscount Full
3
+ * Graphics Smart Controller (ST7920-based 128x64 LCD)
4
+ *
5
+ * (c) 2017 Aleph Objects, Inc.
6
+ *
7
+ * The code in this page is free software: you can
8
+ * redistribute it and/or modify it under the terms of the GNU
9
+ * General Public License (GNU GPL) as published by the Free Software
10
+ * Foundation, either version 3 of the License, or (at your option)
11
+ * any later version.  The code is distributed WITHOUT ANY WARRANTY;
12
+ * without even the implied warranty of MERCHANTABILITY or FITNESS
13
+ * FOR A PARTICULAR PURPOSE.  See the GNU GPL for more details.
14
+ *
15
+ */
16
+
17
+ /* This is an implementation of a status screen for the RepRapDiscount
18
+  * Full Graphics Smart Controller using native ST7920 commands rather
19
+  * than using U8Glib.
20
+  *
21
+  * This alternative status screen makes use of the built-in character
22
+  * generation capabilities of the ST7920 to update the status screen
23
+  * with less SPI traffic and CPU use. In particular:
24
+  *
25
+  *    - The fan and bed animations are handled using custom characters
26
+  *      that are stored in CGRAM. This allows for the animation to be
27
+  *      updated by writing a single character to the text-buffer (DDRAM).
28
+  *
29
+  *    - All the information in the status screen is text that is written
30
+  *      to DDRAM, so the work of generating the bitmaps is offloaded to
31
+  *      the ST7920 rather than being render by U8Glib on the MCU.
32
+  *
33
+  *    - The graphics buffer (GDRAM) is only used for static graphics
34
+  *      elements (nozzle and feedrate bitmaps) and for the progress
35
+  *      bar, so updates are sporadic.
36
+  */
37
+
38
+#include "../../libs/duration_t.h"
39
+
40
+typedef const __FlashStringHelper *progmem_str;
41
+
42
+#include "ultralcd_impl_st7920_lite_status_screen.h"
43
+
44
+#define BUFFER_WIDTH   256
45
+#define BUFFER_HEIGHT  32
46
+
47
+#define DDRAM_LINE_1   0x00
48
+#define DDRAM_LINE_2   0x10
49
+#define DDRAM_LINE_3   0x08
50
+#define DDRAM_LINE_4   0x18
51
+
52
+ST7920_Lite_Status_Screen::st7920_state_t ST7920_Lite_Status_Screen::current_bits;
53
+
54
+void ST7920_Lite_Status_Screen::cmd(uint8_t cmd) {
55
+  if(!current_bits.synced || !current_bits.cmd) {
56
+    current_bits.synced = true;
57
+    current_bits.cmd    = true;
58
+    sync_cmd();
59
+  }
60
+  write_byte(cmd);
61
+}
62
+
63
+void ST7920_Lite_Status_Screen::begin_data() {
64
+  extended_function_set(false);
65
+  if(!current_bits.synced || current_bits.cmd) {
66
+    current_bits.synced = true;
67
+    current_bits.cmd    = false;
68
+    sync_dat();
69
+  }
70
+}
71
+
72
+void ST7920_Lite_Status_Screen::write_word(uint16_t w) {
73
+  write_byte((w >> 8) & 0xFF);
74
+  write_byte((w >> 0) & 0xFF);
75
+}
76
+
77
+void ST7920_Lite_Status_Screen::write_str(const char *str) {
78
+  while(*str) {
79
+     write_byte(*str++);
80
+  }
81
+}
82
+
83
+void ST7920_Lite_Status_Screen::write_str(const char *str, uint8_t len) {
84
+  while(*str && len--) {
85
+     write_byte(*str++);
86
+  }
87
+}
88
+
89
+void ST7920_Lite_Status_Screen::write_str_P(const char *str) {
90
+  const char *p_str = (const char *)str;
91
+  char c = pgm_read_byte_near(p_str++);
92
+  while(c) {
93
+     write_byte(c);
94
+     c = pgm_read_byte_near(p_str++);
95
+  }
96
+}
97
+
98
+void ST7920_Lite_Status_Screen::write_str(progmem_str str) {
99
+  write_str_P((const char*)str);
100
+}
101
+
102
+void ST7920_Lite_Status_Screen::write_number(uint8_t value, uint8_t digits=3) {
103
+  char  str[7];
104
+  const char *fmt;
105
+  switch(digits) {
106
+    case 6: fmt = PSTR("%6d"); break;
107
+    case 5: fmt = PSTR("%5d"); break;
108
+    case 4: fmt = PSTR("%4d"); break;
109
+    case 3: fmt = PSTR("%3d"); break;
110
+    case 2: fmt = PSTR("%2d"); break;
111
+    case 1: fmt = PSTR("%1d"); break;
112
+  }
113
+  sprintf_P(str,fmt,value);
114
+  write_str(str);
115
+}
116
+
117
+void ST7920_Lite_Status_Screen::display_status(bool display_on, bool cursor_on, bool blink_on) {
118
+  extended_function_set(false);
119
+  cmd(0b00001000 |
120
+    (display_on ? 0b0100 : 0) |
121
+    (cursor_on  ? 0b0010 : 0) |
122
+    (blink_on   ? 0b0001 : 0)
123
+  );
124
+}
125
+
126
+// Sets the extended and graphics bits simultaneously, regardless of
127
+// the current state. This is a helper function for extended_function_set()
128
+// and graphics()
129
+void ST7920_Lite_Status_Screen::_extended_function_set(bool extended, bool graphics) {
130
+  cmd(  0b00100000 |
131
+    (extended   ? 0b00000100 : 0) |
132
+    (graphics   ? 0b00000010 : 0)
133
+  );
134
+  current_bits.extended = extended;
135
+  current_bits.graphics = graphics;
136
+}
137
+
138
+void ST7920_Lite_Status_Screen::extended_function_set(bool extended) {
139
+  if(extended != current_bits.extended) {
140
+    _extended_function_set(extended, current_bits.graphics);
141
+  }
142
+}
143
+
144
+void ST7920_Lite_Status_Screen::graphics(bool graphics) {
145
+  if(graphics != current_bits.graphics) {
146
+    _extended_function_set(current_bits.extended, graphics);
147
+  }
148
+}
149
+
150
+void ST7920_Lite_Status_Screen::entry_mode_select(bool ac_increase, bool shift) {
151
+  extended_function_set(false);
152
+  cmd(0b00000100 |
153
+    (ac_increase ? 0b00000010 : 0) |
154
+    (shift       ? 0b00000001 : 0)
155
+  );
156
+}
157
+
158
+// Sets the sa bit regardless of the current state. This is a helper
159
+// function for scroll_or_addr_select()
160
+void ST7920_Lite_Status_Screen::_scroll_or_addr_select(bool sa) {
161
+  extended_function_set(true);
162
+  cmd(0b00100010 |
163
+    (sa   ? 0b000001 : 0)
164
+  );
165
+  current_bits.sa = sa;
166
+}
167
+
168
+void ST7920_Lite_Status_Screen::scroll_or_addr_select(bool sa) {
169
+  if(sa != current_bits.sa) {
170
+    _scroll_or_addr_select(sa);
171
+  }
172
+}
173
+
174
+void ST7920_Lite_Status_Screen::set_ddram_address(uint8_t addr) {
175
+  extended_function_set(false);
176
+  cmd(0b10000000 | (addr & 0b00111111));
177
+}
178
+
179
+void ST7920_Lite_Status_Screen::set_cgram_address(uint8_t addr) {
180
+  extended_function_set(false);
181
+  cmd(0b01000000 | (addr & 0b00111111));
182
+}
183
+
184
+void ST7920_Lite_Status_Screen::set_gdram_address(uint8_t x, uint8_t y) {
185
+  extended_function_set(true);
186
+  cmd(0b10000000 | (y & 0b01111111));
187
+  cmd(0b10000000 | (x & 0b00001111));
188
+}
189
+
190
+void ST7920_Lite_Status_Screen::clear() {
191
+  extended_function_set(false);
192
+  cmd(0x00000001);
193
+  delay(15);                 //delay for CGRAM clear
194
+}
195
+
196
+void ST7920_Lite_Status_Screen::home() {
197
+  extended_function_set(false);
198
+  cmd(0x00000010);
199
+}
200
+
201
+/* This fills the entire text buffer with spaces */
202
+void ST7920_Lite_Status_Screen::clear_ddram()
203
+{
204
+  set_ddram_address(DDRAM_LINE_1);
205
+  begin_data();
206
+  for(int i=0; i < 64;i++) {
207
+    write_byte(' ');
208
+  }
209
+}
210
+
211
+/* This fills the entire graphics buffer with zeros */
212
+void ST7920_Lite_Status_Screen::clear_gdram()
213
+{
214
+  for(int y = 0; y < BUFFER_HEIGHT; y++) {
215
+    set_gdram_address(0,y);
216
+    begin_data();
217
+    for(int i = 0; i < (BUFFER_WIDTH / 16); i++) {
218
+      write_byte(0);
219
+      write_byte(0);
220
+    }
221
+  }
222
+}
223
+
224
+void ST7920_Lite_Status_Screen::load_cgram_icon(uint16_t addr, const void *data) {
225
+  const uint16_t *p_word = (const uint16_t *)data;
226
+  set_cgram_address(addr);
227
+  begin_data();
228
+  for(int i = 0; i < 16; i++) {
229
+    uint16_t word = pgm_read_word_near(p_word++);
230
+    write_byte((word & 0xFF00) >> 8);
231
+    write_byte((word & 0x00FF) >> 0);
232
+  }
233
+}
234
+
235
+/* Draws an icon in GDRAM. The position is specified in
236
+   as if they were DDRAM coordinates, i.e. the x position
237
+   is [1-8], while the y position is [1-4] */
238
+void ST7920_Lite_Status_Screen::draw_gdram_icon(uint8_t x, uint8_t y, const void *data) {
239
+  const uint16_t *p_word = (const uint16_t *)data;
240
+  if(y > 2) {
241
+    // Handle display folding
242
+    y -= 2;
243
+    x += 8;
244
+  }
245
+  x -= 1;
246
+  y -= 1;
247
+  for(int i = 0; i < 16; i++) {
248
+    uint16_t word = pgm_read_word_near(p_word++);
249
+    set_gdram_address(x,i+y*16);
250
+    begin_data();
251
+    write_byte((word & 0xFF00) >> 8);
252
+    write_byte((word & 0x00FF) >> 0);
253
+  }
254
+}
255
+
256
+/************************** MAIN SCREEN *************************************/
257
+
258
+void ST7920_Lite_Status_Screen::draw_static_elements() {
259
+  scroll_or_addr_select(0);
260
+
261
+  // Load the animated bed and fan icons
262
+  load_cgram_icon(CGRAM_ICON_1_ADDR, heat1_icon);
263
+  load_cgram_icon(CGRAM_ICON_2_ADDR, heat2_icon);
264
+  load_cgram_icon(CGRAM_ICON_3_ADDR, fan1_icon);
265
+  load_cgram_icon(CGRAM_ICON_4_ADDR, fan2_icon);
266
+
267
+  // Draw the static icons in GDRAM
268
+  draw_gdram_icon(1,1,nozzle_icon);
269
+  #if EXTRUDERS == 2
270
+  draw_gdram_icon(1,2,nozzle_icon);
271
+  #endif
272
+  draw_gdram_icon(6,2,feedrate_icon);
273
+  draw_gdram_icon(1,2,bed_icon);
274
+
275
+  // Draw the initial fan icon
276
+  draw_fan_icon(false);
277
+}
278
+
279
+/* Although this is undocumented, the ST7920 allows the character
280
+ * data buffer (DDRAM) to be used in conjunction with the graphics
281
+ * bitmap buffer (CGRAM). The contents of the graphics buffer is
282
+ * XORed with the data from the character generator. This allows
283
+ * us to make the progess bar out of graphical data (the bar) and
284
+ * text data (the percentage).
285
+ */
286
+void ST7920_Lite_Status_Screen::draw_progress_bar(uint8_t value) {
287
+  #if EXTRUDERS == 1
288
+    // If we have only one extruder, draw a long progress bar on the third line
289
+    const int top        = 1;         // Top in pixels
290
+    const int bottom     = 13;        // Bottom in pixels
291
+    const int left       = 8;         // Left edge, in 16-bit words
292
+    const int width      = 5;         // Width of progress bar, in 16-bit words
293
+  #else
294
+    const int top        = 16 + 1;    // Top in pixels
295
+    const int bottom     = 16 + 13;   // Bottom in pixels
296
+    const int left       = 5;         // Left edge, in 16-bit words
297
+    const int width      = 3;         // Width of progress bar, in 16-bit words
298
+  #endif
299
+  const int char_pcnt  = 100/width; // How many percent does each 16-bit word represent?
300
+
301
+  // Draw the progress bar as a bitmap in CGRAM
302
+
303
+  for(int y = top; y <= bottom; y++) {
304
+    set_gdram_address(left,y);
305
+    begin_data();
306
+    for(int x = 0; x < width; x++) {
307
+      uint16_t gfx_word = 0x0000;
308
+      if((x+1)*char_pcnt <= value) {
309
+        // Draw completely filled bytes
310
+        gfx_word = 0xFFFF;
311
+      } else if((x*char_pcnt) < value) {
312
+        // Draw partially filled bytes
313
+        gfx_word = int(0x8000) >> (value % char_pcnt)*16/char_pcnt;
314
+      }
315
+      // Draw the frame around the progress bar
316
+      if(y == top || y == bottom) {
317
+        // Draw top/bottom border
318
+        gfx_word = 0xFFFF;
319
+      } else if (x == (width-1)) {
320
+        // Draw right border
321
+        gfx_word |= 0x0001;
322
+      } else if (x == 0) {
323
+        // Draw left border
324
+        gfx_word |= 0x8000;
325
+      }
326
+      write_word(gfx_word);
327
+    }
328
+  }
329
+
330
+  // Draw the percentage as text in DDRAM
331
+
332
+  #if EXTRUDERS == 1
333
+    set_ddram_address(DDRAM_LINE_3 + 1);
334
+  #else
335
+    set_ddram_address(DDRAM_LINE_2 + left);
336
+  #endif
337
+
338
+  begin_data();
339
+  if(value > 9) {
340
+    write_number(value,4);
341
+    write_str(F("% "));
342
+  } else {
343
+    write_number(value,3);
344
+    write_str(F("%  "));
345
+  }
346
+}
347
+
348
+void ST7920_Lite_Status_Screen::draw_fan_icon(bool whichIcon) {
349
+  set_ddram_address(DDRAM_LINE_1+5);
350
+  begin_data();
351
+  write_word(whichIcon ? CGRAM_ICON_3_WORD : CGRAM_ICON_4_WORD);
352
+}
353
+
354
+void ST7920_Lite_Status_Screen::draw_heat_icon(bool whichIcon, bool heating) {
355
+  #if EXTRUDERS == 1
356
+    set_ddram_address(DDRAM_LINE_2);
357
+  #else
358
+    set_ddram_address(DDRAM_LINE_3);
359
+  #endif
360
+  begin_data();
361
+  if(heating) {
362
+    write_word(whichIcon ? CGRAM_ICON_1_WORD : CGRAM_ICON_2_WORD);
363
+  } else {
364
+    write_byte(' ');
365
+    write_byte(' ');
366
+  }
367
+}
368
+
369
+#define FAR(a,b) (((a > b) ? (a-b) : (b-a)) > 1)
370
+
371
+void ST7920_Lite_Status_Screen::draw_extruder_1_temp(uint8_t temp, uint8_t target) {
372
+  set_ddram_address(DDRAM_LINE_1+1);
373
+  begin_data();
374
+  write_number(temp);
375
+  if(target && FAR(temp, target)) {
376
+    write_str(F("\x1A"));
377
+    write_number(target);
378
+  } else {
379
+    write_str(F("    "));
380
+  }
381
+}
382
+
383
+void ST7920_Lite_Status_Screen::draw_extruder_2_temp(uint8_t temp, uint8_t target) {
384
+  set_ddram_address(DDRAM_LINE_2+1);
385
+  begin_data();
386
+  write_number(temp);
387
+  if(target && FAR(temp, target)) {
388
+    write_str(F("\x1A"));
389
+    write_number(target);
390
+  } else {
391
+    write_str(F("    "));
392
+  }
393
+}
394
+
395
+void ST7920_Lite_Status_Screen::draw_bed_temp(uint8_t temp, uint8_t target) {
396
+  #if EXTRUDERS == 1
397
+  set_ddram_address(DDRAM_LINE_2+1);
398
+  #else
399
+  set_ddram_address(DDRAM_LINE_3+1);
400
+  #endif
401
+  begin_data();
402
+  write_number(temp);
403
+  if(target && FAR(temp, target)) {
404
+    write_str(F("\x1A"));
405
+    write_number(target);
406
+  } else {
407
+    write_str(F("    "));
408
+  }
409
+}
410
+
411
+void ST7920_Lite_Status_Screen::draw_fan_speed(uint8_t value) {
412
+  set_ddram_address(DDRAM_LINE_1+6);
413
+  begin_data();
414
+  write_number(value,4);
415
+}
416
+
417
+void ST7920_Lite_Status_Screen::draw_print_time(uint32_t elapsed) {
418
+  const uint8_t hrs = elapsed/3600;
419
+  const uint8_t min = (elapsed/60)%60;
420
+  char  str[7];
421
+  sprintf_P(str,hrs > 99 ? PSTR("%03d:%02d") : PSTR(" %02d:%02d"),hrs,min);
422
+
423
+  set_ddram_address(DDRAM_LINE_3+5);
424
+  begin_data();
425
+  write_str(str);
426
+}
427
+
428
+void ST7920_Lite_Status_Screen::draw_feedrate_percentage(uint8_t percentage) {
429
+  // We only have enough room for the feedrate when
430
+  // we have one extruder
431
+  #if EXTRUDERS == 1
432
+    set_ddram_address(DDRAM_LINE_2+6);
433
+    begin_data();
434
+    write_number(percentage,4);
435
+  #endif
436
+}
437
+
438
+void ST7920_Lite_Status_Screen::draw_status_message(const unsigned char *str) {
439
+  set_ddram_address(DDRAM_LINE_4);
440
+  begin_data();
441
+  #if ENABLED(STATUS_MESSAGE_SCROLLING)
442
+    const uint8_t lcd_len = 16;
443
+    const uint8_t padding = 2;
444
+    uint8_t str_len = strlen(str);
445
+
446
+    // Trim whitespace at the end of the str, as for some reason
447
+    // messages like "Card Inserted" are padded with many spaces
448
+    while(str_len > 0 && str[str_len-1] == ' ') {
449
+      str_len--;
450
+    }
451
+
452
+    if(str_len <= lcd_len) {
453
+      // It all fits on the LCD without scrolling
454
+      write_str(str);
455
+    } else {
456
+      // Print the message repeatedly until covering the LCD
457
+      uint8_t c = status_scroll_pos;
458
+      for(uint8_t n = 0; n < lcd_len; n++) {
459
+        write_byte(c < str_len ? str[c] : ' ');
460
+        c++;
461
+        c %= str_len + padding; // Wrap around
462
+      }
463
+
464
+      // Scroll the message
465
+      if(status_scroll_pos == str_len + padding) {
466
+        status_scroll_pos = 0;
467
+      } else {
468
+        status_scroll_pos++;
469
+      }
470
+    }
471
+  #else
472
+    write_str(str, 16);
473
+  #endif
474
+}
475
+
476
+void ST7920_Lite_Status_Screen::draw_position(const float x, const float y, const float z, bool position_known) {
477
+  char str[7];
478
+  set_ddram_address(DDRAM_LINE_4);
479
+  begin_data();
480
+
481
+  // If position is unknown, flash the labels.
482
+  const unsigned char alt_label = position_known ? 0 : (lcd_blink() ? ' ' : 0);
483
+
484
+  dtostrf(x, -4, 0, str);
485
+  write_byte(alt_label ? alt_label : 'X');
486
+  write_str(str, 4);
487
+
488
+  dtostrf(y, -4, 0, str);
489
+  write_byte(alt_label ? alt_label : 'Y');
490
+  write_str(str, 4);
491
+
492
+  dtostrf(z, -5, 1, str);
493
+  write_byte(alt_label ? alt_label : 'Z');
494
+  write_str(str, 5);
495
+}
496
+
497
+bool ST7920_Lite_Status_Screen::indicators_changed() {
498
+  // We only add the target temperatures to the checksum
499
+  // because the actual temps fluctuate so by updating
500
+  // them only during blinks we gain a bit of stability.
501
+  const bool       blink             = lcd_blink();
502
+  const uint8_t    feedrate_perc     = feedrate_percentage;
503
+  const uint8_t    fan_speed         = ((fanSpeeds[0] + 1) * 100) / 256;
504
+  const float      extruder_1_target = thermalManager.degTargetHotend(0);
505
+  #if EXTRUDERS == 2
506
+  const float      extruder_2_target = thermalManager.degTargetHotend(1);
507
+  #endif
508
+  const float      bed_target        = thermalManager.degTargetBed();
509
+
510
+  static uint8_t last_checksum = 0;
511
+
512
+  const  uint8_t checksum =
513
+    uint8_t(blink) ^
514
+    uint8_t(feedrate_perc) ^
515
+    uint8_t(fan_speed) ^
516
+    uint8_t(extruder_1_target) ^
517
+#if EXTRUDERS == 2
518
+    uint8_t(extruder_2_target) ^
519
+#endif
520
+    uint8_t(bed_target);
521
+
522
+  if(last_checksum == checksum) {
523
+    return false;
524
+  } else {
525
+    last_checksum = checksum;
526
+    return true;
527
+  }
528
+}
529
+
530
+void ST7920_Lite_Status_Screen::update_indicators(bool forceUpdate) {
531
+  if(forceUpdate || indicators_changed()) {
532
+    const bool       blink             = lcd_blink();
533
+    const duration_t elapsed           = print_job_timer.duration();
534
+    const uint32_t   seconds_elapsed   = elapsed.value;
535
+    const uint8_t    feedrate_perc     = feedrate_percentage;
536
+    const uint8_t    fan_speed         = ((fanSpeeds[0] + 1) * 100) / 256;
537
+    const float      extruder_1_temp   = thermalManager.degHotend(0);
538
+    const float      extruder_1_target = thermalManager.degTargetHotend(0);
539
+    #if EXTRUDERS == 2
540
+    const float      extruder_2_temp   = thermalManager.degHotend(1);
541
+    const float      extruder_2_target = thermalManager.degTargetHotend(1);
542
+    #endif
543
+    const float      bed_temp          = thermalManager.degBed();
544
+    const float      bed_target        = thermalManager.degTargetBed();
545
+
546
+    draw_extruder_1_temp(extruder_1_temp, extruder_1_target);
547
+    #if EXTRUDERS == 2
548
+    draw_extruder_2_temp(extruder_2_temp, extruder_2_target);
549
+    #endif
550
+    draw_bed_temp(bed_temp, bed_target);
551
+    draw_fan_speed(fan_speed);
552
+    draw_print_time(seconds_elapsed);
553
+    draw_feedrate_percentage(feedrate_perc);
554
+
555
+    // Update the fan and bed animations
556
+    if(fan_speed > 0) {
557
+      draw_fan_icon(blink);
558
+    }
559
+    if(bed_target > 0) {
560
+      draw_heat_icon(blink, true);
561
+    } else {
562
+      draw_heat_icon(false, false);
563
+    }
564
+  }
565
+}
566
+
567
+bool ST7920_Lite_Status_Screen::position_changed() {
568
+  const float x_pos = current_position[X_AXIS];
569
+  const float y_pos = current_position[Y_AXIS];
570
+  const float z_pos = current_position[Z_AXIS];
571
+  const uint8_t checksum = uint8_t(x_pos) ^ uint8_t(y_pos) ^ uint8_t(z_pos);
572
+
573
+  static uint8_t last_checksum = 0;
574
+  if(last_checksum == checksum) {
575
+    return false;
576
+  } else {
577
+    last_checksum = checksum;
578
+    return true;
579
+  }
580
+}
581
+
582
+bool ST7920_Lite_Status_Screen::status_changed() {
583
+  uint8_t checksum = 0;
584
+  for(const char *p = lcd_status_message; *p; p++) {
585
+    checksum ^= *p;
586
+  }
587
+
588
+  static uint8_t last_checksum = 0;
589
+  if(last_checksum == checksum) {
590
+    return false;
591
+  } else {
592
+    last_checksum = checksum;
593
+    return true;
594
+  }
595
+}
596
+
597
+bool ST7920_Lite_Status_Screen::blink_changed() {
598
+  static uint8_t last_blink = 0;
599
+
600
+  const bool blink = lcd_blink();
601
+  if(last_blink == blink) {
602
+    return false;
603
+  } else {
604
+    last_blink = blink;
605
+    return true;
606
+  }
607
+}
608
+
609
+void ST7920_Lite_Status_Screen::update_status_or_position(bool forceUpdate) {
610
+  static uint8_t countdown = 0;
611
+
612
+  /* There is only enough room in the display for either the
613
+   * status message or the position, not both, so we choose
614
+   * one or another. Whenever the status message changes,
615
+   * we show it for a number of consecutive seconds, but
616
+   * then go back to showing the position as soon as the
617
+   * head moves, i.e:
618
+   *
619
+   *    countdown > 1    -- Show status
620
+   *    countdown = 1    -- Show status, until movement
621
+   *    countdown = 0    -- Show position
622
+   */
623
+  if( forceUpdate || status_changed() ) {
624
+    #if ENABLED(STATUS_MESSAGE_SCROLLING)
625
+      status_scroll_pos = 0;
626
+    #endif
627
+    if(lcd_strlen(lcd_status_message)) {
628
+      countdown = DELAY_TO_SHOW_POSITION;
629
+    } else {
630
+      countdown = 0;
631
+    }
632
+    draw_status_message(lcd_status_message);
633
+    blink_changed(); // Clear changed flag
634
+  }
635
+  else if(countdown > 1 && blink_changed() ) {
636
+    countdown--;
637
+    #if ENABLED(STATUS_MESSAGE_SCROLLING)
638
+    draw_status_message(lcd_status_message);
639
+    #endif
640
+  }
641
+  else if(countdown > 0 && blink_changed() ) {
642
+    if(position_changed()) {
643
+      countdown--;
644
+      forceUpdate = true;
645
+    }
646
+    #if ENABLED(STATUS_MESSAGE_SCROLLING)
647
+    draw_status_message(lcd_status_message);
648
+    #endif
649
+  }
650
+  if(countdown == 0 && (forceUpdate || position_changed() ||
651
+    #if DISABLED(DISABLE_REDUCED_ACCURACY_WARNING)
652
+    blink_changed()
653
+    #endif
654
+  )) {
655
+    draw_position(
656
+      current_position[X_AXIS],
657
+      current_position[Y_AXIS],
658
+      current_position[Z_AXIS],
659
+      #if ENABLED(DISABLE_REDUCED_ACCURACY_WARNING)
660
+        true
661
+      #else
662
+        axis_known_position[X_AXIS] &&
663
+        axis_known_position[Y_AXIS] &&
664
+        axis_known_position[Z_AXIS]
665
+      #endif
666
+    );
667
+  }
668
+}
669
+
670
+void ST7920_Lite_Status_Screen::update_progress(bool forceUpdate) {
671
+  #if ENABLED(SDSUPPORT)
672
+    const uint8_t percent_done = card.percentDone();
673
+  #else
674
+    const uint8_t percent_done = 0;
675
+  #endif
676
+
677
+  // Since the progress bar involves writing
678
+  // quite a few bytes to GDRAM, only do this
679
+  // when an update is actually necessary.
680
+
681
+  static uint8_t last_progress = 0;
682
+  if(!forceUpdate && last_progress == percent_done)
683
+    return;
684
+  last_progress = percent_done;
685
+
686
+  draw_progress_bar(percent_done);
687
+}
688
+
689
+void ST7920_Lite_Status_Screen::update(bool forceUpdate) {
690
+  cs();
691
+  update_indicators(forceUpdate);
692
+  update_status_or_position(forceUpdate);
693
+  update_progress(forceUpdate);
694
+  ncs();
695
+}
696
+
697
+void ST7920_Lite_Status_Screen::reset_state_from_unknown() {
698
+  _extended_function_set(true, true); // Do it twice as only one bit
699
+  _extended_function_set(true, true); // get set at a time.
700
+  _scroll_or_addr_select(false);
701
+}
702
+
703
+void ST7920_Lite_Status_Screen::on_entry() {
704
+  cs();
705
+  reset_state_from_unknown();
706
+  clear();
707
+  clear_gdram();
708
+  draw_static_elements();
709
+  update(true);
710
+  ncs();
711
+}
712
+
713
+void ST7920_Lite_Status_Screen::on_exit() {
714
+  cs();
715
+  clear();
716
+  _extended_function_set(true, true); // Restore state to what u8g expects.
717
+  ncs();
718
+}
719
+
720
+// This is called prior to the KILL screen to
721
+// clear the screen so we don't end up with a
722
+// garbled display.
723
+void ST7920_Lite_Status_Screen::clear_text_buffer() {
724
+  cs();
725
+  reset_state_from_unknown();
726
+  clear();
727
+  _extended_function_set(true, true); // Restore state to what u8g expects.
728
+  ncs();
729
+}
730
+
731
+static void lcd_implementation_status_screen() {
732
+  ST7920_Lite_Status_Screen::update(false);
733
+}
734
+
735
+/* In order to properly update the lite status screen,
736
+ * we must know when we have entered and left the
737
+ * status screen. Since the ultralcd code is not
738
+ * set up for doing this, we call this function before
739
+ * each update indicating whether the current screen
740
+ * is the status screen.
741
+ *
742
+ * This function keeps track of whether we have left or
743
+ * entered the status screen and calls the on_entry()
744
+ * and on_exit() methods for cleanup.
745
+ */
746
+
747
+static void lcd_in_status(bool inStatus) {
748
+  static bool lastInStatus = false;
749
+  if(!lastInStatus && inStatus) {
750
+    ST7920_Lite_Status_Screen::on_entry();
751
+    lastInStatus = true;
752
+  }
753
+  if(lastInStatus && !inStatus) {
754
+    ST7920_Lite_Status_Screen::on_exit();
755
+    lastInStatus = false;
756
+  }
757
+}

+ 39
- 0
Marlin/src/lcd/dogm/ultralcd_impl_st7920_lite_status_screen_impl_spi.h View File

@@ -0,0 +1,39 @@
1
+/*
2
+ * Lightweight Status Screen for the RepRapDiscount Full
3
+ * Graphics Smart Controller (ST7920-based 128x64 LCD)
4
+ *
5
+ * (c) 2017 Aleph Objects, Inc.
6
+ *
7
+ * The code in this page is free software: you can
8
+ * redistribute it and/or modify it under the terms of the GNU
9
+ * General Public License (GNU GPL) as published by the Free Software
10
+ * Foundation, either version 3 of the License, or (at your option)
11
+ * any later version.  The code is distributed WITHOUT ANY WARRANTY;
12
+ * without even the implied warranty of MERCHANTABILITY or FITNESS
13
+ * FOR A PARTICULAR PURPOSE.  See the GNU GPL for more details.
14
+ *
15
+ */
16
+
17
+#include "ultralcd_impl_st7920_lite_status_screen.h"
18
+
19
+void ST7920_Lite_Status_Screen::cs() {
20
+  ST7920_CS();
21
+  current_bits.synced = false;
22
+}
23
+
24
+void ST7920_Lite_Status_Screen::ncs() {
25
+  ST7920_NCS();
26
+  current_bits.synced = false;
27
+}
28
+
29
+void ST7920_Lite_Status_Screen::sync_cmd() {
30
+  ST7920_SET_CMD();
31
+}
32
+
33
+void ST7920_Lite_Status_Screen::sync_dat() {
34
+  ST7920_SET_DAT();
35
+}
36
+
37
+void ST7920_Lite_Status_Screen::write_byte(uint8_t data) {
38
+  ST7920_WRITE_NIBBLES(data);
39
+}

Loading…
Cancel
Save