Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:23:04

0001 /**
0002  * @file
0003  *
0004  * @ingroup raspberrypi
0005  *
0006  * @brief displaying characters on the console
0007  */
0008 
0009 /**
0010  *
0011  * Copyright (c) 2015 Yang Qiao
0012  * based on work by:
0013  * Copyright (C) 1998  Eric Valette (valette@crf.canon.fr)
0014  *                     Canon Centre Recherche France.
0015  *
0016  *  The license and distribution terms for this file may be
0017  *  found in the file LICENSE in this distribution or at
0018  *  http://www.rtems.org/license/LICENSE.
0019  *
0020  * Till Straumann <strauman@slac.stanford.edu>, 2003/9:
0021  *  - added handling of basic escape sequences (cursor movement
0022  *    and erasing; just enough for the line editor 'libtecla' to
0023  *    work...)
0024  *
0025  */
0026 
0027 #include <bsp.h>
0028 #include <bsp/vc.h>
0029 #include <bsp/rpi-fb.h>
0030 #include <rtems/fb.h>
0031 
0032 #include <stdlib.h>
0033 #include <string.h>
0034 #include "font_data.h"
0035 
0036 static void wr_cursor(
0037   int           r,
0038   int           c
0039 )
0040 {
0041   /* dummy function for now */
0042 }
0043 
0044 #define TAB_SPACE 4
0045 #define CONSOLE_BG_COL 0x00
0046 #define CONSOLE_FG_COL 0xa0
0047 
0048 static void          *fb_mem = NULL;
0049 static unsigned short maxCol;
0050 static unsigned short maxRow;
0051 static unsigned short bytes_per_pixel;
0052 static unsigned int   bytes_per_line;
0053 static unsigned int   bytes_per_char_line;
0054 static unsigned char  row;
0055 static unsigned char  column;
0056 static unsigned int   nLines;
0057 static uint32_t       fgx, bgx, eorx;
0058 static int            rpi_video_initialized;
0059 
0060 static const int video_font_draw_table32[ 16 ][ 4 ] = {
0061   { 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
0062   { 0x00000000, 0x00000000, 0x00000000, 0x00ffffff },
0063   { 0x00000000, 0x00000000, 0x00ffffff, 0x00000000 },
0064   { 0x00000000, 0x00000000, 0x00ffffff, 0x00ffffff },
0065   { 0x00000000, 0x00ffffff, 0x00000000, 0x00000000 },
0066   { 0x00000000, 0x00ffffff, 0x00000000, 0x00ffffff },
0067   { 0x00000000, 0x00ffffff, 0x00ffffff, 0x00000000 },
0068   { 0x00000000, 0x00ffffff, 0x00ffffff, 0x00ffffff },
0069   { 0x00ffffff, 0x00000000, 0x00000000, 0x00000000 },
0070   { 0x00ffffff, 0x00000000, 0x00000000, 0x00ffffff },
0071   { 0x00ffffff, 0x00000000, 0x00ffffff, 0x00000000 },
0072   { 0x00ffffff, 0x00000000, 0x00ffffff, 0x00ffffff },
0073   { 0x00ffffff, 0x00ffffff, 0x00000000, 0x00000000 },
0074   { 0x00ffffff, 0x00ffffff, 0x00000000, 0x00ffffff },
0075   { 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00000000 },
0076   { 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff }
0077 };
0078 
0079 static void scroll( void )
0080 {
0081   int      i, j;      /* Counters */
0082   uint8_t *pt_scroll, *pt_bitmap;  /* Pointers on the bit-map  */
0083 
0084   pt_bitmap = fb_mem;
0085   j = 0;
0086   pt_bitmap = pt_bitmap + j;
0087   pt_scroll = pt_bitmap + bytes_per_char_line;
0088 
0089   for ( i = j; i < maxRow - 1; i++ ) {
0090     memcpy( pt_bitmap, pt_scroll, bytes_per_char_line );
0091     pt_bitmap = pt_bitmap + bytes_per_char_line;
0092     pt_scroll = pt_bitmap + bytes_per_char_line;
0093   }
0094 
0095   /*
0096    * Blank characters are displayed on the last line.
0097    */
0098   memset( pt_bitmap, 0, bytes_per_char_line );
0099 }
0100 
0101 static void doCRNL(
0102   int cr,
0103   int nl
0104 )
0105 {
0106   if ( nl ) {
0107     if ( ++row == maxRow ) {
0108       scroll();   /* Scroll the screen now */
0109       row = maxRow - 1;
0110     }
0111 
0112     nLines++;
0113   }
0114 
0115   if ( cr )
0116     column = 0;
0117 
0118   /* Move cursor on the next location  */
0119   if ( cr || nl ) {
0120     wr_cursor( row, column );
0121   }
0122 }
0123 
0124 static void advanceCursor( void )
0125 {
0126   if ( ++column == maxCol )
0127     doCRNL( 1, 1 );
0128   else
0129     wr_cursor( row, column );
0130 }
0131 
0132 static void gotorc(
0133   int r,
0134   int c
0135 )
0136 {
0137   column = c;
0138   row = r;
0139   wr_cursor( row, column );
0140 }
0141 
0142 static void video_drawchars(
0143   int           r,
0144   int           c,
0145   unsigned char ch
0146 )
0147 {
0148   if ( fb_mem == NULL ) {
0149     return;
0150   }
0151 
0152   uint8_t *cdat, *dest, *dest0;
0153   int      rows, offset;
0154 
0155   offset = r * bytes_per_char_line + c * bytes_per_pixel * RPI_FONT_WIDTH;
0156   dest0 = fb_mem + offset;
0157 
0158   /*
0159    * only 32-bit per pixel format is supported for now
0160    */
0161   cdat = rpi_font + ch * RPI_FONT_HEIGHT;
0162 
0163   for ( rows = RPI_FONT_HEIGHT, dest = dest0;
0164         rows--; dest += bytes_per_line ) {
0165     uint8_t bits = *cdat++;
0166 
0167     ( (uint32_t *) dest )[ 0 ] =
0168       ( video_font_draw_table32
0169         [ bits >> 4 ][ 0 ] & eorx ) ^ bgx;
0170     ( (uint32_t *) dest )[ 1 ] =
0171       ( video_font_draw_table32
0172         [ bits >> 4 ][ 1 ] & eorx ) ^ bgx;
0173     ( (uint32_t *) dest )[ 2 ] =
0174       ( video_font_draw_table32
0175         [ bits >> 4 ][ 2 ] & eorx ) ^ bgx;
0176     ( (uint32_t *) dest )[ 3 ] =
0177       ( video_font_draw_table32
0178         [ bits >> 4 ][ 3 ] & eorx ) ^ bgx;
0179 
0180     ( (uint32_t *) dest )[ 4 ] =
0181       ( video_font_draw_table32
0182         [ bits & 15 ][ 0 ] & eorx ) ^ bgx;
0183     ( (uint32_t *) dest )[ 5 ] =
0184       ( video_font_draw_table32
0185         [ bits & 15 ][ 1 ] & eorx ) ^ bgx;
0186     ( (uint32_t *) dest )[ 6 ] =
0187       ( video_font_draw_table32
0188         [ bits & 15 ][ 2 ] & eorx ) ^ bgx;
0189     ( (uint32_t *) dest )[ 7 ] =
0190       ( video_font_draw_table32
0191         [ bits & 15 ][ 3 ] & eorx ) ^ bgx;
0192   }
0193 }
0194 
0195 #define ESC ( (char) 27 )
0196 /* erase current location without moving the cursor */
0197 #define BLANK ( (char) 0x7f )
0198 
0199 static void videoPutChar( char ch )
0200 {
0201   switch ( ch ) {
0202     case '\b': {
0203       if ( column )
0204         column--;
0205 
0206       /* Move cursor on the previous location  */
0207       wr_cursor( row, column );
0208       return;
0209     }
0210     case '\t': {
0211       int i;
0212 
0213       i = TAB_SPACE - ( column & ( TAB_SPACE - 1 ) );
0214 
0215       while ( i-- ) {
0216 
0217         video_drawchars( row, column, ' ' );
0218         column += 1;
0219 
0220         if ( column >= maxCol ) {
0221           doCRNL( 1, 1 );
0222           return;
0223         }
0224       }
0225 
0226       wr_cursor( row, column );
0227 
0228       return;
0229     }
0230     case '\n': {
0231       doCRNL( 0, 1 );
0232       return;
0233     }
0234     case 7:   {     /* Bell code must be inserted here */
0235       return;
0236     }
0237     case '\r': {
0238       doCRNL( 1, 0 );
0239       return;
0240     }
0241     case BLANK: {
0242       video_drawchars( row, column, ' ' );
0243 
0244       wr_cursor( row, column );
0245 
0246       return;
0247     }
0248     default: {
0249       // *pt_bitmap = (unsigned char)ch | attribute;
0250       video_drawchars( row, column, ch );
0251       advanceCursor();
0252       return;
0253     }
0254   }
0255 }
0256 
0257 /* trivial state machine to handle escape sequences:
0258  *
0259  *                    ---------------------------------
0260  *                   |                                 |
0261  *                   |                                 |
0262  * KEY:        esc   V    [          DCABHKJ       esc |
0263  * STATE:   0 -----> 27 -----> '[' ----------> -1 -----
0264  *          ^\        \          \               \
0265  * KEY:     | \other   \ other    \ other         \ other
0266  *           <-------------------------------------
0267  *
0268  * in state '-1', the DCABHKJ cases are handled
0269  *
0270  * (cursor motion and screen clearing)
0271  */
0272 
0273 #define DONE ( -1 )
0274 
0275 static int handleEscape(
0276   int  oldState,
0277   char ch
0278 )
0279 {
0280   int rval = 0;
0281   int ro, co;
0282 
0283   switch ( oldState ) {
0284     case DONE:  /*  means the previous char terminated an ESC sequence... */
0285     case 0:
0286 
0287       if ( 27 == ch ) {
0288         rval = 27;   /* START of an ESC sequence */
0289       }
0290 
0291       break;
0292 
0293     case 27:
0294 
0295       if ( '[' == ch ) {
0296         rval = ch;  /* received ESC '[', so far */
0297       } else {
0298         /* dump suppressed 'ESC'; outch will append the char */
0299         videoPutChar( ESC );
0300       }
0301 
0302       break;
0303 
0304     case '[':
0305       /* handle 'ESC' '[' sequences here */
0306       ro = row;
0307       co = column;
0308       rval = DONE; /* done */
0309 
0310       switch ( ch ) {
0311         case 'D': /* left */
0312 
0313           if ( co > 0 )
0314             co--;
0315 
0316           break;
0317         case 'C': /* right */
0318 
0319           if ( co < maxCol )
0320             co++;
0321 
0322           break;
0323         case 'A': /* up    */
0324 
0325           if ( ro > 0 )
0326             ro--;
0327 
0328           break;
0329         case 'B': /* down */
0330 
0331           if ( ro < maxRow )
0332             ro++;
0333 
0334           break;
0335         case 'H': /* home */
0336           ro = co = 0;
0337           break;
0338         case 'K': /* clear to end of line */
0339 
0340           while ( column < maxCol - 1 )
0341             videoPutChar( ' ' );
0342 
0343           videoPutChar( BLANK );
0344           break;
0345         case 'J':     /* clear to end of screen */
0346 
0347           while ( ( ( row < maxRow - 1 ) || ( column < maxCol - 1 ) ) )
0348             videoPutChar( ' ' );
0349 
0350           videoPutChar( BLANK );
0351           break;
0352         default:
0353           videoPutChar( ESC );
0354           videoPutChar( '[' );
0355           /* DONT move the cursor */
0356           ro = -1;
0357           rval = 0;
0358           break;
0359       }
0360 
0361       // /* reset cursor */
0362       if ( ro >= 0 )
0363         gotorc( ro, co );
0364 
0365     default:
0366       break;
0367   }
0368 
0369   return rval;
0370 }
0371 
0372 static void clear_screen( void )
0373 {
0374   int i, j;
0375 
0376   for ( j = 0; j < maxRow; j++ ) {
0377     for ( i = 0; i < maxCol; i++ ) {
0378       videoPutChar( ' ' );
0379     }
0380   }
0381 
0382   column = 0;
0383   row = 0;
0384 }
0385 
0386 void rpi_fb_outch( char c )
0387 {
0388   static int escaped = 0;
0389 
0390   if ( !( escaped = handleEscape( escaped, c ) ) ) {
0391     if ( '\n' == c )
0392       videoPutChar( '\r' );
0393 
0394     videoPutChar( c );
0395   }
0396 }
0397 
0398 void rpi_video_init( void )
0399 {
0400   int ret = rpi_fb_init();
0401 
0402   if ( ( ret != RPI_FB_INIT_OK ) &&
0403        ( ret != RPI_FB_INIT_ALREADY_INITIALIZED ) ) {
0404     rpi_video_initialized = 0;
0405     return;
0406   }
0407 
0408   struct fb_var_screeninfo fb_var_info;
0409   struct fb_fix_screeninfo fb_fix_info;
0410   rpi_get_var_screen_info( &fb_var_info );
0411   rpi_get_fix_screen_info( &fb_fix_info );
0412   maxCol = fb_var_info.xres / RPI_FONT_WIDTH;
0413   maxRow = fb_var_info.yres / RPI_FONT_HEIGHT;
0414   bytes_per_pixel = fb_var_info.bits_per_pixel / 8;
0415   bytes_per_line = bytes_per_pixel * fb_var_info.xres;
0416   bytes_per_char_line = RPI_FONT_HEIGHT * bytes_per_line;
0417   fb_mem = RTEMS_DEVOLATILE( void *, fb_fix_info.smem_start );
0418   column = 0;
0419   row = 0;
0420   nLines = 0;
0421   fgx = ( CONSOLE_FG_COL << 24 ) |
0422         ( CONSOLE_FG_COL << 16 ) |
0423         ( CONSOLE_FG_COL << 8 ) |
0424         CONSOLE_FG_COL;
0425   bgx = ( CONSOLE_BG_COL << 24 ) |
0426         ( CONSOLE_BG_COL << 16 ) |
0427         ( CONSOLE_BG_COL << 8 ) |
0428         CONSOLE_BG_COL;
0429   eorx = fgx ^ bgx;
0430   clear_screen();
0431   rpi_video_initialized = 1;
0432 }
0433 
0434 int rpi_video_is_initialized( void )
0435 {
0436   return rpi_video_initialized;
0437 }
0438 
0439 /* for old DOS compatibility n-curses type of applications */
0440 void gotoxy(
0441   int x,
0442   int y
0443 );
0444 int whereX( void );
0445 int whereY( void );
0446 
0447 void gotoxy(
0448   int x,
0449   int y
0450 )
0451 {
0452   gotorc( y, x );
0453 }
0454 
0455 int whereX( void )
0456 {
0457   return row;
0458 }
0459 
0460 int whereY( void )
0461 {
0462   return column;
0463 }