@@ -65,7 +65,13 @@ struct image_render_state {
65
65
66
66
LcdTask::LcdTask () :
67
67
MicroTasks::Task(),
68
- _lcd()
68
+ _tft(),
69
+ #ifdef ENABLE_DOUBLE_BUFFER
70
+ _back_buffer (&_tft),
71
+ _screen(_back_buffer)
72
+ #else
73
+ _screen (_tft)
74
+ #endif
69
75
{
70
76
}
71
77
@@ -104,66 +110,106 @@ unsigned long LcdTask::loop(MicroTasks::WakeReason reason)
104
110
105
111
unsigned long nextUpdate = MicroTask.Infinate ;
106
112
113
+ if (_initialise)
114
+ {
115
+ // We need to initialise after the Networking as that brackes the display
116
+ DBUGVAR (ESP.getFreeHeap ());
117
+ _tft.init ();
118
+ _tft.setRotation (1 );
119
+ DBUGF (" Screen initialised, size: %dx%d" , _screen_width, _screen_height);
120
+
121
+ #ifdef ENABLE_DOUBLE_BUFFER
122
+ _back_buffer_pixels = (uint16_t *)_back_buffer.createSprite (_screen_width, _screen_height);
123
+ _back_buffer.setTextDatum (MC_DATUM);
124
+ DBUGF (" Back buffer %p" , _back_buffer_pixels);
125
+ #endif
126
+
127
+ _initialise = false ;
128
+ }
129
+
130
+ #ifdef ENABLE_DOUBLE_BUFFER
131
+ _tft.startWrite ();
132
+ #endif
133
+
107
134
switch (_state)
108
135
{
109
136
case State::Boot:
110
137
{
111
138
DBUGLN (" LCD UI setup" );
112
139
113
- _lcd.begin ();
114
- _lcd.setRotation (1 );
140
+ if (_full_update)
141
+ {
142
+ _screen.fillScreen (TFT_OPENEVSE_BACK);
143
+ _screen.fillSmoothRoundRect (90 , 90 , 300 , 110 , 15 , TFT_WHITE);
144
+ render_image (" /logo.png" , 104 , 115 );
145
+ _full_update = false ;
146
+ }
115
147
116
- _lcd.fillScreen (TFT_OPENEVSE_BACK);
117
- _lcd.fillSmoothRoundRect (90 , 90 , 300 , 110 , 15 , TFT_WHITE);
118
- _lcd.fillSmoothRoundRect (90 , 235 , 300 , 16 , 8 , TFT_OPENEVSE_GREEN);
119
- render_image (" /logo.png" , 104 , 115 );
148
+ _screen.fillRoundRect (90 , 235 , 300 , 16 , 8 , TFT_WHITE);
149
+ if (_boot_progress > 0 ) {
150
+ _screen.fillRoundRect (90 , 235 , _boot_progress, 16 , 8 , TFT_OPENEVSE_GREEN);
151
+ }
152
+ _boot_progress += 10 ;
120
153
121
154
pinMode (LCD_BACKLIGHT_PIN, OUTPUT);
122
155
digitalWrite (LCD_BACKLIGHT_PIN, HIGH);
123
- nextUpdate = 5000 ;
124
- _state = State::Charge;
156
+ nextUpdate = 166 ;
157
+ if (_boot_progress >= 300 ) {
158
+ _state = State::Charge;
159
+ _full_update = true ;
160
+ }
125
161
} break ;
126
162
127
163
case State::Charge:
128
164
{
129
- _lcd.fillRect (DISPLAY_AREA_X, DISPLAY_AREA_Y, DISPLAY_AREA_WIDTH, DISPLAY_AREA_HEIGHT, TFT_OPENEVSE_BACK);
130
- _lcd.fillSmoothRoundRect (WHITE_AREA_X, WHITE_AREA_Y, WHITE_AREA_WIDTH, WHITE_AREA_HEIGHT, 6 , TFT_WHITE);
131
- render_image (" /button_bar.png" , BUTTON_BAR_X, BUTTON_BAR_Y);
132
- render_image (" /not_connected.png" , 16 , 52 );
165
+ if (_full_update)
166
+ {
167
+ _screen.fillRect (DISPLAY_AREA_X, DISPLAY_AREA_Y, DISPLAY_AREA_WIDTH, DISPLAY_AREA_HEIGHT, TFT_OPENEVSE_BACK);
168
+ _screen.fillSmoothRoundRect (WHITE_AREA_X, WHITE_AREA_Y, WHITE_AREA_WIDTH, WHITE_AREA_HEIGHT, 6 , TFT_WHITE);
169
+ render_image (" /button_bar.png" , BUTTON_BAR_X, BUTTON_BAR_Y);
170
+ render_image (" /not_connected.png" , 16 , 52 );
171
+ }
133
172
134
173
char buffer[32 ];
135
174
136
175
snprintf (buffer, sizeof (buffer), " %d" , _evse->getChargeCurrent ());
137
- render_right_text (buffer, 220 , 200 , &FreeSans24pt7b, TFT_BLACK, 3 );
138
- _lcd.setTextSize (1 );
139
- _lcd.print (" A" );
176
+ render_right_text_box (buffer, 70 , 220 , 150 , &FreeSans24pt7b, TFT_BLACK, TFT_WHITE, !_full_update, 3 );
177
+ if (_full_update) {
178
+ render_left_text_box (" A" , 224 , 200 , 20 , &FreeSans24pt7b, TFT_BLACK, TFT_WHITE, false , 1 );
179
+ }
140
180
141
- render_centered_text (esp_hostname.c_str (), INFO_BOX_X, 72 , INFO_BOX_WIDTH, &FreeSans9pt7b, TFT_OPENEVSE_TEXT);
181
+ render_centered_text_box (esp_hostname.c_str (), INFO_BOX_X, 74 , INFO_BOX_WIDTH, &FreeSans9pt7b, TFT_OPENEVSE_TEXT, TFT_WHITE, !_full_update );
142
182
143
183
timeval local_time;
144
184
gettimeofday (&local_time, NULL );
145
185
struct tm timeinfo;
146
186
localtime_r (&local_time.tv_sec , &timeinfo);
147
187
strftime (buffer, sizeof (buffer), " %d/%m/%Y, %l:%M %p" , &timeinfo);
148
- render_centered_text (buffer, INFO_BOX_X, 94 , INFO_BOX_WIDTH, &FreeSans9pt7b, TFT_OPENEVSE_TEXT);
188
+ render_centered_text_box (buffer, INFO_BOX_X, 96 , INFO_BOX_WIDTH, &FreeSans9pt7b, TFT_OPENEVSE_TEXT, TFT_WHITE, !_full_update );
149
189
150
190
uint32_t elapsed = _evse->getSessionElapsed ();
151
191
uint32_t hours = elapsed / 3600 ;
152
192
uint32_t minutes = (elapsed % 3600 ) / 60 ;
153
193
uint32_t seconds = elapsed % 60 ;
154
194
snprintf (buffer, sizeof (buffer), " %02d:%02d:%02d" , hours, minutes, seconds);
155
- render_info_box (" ELAPSED" , buffer, INFO_BOX_X, 110 , INFO_BOX_WIDTH, INFO_BOX_HEIGHT);
195
+ render_info_box (" ELAPSED" , buffer, INFO_BOX_X, 110 , INFO_BOX_WIDTH, INFO_BOX_HEIGHT, _full_update );
156
196
157
197
get_scaled_number_value (_evse->getSessionEnergy (), 0 , " Wh" , buffer, sizeof (buffer));
158
- render_info_box (" DELIVERED" , buffer, INFO_BOX_X, 175 , INFO_BOX_WIDTH, INFO_BOX_HEIGHT);
198
+ render_info_box (" DELIVERED" , buffer, INFO_BOX_X, 175 , INFO_BOX_WIDTH, INFO_BOX_HEIGHT, _full_update );
159
199
160
- // nextUpdate = 1000;
200
+ nextUpdate = 1000 ;
201
+ _full_update = false ;
161
202
} break ;
162
203
163
204
default :
164
205
break ;
165
206
}
166
207
208
+ #ifdef ENABLE_DOUBLE_BUFFER
209
+ _tft.pushImage (0 , 0 , _screen_width, _screen_height, _back_buffer_pixels);
210
+ _tft.endWrite ();
211
+ #endif
212
+
167
213
DBUGVAR (nextUpdate);
168
214
return nextUpdate;
169
215
}
@@ -189,35 +235,42 @@ void LcdTask::get_scaled_number_value(double value, int precision, const char *u
189
235
snprintf (buffer, size, " %.*f %s%s" , precision, value, mod[index ], unit);
190
236
}
191
237
192
- void LcdTask::render_info_box (const char *title, const char *text, int16_t x, int16_t y, int16_t width, int16_t height)
238
+ void LcdTask::render_info_box (const char *title, const char *text, int16_t x, int16_t y, int16_t width, int16_t height, bool full_update )
193
239
{
194
- _lcd.fillSmoothRoundRect (x, y, width, height, 6 , TFT_OPENEVSE_INFO_BACK, TFT_WHITE);
195
- render_centered_text (title, x, y+22 , width, &FreeSans9pt7b, TFT_OPENEVSE_GREEN);
196
- render_centered_text (text, x, y+(height-10 ), width, &FreeSans9pt7b, TFT_WHITE);
240
+ if (full_update)
241
+ {
242
+ _screen.fillSmoothRoundRect (x, y, width, height, 6 , TFT_OPENEVSE_INFO_BACK, TFT_WHITE);
243
+ render_centered_text_box (title, x, y+24 , width, &FreeSans9pt7b, TFT_OPENEVSE_GREEN, TFT_OPENEVSE_INFO_BACK, false );
244
+ }
245
+ render_centered_text_box (text, x, y+(height-4 ), width, &FreeSans9pt7b, TFT_WHITE, TFT_OPENEVSE_INFO_BACK, !full_update);
246
+ }
247
+
248
+ void LcdTask::render_centered_text_box (const char *text, int16_t x, int16_t y, int16_t width, const GFXfont *font, uint16_t text_colour, uint16_t back_colour, bool fill_back, uint8_t size)
249
+ {
250
+ render_text_box (text, x + (width / 2 ), y, width, font, text_colour, back_colour, fill_back, BC_DATUM, size);
197
251
}
198
252
199
- void LcdTask::render_centered_text (const char *text, int16_t x, int16_t y, int16_t width, const GFXfont *font, uint16_t color , uint8_t size)
253
+ void LcdTask::render_right_text_box (const char *text, int16_t x, int16_t y, int16_t width, const GFXfont *font, uint16_t text_colour, uint16_t back_colour, bool fill_back , uint8_t size)
200
254
{
201
- _lcd.setFreeFont (font);
202
- _lcd.setTextSize (size);
203
- int16_t text_width = _lcd.textWidth (text);
204
- int16_t text_x = x + ((width - text_width) / 2 );
205
- _lcd.setTextColor (color);
206
- _lcd.setCursor (text_x, y);
207
- _lcd.print (text);
255
+ render_text_box (text, x + width, y, width, font, text_colour, back_colour, fill_back, BR_DATUM, size);
208
256
}
209
257
210
- void LcdTask::render_right_text (const char *text, int16_t x, int16_t y, const GFXfont *font, uint16_t color , uint8_t size)
258
+ void LcdTask::render_left_text_box (const char *text, int16_t x, int16_t y, int16_t width, const GFXfont *font, uint16_t text_colour, uint16_t back_colour, bool fill_back , uint8_t size)
211
259
{
212
- _lcd.setFreeFont (font);
213
- _lcd.setTextSize (size);
214
- int16_t text_width = _lcd.textWidth (text);
215
- int16_t text_x = x - text_width;
216
- _lcd.setTextColor (color);
217
- _lcd.setCursor (text_x, y);
218
- _lcd.print (text);
260
+ render_text_box (text, x, y, width, font, text_colour, back_colour, fill_back, BL_DATUM, size);
219
261
}
220
262
263
+ void LcdTask::render_text_box (const char *text, int16_t x, int16_t y, int16_t width, const GFXfont *font, uint16_t text_colour, uint16_t back_colour, bool fill_back, uint8_t d, uint8_t size)
264
+ {
265
+ _screen.setTextDatum (d);
266
+ _screen.setFreeFont (font);
267
+ _screen.setTextSize (size);
268
+ _screen.setTextPadding (width);
269
+ _screen.setTextColor (text_colour, back_colour, /* back_colour*/ TFT_BLUE);
270
+ _screen.drawString (text, x, y);
271
+ }
272
+
273
+
221
274
void LcdTask::render_image (const char *filename, int16_t x, int16_t y)
222
275
{
223
276
StaticFile *file = NULL ;
@@ -229,12 +282,12 @@ void LcdTask::render_image(const char *filename, int16_t x, int16_t y)
229
282
{
230
283
DBUGLN (" Successfully opened png file" );
231
284
DBUGF (" image specs: (%d x %d), %d bpp, pixel type: %d\n " , png.getWidth (), png.getHeight (), png.getBpp (), png.getPixelType ());
232
- _lcd .startWrite ();
285
+ _screen .startWrite ();
233
286
uint32_t dt = millis ();
234
- image_render_state state = {&_lcd , x, y};
287
+ image_render_state state = {&_screen , x, y};
235
288
rc = png.decode (&state, 0 );
236
289
DBUG (millis () - dt); DBUGLN (" ms" );
237
- _lcd .endWrite ();
290
+ _screen .endWrite ();
238
291
// png.close(); // not needed for memory->memory decode
239
292
}
240
293
}
0 commit comments