/
tb_display.cpp
414 lines (398 loc) · 13.5 KB
/
tb_display.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
/******************************************************************************
* tb_display.cpp
* Library for a simple text buffer scrolling display on the M5StickC.
* Hague Nusseck @ electricidea
* v1.3 04.Feb.2020
* https://github.com/electricidea/M5StickC-TB_Display
*
* This library makes it easy to display texts on the M5StickC.
* The display behaves like a terminal: New text is added at the bottom.
* The text scrolls up with every new line. The lines are automatically wrapped.
* The display can be used in any orientation.
*
* Changelog:
* v1.0 = - initial version
* v1.1 = - Added delay parameter to tb_display_print_String function
* - Added text demo in Example (Button B on M5StickC)
* v1.2 = - Supress of space characters as first character on a new row
* after a new line
* - Add a word wrapping fuction inside the print_char function
* v1.3 = - Bugfix if the character that causes a word wrap is a space character
*
* Distributed as-is; no warranty is given.
******************************************************************************/
#include <M5StickCPlus.h>
#include "tb_display.h"
const uint8_t screenWidth=240;
const uint8_t screenHeight=135;
int text_size=1;
int text_font=2; // 2==Proportional Font, 1==Fixed Font (not supported)
int text_height=20;
// TextSize 1 is very small on the display = hard to read
// Textsize 2 is good readable without the need of an microscope.
// This code only runs with text size 2!
//#define TEXT_SIZE 2
//#define TEXT_HEIGHT 16 // Height of text to be printed
// Display size of M5StickCPlus = 240x135
// With TEXT_HEIGHT=16, the screen can display:
// 5 rows of text in portrait mode
// 8 rows of text in landscape mode
// screen buffer for 12 rows of 70 characters max.
#define TEXT_BUFFER_HEIGHT_MAX 18
#define TEXT_BUFFER_LINE_LENGTH_MAX 70
char text_buffer[TEXT_BUFFER_HEIGHT_MAX][TEXT_BUFFER_LINE_LENGTH_MAX];
int text_buffer_height;
int text_buffer_line_length;
int text_buffer_write_pointer_x;
int text_buffer_write_pointer_y;
int text_buffer_read_pointer;
// with M5.Lcd.setRotation(1)
// the position 0,0 is the upper left corner
// starting a bit more right...
#define SCREEN_XSTARTPOS 5
int screen_xpos = SCREEN_XSTARTPOS;
// start writing at the last line
int screen_ypos;
// maximum width of the screen
int screen_max;
// Enable or disable Word Wrap
boolean tb_display_word_wrap = true;
// =============================================================
// Initialization of the Text Buffer and Screen
// ScreenRotation values:
// 1 = Button right
// 2 = Button above
// 3 = Button left
// 4 = Button below
// Display size of M5StickCPlus = 240x135 pixel
// With TEXT_HEIGHT=16, the screen can display:
// 8 rows of text in landscape mode
// 12 rows of text in portrait mode
// =============================================================
void tb_display_init(int ScreenRotation, int textSize){
text_size=textSize;
M5.Lcd.setRotation(ScreenRotation);
switch (ScreenRotation) {
case 1:
case 3:
{
switch (textSize)
{
case 0:
{
// 8 rows of text in landscape mode
text_buffer_height = 12;
text_buffer_line_length = 60;
text_height=8;
break;
}
case 1:
{
// 8 rows of text in landscape mode
text_buffer_height = 8;
text_buffer_line_length = 60;
text_height=16*textSize;
break;
}
case 2:
{
// 4 rows of text in landscape mode
text_buffer_height = 4;
text_buffer_line_length = 30;
text_height=16*textSize;
break;
}
case 3:
{
// 2 rows of text in landscape mode
text_buffer_height = 3;
text_buffer_line_length = 30;
text_height=16*textSize;
break;
}
case 4:
{
// 1 rows of text in landscape mode
text_buffer_height = 2;
text_buffer_line_length = 30;
text_height=16*textSize;
break;
}
case 5:
{
// 1 rows of text in landscape mode
text_buffer_height = 1;
text_buffer_line_length = 30;
text_height=16*textSize;
break;
}
case 6:
{
// 1 rows of text in landscape mode
text_buffer_height = 1;
text_buffer_line_length = 30;
text_height=16*textSize;
break;
}
case 7:
{
// 1 rows of text in landscape mode
text_buffer_height = 1;
text_buffer_line_length = 30;
text_height=16*textSize;
break;
}
default:
break;
}
// width of the screen in landscape mode is 240 pixel
// A small margin on the right side prevent false print results
screen_max = screenWidth-2;
break;
}
case 2:
case 4:
{
switch (textSize)
{
case 0:
{
// 10 rows of text in portrait mode
text_buffer_height = 18;
text_buffer_line_length = 40;
text_height=8;
break;
}
case 1:
{
// 10 rows of text in portrait mode
text_buffer_height = 14;
text_buffer_line_length = 40;
text_height=16*textSize;
break;
}
case 2:
{
// 4 rows of text in landscape mode
text_buffer_height = 7;
text_buffer_line_length = 40;
text_height=16*textSize;
break;
}
case 3:
{
// 2 rows of text in landscape mode
text_buffer_height = 4;
text_buffer_line_length = 40;
text_height=16*textSize;
break;
}
case 4:
{
// 1 rows of text in landscape mode
text_buffer_height = 3;
text_buffer_line_length = 40;
text_height=16*textSize;
break;
}
case 5:
{
// 1 rows of text in landscape mode
text_buffer_height = 3;
text_buffer_line_length = 30;
text_height=16*textSize;
break;
}
case 6:
{
// 1 rows of text in landscape mode
text_buffer_height = 2;
text_buffer_line_length = 30;
text_height=16*textSize;
break;
}
case 7:
{
// 1 rows of text in landscape mode
text_buffer_height = 2;
text_buffer_line_length = 30;
text_height=16*textSize;
break;
}
default:
break;
}
// width of the screen in portrait mode is 135 pixel
// A small margin on the right side prevent false print results
screen_max = screenHeight-2;
break;
}
default:
break;
}
tb_display_clear();
tb_display_show();
}
// =============================================================
// clear the text buffer
// without refreshing the screen
// call tb_display_show(); to clear the screen
// =============================================================
void tb_display_clear(){
for(int line=0; line<TEXT_BUFFER_HEIGHT_MAX; line++){
for(int charpos=0; charpos<TEXT_BUFFER_LINE_LENGTH_MAX; charpos++){
text_buffer[line][charpos]='\0';
}
}
text_buffer_read_pointer = 0;
text_buffer_write_pointer_x = 0;
text_buffer_write_pointer_y = text_buffer_height-1;
screen_xpos = SCREEN_XSTARTPOS;
screen_ypos = text_height*(text_buffer_height-1);
}
// =============================================================
// clear the screen and display the text buffer
// =============================================================
void tb_display_show(){
M5.Lcd.fillScreen(TFT_BLACK);
int yPos = 0;
for(int n=0; n<text_buffer_height; n++){
// modulo operation for line position
int line = (text_buffer_read_pointer+n) % text_buffer_height;
int xPos = SCREEN_XSTARTPOS;
int charpos=0;
while(xPos < screen_max && text_buffer[line][charpos] != '\0'){
xPos += M5.Lcd.drawChar(text_buffer[line][charpos],xPos,yPos,text_font);
charpos++;
}
yPos = yPos + text_height;
}
screen_xpos = SCREEN_XSTARTPOS;
}
// =============================================================
// creates a new line and scroll the display upwards
// =============================================================
void tb_display_new_line(){
text_buffer_write_pointer_x = 0;
text_buffer_write_pointer_y++;
text_buffer_read_pointer++;
// circular buffer...
if(text_buffer_write_pointer_y >= text_buffer_height)
text_buffer_write_pointer_y = 0;
if(text_buffer_read_pointer >= text_buffer_height)
text_buffer_read_pointer = 0;
// clear the actual new line for writing (first character a null terminator)
text_buffer[text_buffer_write_pointer_y][text_buffer_write_pointer_x] = '\0';
tb_display_show();
}
// =============================================================
// print a single character
// the character is added to the text buffer and
// directly printed on the screen.
// The text is automatically wrapped if longer than the display
// example:
// tb_display_print_char('X');
// =============================================================
void tb_display_print_char(byte data){
// check for LF for new line
if (data == '\n') {
// last character in the text_buffer line should be always a null terminator
text_buffer[text_buffer_write_pointer_y][text_buffer_write_pointer_x] = '\0';
tb_display_new_line();
}
// only 'printable' characters
if (data > 31 && data < 128) {
// print the character and get the new xpos
screen_xpos += M5.Lcd.drawChar(data,screen_xpos,screen_ypos,text_font);
// if maximum number of characters reached
if(text_buffer_write_pointer_x >= text_buffer_line_length-1){
tb_display_new_line();
// draw the character again because it was out of the screen last time
screen_xpos += M5.Lcd.drawChar(data,screen_xpos,screen_ypos,text_font);
}
// or if line wrap is reached
if(screen_xpos >= screen_max) {
// prepare for Word-Wrap stuff...
// the buffer for storing the last word content
char Char_buffer[TEXT_BUFFER_LINE_LENGTH_MAX];
int n = 1;
Char_buffer[0] = data;
Char_buffer[n] = '\0';
// if Word-Wrap, go backwards and get the last "word" by finding the
// last space character:
if(tb_display_word_wrap){
int test_pos = text_buffer_write_pointer_x-1;
// get backwards and search a space character
while(test_pos > 0 && text_buffer[text_buffer_write_pointer_y][test_pos] != ' '){
// store all the characters on the way back to the last space character
Char_buffer[n] = text_buffer[text_buffer_write_pointer_y][test_pos];
test_pos--;
n++;
Char_buffer[n] = '\0';
}
// if there was no space character in the row, Word-Wrap is not possible
if(test_pos == 0) {
// don't use the buffer but draw the character passed to the function
n = 1;
} else {
// otherwise use the buffer to print the last found characters of the word
// but only, if the charachter that causes a word wrap is not a space character
if(data != ' '){
// place a \0 at the position of the found space so that the drawing fuction ends here
text_buffer[text_buffer_write_pointer_y][test_pos] = '\0';
}
}
}
tb_display_new_line();
// icharacter passed to the function is a space character, then don't display
// it as the first character of the new line
if(data == ' ')
// don't use the buffer at all
n = 0;
n--;
while(n >= 0){
// draw the characters from the buffer back on the screen
screen_xpos += M5.Lcd.drawChar(Char_buffer[n],screen_xpos,screen_ypos,text_font);
// write the characters into the screen buffer of the new line
text_buffer[text_buffer_write_pointer_y][text_buffer_write_pointer_x] = Char_buffer[n];
text_buffer_write_pointer_x++;
n--;
}
text_buffer[text_buffer_write_pointer_y][text_buffer_write_pointer_x] = '\0';
} else {
// write the character into the screen buffer
text_buffer[text_buffer_write_pointer_y][text_buffer_write_pointer_x] = data;
text_buffer_write_pointer_x++;
// following character a null terminator to clear the old characters of the line
text_buffer[text_buffer_write_pointer_y][text_buffer_write_pointer_x] = '\0';
}
}
}
// =============================================================
// print a string
// The string is added to the text buffer and directly printed
// on the screen.
// The otional parameter "chr_delay" allows a "character by character"
// processing of the String. Then, it looks like Teletype or Typewriter
// The delay is in milliseconds.
// The text is automatically wrapped if longer than the display
// example:
// tb_display_print_String("a new line\n");
// tb_display_print_String("one\nand two lines\n");
//
// char String_buffer[128];
// snprintf(String_buffer, sizeof(String_buffer), "\nthe value: %i",value);
// tb_display_print_String(String_buffer);
//
// std::string msg;
// msg = ss.str();
// const char * c_msg = msg.c_str();
// tb_display_print_String(c_msg);
// =============================================================
void tb_display_print_String(const char *s, int chr_delay){
while(*s != 0){
tb_display_print_char(*s++);
if(chr_delay > 0)
delay(chr_delay);
}
}