EFM32 Gecko Software Documentation  efm32g-doc-5.1.2
textdisplay.c
Go to the documentation of this file.
1 /***************************************************************************/
17 #include <stdint.h>
18 #include <stdbool.h>
19 #include <stdlib.h>
20 #include <stdio.h>
21 #include <string.h>
22 #include <ctype.h>
23 
24 #include "displayconfigall.h"
25 #include "display.h"
26 #include "textdisplay.h"
27 
28 #ifdef TEXTDISPLAY_FONT_8x8
29 #include "displayfont8x8.h"
30 #define FONT_ASCII_START (' ')
31 #define FONT_CHARACTERS (100)
32 #define FONT_BITS_MASK (0x7)
33 #define FONT_BITS_LOG2 (3)
34 #define fontBits chars_8x8_bits
35 #endif
36 
37 #ifdef TEXTDISPLAY_FONT_6x8
38 #include "displayfont6x8.h"
39 #define FONT_ASCII_START (' ')
40 #define FONT_CHARACTERS (100)
41 #define FONT_BITS_MASK (0x7)
42 #define FONT_BITS_LOG2 (3)
43 #define fontBits chars_6x8_bits
44 #endif
45 
46 #ifdef TEXTDISPLAY_NUMBER_FONT_16x20
47 #include "displayfont16x20.h"
48 #define FONT_ASCII_START ('0')
49 #define FONT_CHARACTERS (12)
50 #define FONT_BITS_MASK (0xF)
51 #define FONT_BITS_LOG2 (4)
52 #define fontBits numbers_16x20_bits
53 #endif
54 
55 
58 /*******************************************************************************
59  ******************************* TYPEDEFS ***********************************
60  ******************************************************************************/
61 
62 typedef enum TEXTDISPLAY_UpdateMode_t
63 {
64  TEXTDISPLAY_UPDATE_MODE_FULL,
65  TEXTDISPLAY_UPDATE_MODE_LINE,
66  TEXTDISPLAY_UPDATE_MODE_CHAR,
67  TEXTDISPLAY_UPDATE_MODE_NONE
68 } TEXTDISPLAY_UpdateMode_t;
69 
70 
71 typedef struct TEXTDISPLAY_Device_t
72 {
73  int displayDeviceNo; /* Display device number to initialize
74  test display on. */
75  DISPLAY_Device_t displayDevice; /* Display properties. */
76 
77  unsigned int columns; /* Number of columns to use. */
78  unsigned int lines; /* Number of lines to use. */
79 
80  bool scrollEnable; /* Enable/disable scrolling mode on the
81  text display. Scrolling mode will
82  consume more memory because the lines
83  lines will have to be stored in
84  memory. */
85 
86  bool lfToCrLf;
89  DISPLAY_PixelMatrix_t lineBuffer;
92  char* charBuffer;
93  char** charArray;
95  uint8_t rgbColor[3];
97  unsigned int xpos;
98  unsigned int ypos;
100  TEXTDISPLAY_UpdateMode_t updateMode;
102  bool initialized;
104 } TEXTDISPLAY_Device_t;
105 
106 
107 typedef struct TEXTDISPLAY_CharBuffers_t
108 {
109  unsigned int lines;
110  unsigned int columns;
112  char* charBuffer;
113  char** charArray;
114 } TEXTDISPLAY_CharBuffers_t;
115 
116 
117 /*******************************************************************************
118  ******************************* STATICS ***********************************
119  ******************************************************************************/
120 
121 /* Table of text display device structures. */
122 static TEXTDISPLAY_Device_t textdisplayTbl[TEXTDISPLAY_DEVICES_MAX];
123 
124 
125 /* Static Character buffers */
126 char charBufferDevice0[TEXTDISPLAY_DEVICE_0_LINES * TEXTDISPLAY_DEVICE_0_COLUMNS];
127 char* charArrayDevice0[TEXTDISPLAY_DEVICE_0_LINES];
128 
129 #if (TEXTDISPLAY_DEVICES_MAX == 2)
130 char charBufferDevice1[TEXTDISPLAY_DEVICE_1_LINES * TEXTDISPLAY_DEVICE_1_COLUMNS];
131 char* charArrayDevice1[TEXTDISPLAY_DEVICE_1_LINES];
132 #endif
133 
134 #if (TEXTDISPLAY_DEVICES_MAX == 3)
135 char charBufferDevice2[TEXTDISPLAY_DEVICE_2_LINES * TEXTDISPLAY_DEVICE_2_COLUMNS];
136 char* charArrayDevice2[TEXTDISPLAY_DEVICE_2_LINES];
137 #endif
138 
139 #if (TEXTDISPLAY_DEVICES_MAX == 4)
140 char charBufferDevice3[TEXTDISPLAY_DEVICE_3_LINES * TEXTDISPLAY_DEVICE_3_COLUMNS];
141 char* charArrayDevice3[TEXTDISPLAY_DEVICE_3_LINES];
142 #endif
143 
144 
145 static TEXTDISPLAY_CharBuffers_t charBufferTbl[TEXTDISPLAY_DEVICES_MAX] =
146  {
147  {
148  TEXTDISPLAY_DEVICE_0_LINES,
149  TEXTDISPLAY_DEVICE_0_COLUMNS,
150  charBufferDevice0,
151  charArrayDevice0
152  },
153 #if (TEXTDISPLAY_DEVICES_MAX == 2)
154  {
155  TEXTDISPLAY_DEVICE_1_LINES,
156  TEXTDISPLAY_DEVICE_1_COLUMNS,
157  charBufferDevice1,
158  charArrayDevice1
159  },
160 #endif
161 #if (TEXTDISPLAY_DEVICES_MAX == 3)
162  {
163  TEXTDISPLAY_DEVICE_2_LINES,
164  TEXTDISPLAY_DEVICE_2_COLUMNS,
165  charBufferDevice2,
166  charArrayDevice2
167  },
168 #endif
169 #if (TEXTDISPLAY_DEVICES_MAX == 4)
170  {
171  TEXTDISPLAY_DEVICE_3_LINES,
172  TEXTDISPLAY_DEVICE_3_COLUMNS,
173  charBufferDevice3,
174  charArrayDevice3
175  },
176 #endif
177  };
178 
179 
180 /*******************************************************************************
181  ************************ STATIC FUNCTION PROTOTYPES ***********************
182  ******************************************************************************/
183 
184 /* Static functions: */
185 static void TextdisplayClear (TEXTDISPLAY_Device_t* textdisplay);
186 static void TextdisplayScrollUp (TEXTDISPLAY_Device_t* textdisplay);
187 static void TextdisplayCharAdd (TEXTDISPLAY_Device_t* textdisplay,
188  int c);
189 static EMSTATUS TextdisplayLineDraw (TEXTDISPLAY_Device_t* textdisplay,
190  unsigned int y);
191 static EMSTATUS TextdisplayUpdate (TEXTDISPLAY_Device_t* textdisplay);
192 
196 /*******************************************************************************
197  ************************** GLOBAL FUNCTIONS **************************
198  ******************************************************************************/
199 
200 /**************************************************************************/
211  TEXTDISPLAY_Handle_t *handle)
212 {
213  TEXTDISPLAY_Device_t* textdisplay;
214  int deviceNo;
215  unsigned int i;
216  EMSTATUS status;
217 
218  /* Find unused text display device structure. */
219  for (textdisplay=NULL,
220  deviceNo=0; deviceNo<TEXTDISPLAY_DEVICES_MAX; deviceNo++)
221  {
222  if (false == textdisplayTbl[deviceNo].initialized)
223  {
224  textdisplay = &textdisplayTbl[deviceNo];
225  break;
226  }
227  }
228  if (NULL == textdisplay)
229  {
231  }
232 
233  /* Retrieve the properties of the DISPLAY. */
234  status =
235  DISPLAY_DeviceGet(config->displayDeviceNo, &textdisplay->displayDevice);
236  if (DISPLAY_EMSTATUS_OK != status)
237  return status;
238 
239  /* If the display address mode is DISPLAY_ADDRESSING_BY_ROWS_ONLY we need
240  a buffer to draw the current line with new characters as they arrive. */
241  if (DISPLAY_ADDRESSING_BY_ROWS_ONLY == textdisplay->displayDevice.addressMode)
242  {
243  status =
244  textdisplay->displayDevice.
245  pPixelMatrixAllocate (&textdisplay->displayDevice,
246  textdisplay->displayDevice.geometry.width,
247 #ifdef EMWIN_WORKAROUND
248  textdisplay->displayDevice.geometry.width,
249 #endif
250  FONT_HEIGHT,
251  &textdisplay->lineBuffer);
252  if (DISPLAY_EMSTATUS_OK != status)
253  return status;
254 
255  status =
256  textdisplay->displayDevice.
257  pPixelMatrixClear (&textdisplay->displayDevice,
258  textdisplay->lineBuffer,
259  textdisplay->displayDevice.geometry.width,
260  FONT_HEIGHT);
261 
262  if (DISPLAY_EMSTATUS_OK != status)
263  return status;
264  }
265  else
266  {
267  textdisplay->lineBuffer = NULL;
268  }
269 
270  /* Check that the requested number of text rows and columns fits inside the
271  geometry of the display device. */
272  if (charBufferTbl[deviceNo].lines >
273  textdisplay->displayDevice.geometry.height / FONT_HEIGHT)
275  if (charBufferTbl[deviceNo].columns >
276  textdisplay->displayDevice.geometry.width / FONT_WIDTH)
278 
279  /* Remember the character buffer parameters. */
280  textdisplay->lines = charBufferTbl[deviceNo].lines;
281  textdisplay->columns = charBufferTbl[deviceNo].columns;
282  textdisplay->charBuffer = charBufferTbl[deviceNo].charBuffer;
283  textdisplay->charArray = charBufferTbl[deviceNo].charArray;
284 
285  /* Store user configuration options */
286  textdisplay->displayDeviceNo = config->displayDeviceNo;
287  textdisplay->scrollEnable = config->scrollEnable;
288  textdisplay->lfToCrLf = config->lfToCrLf;
289 
290  /* Setup char pointer array */
291  for (i=0; i<textdisplay->lines; i++)
292  textdisplay->charArray[i] =
293  textdisplay->charBuffer + textdisplay->columns * i;
294 
295  /* Initialize color for text */
296  /* Use \b for red text (bell/warning) */
297  textdisplay->rgbColor[0] = 0xff;
298  textdisplay->rgbColor[1] = 0xff;
299  textdisplay->rgbColor[2] = 0xff;
300 
301  /* Clear character buffer */
302  TextdisplayClear(textdisplay);
303 
304  textdisplay->initialized = true;
305 
306  *handle = (TEXTDISPLAY_Handle_t*) textdisplay;
307 
309 }
310 
311 
312 /**************************************************************************/
323 {
324  TEXTDISPLAY_Device_t* textdisplay = (TEXTDISPLAY_Device_t*) handle;
325 
326  if (textdisplay->initialized)
327  {
328  textdisplay->charBuffer = NULL;
329  textdisplay->charArray = NULL;
330 
331  if (textdisplay->lineBuffer)
332  {
333  textdisplay->displayDevice.pPixelMatrixFree (&textdisplay->displayDevice,
334  textdisplay->lineBuffer);
335  textdisplay->lineBuffer = NULL;
336  }
337 
338  /* Clear display device number to allow reinitialization of this display.*/
339  textdisplay->displayDeviceNo = -1;
340 
341  textdisplay->initialized = false;
342 
344  }
345 
347 }
348 
349 
350 /**************************************************************************/
362  bool on)
363 {
364  TEXTDISPLAY_Device_t* textdisplay = (TEXTDISPLAY_Device_t*) handle;
365 
366  textdisplay->lfToCrLf = on;
367 
369 }
370 
371 
372 /**************************************************************************/
382  char c)
383 {
384  TEXTDISPLAY_Device_t* textdisplay = (TEXTDISPLAY_Device_t*) handle;
385 
386  /* Check that we are initialized. */
387  if (false == textdisplay->initialized)
388  {
390  }
391 
392  /* Determine initial display update mode. */
393  if (DISPLAY_ADDRESSING_BY_ROWS_ONLY == textdisplay->displayDevice.addressMode)
394  {
395  textdisplay->updateMode = TEXTDISPLAY_UPDATE_MODE_LINE;
396  }
397  else
398  {
399  textdisplay->updateMode = TEXTDISPLAY_UPDATE_MODE_CHAR;
400  }
401 
402  if (textdisplay->scrollEnable)
403  {
404  /* Update the full screen (which has been scrolled up) if we start at the
405  bottom left position and scroll is enabled. */
406  if ((0==textdisplay->xpos) && (textdisplay->ypos == textdisplay->lines-1))
407  {
408  textdisplay->updateMode = TEXTDISPLAY_UPDATE_MODE_FULL;
409  }
410  }
411  else
412  {
413  /* Update the full screen (which is cleared) if we start at top left
414  position and scroll is not enabled. */
415  if ((0==textdisplay->xpos) && (0==textdisplay->ypos))
416  {
417  textdisplay->updateMode = TEXTDISPLAY_UPDATE_MODE_FULL;
418  }
419  }
420 
421  /* Check for form feed - clear screen */
422  if (c == '\f')
423  {
424  TextdisplayClear(textdisplay);
425  /* Update the whole display and return. */
426  textdisplay->updateMode = TEXTDISPLAY_UPDATE_MODE_FULL;
427  return TextdisplayUpdate(textdisplay);
428  }
429 
430  /* Add CR or LF to CRLF if enabled */
431  if (textdisplay->lfToCrLf && (c == '\n'))
432  {
433  TextdisplayCharAdd(textdisplay, '\r');
434  }
435  TextdisplayCharAdd(textdisplay, c);
436 
437  if (TEXTDISPLAY_UPDATE_MODE_NONE != textdisplay->updateMode)
438  /* Update display and return. */
439  return TextdisplayUpdate(textdisplay);
440  else
442 }
443 
444 
445 /**************************************************************************/
455  const char* str)
456 {
457  TEXTDISPLAY_Device_t* textdisplay = (TEXTDISPLAY_Device_t*) handle;
458  EMSTATUS status;
459  char c;
460  bool displayUpdated=false;
461 
462  /* Check that we are initialized. */
463  if (false == textdisplay->initialized)
464  {
466  }
467 
468  /* Determine initial display update mode. */
469  if (DISPLAY_ADDRESSING_BY_ROWS_ONLY == textdisplay->displayDevice.addressMode)
470  {
471  textdisplay->updateMode = TEXTDISPLAY_UPDATE_MODE_LINE;
472  }
473  else
474  {
475  textdisplay->updateMode = TEXTDISPLAY_UPDATE_MODE_CHAR;
476  }
477 
478  while (*str)
479  {
480  /* Mark display as NOT updated. */
481  displayUpdated = false;
482 
483  /* Clear screen if we start at top left position and scroll is not
484  enabled. */
485  if ((0==textdisplay->xpos) && (0==textdisplay->ypos) &&
486  (false == textdisplay->scrollEnable))
487  {
488  TextdisplayClear(textdisplay);
489  textdisplay->updateMode = TEXTDISPLAY_UPDATE_MODE_FULL;
490  }
491 
492  c = *str;
493 
494  switch (c)
495  {
496  case '\f':
497  /* Form feed - clear screen */
498  TextdisplayClear(textdisplay);
499  textdisplay->updateMode = TEXTDISPLAY_UPDATE_MODE_FULL;
500  break;
501 
502  case '\n':
503  /* Update display before proceeding to the next line. */
504  status = TextdisplayUpdate(textdisplay);
505  if (status != TEXTDISPLAY_EMSTATUS_OK)
506  return status;
507 
508  displayUpdated = true;
509 
510  /* Add CR or LF to CRLF if enabled */
511  if (textdisplay->lfToCrLf)
512  {
513  TextdisplayCharAdd(textdisplay, '\r');
514  }
515 
516  TextdisplayCharAdd(textdisplay, c);
517  break;
518 
519  default:
520  TextdisplayCharAdd(textdisplay, c);
521  break;
522  }
523 
524  /* Update display if we reach the end of the line or a full display update
525  is required. */
526  if ((textdisplay->xpos >= textdisplay->columns) ||
527  (textdisplay->updateMode == TEXTDISPLAY_UPDATE_MODE_FULL))
528  {
529  status = TextdisplayUpdate(textdisplay);
530  if (status != TEXTDISPLAY_EMSTATUS_OK)
531  return status;
532  displayUpdated = true;
533  }
534 
535  str++;
536  }
537 
538  /* Update display if not updated. */
539  if (!displayUpdated)
540  return TextdisplayUpdate(textdisplay);
541  else
543 }
544 
545 
548 /*******************************************************************************
549  **************************** STATIC FUNCTIONS *****************************
550  ******************************************************************************/
551 
552 /**************************************************************************/
557 static void TextdisplayClear(TEXTDISPLAY_Device_t* textdisplay)
558 {
559  if (textdisplay->charArray)
560  {
561 
562 #if (FONT_ASCII_START>' ') || (FONT_ASCII_START+FONT_CHARACTERS<' ')
563  /* The font does not include the space character at the standard position
564  according to the ascii table. Then the pace should be placed at the
565  "end" of the font table. */
566  memset(textdisplay->charBuffer, FONT_CHARACTERS - 1,
567  textdisplay->lines * textdisplay->columns);
568 #else
569  memset(textdisplay->charBuffer, 0,
570  textdisplay->lines * textdisplay->columns);
571 #endif
572 
573  /* Set cursor position to upper left */
574  textdisplay->xpos = 0;
575  textdisplay->ypos = 0;
576 
577  textdisplay->updateMode = TEXTDISPLAY_UPDATE_MODE_FULL;
578  }
579 }
580 
581 
582 /**************************************************************************/
587 static void TextdisplayScrollUp(TEXTDISPLAY_Device_t* textdisplay)
588 {
589  unsigned int y;
590 
591  /* copy all lines one line up */
592  for (y = 0; y < (textdisplay->lines - 1); y++)
593  {
594  memcpy(textdisplay->charArray[y],
595  textdisplay->charArray[y + 1],
596  textdisplay->columns);
597  }
598 
599  /* clear last line */
600  memset(&textdisplay->charArray[textdisplay->lines - 1][0],
601  0,
602  textdisplay->columns);
603 
604  textdisplay->xpos = 0;
605  textdisplay->ypos = textdisplay->lines - 1;
606  textdisplay->updateMode = TEXTDISPLAY_UPDATE_MODE_FULL;
607 }
608 
609 
610 #ifdef INCLUDE_VIDEO_TERMINAL_ESCAPE_SEQUENCE_SUPPORT
611 /**************************************************************************/
622 static bool TextdisplayEscapeSequence(TEXTDISPLAY_Device_t* textdisplay,
623  int c)
624 {
625 #define ASCII_ESC (27)
626 #define ESC_SEQ_SIZE_MAX (4)
627 #define ESC_SEQ_MAX (6)
628  static char escapeSequence[ESC_SEQ_SIZE_MAX]= {0,0,0,0};
629  static const char escapeSequences[ESC_SEQ_MAX][ESC_SEQ_SIZE_MAX] =
630  {
631  /* Do not change the order of the escape sequences in the table below,
632  and make sure they correspond to the TEXTDISPLAY_ESC_SEQNO_XXX contants
633  below. */
634  TEXTDISPLAY_ESC_SEQ_CURSOR_HOME_VT100,
635  TEXTDISPLAY_ESC_SEQ_CURSOR_HOME_VT52,
636  TEXTDISPLAY_ESC_SEQ_CURSOR_UP_ONE_LINE,
637  TEXTDISPLAY_ESC_SEQ_CURSOR_DOWN_ONE_LINE,
638  TEXTDISPLAY_ESC_SEQ_CURSOR_RIGHT_ONE_CHAR,
639  TEXTDISPLAY_ESC_SEQ_CURSOR_LEFT_ONE_CHAR
640  };
641 #define TEXTDISPLAY_ESC_SEQNO_CURSOR_HOME_VT100 (0)
642 #define TEXTDISPLAY_ESC_SEQNO_CURSOR_HOME_VT52 (1)
643 #define TEXTDISPLAY_ESC_SEQNO_CURSOR_UP_ONE_LINE (2)
644 #define TEXTDISPLAY_ESC_SEQNO_CURSOR_DOWN_ONE_LINE (3)
645 #define TEXTDISPLAY_ESC_SEQNO_CURSOR_RIGHT_ONE_CHAR (4)
646 #define TEXTDISPLAY_ESC_SEQNO_CURSOR_LEFT_ONE_CHAR (5)
647 
648  char* pChar;
649  int seqNo;
650  bool anyMatch = false;
651 
652  /* Handle escape sequence */
653  if (ASCII_ESC == c)
654  {
655  /* Clear escape sequence, store the ESC character, update mode none and
656  return true. */
657  memset(escapeSequence, 0, ESC_SEQ_SIZE_MAX);
658  escapeSequence[0]=c;
659  textdisplay->updateMode = TEXTDISPLAY_UPDATE_MODE_NONE;
660  return true;
661  }
662 
663  if (ASCII_ESC != escapeSequence[0])
664  {
665  /* We are not currently receiving an escape sequence. Just return false. */
666  return false;
667  }
668  else
669  {
670  unsigned int len;
671 
672  /* We are currently receiving an escape sequence. Append the character to
673  the end of the current escape sequence buffer and check if the sequence
674  matches any of the supported sequences. */
675 
676  pChar = escapeSequence;
677  while (*(++pChar));
678  *pChar = c;
679 
680  len = strlen(escapeSequence);
681 
682  for (seqNo=0; seqNo<ESC_SEQ_MAX; seqNo++)
683  {
684  /* Check for supported escape sequences.*/
685  if (0 == strncmp(escapeSequence, escapeSequences[seqNo], len))
686  {
687  /* We match part of the cursor home sequence. Set anyMatch and update
688  mode to none. */
689  anyMatch = true;
690  textdisplay->updateMode = TEXTDISPLAY_UPDATE_MODE_NONE;
691 
692  /* Full match? */
693  if (len == strlen(escapeSequences[seqNo]))
694  {
695  switch (seqNo)
696  {
697  case TEXTDISPLAY_ESC_SEQNO_CURSOR_HOME_VT100:
698  case TEXTDISPLAY_ESC_SEQNO_CURSOR_HOME_VT52:
699  /* Move cursor to upper left corner, and set update mode to none. */
700  textdisplay->ypos = 0;
701  textdisplay->xpos = 0;
702  break;
703  case TEXTDISPLAY_ESC_SEQNO_CURSOR_UP_ONE_LINE:
704  /* Move cursor up one line. */
705  if (textdisplay->ypos)
706  textdisplay->ypos--;
707  break;
708  case TEXTDISPLAY_ESC_SEQNO_CURSOR_DOWN_ONE_LINE:
709  /* Move cursor down one line. */
710  if (textdisplay->ypos < textdisplay->lines-1)
711  textdisplay->ypos++;
712  break;
713  case TEXTDISPLAY_ESC_SEQNO_CURSOR_RIGHT_ONE_CHAR:
714  /* Move cursor right one column. */
715  if (textdisplay->xpos < textdisplay->columns-1)
716  textdisplay->xpos++;
717  break;
718  case TEXTDISPLAY_ESC_SEQNO_CURSOR_LEFT_ONE_CHAR:
719  /* Move cursor left one column. */
720  if (textdisplay->xpos)
721  textdisplay->xpos--;
722  break;
723  }
724 
725  /* Clear escape sequence, set no display update and return true. */
726  memset(escapeSequence, 0, ESC_SEQ_SIZE_MAX);
727  textdisplay->updateMode = TEXTDISPLAY_UPDATE_MODE_NONE;
728  return true;
729  }
730 
731  /* We found a partial match. Break out of the loop and return in order
732  to await the next character. */
733  break;
734  }
735  }
736 
737  if (false == anyMatch)
738  {
739  /* No match found. Clear escape sequence and return false. */
740  memset(escapeSequence, 0, ESC_SEQ_SIZE_MAX);
741  return false;
742  }
743 
744  if (ESC_SEQ_SIZE_MAX-1 == len)
745  {
746  /* The next character will overflow the escape sequence buffer.
747  Clear the escape sequence buffer and return true. */
748  memset(escapeSequence, 0, ESC_SEQ_SIZE_MAX);
749  textdisplay->updateMode = TEXTDISPLAY_UPDATE_MODE_NONE;
750  return true;
751  }
752 
753  return anyMatch;
754  }
755 }
756 
757 #endif /* INCLUDE_VIDEO_TERMINAL_ESCAPE_SEQUENCE_SUPPORT */
758 
759 
760 /**************************************************************************/
773 static void TextdisplayCharAdd(TEXTDISPLAY_Device_t* textdisplay,
774  int c)
775 {
776  switch (c)
777  {
778  case '\r': /* check for CR */
779  textdisplay->xpos = 0;
780  return;
781 
782  case '\n': /* check for LF */
783  textdisplay->ypos = textdisplay->ypos + 1;
784  textdisplay->xpos = 0;
785  if (textdisplay->ypos >= textdisplay->lines)
786  {
787  if (textdisplay->scrollEnable)
788  {
789  /* Scroll characters one line up */
790  TextdisplayScrollUp(textdisplay);
791  textdisplay->ypos = (textdisplay->lines - 1);
792  }
793  else
794  {
795  TextdisplayClear(textdisplay);
796  }
797  }
798  return;
799 
800  case '\b': /* check for bell character, changes color to red */
802  textdisplay->displayDevice.colourMode) &&
804  textdisplay->displayDevice.colourMode) )
805  {
806  if (textdisplay->rgbColor[1] == 0xff)
807  {
808  textdisplay->rgbColor[1] = 0x00;
809  textdisplay->rgbColor[2] = 0x00;
810  }
811  else
812  {
813  textdisplay->rgbColor[1] = 0xff;
814  textdisplay->rgbColor[2] = 0xff;
815  }
816  return;
817  }
818 
819  }
820 
821 #ifdef INCLUDE_VIDEO_TERMINAL_ESCAPE_SEQUENCE_SUPPORT
822  if (TextdisplayEscapeSequence(textdisplay, c))
823  {
824  /* We have detected an escape sequence. Return now. */
825  return;
826  }
827 #endif
828 
829  /* Check for non-printable characters, and, if so, replace with space. */
830  if (!isprint(c))
831  {
832  c = ' ';
833  }
834 
835 #if 100 > FONT_CHARACTERS
836  /* The font does not have all printable characters in the ASCII table.
837  Check if character is supported. */
838  if ( (FONT_ASCII_START>c) || (FONT_ASCII_START+FONT_CHARACTERS<=c) )
839  {
840 #if (FONT_ASCII_START>' ') || (FONT_ASCII_START+FONT_CHARACTERS<' ')
841  /* Replace with an empty character (space) which should be placed at the
842  "end" of the font table. */
843  c = FONT_ASCII_START + FONT_CHARACTERS - 1;
844 #else
845  c = ' ';
846 #endif
847  }
848 #endif
849 
850  if (textdisplay->xpos >= textdisplay->columns)
851  {
852  textdisplay->xpos = 0;
853  textdisplay->ypos = textdisplay->ypos + 1;
854  }
855  if (textdisplay->ypos >= textdisplay->lines)
856  {
857  if (textdisplay->scrollEnable)
858  {
859  TextdisplayScrollUp(textdisplay);
860  textdisplay->ypos = textdisplay->lines - 1;
861  }
862  else
863  {
864  TextdisplayClear(textdisplay);
865  }
866  }
867  textdisplay->charArray[textdisplay->ypos][textdisplay->xpos] =
868  c - FONT_ASCII_START;
869 
870  textdisplay->xpos = textdisplay->xpos + 1;
871 
872  return;
873 }
874 
875 
876 /**************************************************************************/
884 static EMSTATUS TextdisplayLineDraw(TEXTDISPLAY_Device_t* textdisplay,
885  unsigned int y)
886 {
887  unsigned int x, i;
888  uint8_t c;
889  FontBits_t* rowPtr = (FontBits_t*) textdisplay->lineBuffer;
890  FontBits_t pixelBits;
891 
892  for (i = 0; i < FONT_HEIGHT; i++)
893  {
894  for (x = 0; x < textdisplay->columns; x++)
895  {
896  c = textdisplay->charArray[y][x];
897 
898  pixelBits = fontBits[c + FONT_CHARACTERS * i];
899 
900  switch (textdisplay->displayDevice.colourMode)
901  {
902 #if (8 == FONT_WIDTH) || (16 == FONT_WIDTH)
904  rowPtr[x] = pixelBits;
905  break;
906 
908  rowPtr[x] = ~pixelBits;
909  break;
910 #elif (8 > FONT_WIDTH) || (16 > FONT_WIDTH)
912  pixelBits = ~pixelBits;
914  {
915  int startPixel = x * FONT_WIDTH;
916  int pixelNo = startPixel;
917  for (; pixelNo<startPixel+FONT_WIDTH; pixelBits>>=1, pixelNo++)
918  {
919  if (pixelBits & 0x1)
920  {
921  rowPtr[pixelNo>>FONT_BITS_LOG2] |= 1 << (pixelNo&FONT_BITS_MASK);
922  }
923  else
924  {
925  rowPtr[pixelNo>>FONT_BITS_LOG2] &= ~(1 << (pixelNo&FONT_BITS_MASK));
926  }
927  }
928  }
929  break;
930 #endif
931  }
932  }
933 
934 #if (8 != FONT_WIDTH) || (16 != FONT_WIDTH)
935  /* Set background colour at the end of the display line. */
936  if (textdisplay->displayDevice.colourMode ==
938  {
939  int usedBits;
940  int startPixel = x * FONT_WIDTH;
941  /* Check if the startPixel is not aligned at an FontBits_t boundary,
942  meaning that we need to adjust it to the next FontBits_t boundary. */
943  usedBits = startPixel & FONT_BITS_MASK;
944  if (usedBits)
945  {
946  /* First, clear the last bits in the FontBits_t word of the startPixel. */
947  rowPtr[startPixel>>FONT_BITS_LOG2] &= (1<<usedBits)-1;
948  /* Adjust the startPixel to the next FontBits_t boundary. */
949  startPixel += (sizeof(FontBits_t)*8) - usedBits;
950  }
951  memset (&rowPtr[startPixel>>FONT_BITS_LOG2], 0xff,
952  (textdisplay->displayDevice.geometry.width - startPixel)/8);
953  }
954 #endif
955 
956  rowPtr +=
957  textdisplay->displayDevice.geometry.stride / (sizeof(FontBits_t) * 8) ;
958  }
959 
960  return
961  textdisplay->displayDevice.pPixelMatrixDraw(&textdisplay->displayDevice,
962  textdisplay->lineBuffer,
963  0,
964  textdisplay->columns*FONT_WIDTH,
965 #ifdef EMWIN_WORKAROUND
966  textdisplay->columns*FONT_WIDTH,
967 #endif
968  y * FONT_HEIGHT,
969  FONT_HEIGHT);
970 }
971 
972 
973 /**************************************************************************/
980 static EMSTATUS TextdisplayUpdate(TEXTDISPLAY_Device_t* textdisplay)
981 {
982  unsigned int i;
983  EMSTATUS status;
984 
985  switch (textdisplay->updateMode)
986  {
987  case TEXTDISPLAY_UPDATE_MODE_NONE:
988  default:
989  break;
990 
991  case TEXTDISPLAY_UPDATE_MODE_FULL:
992 
993  /* Draw a full screen */
994 
995  switch (textdisplay->displayDevice.addressMode)
996  {
998 
999  /* Update all text lines. */
1000  for (i=0; i<textdisplay->lines; i++)
1001  /* Draw the current text line on the display. */
1002  TextdisplayLineDraw(textdisplay, i);
1003 
1004  /* Clear lowest and unused part of the screen. */
1005  if (textdisplay->lines * FONT_HEIGHT <
1006  textdisplay->displayDevice.geometry.height)
1007  {
1008  switch (textdisplay->displayDevice.colourMode)
1009  {
1011  memset (textdisplay->lineBuffer, 0x00,
1012  textdisplay->displayDevice.geometry.width/8);
1013  break;
1015  memset (textdisplay->lineBuffer, 0xff,
1016  textdisplay->displayDevice.geometry.width/8);
1017  break;
1018  default:
1020  }
1021 
1022  for (i = textdisplay->lines * FONT_HEIGHT;
1023  i < textdisplay->displayDevice.geometry.height;
1024  i++)
1025  {
1026  status =
1027  textdisplay->displayDevice.pPixelMatrixDraw(&textdisplay->displayDevice,
1028  textdisplay->lineBuffer,
1029  0,
1030  textdisplay->displayDevice.geometry.width,
1031 #ifdef EMWIN_WORKAROUND
1032  textdisplay->displayDevice.geometry.width,
1033 #endif
1034  i,
1035  1);
1036  if (DISPLAY_EMSTATUS_OK != status)
1037  return status;
1038  }
1039  }
1040  break;
1041 
1042  default:
1044  }
1045 
1046  case TEXTDISPLAY_UPDATE_MODE_LINE:
1047 
1048  switch (textdisplay->displayDevice.addressMode)
1049  {
1051 
1052  /* Draw the current text line on the display. */
1053  return TextdisplayLineDraw(textdisplay, textdisplay->ypos);
1054 
1055  default:
1057  }
1058 
1059  case TEXTDISPLAY_UPDATE_MODE_CHAR:
1061  }
1062  return TEXTDISPLAY_EMSTATUS_OK;
1063 }
1064 
1068 /*************** THE REST OF THE FILE IS DOCUMENTATION ONLY ! ***************/
1069 
1070 /*******************************************************************************
1071  ************************** DOCUMENTATION **************************
1072  ******************************************************************************/
1073 
1074 /**************************************************************************/
static int xpos
Definition: retargettft.c:37
#define TEXTDISPLAY_EMSTATUS_NOT_ENOUGH_MEMORY
Definition: textdisplay.h:48
static bool initialized
#define TEXTDISPLAY_EMSTATUS_OK
Definition: textdisplay.h:43
EMSTATUS TEXTDISPLAY_New(TEXTDISPLAY_Config_t *config, TEXTDISPLAY_Handle_t *handle)
Create a new text display device.
Definition: textdisplay.c:210
static uint8_t charBuffer[LINES][CHARS]
Definition: retargettft.c:33
8x8 font with all characters
Text display interface.
EMSTATUS TEXTDISPLAY_WriteString(TEXTDISPLAY_Handle_t handle, const char *str)
Write a string of characters to a text display.
Definition: textdisplay.c:454
#define TEXTDISPLAY_EMSTATUS_NOT_SUPPORTED
Definition: textdisplay.h:47
16x20 font with only number characters and the colon':' and space ' ' signs.
6x8 font with all characters
static uint8_t rgbColor[3]
Definition: retargettft.c:34
Display device interface.
#define TEXTDISPLAY_EMSTATUS_INVALID_PARAM
Definition: textdisplay.h:44
#define DISPLAY_EMSTATUS_OK
Definition: display.h:45
Main configuration file for the DISPLAY driver software stack.
#define fontBits
Definition: retargettft.c:28
#define TEXTDISPLAY_EMSTATUS_NOT_INITIALIZED
Definition: textdisplay.h:49
#define TEXTDISPLAY_EMSTATUS_OUT_OF_RANGE
Definition: textdisplay.h:45
EMSTATUS TEXTDISPLAY_LfToCrLf(TEXTDISPLAY_Handle_t handle, bool on)
Enable or disable LF to CR+LF conversion.
Definition: textdisplay.c:361
static int ypos
Definition: retargettft.c:37
void * TEXTDISPLAY_Handle_t
Definition: textdisplay.h:68
EMSTATUS TEXTDISPLAY_WriteChar(TEXTDISPLAY_Handle_t handle, char c)
Write a single character to a text display.
Definition: textdisplay.c:381
EMSTATUS DISPLAY_DeviceGet(int displayDeviceNo, DISPLAY_Device_t *device)
Get the display device data structure corresponding to the device number.
Definition: display.c:139
EMSTATUS TEXTDISPLAY_Delete(TEXTDISPLAY_Handle_t handle)
Delete a text display device.
Definition: textdisplay.c:322
void * DISPLAY_PixelMatrix_t
Definition: display.h:81