One of the most basic needs is to provide status information back to the user of your web application. The HTTP server provides for this using dynamic variable substitution callbacks. These commands in your HTML code will alert the server to execute a callback function at that point, which the developer creates to write data into the web page. Dynamic Variables should be considered the output of your application.
To create a dynamic variable, simply enclose the name of the variable inside a pair of tilde (~) characters within the web pages' HTML source code. (ex: ~myVariable~) When you run the MPFS2 Utility to generate the web pages, it will automatically index these variables in HTTPPrint.h. This index will instruct your application to invoke the function HTTPPrint_myVariable when this string is encountered.
Here is an example of using a dynamic variable to insert the build date of your application into the web pages:
<div class="examplebox code">~builddate~</div>
The associated callback will print the value into the web page:
void HTTPPrint_builddate(void) { TCPPutROMString(sktHTTP,(ROM void*)__DATE__); }
You can also pass parameters to dynamic variables by placing numeric values inside of parenthesis after the variable name. For example, ~led(2)~ will print the value of the second LED. The numeric values are passed as WORD values to your callback function. You can pass as many parameters as you wish to these functions, and if your C code has constants defined, those will be parsed as well. (ex: ~pair(3,TRUE)~)
The following code inserts the value of the push buttons into the web page, all using the same callback function:
<div class="examplebox code">btn(3)~ btn(2)~ btn(1)~ btn(0)~</div>
This associated callback will print the value of the requested button to the web page:
void HTTPPrint_btn(WORD num) { // Determine which button switch(num) { case 0: num = BUTTON0_IO; break; case 1: num = BUTTON1_IO; break; case 2: num = BUTTON2_IO; break; case 3: num = BUTTON3_IO; break; default: num = 0; } // Print the output if(num == 1) TCPPutROMString(sktHTTP, "up"); else TCPPutROMString(sktHTTP, "down"); }
The HTTP protocol operates in a fixed memory buffer for transmission, so not all data can be sent at once. Care must be taken inside of your callback function to avoid overrunning this buffer.
The HTTP2 web server verifies that at least 16 bytes are free in this buffer before invoking a callback. For short outputs (less than 16 bytes), callbacks need only to call the appropriate TCPPut function and return. For longer outputs, callback functions must check how much space is available, write up to that many bytes, then return. The callback will be invoked again when more space is free.
To manage the output state, callbacks should make use of curHTTP.callbackPos. This DWORD value is set to zero when a callback is first invoked. If a callback is only writing part of its output, it should set this field to a non-zero value to indicate that it should be called again when more space is available. This value will be available to the callback during the next call, which allows the function to resume output where it left off. A common use is to store the number of bytes written, or remaining to be written, in this field. Once the callback is finished writing its output, it must set curHTTP.callbackPos back to zero in order to indicate completion.
As an example, this code outputs the current value of the LCD display, which is 32 bytes on many Microchip development boards:
<div class="examplebox code">~lcdtext~</div>
The following callback function handles the output, and manages its state for multiple calls:
void HTTPPrint_lcdtext(void) { WORD len; // Determine how many bytes we can write len = TCPIsPutReady(sktHTTP); // If just starting, set callbackPos if(curHTTP.callbackPos == 0) curHTTP.callbackPos = 32; // Write a byte at a time while we still can // It may take up to 12 bytes to write a character // (spaces and newlines are longer) while(len > 12 && curHTTP.callbackPos) { // After 16 bytes write a newline if(curHTTP.callbackPos == 16) len -= TCPPutROMString(sktHTTP, (ROM BYTE*)"<br />"); if(LCDText[32-curHTTP.callbackPos] == ' ' || LCDText[32-curHTTP.callbackPos] == '\0') len -= TCPPutROMString(sktHTTP, (ROM BYTE*)" "); else len -= TCPPut(sktHTTP, LCDText[32-curHTTP.callbackPos]); curHTTP.callbackPos--; } }
The initial call to TCPIsPutReady determines how many bytes can be written to the buffer right now. The TCPPut functions all return the number of bytes written, so we can subtract that value from len to track how much buffer space is left. When buffer space is exhausted, the function exits and waits to be called again. For subsequent calls, the value of curHTTP.callbackPos is exactly as we left it. The function resumes its output at that point.
Often it is useful to include the entire contents of another file in your output. Most web pages have at least some portion that does not change, such as the header, menu of links, and footer. These sections can be abstracted out into separate files which makes them easier to manage and conserves storage space.
To include the entire contents of another file, use a dynamic variable that starts with "inc:", such as ~inc:header.inc~. This sequence will cause the file header.inc to be read from the file system and inserted at this location.
The following example indicates how to include a standard menu bar section into every page:
<div id="menu">~inc:menu.inc~</div>
At this time, dynamic variables are not recursive, so any variables located inside files included in this manner are not parsed.