/////////////////////////////////////////////////////////////////////////////////////// // file : windows.c // date : october 2020 // author : Alain Greiner /////////////////////////////////////////////////////////////////////////////////////// // This file describes the single thread interactive "windows" application, // that uses the ALMOS-MKH specific system calls to access the Frame Buffer. // It can create, destroy, and/or modify up to MAX_WINDOWS simultaneous windows. // The supported commands are defined in the command[] array below: // - CREATE : create a new user accessible window. // - DELETE : delete a previously created window. // - MOVE : move a previously created window in Frame Buffer. // - DISPLAY : display a raw image stored on disk in a previously created window. // - BUILD : build a synthetic image in a previously created window. // - REFRESH : refresh a previously created window from the user buffer. // - STATE : display current status for all created windows. // - EXIT / delete all created windows and exit the application. /////////////////////////////////////////////////////////////////////////////////////// #include #include #include #include #include #include #define MAX_BYTES 256 // max number of bytes for one single command #define MAX_ARGS 8 // max number of arguments in one single command #define MAX_WINDOWS 32 // max number of simultaneously created windows #define CMD_CREATE 0 #define CMD_DELETE 1 #define CMD_MOVE 2 #define CMD_DISPLAY 3 #define CMD_BUILD 4 #define CMD_REFRESH 5 #define CMD_FRONT 5 #define CMD_STATE 6 #define CMD_EXIT 7 #define DEBUG_MAIN 0 #define DEBUG_CREATE 0 #define DEBUG_DELETE 0 #define DEBUG_MOVE 0 #define DEBUG_DISPLAY 0 #define DEBUG_REFRESH 0 #define DEBUG_FRONT 0 typedef struct windows_cmd_s { char * type; /*! command type */ char * args; /*! command arguments */ } windows_cmd_t; ////////////////////////////////////////////////////////////////////////////////////// // Global Variables ////////////////////////////////////////////////////////////////////////////////////// // Array of supported commands : it must be kept consistent with // the CMD_*** define above, and with the decoding done in the main() windows_cmd_t command[] = { { "create ", "lzero pzero nlines npixels" }, { "delete ", "u_wid" }, { "move ", "u_wid lzero pzero" }, { "display", "u_wid path" }, { "build" , "u_wid" }, { "refresh", "u_wid" }, { "front ", "u_wid" }, { "state ", "" }, { "exit ", "" } }; // Frame Buffer physical parameters int fbf_width; // number of pixels per line int fbf_height; // number of lines int fbf_type; // pixel encoding // user created windows int windows_count; // number of created windows int k_wid[MAX_WINDOWS]; // array of kernel defined WID void * u_buf[MAX_WINDOWS]; // array of pointers on buffer in user space int lines[MAX_WINDOWS]; // array of windows height (number of lines) int pixels[MAX_WINDOWS]; // array of windows width (nunber of pixels) int l_zero[MAX_WINDOWS]; // array of uper left coner X coordinate int p_zero[MAX_WINDOWS]; // array of uper left coner X coordinate // used for debug by display_string() char string[128]; //////////////////////////////// void print_windows_state( void ) { printf("\n u_wid | k_wid | lzero | pzero | lines | pixels\n" ); int i; for( i = 0 ; i< windows_count ; i ++ ) { if( k_wid[i] != -1 ) printf(" %d\t | %d\t | %d\t | %d\t | %d\t | %d\n", i , k_wid[i] , l_zero[i] , p_zero[i] , lines[i] , pixels[i] ); } } ////////////////////////////// void cmd_create( int argc, char ** argv ) { int user_wid = 0; int found; int i; // check argc if( argc != 5 ) { printf("\n usage: %s %s\n", command[CMD_CREATE].type , command[CMD_CREATE].args ); return; } // get a free slot in user windows array for( i = 0 , found = 0 ; (i < MAX_WINDOWS) && (found == 0) ; i++ ) { if( k_wid[i] == -1 ) { user_wid = i; found = 1; } } if( found == 0 ) { printf("\n error: too much windows\n"); return; } #if DEBUG_CREATE printf("\n[%s] get a free user_wid ( %d )\n", __FUNCTION__, user_wid ); #endif // pointer on window buffer in user space void * buf; // get new window arguments int lzero = atoi( argv[1] ); int pzero = atoi( argv[2] ); int nlines = atoi( argv[3] ); int npixels = atoi( argv[4] ); // call relevant FBF access function int kern_wid = fbf_create_window( lzero, pzero, nlines, npixels, &buf ); if( kern_wid < 0 ) { printf("\n error: illegal arguments\n"); return; } #if DEBUG_CREATE printf("\n[%s] get a kern_wid ( %d )\n", __FUNCTION__, user_wid ); #endif // register kernel WID and buffer pointer in relevant arrays windows_count++; k_wid[user_wid] = kern_wid; u_buf[user_wid] = buf; lines[user_wid] = nlines; pixels[user_wid] = npixels; l_zero[user_wid] = lzero; p_zero[user_wid] = pzero; #if DEBUG_CREATE print_windows_state(); #endif } // end cmd_create() ////////////////////////////////////////// void cmd_delete( int argc , char ** argv ) { if( argc != 2 ) { printf("\n usage: %s %s\n", command[CMD_DELETE].type , command[CMD_DELETE].args ); return; } // get user_wid argument int user_wid = atoi( argv[1] ); if( user_wid >= MAX_WINDOWS ) { printf("\n error: illegal user_id argument\n"); return; } // get kern_wid from user_wid int kern_wid = k_wid[user_wid]; // call relevant FBF access function if( fbf_delete_window( kern_wid ) ) { printf("\n error: undefined user_id argument\n"); return; } // reset the k_wid and u_buf arrays k_wid[user_wid] = -1; u_buf[user_wid] = NULL; #if DEBUG_DELETE print_windows_state(); #endif } // end cmd_delete() //////////////////////////////////////// void cmd_move( int argc , char ** argv ) { if( argc != 4 ) { printf("\n usage: %s %s\n", command[CMD_MOVE].type , command[CMD_MOVE].args ); return; } // get arguments int user_wid = atoi( argv[1] ); int lzero = atoi( argv[2] ); int pzero = atoi( argv[3] ); if( user_wid >= MAX_WINDOWS ) { printf("\n error: illegal user_id argument\n"); return; } // get kern_wid from user_wid int kern_wid = k_wid[user_wid]; // call relevant FBF access function if( fbf_move_window( kern_wid, lzero, pzero ) ) { printf("\n error: illegal lzero / pzero arguments\n"); return; } // update moved window l_zero[user_wid] = lzero; p_zero[user_wid] = pzero; #if DEBUG_MOVE print_windows_state(); #endif } // end cmd_move() /////////////////////////////////////////// void cmd_display( int argc , char ** argv ) { if( argc != 3 ) { printf("\n usage: %s %s\n", command[CMD_DISPLAY].type , command[CMD_DISPLAY].args ); return; } // get arguments int user_wid = atoi( argv[1] ); char * path = argv[2]; #if DEBUG_DISPLAY printf("\n[%s] enter for path <%s>\n", __FUNCTION__, path ); #endif if( user_wid >= MAX_WINDOWS ) { printf("\n error: illegal user_id argument\n"); return; } else if( k_wid[user_wid] == -1 ) { printf("\n error: undefined user_id argument\n"); return; } // open file int fd = open( path , O_RDONLY , 0 ); if( fd < 0 ) { printf("\n error: cannot open file <%s>\n", path ); return; } // load user buffer from file int nbytes = lines[user_wid] * pixels[user_wid]; if( read( fd , u_buf[user_wid] , nbytes ) != nbytes ) { printf("\n error: cannot load file <%s>\n", path ); return; } #if DEBUG_DISPLAY printf("\n[%s] file <%s> loaded in user buffer\n", __FUNCTION__, path ); #endif // close file close( fd ); // activate window if( fbf_active_window( k_wid[user_wid], 1 ) ) { printf("\n error: cannot activate window <%d>\n", user_wid ); return; } #if DEBUG_DISPLAY printf("\n[%s] window <%d> activated\n", __FUNCTION__, user_wid ); #endif // refresh window if( fbf_refresh_window( k_wid[user_wid], 0, lines[user_wid] ) ) { printf("\n error: cannot refresh user window <%d>\n", user_wid ); return; } #if DEBUG_DISPLAY printf("\n[%s] window <%d> refreshed\n", __FUNCTION__, user_wid ); #endif } // end cmd_display() ///////////////////////////////////////// void cmd_build( int argc , char ** argv ) { if( argc != 2 ) { printf("\n usage: %s %s\n", command[CMD_BUILD].type , command[CMD_BUILD].args ); return; } #if DEBUG_BUILD printf("\n[%s] enter\n", __FUNCTION__ ); #endif // get user_wid argument int user_wid = atoi( argv[1] ); if( user_wid >= MAX_WINDOWS ) { printf("\n error: illegal user_id argument\n"); return; } else if( k_wid[user_wid] == -1 ) { printf("\n error: undefined user_id argument\n"); return; } // get window nlines, npixels, and buf int nlines = lines[user_wid]; int npixels = pixels[user_wid]; char * base = u_buf[user_wid]; // build image int line; int pixel; for( line = 0 ; line < nlines ; line++ ) { for( pixel = 0 ; pixel < npixels ; pixel++ ) { char * buf = base + (line * npixels) + pixel; *buf = ( ((pixel < (npixels>>1)) && (line < (nlines>>1))) || ((pixel >= (npixels>>1)) && (line >= (nlines>>1))) ) ? 0xFF : 0; } } #if DEBUG_BUILD printf("\n[%s] image build in user buffer\n", __FUNCTION__ ); #endif // activate window if( fbf_active_window( k_wid[user_wid], 1 ) ) { printf("\n error: cannot activate window <%d>\n", user_wid ); return; } #if DEBUG_DISPLAY printf("\n[%s] window <%d> activated\n", __FUNCTION__, user_wid ); #endif // refresh window if ( fbf_refresh_window( k_wid[user_wid], 0, lines[user_wid] ) ) { printf("\n error: cannot refresh user window <%d>\n", user_wid ); return; } #if DEBUG_DISPLAY printf("\n[%s] window <%d> refreshed\n", __FUNCTION__, user_wid ); #endif } // enc cmd_build() /////////////////////////////////////////// void cmd_refresh( int argc , char ** argv ) { if( argc != 2 ) { printf("\n usage: %s %s\n", command[CMD_DISPLAY].type , command[CMD_DISPLAY].args ); return; } // get user_wid argument int user_wid = atoi( argv[1] ); if( user_wid >= MAX_WINDOWS ) { printf("\n error: illegal user_id argument\n"); return; } else if( k_wid[user_wid] == -1 ) { printf("\n error: undefined user_id argument\n"); return; } // refresh window if ( fbf_refresh_window( k_wid[user_wid] , 0 , lines[user_wid] ) ) { printf("\n error: cannot refresh user window <%d>\n", user_wid ); return; } } // end cmd_refresh() ///////////////////////////////////////// void cmd_front( int argc , char ** argv ) { if( argc != 2 ) { printf("\n usage: %s %s\n", command[CMD_FRONT].type , command[CMD_FRONT].args ); return; } #if DEBUG_FRONT printf("\n[%s] enter\n", __FUNCTION__ ); #endif // get user_wid argument int user_wid = atoi( argv[1] ); if( user_wid >= MAX_WINDOWS ) { printf("\n error: illegal user_id argument\n"); return; } // get kern_wid from user_wid int kern_wid = k_wid[user_wid]; // call relevant FBF access function if( fbf_front_window( kern_wid ) ) { printf("\n error: undefined user_id argument\n"); return; } #if DEBUG_FRONT printf("\n[%s] exit\n", __FUNCTION__ ); #endif } // end cmd_delete() ////////////////////// void cmd_state( void ) { print_windows_state() ; } // end cmd_state() ///////////////////// void cmd_exit( void ) { int kern_wid; int i; // delete all created windows for( i = 0 ; i < MAX_WINDOWS ; i++ ) { kern_wid = k_wid[i]; if( kern_wid != -1 ) fbf_delete_window( kern_wid ); } // exit application exit( 0 ); } // end cmd_exit() //////////////// int main( void ) { char cmd[MAX_BYTES]; // string for one command int argc = 0; // number of arguments in command (including type) char * argv[MAX_ARGS]; // array or arguments for one command int len; // command length in bytes (including NUL) int i; // check frame buffer size fbf_get_config( &fbf_width , &fbf_height , &fbf_type ); printf("\n[windows] start / FBF = %d lines * %d pixels\n", fbf_height, fbf_width ); // initialize windows counter windows_count = 0; // initialize windows arrays for( i = 0 ; i < MAX_WINDOWS ; i++ ) { k_wid[i] = -1; u_buf[i] = NULL; } // command interpreter : acquire and execute one command per iteration while( 1 ) { // display prompt printf("\n[windows] "); // get command len = get_string( cmd , MAX_BYTES ); if( len < 0 ) { printf("\n\n[error in windows] cannot get command\n"); exit( 0 ); } // decompose command <=> build argc/argv argc = 0; for( i = 0 ; i < len ; i++ ) { // convert SPACE to NUL if (cmd[i] == ' ') { cmd[i] = '\0'; } else if (i == 0 || cmd[i - 1] == '\0') { if (argc < MAX_ARGS) { argv[argc] = &cmd[i]; argc++; } } } #if DEBUG_MAIN printf("\n[%s] command %s / argc %d\n", __FUNCTION__, argv[0], argc ); #endif // handle empty case if( argc == 0 ) continue; // analyse command if ( strcmp( argv[0] , "create" ) == 0 ) cmd_create ( argc , argv ); else if( strcmp( argv[0] , "delete" ) == 0 ) cmd_delete ( argc , argv ); else if( strcmp( argv[0] , "move" ) == 0 ) cmd_move ( argc , argv ); else if( strcmp( argv[0] , "display" ) == 0 ) cmd_display( argc , argv ); else if( strcmp( argv[0] , "build" ) == 0 ) cmd_build ( argc , argv ); else if( strcmp( argv[0] , "refresh" ) == 0 ) cmd_refresh( argc , argv ); else if( strcmp( argv[0] , "front" ) == 0 ) cmd_front ( argc , argv ); else if( strcmp( argv[0] , "state" ) == 0 ) cmd_state ( ); else if( strcmp( argv[0] , "exit" ) == 0 ) cmd_exit ( ); else { printf(" usage: %s %s\n" " %s %s\n" " %s %s\n" " %s %s\n" " %s %s\n" " %s %s\n" " %s %s\n" " %s %s\n" " %s %s\n", command[CMD_CREATE ].type , command[CMD_CREATE ].args, command[CMD_DELETE ].type , command[CMD_DELETE ].args, command[CMD_MOVE ].type , command[CMD_MOVE ].args, command[CMD_DISPLAY].type , command[CMD_DISPLAY].args, command[CMD_BUILD ].type , command[CMD_BUILD ].args, command[CMD_REFRESH].type , command[CMD_REFRESH].args, command[CMD_FRONT ].type , command[CMD_FRONT ].args, command[CMD_STATE ].type , command[CMD_STATE ].args, command[CMD_EXIT ].type , command[CMD_EXIT ].args ); } } // end while // avoid a warning return 0; } // end main()