Introduction
If you own a wireless router or set-top box, you probably know about the W.A.P. (web admin page) used to configure it.
Besides embedded systems, web interfaces also come in handy for server applications (such as auto-builders) where you want more security than VNC, dynamically generated forms that look good, and debug tools for real-time simulation like games. Adding an HTTP server to your application means you can control it with a web browser through a network connection.
Form Design
The way I usually organize my web interface is with a navigation sidebar on the left and a form on the right. The form is a simple table with label and input columns.
Game designers want instant feedback so I use onclick
and onchange
to auto-submit certain forms. Each form is a collection of inputs that are related, such as "Debug" or "Camera".
Using the Code
Adding an input in the code is brief, so it can be removed later before shipping. The input is named by the form and label. Lambda expressions are used to get and set the value.
string name = "david";
bool showStats = false;
int choice = 2;
int fun = 50;
new WebConfig.InputText("debug/name", () => name, (val) => name = val);
new WebConfig.InputBool("debug/show stats", () => showStats,
(val) => showStats = val);
new WebConfig.InputSelect("debug/choose", () => choice,
(val) => choice = val).SetOptions("now", "later", "never");
new WebConfig.InputSliderInt("debug/fun", () => fun, (val) => { fun = val; });
new WebConfig.InputButton("debug/Capture Screen", (val) => CaptureScreen());
new WebConfig.InputLink("debug/View Screen", "Screen.JPG");
int numRequested = 10;
int BallRadius = 10;
float BallSpeed = 1;
new WebConfig.InputSliderInt("game/Number of Balls",
() => numRequested, (val) => { numRequested = val; StartAnimation(); });
new WebConfig.InputSliderInt("game/Ball Radius",
() => BallRadius, (val) => { BallRadius = val; }).SetRange(0, 20, 0);
new WebConfig.InputSliderFloat("game/Speed Factor",
() => BallSpeed, (val) => { BallSpeed = val; }).SetRange(0.1f, 2, 1);
bool showPos = false;
int choice = 1;
new WebConfig.InputBool("game/show pos", () => showPos, (val) => showPos = val);
new WebConfig.InputSelect("game/choose", () => choice,
(val) => choice = val).SetOptions("now", "later", "never");
Vec3 BallColor = new Vec3(0, 1, 0);
new WebConfig.InputSliderFloat("game/Color.Red",
() => BallColor.x, (val) => { BallColor.x = val; }).SetRange(0, 1, 1);
new WebConfig.InputSliderFloat("game/Color.Green",
() => BallColor.y, (val) => { BallColor.y = val; }).SetRange(0, 1, 1);
new WebConfig.InputSliderFloat("game/Color.Blue",
() => BallColor.z, (val) => { BallColor.z = val; }).SetRange(0, 1, 1);
Sliders can be int
or float
with decimal places, forms can be set to auto-save and auto-submit, and buttons and links can be used to perform actions and show resource files.
Sample Application
To demonstrate WebConfig, I used a bouncing ball simulation. WebConfig inputs configure various simulation parameters in real-time. Change the number of balls and see the animation change accordingly.
Going Forward
Embedded systems are normally written in C++. I leave the port to the reader. The port is straightforward, if not trivial. I avoided threads and heavy reliance on .NET interfaces.
A useful feature for embedded systems and server applications would be a secure password form.
Compatibility
I tested on Firefox 3.0 and IE 8.0; notice they look a little different.
Credits
It would have taken a lot longer to write this article without: