C Language Remote Front Panel Demo for QScreen / QVGA Controller
This C Language demonstration program is meant for use with the QVGA (Legacy) or QScreen Controller SBC's sold by Mosaic. This source code provides a web enabled remote access control panel for controlling the instrument. This demonstration is compatible with both the WiFi Wildcard and Ethersmart Wildcard. The demonstration serves a pixel-accurate clickable version of the screen image.
Source Code
// this demonstration code is provided in source form. // Top level function: // Ether_GUI_Web_Demo( ) \ no input parameters; runs gui and web page on EtherSmart WC // WiFi_GUI_Web_Demo( ) \ no input parameters; runs gui and web page on WiFi WC // at the bottom of this file: // you can edit main to call the version of the web GUI demo for your Wildcard // *************** IMPORTANT: SET MODULENUM TO MATCH HARDWARE JUMPERS ****************** // recall: modulenum 0 is reserved on the QScreen! #define E_MODULENUM 4 // ******** SET THIS TO MATCH HARDWARE JUMPERS J1 AND J2! ***** // This specifies the modulenum for the high level functions in this file // except for Ether_Monitor_Demo (see its comments). // If EtherSmart is installed on module bus 0, E_MODULENUM = 0, 1, 2, or 3 // If EtherSmart is installed on module bus 1, E_MODULENUM = 4, 5, 6, or 7 // That is, the bus specifies the top bit of a 3-bit modulenum, // and [J2, J1] specifies the remaining 2 bits of the modulenum. // Example: On module bus 0, if neither jumper cap is installed: E_MODULENUM = 0 // Example: On module bus 0, if both jumper caps are installed: E_MODULENUM = 3 // Example: On module bus 1, if J2 is installed but J1 is not: E_MODULENUM = 6 // ************** #includes ************** #include <\mosaic\allqed.h> // include all of the qed and C utilities // choose the correct controller product, comment in/out the appropriate #includes: #include "Library\esmart_gui_qvga\library.h" // for QVGA controller #include "Library\esmart_gui_qvga\library.c" // #include "Library\esmart_gui_qscreen\library.h" // for QScreen controller // #include "Library\esmart_gui_qscreen\library.c" // include the header file that defines the base xaddress and 32-bit size for each resource: #include "Resources\qvga\image_headers.h" // for QVGA controller // #include "Resources\qscreen\image_headers.h" // for QScreen controller #include "guidemo_qvga.c" // gui demo program for qvga controller // #include "guidemo_qscreen.c" // gui demo program for qscreen controller #include "strdefs.h" // defines STRING_XADDR(str_addr) macro; see comments below // ************** USEFUL MACRO FOR STRINGS IN V4.xx C COMPILER ************** // the TO_XADDR defined in /mosaic/include/types.h // transforms a separate 16-bit addr, page into a 32-bit xaddress: // #define TO_XADDR(address,page) ((xaddr) (((page)<<16)+ (0xFFFF & (address)))) // We want to substitute THIS_PAGE (also defined in types.h) for the page, // as the V4.xx C compiler replicates the strings on each page; // therefore, in most cases, the calling function's page is the same as the string page: // #define STRING_XADDR(str_addr) ((xaddr) TO_XADDR(((xaddr) str_addr), ((xaddr) THIS_PAGE))) // ************** USEFUL CONSTANTS ************** #ifdef __FABIUS__ #define BITMAP_BUFFER 0x020000 // if V4.xx, put on pg 2 #else #define BITMAP_BUFFER 0x148000 // if V6.xx, put on pg 0x14 #endif // __FABIUS__ #define BITMAP_MAXBYTES 0x8000 // 32K max, plenty for monochrome displays #define BITMAP_SCREEN_FORMAT 1 // used by Screen_To_Image, Simulated_Touch_To_Image // ************** SETUP ETHERNET TASK TO RUN WEB AND TUNNELING SERVICES ************** TASK ether_control_task; // 1 Kbyte per task area _Q void Ether_Task_Setup_Default( void ) // performs full initialization of the ether_info struct and mailboxes for the // specified EtherSmart modulenum, and // builds and activates an ethernet control task to service the xport { // NEXT_TASK = TASKBASE; // empties task loop; comment out if other tasks are allowed Ether_Task_Setup( ðer_control_task, E_MODULENUM); } _Q void WiFi_Task_Setup_Default( void ) // performs full initialization of the ether_info struct and mailboxes for the // specified WiFi modulenum, and // builds and activates an ethernet control task to service the xport { // NEXT_TASK = TASKBASE; // empties task loop; comment out if other tasks are allowed WiFi_Task_Setup( ðer_control_task, E_MODULENUM); } // ********************* URL STRINGS ************************** char* slash_url_str = "/"; // synonym for home page url char* index_url_str = "/index.html"; // home page url char* screen_image_str = "/screen_image.bmp"; // screen image url char* gui_response_str = "/gui_response.cgi"; // gui response url // *********************** WEBSERVER *************************** // the following is created using the Image Converter program which creates 2 constants: // GUI_RESPONSE_TEXT_HTML_XADDR // GUI_RESPONSE_TEXT_HTML_SIZE // <html><head><title>EtherSmart/GUI Remote Front Panel</title></head> // <body> // <H3>EtherSmart/GUI Remote Front Panel</H3><p> // <H4>Click on the screen image to operate the touchscreen remotely</H3><p><p> // <a href="/gui_response.cgi"><img src="/screen_image.bmp" ismap></a> // </body></html> // make sure to declare gui_response.cgi as Cache-Control: no-cache (dynamic content). // Notes: this works very nicely with Opera, the recommended browser. void Screen_Image_Response( int modulenum ) // handler for /screen_image.bmp url. serves the screen image. // assumes that Simulated_Touch_To_Image has run. // xbuffer contains 32-bit count (NOTE!) followed by image data. // marks as no-cache (always reloads). // NOTE: this function is NOT a gui handler; it should be posted by http_add_handler. { xaddr http_outbuf_base = HTTP_Outbuf(modulenum); uint http_outbuf_size = HTTP_Outbufsize(modulenum); uint image_size = FetchInt((xaddr) (BITMAP_BUFFER+2)); // get size of image we created uint http_header_size; HTTP_Put_Headers(http_outbuf_base, http_outbuf_size, TRUE, TRUE, HTTP_IMAGE_BITMAP_CONTENT); // params: xlbuf,maxbufsize,ok?,dynamic?,content_type // dynamic bitmap image content ->outbuf;header is done http_header_size = FetchInt(http_outbuf_base); // get size of http header we created HTTP_Send_Buffer(http_outbuf_base+2, http_header_size, modulenum); HTTP_Send_Buffer((xaddr)(BITMAP_BUFFER+4), image_size, modulenum); } // send http header and bitmap image // from types.h, used in GUI_Response to hold HTTP_Imagemap x,y results. // typedef union // { ulong int32; // struct // { int msInt; // int lsInt; // } twoNums; // } TWO_INTS; void GUI_Response( int modulenum ) // a clickable ismap version of the screen image that runs the gui toolkit simulated touch. // url = /gui_response.cgi // this routine is called via ether_check_gui which runs in the application task // that runs Service_GUI_Events. it is posted using http_gui_add_handler. { xaddr http_outbuf_base = HTTP_Outbuf(modulenum); uint http_outbuf_size = HTTP_Outbufsize(modulenum); uint http_header_size, x, y; TWO_INTS x_and_y; x_and_y = HTTP_Imagemap( modulenum); // get mouseclick x,y coordinates x = x_and_y.twoNums.msInt; // get x from most significant 16bits y = x_and_y.twoNums.lsInt; // get y from least significant 16bits Simulated_Touch_To_Image(BITMAP_BUFFER, BITMAP_MAXBYTES, BITMAP_SCREEN_FORMAT, x, y); HTTP_Put_Headers(http_outbuf_base, http_outbuf_size, TRUE, FALSE, HTTP_TEXT_HTML_CONTENT); // params: xlbuf,maxbufsize,ok?,dynamic?,content_type // dynamic bitmap image content ->outbuf;header is done http_header_size = FetchInt(http_outbuf_base); // get size of http header we created HTTP_GUI_Send_2Buffers(http_outbuf_base+2, http_header_size, GUI_RESPONSE_TEXT_HTML_XADDR, GUI_RESPONSE_TEXT_HTML_SIZE, modulenum); } // send http header and content _Q int Init_Screen_Image( void ) // if return value=0, image has been created { return Screen_To_Image((xaddr) BITMAP_BUFFER, BITMAP_MAXBYTES, BITMAP_SCREEN_FORMAT); } void Remote_Panel_Start( int modulenum ) // serves an initial clickable ismap version of the screen image. // url = /index.html // puts initial version of screen into bitmap_buffer. // this routine is called via ether_check_gui which runs in the application task // that runs Service_GUI_Events. it is posted using http_gui_add_handler { xaddr http_outbuf_base = HTTP_Outbuf(modulenum); uint http_outbuf_size = HTTP_Outbufsize(modulenum); int http_header_size; HTTP_Put_Headers(http_outbuf_base, http_outbuf_size, TRUE, FALSE, HTTP_TEXT_HTML_CONTENT); // params: xlbuf,maxbufsize,ok?,dynamic?,content_type // static html type->outbuf, cnt in first 2bytes; header's done Init_Screen_Image(); // ignore return value; image has been created http_header_size = FetchInt(http_outbuf_base); // get size of http header we created HTTP_GUI_Send_2Buffers(http_outbuf_base+2, http_header_size, GUI_RESPONSE_TEXT_HTML_XADDR, GUI_RESPONSE_TEXT_HTML_SIZE, modulenum); // params: xbuf1,cnt1,xbuf2,count2,modulenum } // send header&content, ignore numbytes_sent #ifdef __FABIUS__ #pragma option init=.doubleword // declare 32-bit function pointers in code area #include </mosaic/gui_tk/to_large.h> #endif // __FABIUS__ xaddr (*screen_image_response_ptr)(void) = Screen_Image_Response; xaddr (*gui_response_ptr)(void) = GUI_Response; xaddr (*remote_panel_start_ptr)(void) = Remote_Panel_Start; // home page #ifdef __FABIUS__ #include </mosaic/gui_tk/fr_large.h> #pragma option init=.init // return the initialized variable area to RAM; #endif // __FABIUS__ int Install_GUI_Web_Handlers( int modulenum ) // call this after ETHER_Task_Setup_DEFAULT point browser to raw ip or to // ip/index.html to see the home GUI web page = remote front panel. // urls are case sensitive. // any other url's serve out: page not found. // returns nonzero error if too many handlers were added // (limited by AUTOSERVE_DEFAULT_ROWS passed to ether_init) // Some of the gui web handlers in this example are handled by the application task. { int error = 0; // we'll OR error results together and return final result error |= HTTP_Add_GUI_Handler(STRING_XADDR(slash_url_str), strlen(slash_url_str), remote_panel_start_ptr, modulenum); error |= HTTP_Add_GUI_Handler(STRING_XADDR(index_url_str), strlen(index_url_str), remote_panel_start_ptr, modulenum); error |= HTTP_Add_Handler(STRING_XADDR(screen_image_str), strlen(screen_image_str), screen_image_response_ptr, modulenum); error |= HTTP_Add_GUI_Handler(STRING_XADDR(gui_response_str), strlen(gui_response_str), gui_response_ptr, modulenum); InitElapsedTime(); // start at zero so home page reports correct elapsed time return(error); } _Q void Ether_GUI_Web_Demo( void ) { Ether_Task_Setup_Default(); // init EtherSmart WC, start ethernet task Install_GUI_Web_Handlers(E_MODULENUM); // setup web; ignore error flag GUI_Demo(); // start the gui demo on local touchscreen } // NOTE: for QScreen, GUI_Demo MUST call Globalize_TVars(TVARS); _Q void WiFi_GUI_Web_Demo( void ) { WiFi_Task_Setup_Default(); // init WiFi WC, start ethernet task Install_GUI_Web_Handlers(E_MODULENUM); // setup web; ignore error flag GUI_Demo(); // start the gui demo on local touchscreen } // NOTE: for QScreen, GUI_Demo MUST call Globalize_TVars(TVARS); void main( void ) { // comment in the correct version for your wildcard: Ether_GUI_Web_Demo(); // WiFi_GUI_Web_Demo(); } // NOTES: place a call to Ether_Check_GUI(E_MODULENUM); in the application task // that invokes the GUI Routine // (for example, after the call to Service_GUI_Events on a QVGA Controller system). // Add a call to Screen_Has_Changed(); in each GUI handler that changes screen appearance. // QScreen Controllers require a call to Globalize_TVars(TVARS); in the init function. // When building tasks, do NOT include the statement NEXT_TASK = TASKBASE; // because we want to allow multiple tasks to be built. // Type WARM or COLD before re-running the program.
The EtherSmart Wildcard is based on the Lantronix Xport Ethernet device server, and the WiFi Wildcard is based on the Lantronix WiPort wireless device server. Software examples coded in C or Forth let you implement a remote clickable front panel, send emails from the instrument, serve out static and dynamic web pages to your PC-based browser, and perform serial data exchanges with peripheral devices (known as "Serial Tunneling"). These tiny 2" by 2.5" boards are members of the Wildcard™ series that connects to Mosaic's embedded computers to implement web-enabled instrumentation and automation functions.
See also → Forth Remote Front Panel Demo for QScreen / QVGA Controller