📄 console_demo.c
字号:
/*
Graphics demo for Console model
NOTE: THIS DEMO ONLY WORKS FOR 8 OR 2 BITS/PIXEL!
*/
#include "..\console.h"
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#define MIN(x,y) x < y ? x : y;
#define MAX(x,y) x < y ? y : x;
/*
typedef struct tagBITMAPFILEHEADER {
WORD bfType;
DWORD bfSize;
WORD bfReserved1;
WORD bfReserved2;
DWORD bfOffBits;
} BITMAPFILEHEADER
*/
typedef __packed struct tagBITMAPFILEHEADER {
unsigned short bfType;
unsigned int bfSize;
unsigned short bfReserved1;
unsigned short bfReserved2;
unsigned int bfOffBits;
} BITMAPFILEHEADER;
extern BITMAPFILEHEADER armlogo;
extern BITMAPFILEHEADER chars;
extern BITMAPFILEHEADER backdrop;
/*
typedef struct tagBITMAPINFOHEADER{
DWORD biSize;
LONG biWidth;
LONG biHeight;
WORD biPlanes;
WORD biBitCount;
DWORD biCompression;
DWORD biSizeImage;
LONG biXPelsPerMeter;
LONG biYPelsPerMeter;
DWORD biClrUsed;
DWORD biClrImportant;
} BITMAPINFOHEADER */
typedef __packed struct tagBITMAPINFOHEADER{
unsigned int biSize;
int biWidth;
int biHeight;
unsigned short biPlanes;
unsigned short biBitCount;
unsigned int biCompression;
unsigned int biSizeImage;
int biXPelsPerMeter;
int biYPelsPerMeter;
unsigned int biClrUsed;
unsigned int biClrImportant;
} BITMAPINFOHEADER;
/* typedef struct tagRECT
{
LONG left;
LONG top;
LONG right;
LONG bottom;
} RECT
*/
typedef struct tagRECT
{
int left;
int top;
int right;
int bottom;
} RECT;
// Define this to use inline assembler drawing routines for speed
#define FAST_DRAW
unsigned Install_Handler( unsigned routine, unsigned *vector );
__inline void enable_IRQ(void);
void __irq myIRQhandler(void);
/* Write a character */
//__swi(SemiSWI) void _WriteC(unsigned op, char *c);
//#define WriteC(c) _WriteC (0x3,c)
struct __FILE { int handle; /* Add whatever you need here */};
//FILE __stdout;
volatile int keyflag = 0; // used to indicate when a key has been pressed
int getc_echo = 0; // used to specify whether getc call will echo or not
static RECT curr_pos = { 0, 0, 0, 0 }; // used by fputc for positioning
/* Helper function prototypes */
unsigned random( unsigned min, unsigned max );
/* info funcs ***************************/
__inline unsigned getPixelsX( void );
__inline unsigned getPixelsY( void );
/* setup funcs **************************/
void initLCD( void );
/* attribute funcs **********************/
/* 2 bpp */
/* #define BYTES_PER_LINE (unsigned)120 */
/* 8 bpp */
//#define BYTES_PER_LINE (unsigned)480
// this needs tweaking to get on a DWORD boundrary
#define BYTES_PER_LINE (getPixelsX()+getAlignmentTweak()) / (8 / BITS_PER_PIXEL)
/* character drawing */
#define CHAR_WIDTH 8
#define CHAR_HEIGHT 16
static char forecolor, backcolor;
__inline unsigned getAlignmentTweak( void );
__inline void setForeColor( char col );
__inline void setBackColor( char col );
/* drawing funcs ************************/
void setPixelXY( unsigned x, unsigned y );
int __inline drawSpriteXY( BITMAPFILEHEADER* pBmFile, RECT* rectSrc, RECT* rectDest );
void __inline drawCharXY( char c, RECT* rectDest );
void __inline drawStringXY( char* string, RECT* rectDest );
void __inline scrollUp( unsigned lines );
/* main drawing routines */
void demo2BPP( void );
void demo8BPP( void );
/* MAIN PROGRAM *************************/
/* TODO: add greyscale, basic sprites and scrolling */
int main()
{
/* Set up keyboard input */
unsigned *irqvec = (unsigned *)0x18;
initLCD();
Install_Handler( (unsigned)myIRQhandler, irqvec );
/* DR added - ENABLE IRQs */
enable_IRQ();
switch( BITS_PER_PIXEL ) {
case 2:
demo2BPP();
break;
case 8:
demo8BPP();
break;
default:
// the demo does not support these color depths
return 1;
}
return 0;
}
/* Simple demo in 2bpp mode */
void demo2BPP( void )
{
/* examine corners */
setPixelXY( 0, 0 );
setPixelXY( getPixelsX()-1, 0 );
setPixelXY( 0, getPixelsY()-1 );
setPixelXY( getPixelsX()-1, getPixelsY()-1 );
/* randomly turn on pixels for background */
while(1) {
setForeColor( random( 0, 3 ) );
setPixelXY( random( 0, getPixelsX()-1 ), random( 0, getPixelsY()-1 ) );
}
}
void demo8BPP( void )
{
int i, vel;
char c;
RECT rectSrc, rectDest;
/* a value of -1 indicates that source rectangle is that of whole bitmap */
rectSrc.left = rectSrc.top = -1;
rectSrc.right = rectSrc.bottom = -1;
/* draw ARM logo in approx. centre of screen */
rectDest.right = rectDest.bottom = 0; // unused as yet
rectDest.left = (getPixelsX() - 480) / 2;
rectDest.top = (getPixelsY() - 240) / 2;
// note that the backdrop has dimensions 480x240 thus this operation
// will overwrite memory outside the display region if the size of display
// is smaller.
drawSpriteXY( &backdrop, &rectSrc, &rectDest );
/* enable keyboard interrupts through the ODO keyb setup reg. */
*((unsigned*)CPU_MR) |= KEYB_INTR;
*((unsigned*)KB_CSR) |= KB_CLK_EN;
/* Query and response */
printf( "Hello! Enter your age: " );
getc_echo = 1;
scanf( "%d", &i );
getc_echo = 0;
printf( "\nTwice your age is: %d\n\nPress (1) for animation, (2) to type", i * 2 );
c = getchar();
switch( c ) {
case '1':
/* animation */
i = 20;
vel = 1;
rectDest.top = 0;
while(1) {
rectDest.left = i;
drawSpriteXY( &armlogo, &rectSrc, &rectDest );
if( i > (getPixelsX()-64) || i < 1 ) vel = -vel;
i += vel;
}
break;
case '2':
/* Just echo keyboard characters */
printf( "\n\nKeystrokes will be echoed below:\n" );
while( 1 ) putchar(getchar());
break;
default:
printf( "\n\nInvalid choice - quitting" );
}
}
__inline unsigned getPixelsX( void ) {
return *((unsigned*)DISP_XSIZE);
}
__inline unsigned getPixelsY( void ) {
return *((unsigned*)DISP_YSIZE);
}
__inline unsigned getAlignmentTweak( void ) {
unsigned alignment_tweak;
alignment_tweak = 4 - getPixelsX() % 4;
if( alignment_tweak == 4 ) alignment_tweak = 0;
return alignment_tweak;
}
void initLCD( void ) {
/* fill the display with background colour */
unsigned char* pDisp = (unsigned char*)DISPLAY_PTR;
unsigned char* pTop;
unsigned char temp_byte;
int i;
pTop = pDisp + BYTES_PER_LINE * getPixelsY();
// set up fputc function
curr_pos.top = getPixelsY()-CHAR_HEIGHT;
switch( BITS_PER_PIXEL ) {
case 2:
setForeColor( 0 );
setBackColor( 3 );
// set up the byte
temp_byte = backcolor;
for( i = 0; i < 3; i++ ) {
temp_byte <<= 2;
temp_byte |= backcolor;
}
while( pDisp < pTop ) {
*pDisp = temp_byte;
pDisp++;
}
break;
case 8:
setForeColor( 0 );
// white
setBackColor( 215 );
while( pDisp < pTop ) {
*pDisp = backcolor;
pDisp++;
}
break;
default:
return;
}
}
__inline void setForeColor( char col ) {
forecolor = col;
}
__inline void setBackColor( char col ) {
backcolor = col;
}
void setPixelXY( unsigned x, unsigned y ) {
char shift, mask, masked_old, new_byte;
/* determine which byte to set (calculate address from x and y ) */
char *addr;
//addr = (char*)DISPLAY_PTR + y * BYTES_PER_LINE + (x >> 2);
//addr = (char*)DISPLAY_PTR + y * BYTES_PER_LINE + x;
addr = (char*)DISPLAY_PTR + y * BYTES_PER_LINE;
switch( BITS_PER_PIXEL ) {
case 2:
addr += (x >> 2); // divide x byte position by 4
/* mask off unwanted bits in byte, shift then OR with current word. */
shift = (x % 4) << 1;
/* store the new pixel value */
mask = ~(0x03 << shift);
masked_old = (*addr) & mask;
new_byte = (char)(masked_old | (forecolor << shift));
*addr = new_byte;
break;
case 8:
addr += x;
*addr = forecolor;
break;
default:
// not supported
return;
}
}
int __inline drawSpriteXY( BITMAPFILEHEADER* pBmFile, RECT* rectSrc, RECT* rectDest )
{
BITMAPINFOHEADER* pBmInfo;
char *pBmBytes, *pDest;
unsigned curr_x, curr_y; /* used to indicate current iteration */
unsigned srcwidth, srcheight; /* derived from source rectangle */
unsigned limit_x, limit_y;
unsigned alignment_tweak; /* must tweak the width due to DWORD aligned data */
/* NOTE: This routine cannot be highly optimised because source rectangles do not
have to be word aligned although non-edge blocks can still be copied using
LDM/STM instructions */
/* Takes a pointer to an (8-bpp Windows DIB image),
x and y are the byte no's from left and top */
/* Strip off header and return if invalid i.e. not BM */
if( pBmFile->bfType != 0x4D42 ) return 0;
pBmInfo = (BITMAPINFOHEADER*)((char*)pBmFile+sizeof(BITMAPFILEHEADER));
/* check header for valid formats, currently only 8 bit */
if( pBmInfo->biBitCount != 8 ) return 0;
pBmBytes = (char*)((char*)pBmFile+sizeof(BITMAPFILEHEADER)+pBmFile->bfOffBits-14);
//pBmBytes = (char*)((char*)pBmFile+sizeof(BITMAPFILEHEADER)+pBmFile->bfOffBits-32);
/* Dimensions can be grabbed from pBmInfo->biWidth, pBmInfo->biHeight */
/* Draw the image, assuming DIB is bottom-up so we can just draw
going up from the base display pointer */
pDest = (char*)DISPLAY_PTR +
rectDest->top * BYTES_PER_LINE + rectDest->left;
/* set up loop limits from source rect; -1 indicates use of full bitmap as source */
if( rectSrc->left != -1 ) {
srcwidth = rectSrc->right - rectSrc->left;
srcheight = rectSrc->bottom - rectSrc->top;
limit_y = MIN( pBmInfo->biHeight, srcheight );
limit_x = MIN( pBmInfo->biWidth, srcwidth );
/* adjust byte pointer based on source rect */
pBmBytes += rectSrc->left;
} else {
limit_y = pBmInfo->biHeight;
limit_x = pBmInfo->biWidth;
srcwidth = pBmInfo->biWidth;
srcheight = pBmInfo->biHeight;
}
// source bitmap alignment tweak
alignment_tweak = 4 - pBmInfo->biWidth % 4;
if( alignment_tweak == 4 ) alignment_tweak = 0;
for( curr_y = 0; curr_y < limit_y; curr_y++ ) {
for( curr_x = 0; curr_x < limit_x; curr_x++ ) {
*pDest = *pBmBytes++;
pDest++;
}
/* adjust source pointer to skip any bytes excluded by low x limit
assuming bitmap width is greater than or equal to source rectangle width. */
pBmBytes = pBmBytes + pBmInfo->biWidth - limit_x + alignment_tweak;
/* adjust destination pointer to skip to next line */
pDest = pDest + BYTES_PER_LINE - limit_x;
}
return 1;
}
unsigned random( unsigned min, unsigned max )
{
return rand() % (max-min+1) + min;
}
/* higher-level drawing functions */
void __inline drawCharXY( char c, RECT* rectDest )
{
/* Set up a source rectangle and draw part of the chars image */
/* calculate offset */
RECT rectSrc;
rectSrc.left = (c-32)*CHAR_WIDTH;
rectSrc.top = 0;
rectSrc.right = rectSrc.left + CHAR_WIDTH;
rectSrc.bottom = CHAR_HEIGHT;
drawSpriteXY( &chars, &rectSrc, rectDest );
}
void __inline drawStringXY( char* string, RECT* rectDest )
{
/* loop through, incrementing positions and displaying characters */
unsigned i;
unsigned max_i = strlen( string );
RECT newRect;
newRect = *rectDest;
for( i = 0; i < max_i; i++ ) {
drawCharXY( *(string+i), &newRect );
newRect.left += CHAR_WIDTH;
}
}
void __inline scrollUp( unsigned lines )
{
/* copy bytes 'up' in memory by specified amount -
prime candidate for load/store multiple instruction optimisation */
unsigned no_bytes = lines * BYTES_PER_LINE;
unsigned no_blocks, no_bytes_left, temp_word;
char *pSrc, *pDst, *pTmp;
pDst = (char*)DISPLAY_PTR + BYTES_PER_LINE * getPixelsY();
pSrc = pDst - no_bytes;
// divide number of bytes by 4 (words) then 8 (blocks)
no_blocks = ((unsigned)pSrc - DISPLAY_PTR) / 32 - 1;
no_bytes_left = ((unsigned)pSrc - DISPLAY_PTR) - (no_blocks+1) * 32;
#ifdef FAST_DRAW
__asm {
// copy as much as possible using load/store multiple
// put no of words to copy into d0
// read and write data until
// words left on line < no. words
loop1:
LDMDA pSrc!, {r4-r11}
STMDA pDst!, {r4-r11}
SUBS no_blocks, no_blocks, #1
BGE loop1
// copy any bytes left over, if any
CMP no_bytes_left, #0
BLE fill
loop2:
LDRB temp_word, [pSrc]
SUB pSrc, pSrc, #1
STRB temp_word, [pDst]
SUB pDst, pDst, #1
SUBS no_bytes_left, no_bytes_left, #1
BGE loop2
fill:
}
#else
/* keep copying till source hits bottom of display memory */
while( pSrc >= (char*)DISPLAY_PTR ) {
*pDst-- = *pSrc--;
}
#endif
/* blank off lower region with background color */
pSrc = (char*)DISPLAY_PTR;
pTmp = (char*)DISPLAY_PTR + no_bytes;
while( pSrc < pTmp ) *pSrc++ = backcolor;
}
/* Keyboard/interrupt support */
void __irq myIRQhandler(void)
{
int code = *((unsigned*)KB_CSR) & 0xFF;
/* Ignore keyup events and characters not handled by fputc */
if( code < 127 ) {
/* indicate key to fgetc */
keyflag = code;
}
/* clear interupt by writing to KB_ISR */
*((unsigned*)KB_ISR) |= KB_RDRF;
}
unsigned Install_Handler( unsigned routine, unsigned *vector )
{
unsigned vec, oldvec;
vec = ((routine - (unsigned)vector - 0x8) >> 2 );
vec = 0xea000000 | vec;
oldvec = *vector;
*vector = vec;
return (oldvec);
}
__inline void enable_IRQ(void)
{
int tmp;
__asm
{
MRS tmp, CPSR
BIC tmp, tmp, #0x80
MSR CPSR_c, tmp
}
}
/* Functions retargeted from C library
prevents call to the semihosted function */
int fputc(int ch, FILE *f)
{
// TODO: handle arrow, enter and return keys, newline/CR
if( ch == 13 || ch == 10 ) { // CR
// TODO: print a load of blanks up to the end of the line
curr_pos.left = 0;
curr_pos.top -= CHAR_HEIGHT;
}
// backspace
if( ch == 8 ) {
// head backwards ONLY UP TO THE EDGE
curr_pos.left -= CHAR_WIDTH;
if( curr_pos.left < 0 ) curr_pos.left = 0;
// draw a blank where you are
drawCharXY( ' ', &curr_pos );
}
// check if needs scrolling
if( curr_pos.top < 0 ) {
curr_pos.top += CHAR_HEIGHT;
scrollUp( CHAR_HEIGHT );
}
// make a call to drawCharXY
if( ch >= 32 ) {
drawCharXY( ch, &curr_pos );
curr_pos.left += CHAR_WIDTH;
if( curr_pos.left > getPixelsX() - CHAR_WIDTH ) {
curr_pos.left = 0;
curr_pos.top -= CHAR_HEIGHT;
}
}
return ch;
}
int fgetc(FILE *f)
{
int result;
/* wait for a keyboard interrupt and return next keystroke */
while( !keyflag ) {}
result = keyflag;
keyflag = 0;
if( getc_echo )
putchar( result );
return result;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -