forked from Imagelibrary/rtems
464 lines
9.8 KiB
C
464 lines
9.8 KiB
C
/**
|
|
* @file
|
|
*
|
|
* @ingroup raspberrypi
|
|
*
|
|
* @brief displaying characters on the console
|
|
*/
|
|
|
|
/**
|
|
*
|
|
* Copyright (c) 2015 Yang Qiao
|
|
* based on work by:
|
|
* Copyright (C) 1998 Eric Valette (valette@crf.canon.fr)
|
|
* Canon Centre Recherche France.
|
|
*
|
|
* The license and distribution terms for this file may be
|
|
* found in the file LICENSE in this distribution or at
|
|
* http://www.rtems.org/license/LICENSE.
|
|
*
|
|
* Till Straumann <strauman@slac.stanford.edu>, 2003/9:
|
|
* - added handling of basic escape sequences (cursor movement
|
|
* and erasing; just enough for the line editor 'libtecla' to
|
|
* work...)
|
|
*
|
|
*/
|
|
|
|
#include <bsp.h>
|
|
#include <bsp/vc.h>
|
|
#include <bsp/rpi-fb.h>
|
|
#include <rtems/fb.h>
|
|
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include "font_data.h"
|
|
|
|
static void wr_cursor(
|
|
int r,
|
|
int c
|
|
)
|
|
{
|
|
/* dummy function for now */
|
|
}
|
|
|
|
#define TAB_SPACE 4
|
|
#define CONSOLE_BG_COL 0x00
|
|
#define CONSOLE_FG_COL 0xa0
|
|
|
|
static void *fb_mem = NULL;
|
|
static unsigned short maxCol;
|
|
static unsigned short maxRow;
|
|
static unsigned short bytes_per_pixel;
|
|
static unsigned int bytes_per_line;
|
|
static unsigned int bytes_per_char_line;
|
|
static unsigned char row;
|
|
static unsigned char column;
|
|
static unsigned int nLines;
|
|
static uint32_t fgx, bgx, eorx;
|
|
static int rpi_video_initialized;
|
|
|
|
static const int video_font_draw_table32[ 16 ][ 4 ] = {
|
|
{ 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
|
|
{ 0x00000000, 0x00000000, 0x00000000, 0x00ffffff },
|
|
{ 0x00000000, 0x00000000, 0x00ffffff, 0x00000000 },
|
|
{ 0x00000000, 0x00000000, 0x00ffffff, 0x00ffffff },
|
|
{ 0x00000000, 0x00ffffff, 0x00000000, 0x00000000 },
|
|
{ 0x00000000, 0x00ffffff, 0x00000000, 0x00ffffff },
|
|
{ 0x00000000, 0x00ffffff, 0x00ffffff, 0x00000000 },
|
|
{ 0x00000000, 0x00ffffff, 0x00ffffff, 0x00ffffff },
|
|
{ 0x00ffffff, 0x00000000, 0x00000000, 0x00000000 },
|
|
{ 0x00ffffff, 0x00000000, 0x00000000, 0x00ffffff },
|
|
{ 0x00ffffff, 0x00000000, 0x00ffffff, 0x00000000 },
|
|
{ 0x00ffffff, 0x00000000, 0x00ffffff, 0x00ffffff },
|
|
{ 0x00ffffff, 0x00ffffff, 0x00000000, 0x00000000 },
|
|
{ 0x00ffffff, 0x00ffffff, 0x00000000, 0x00ffffff },
|
|
{ 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00000000 },
|
|
{ 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff }
|
|
};
|
|
|
|
static void scroll( void )
|
|
{
|
|
int i, j; /* Counters */
|
|
uint8_t *pt_scroll, *pt_bitmap; /* Pointers on the bit-map */
|
|
|
|
pt_bitmap = fb_mem;
|
|
j = 0;
|
|
pt_bitmap = pt_bitmap + j;
|
|
pt_scroll = pt_bitmap + bytes_per_char_line;
|
|
|
|
for ( i = j; i < maxRow - 1; i++ ) {
|
|
memcpy( pt_bitmap, pt_scroll, bytes_per_char_line );
|
|
pt_bitmap = pt_bitmap + bytes_per_char_line;
|
|
pt_scroll = pt_bitmap + bytes_per_char_line;
|
|
}
|
|
|
|
/*
|
|
* Blank characters are displayed on the last line.
|
|
*/
|
|
memset( pt_bitmap, 0, bytes_per_char_line );
|
|
}
|
|
|
|
static void doCRNL(
|
|
int cr,
|
|
int nl
|
|
)
|
|
{
|
|
if ( nl ) {
|
|
if ( ++row == maxRow ) {
|
|
scroll(); /* Scroll the screen now */
|
|
row = maxRow - 1;
|
|
}
|
|
|
|
nLines++;
|
|
}
|
|
|
|
if ( cr )
|
|
column = 0;
|
|
|
|
/* Move cursor on the next location */
|
|
if ( cr || nl ) {
|
|
wr_cursor( row, column );
|
|
}
|
|
}
|
|
|
|
static void advanceCursor( void )
|
|
{
|
|
if ( ++column == maxCol )
|
|
doCRNL( 1, 1 );
|
|
else
|
|
wr_cursor( row, column );
|
|
}
|
|
|
|
static void gotorc(
|
|
int r,
|
|
int c
|
|
)
|
|
{
|
|
column = c;
|
|
row = r;
|
|
wr_cursor( row, column );
|
|
}
|
|
|
|
static void video_drawchars(
|
|
int r,
|
|
int c,
|
|
unsigned char ch
|
|
)
|
|
{
|
|
if ( fb_mem == NULL ) {
|
|
return;
|
|
}
|
|
|
|
uint8_t *cdat, *dest, *dest0;
|
|
int rows, offset;
|
|
|
|
offset = r * bytes_per_char_line + c * bytes_per_pixel * RPI_FONT_WIDTH;
|
|
dest0 = fb_mem + offset;
|
|
|
|
/*
|
|
* only 32-bit per pixel format is supported for now
|
|
*/
|
|
cdat = rpi_font + ch * RPI_FONT_HEIGHT;
|
|
|
|
for ( rows = RPI_FONT_HEIGHT, dest = dest0;
|
|
rows--; dest += bytes_per_line ) {
|
|
uint8_t bits = *cdat++;
|
|
|
|
( (uint32_t *) dest )[ 0 ] =
|
|
( video_font_draw_table32
|
|
[ bits >> 4 ][ 0 ] & eorx ) ^ bgx;
|
|
( (uint32_t *) dest )[ 1 ] =
|
|
( video_font_draw_table32
|
|
[ bits >> 4 ][ 1 ] & eorx ) ^ bgx;
|
|
( (uint32_t *) dest )[ 2 ] =
|
|
( video_font_draw_table32
|
|
[ bits >> 4 ][ 2 ] & eorx ) ^ bgx;
|
|
( (uint32_t *) dest )[ 3 ] =
|
|
( video_font_draw_table32
|
|
[ bits >> 4 ][ 3 ] & eorx ) ^ bgx;
|
|
|
|
( (uint32_t *) dest )[ 4 ] =
|
|
( video_font_draw_table32
|
|
[ bits & 15 ][ 0 ] & eorx ) ^ bgx;
|
|
( (uint32_t *) dest )[ 5 ] =
|
|
( video_font_draw_table32
|
|
[ bits & 15 ][ 1 ] & eorx ) ^ bgx;
|
|
( (uint32_t *) dest )[ 6 ] =
|
|
( video_font_draw_table32
|
|
[ bits & 15 ][ 2 ] & eorx ) ^ bgx;
|
|
( (uint32_t *) dest )[ 7 ] =
|
|
( video_font_draw_table32
|
|
[ bits & 15 ][ 3 ] & eorx ) ^ bgx;
|
|
}
|
|
}
|
|
|
|
#define ESC ( (char) 27 )
|
|
/* erase current location without moving the cursor */
|
|
#define BLANK ( (char) 0x7f )
|
|
|
|
static void videoPutChar( char ch )
|
|
{
|
|
switch ( ch ) {
|
|
case '\b': {
|
|
if ( column )
|
|
column--;
|
|
|
|
/* Move cursor on the previous location */
|
|
wr_cursor( row, column );
|
|
return;
|
|
}
|
|
case '\t': {
|
|
int i;
|
|
|
|
i = TAB_SPACE - ( column & ( TAB_SPACE - 1 ) );
|
|
|
|
while ( i-- ) {
|
|
|
|
video_drawchars( row, column, ' ' );
|
|
column += 1;
|
|
|
|
if ( column >= maxCol ) {
|
|
doCRNL( 1, 1 );
|
|
return;
|
|
}
|
|
}
|
|
|
|
wr_cursor( row, column );
|
|
|
|
return;
|
|
}
|
|
case '\n': {
|
|
doCRNL( 0, 1 );
|
|
return;
|
|
}
|
|
case 7: { /* Bell code must be inserted here */
|
|
return;
|
|
}
|
|
case '\r': {
|
|
doCRNL( 1, 0 );
|
|
return;
|
|
}
|
|
case BLANK: {
|
|
video_drawchars( row, column, ' ' );
|
|
|
|
wr_cursor( row, column );
|
|
|
|
return;
|
|
}
|
|
default: {
|
|
// *pt_bitmap = (unsigned char)ch | attribute;
|
|
video_drawchars( row, column, ch );
|
|
advanceCursor();
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* trivial state machine to handle escape sequences:
|
|
*
|
|
* ---------------------------------
|
|
* | |
|
|
* | |
|
|
* KEY: esc V [ DCABHKJ esc |
|
|
* STATE: 0 -----> 27 -----> '[' ----------> -1 -----
|
|
* ^\ \ \ \
|
|
* KEY: | \other \ other \ other \ other
|
|
* <-------------------------------------
|
|
*
|
|
* in state '-1', the DCABHKJ cases are handled
|
|
*
|
|
* (cursor motion and screen clearing)
|
|
*/
|
|
|
|
#define DONE ( -1 )
|
|
|
|
static int handleEscape(
|
|
int oldState,
|
|
char ch
|
|
)
|
|
{
|
|
int rval = 0;
|
|
int ro, co;
|
|
|
|
switch ( oldState ) {
|
|
case DONE: /* means the previous char terminated an ESC sequence... */
|
|
case 0:
|
|
|
|
if ( 27 == ch ) {
|
|
rval = 27; /* START of an ESC sequence */
|
|
}
|
|
|
|
break;
|
|
|
|
case 27:
|
|
|
|
if ( '[' == ch ) {
|
|
rval = ch; /* received ESC '[', so far */
|
|
} else {
|
|
/* dump suppressed 'ESC'; outch will append the char */
|
|
videoPutChar( ESC );
|
|
}
|
|
|
|
break;
|
|
|
|
case '[':
|
|
/* handle 'ESC' '[' sequences here */
|
|
ro = row;
|
|
co = column;
|
|
rval = DONE; /* done */
|
|
|
|
switch ( ch ) {
|
|
case 'D': /* left */
|
|
|
|
if ( co > 0 )
|
|
co--;
|
|
|
|
break;
|
|
case 'C': /* right */
|
|
|
|
if ( co < maxCol )
|
|
co++;
|
|
|
|
break;
|
|
case 'A': /* up */
|
|
|
|
if ( ro > 0 )
|
|
ro--;
|
|
|
|
break;
|
|
case 'B': /* down */
|
|
|
|
if ( ro < maxRow )
|
|
ro++;
|
|
|
|
break;
|
|
case 'H': /* home */
|
|
ro = co = 0;
|
|
break;
|
|
case 'K': /* clear to end of line */
|
|
|
|
while ( column < maxCol - 1 )
|
|
videoPutChar( ' ' );
|
|
|
|
videoPutChar( BLANK );
|
|
break;
|
|
case 'J': /* clear to end of screen */
|
|
|
|
while ( ( ( row < maxRow - 1 ) || ( column < maxCol - 1 ) ) )
|
|
videoPutChar( ' ' );
|
|
|
|
videoPutChar( BLANK );
|
|
break;
|
|
default:
|
|
videoPutChar( ESC );
|
|
videoPutChar( '[' );
|
|
/* DONT move the cursor */
|
|
ro = -1;
|
|
rval = 0;
|
|
break;
|
|
}
|
|
|
|
// /* reset cursor */
|
|
if ( ro >= 0 )
|
|
gotorc( ro, co );
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return rval;
|
|
}
|
|
|
|
static void clear_screen( void )
|
|
{
|
|
int i, j;
|
|
|
|
for ( j = 0; j < maxRow; j++ ) {
|
|
for ( i = 0; i < maxCol; i++ ) {
|
|
videoPutChar( ' ' );
|
|
}
|
|
}
|
|
|
|
column = 0;
|
|
row = 0;
|
|
}
|
|
|
|
void rpi_fb_outch( char c )
|
|
{
|
|
static int escaped = 0;
|
|
|
|
if ( !( escaped = handleEscape( escaped, c ) ) ) {
|
|
if ( '\n' == c )
|
|
videoPutChar( '\r' );
|
|
|
|
videoPutChar( c );
|
|
}
|
|
}
|
|
|
|
void rpi_video_init( void )
|
|
{
|
|
int ret = rpi_fb_init();
|
|
|
|
if ( ( ret != RPI_FB_INIT_OK ) &&
|
|
( ret != RPI_FB_INIT_ALREADY_INITIALIZED ) ) {
|
|
rpi_video_initialized = 0;
|
|
return;
|
|
}
|
|
|
|
struct fb_var_screeninfo fb_var_info;
|
|
struct fb_fix_screeninfo fb_fix_info;
|
|
rpi_get_var_screen_info( &fb_var_info );
|
|
rpi_get_fix_screen_info( &fb_fix_info );
|
|
maxCol = fb_var_info.xres / RPI_FONT_WIDTH;
|
|
maxRow = fb_var_info.yres / RPI_FONT_HEIGHT;
|
|
bytes_per_pixel = fb_var_info.bits_per_pixel / 8;
|
|
bytes_per_line = bytes_per_pixel * fb_var_info.xres;
|
|
bytes_per_char_line = RPI_FONT_HEIGHT * bytes_per_line;
|
|
fb_mem = RTEMS_DEVOLATILE( void *, fb_fix_info.smem_start );
|
|
column = 0;
|
|
row = 0;
|
|
nLines = 0;
|
|
fgx = ( CONSOLE_FG_COL << 24 ) |
|
|
( CONSOLE_FG_COL << 16 ) |
|
|
( CONSOLE_FG_COL << 8 ) |
|
|
CONSOLE_FG_COL;
|
|
bgx = ( CONSOLE_BG_COL << 24 ) |
|
|
( CONSOLE_BG_COL << 16 ) |
|
|
( CONSOLE_BG_COL << 8 ) |
|
|
CONSOLE_BG_COL;
|
|
eorx = fgx ^ bgx;
|
|
clear_screen();
|
|
rpi_video_initialized = 1;
|
|
}
|
|
|
|
int rpi_video_is_initialized( void )
|
|
{
|
|
return rpi_video_initialized;
|
|
}
|
|
|
|
/* for old DOS compatibility n-curses type of applications */
|
|
void gotoxy(
|
|
int x,
|
|
int y
|
|
);
|
|
int whereX( void );
|
|
int whereY( void );
|
|
|
|
void gotoxy(
|
|
int x,
|
|
int y
|
|
)
|
|
{
|
|
gotorc( y, x );
|
|
}
|
|
|
|
int whereX( void )
|
|
{
|
|
return row;
|
|
}
|
|
|
|
int whereY( void )
|
|
{
|
|
return column;
|
|
}
|