Basic Developments and Applications - Web Server
Porting a Web Server Running under VxWorks to PPC403GCX
Summary Compiled by Conor M. Brady
This document is a subset of a document written detailing a design project done at Texas A&M. The original project’s aim was to develop a web-based diagnosis program using a 403EVB. During the course of the project, it was discovered that the most efficient way to do this was using a web server on-board the 403EVB. This document contains relevant information about how the web server was implemented on the 403EVB.
One of the more important technical aspects of our project was getting the VxWorks operating system to function on our board. By reading the VxWorks Programmer’s Guide we found that unlike operating systems that we have used in the past, VxWorks and its applications are really only one piece of executable code. Figure 1 below shows the build process graphically.
When choosing project options at the start of our project, we chose to make a project of type "bootable VxWorks image." We also picked the correct BSP to base our project off of in the "Project Options" screen. By choosing these, we set options in the makefile that directed the compiler, linker, and Board Service Pack (BSP) to create one large piece of binary code at the conclusion of the build process that contained both the operating system and the application code in a format compatible with our board. We found out that is was imperative that the project be based off of the correct BSP, or the compiler would generate code for the wrong type of processor. We also discovered during the installation of the BSPs that you needed to use the correct CD key (in our case the key for the 403EVB BSP) or the installer would copy the wrong BSP code and your project would not build correctly.
Tornado, the development environment, created a group of header files and some source code that defined how VxWorks operates. Our job then was to create the applications that we wanted in our own source files and make a call to our controlling function as soon as the operating system finishes initializing. You can see in the appendices the source code that accomplishes this task. In the usrAppInit.c file you see some sample code for showing display on the console. In the final project, this was replaced with a function call to our web server application code. This is the way most real time operating systems are built because should a reset occur, all of the application code will resume running in a known state.
One other thing that we discovered in our research was how VxWorks and its accompanied applications are loaded onto the board at system start. Figure 2 below shows the format that the VxWorks image has when loaded into the ROM Monitor. At system start, the board checks the memory addressed by the ROM Monitor, notices that there is a new image there, and begins to execute the code in that image. The code’s first instructions are to copy itself into RAM at a specified address and begin running. There is also an option in Tornado to build a compressed ROM image, in which case there is uncompressed code built into the image to uncompress the code.
The values for LOCAL_MEM_LOCAL_ADRS, RAM_LOW_ADRS, and ROM_TEXT_ADRS are defined in Tornado when the code is generated and can be seen by right clicking on the build you are interested in and selecting the "Data" tab.
During the course of our hardware testing, we discovered that our boot parameters were not properly loading the driver for the Ethernet port. To fix this, we had to add the nicEvb component to our project. There are many other pre-packaged components that come with VxWorks, but the procedure for adding one is the same for all components.
To add a component to you project, open the project tree in the VxWorks tab of the Project Manager in Tornado. Locate the component you want to add in the appropriate object tree and right click on the name of the component. On the popup menu, choose the "Include" option. This will add a line to your makefile that will include the features of this component into your project.
Soon after discussing our project with the medical doctor who came to visit our group, we decided that our project needed a rich interface. Many other groups choose to use LCD displays of various dimensions, but our group thought that in order to be useful in an emergency, our method of displaying data had to be very clear to the user. To accomplish this, we decided to use HTML based content to display the results of our diagnosis. This would allow us to easily display text in various colors, as well as graphics.
We found that the most appropriate way to display HTML based content would be to use a web server. While Conor searched for a somewhat compatible implementation to port to our board, Brad, Kevin, and Brian worked on developing the content that eventually was served from the board. They used the Chef web server to prototype a diagnosis engine.
After examining several different options for a web server, Conor decided on the GoAhead web server, made by the GoAhead corporation. GoAhead is an open-source web server implementation that was designed particularly for embedded systems. The server had many ports available, including one to VxWorks. After a quick attempt, Conor discovered that using the web server was not going to be that easy. All of the code was written for other versions of the PowerPC, and he would need to port the code to the 403EVB.
The default implementation for the GoAhead web server included many things that larger web servers use today. Most of the features are not compatible with VxWorks though, and had to be commented out in order to work. The most important feature that had to be edited was SSL support.
SSL is a secure web server add-on that many web servers use to handle encrypted or secure data. Due to board limitations, we could not use it. Conor spent a considerable amount of time searching through the code commenting out pieces of unusable code, as well as re-writing pieces so that were intermingled with the old code.
Once the base code was ported, we had to write a main function that started the web server when the board was booted. VxWorks bootable images have a function defined named usrAppInit() that developers can use to call their own functions at boot time. Since all we were going to be doing with the board would be running the web server, we simply called the websvxmain() function supplied in the GoAhead distribution. For clarification, please see the main.c file attached in the appendix.
One other challenge during development was fixing the errors that Tornado introduced into our project. The development environment would scan source code files and calculate dependencies based on what #include statements it found. The only problem with this though is that the code that we ported had a lot of blocks of code marked with #define directives that the compiler interpreted according to which operating system the web server is being compiled for. Tornado would then modify our makefile and not allow us to compile the web server because of invalid references. We would then need to manually modify the makefile to exclude these invalid dependencies. This occurred several times during the course of development, and was a major pain in the neck. We eventually deleted all invalid #include entries in the source files as part of our port.
After reading the documentation, we found that GoAhead also supports a proprietary format called GoForms. GoForms are simply web pages defined as C functions in ordinary program code, as defined in the GoAhead documentation included electronically with this report. The are also extra routines that allow for fetching of web parameters from forms and from the query string. To implement a GoForm, there are two steps that you need to take. The first step is to write a C function to handle your form. The function MUST comply with the following prototype:
void mypage( webs_t wp, char_t *path, char_t *query)
Next, call the websFormDefine function in your main program to register your GoForm:
Now, whenever a user accesses your web server and uses the extension "/goform/mypage" they will get the output of your function.
GoForms allowed us a great deal of flexibility and power in developing the MARAPP software. In addition to that software, we compiled and loaded all of the documentation pages for GoAhead onto our board. The electronic version of this paper includes all of the source code and web pages.
The most visible aspect of our project is the HTML content that gets displayed. In many embedded systems, a structured file system is available for use, which makes publishing content as easy as copying a file to a disk. VxWorks does offer components that allow you to use a structured file system, but in our project, there was no way to include a hard disk on our board.
The alternative we found is to include web page content in with program content. The GoAhead server has a group of functions that will read content from pre-defined arrays of integer values that automatically get called when certain compiler directives are set. Values in these arrays represent ASCII characters that would appear in a normal HTML file or graphics file. GoAhead comes with a source file named webcomp.c that when compiled on its own, creates a web-page compiler that produces a C file containing these arrays and other needed data.
Once the webcomp executable was built on our development machine, we made a text file containing the names of all of the content files that we wanted to include on the web server. After that, we ran the compiler indicating with the –f option our file list:
webcomp –f filelist > webpages.c
The webpages.c file then contained all of the necessary data, and we included it in the project with the rest of the C files. By defining the compiler directive WEBS_PAGE_ROM in the file webs.c, we let the compiler know to include function calls to access the data structures in webpages.c like normal files would be accessed.
The diagnosis program has several steps:
The diagnosis program will first receive a symptom string. Each symptom corresponds with an ASCII value. Thus we can represent each symptom with one character. Each disease also corresponds with an ASCII character. We can then easily read in a string of symptoms and a disease. We perform calculations on the strings to decide whether they match or not. We then open a text file that contains all diseases’ treatments and severity. After reading and formatting the treatments, we display them in the browser. The program then waits for a new symptom string to be received.
The algorithm we use is simple. For every symptom that the disease matches with the patient, one point is added. For every symptom that the disease has that the patient does not have, one pint is deducted. We then take the point value and compare it with the length of the patient’s symptom string. If the disease count is greater than half the length of the patient count, the disease has at least low probability. If the disease count is greater than or equal to 75% of the patient count or one less than the patient count, whichever is less, then the disease has high probability. Although this algorithm is simple, we could make it better with more time. We will discuss this more in our "room for improvement" section.
We chose the IBM PowerPC 403 Evaluation Board (403EVB) as the platform for our product. The 403EVB is a prefabricated circuit board with all the common components of an embedded system. IBM sells this board primarily to customers who are considering the capabilities of their PowerPC chips. It worked well for us though because we did not have to worry about implementing various pieces of the embedded system on our own. Instead, we concentrated on creating a quality product.
A block diagram of the 403EVB is below.
One of the advantages that this board had was a ready-to-use Ethernet jack. Previous groups have had difficulty with their projects because traditional serial-line communication is rather slow for transferring large files. We were able to cut our development time significantly by using the 10Base2 Ethernet connection for transferring our boot image.
The 403EVB came preloaded with 4MB of RAM, and we upgraded it to 8MB. The bootable VxWorks image for the board was only a few hundred kilobytes, and the addition of the extra memory allowed us to serve a lot more content from our board at the end of the project.
Our original plan was to use both serial ports as interfaces to medical equipment, but as the semester went on, we found that a lot of medical instruments come as PCMCIA cards. Kevin did some research and found that there was no way to interface a PCMCIA bus with our board, so with Dr. Mahapatra’s permission, we concentrated more on making the board work and developing a solid framework for a medical appliance. The idea here was that the hardware interface was only a small part of our project, and future groups could concentrate on making our implementation work on a more robust platform.
The hardware that we used in this project had two distinct configurations. We used one configuration for development purposes, and then for testing and release we switched to a second, more streamlined connection. Both configurations are shown in the figures below. Each layout consists of three basic components, which perform the following functions:
In the Release configuration, our setup becomes very simple. A Host PC is used as a "dumb terminal" for a web browser. The Host PC is connected to the target board by a standard Ethernet bus and can view all of the application software. The other connections to the ROM Monitor and HyperTerminal are not needed. This frees up both serial ports on the target board to be used as data inputs from attached medical instruments. To access the applications on the board when in Release mode, the web browser would simply be supplied with the board’s IP address, which is assigned to the board at setup-time. The software that we design on the board would then reply to the request with the proper graphical interface based on what state the user was in.
During the debug phase of our project, we discovered that even though our BSP had been included in the project correctly, support for the Ethernet port was left out. After some research we discovered that there was a component for the Ethernet port on the board that needed to be included in the build. Using the procedures outlined before, we added the nicEvb VxWorks component to our project. We were notified that it also depended on some other TCP/IP related components, and we agreed to include them as well. Both of these components were found under the "network devices" tree branch.
Beyond including support for the actual Ethernet port, we also needed to supply proper boot parameters to the board. That way on startup, our board would function correctly. The procedure for making a boot parameter file is included in the next section.
Perhaps the most tedious part of the project is creating the boot parameter file. Boot parameters are supplied to the board right after the "run" command is issued to set it in a known state before executing any code. In our case the only boot parameters that we were interested in were those that dealt with the initialization of our Ethernet port.
Looking though the VxWorks networking manual, we found out what a proper boot parameter line looks like. We decided that ours needed to be:
nicEvb(0,0)host:c:\projects\marapp\default\vxworks h=18.104.22.168 e=22.214.171.124
The nicEvb(0,0) parameter informs the board which device driver to use for the Ethernet port. Since we aren’t supplying any special parameters to the device driver we leave (0,0) in the boot parameter line. The next argument, host, is given so that the board can correctly map the source object in a target server environment. We weren’t using the target server, but put the line there for good measure in case we ever did. The last two parameters are the host and the Ethernet port IP addresses. The host IP address is the IP address of the card on the host PC where the image comes from. The Ethernet port IP address is the IP address that the Ethernet port on the board will be set to.
Once we had the boot parameter line defined, we needed to load it into memory. After some more research, we found that on our board, boot parameters needed to be placed at address 0x1400. Using RISCWatch we could manually place ASCII values in memory locations, but we decided to take advantage of the scripting offered by RISCWatch. We defined a command file as follows:
writ 0x1400 0xXXXXXXXX
writ 0x1404 0xYYYYYYYY
Here the XXs and YYs represent the ASCII values of each character in the boot line. As mentioned before, encoding this boot line is very tedious, but since we placed it in a command file, we were able to quickly run it every time we uploaded our image to the board. To run a command file once it is created, type the following command into RISCWatch:
exec "<path of command file>"
The entire loading process for the VxWorks image is discussed in the next section.
To get your image from the host computer to your target board, you have to use the RISCWatch probe. The target server feature of Tornado is not compatible with the 403EVB so you have to transfer the whole image at once instead of being able to request additional code as needed. The RISCWatch probe is the most efficient way to do this. The transfer process is as follows:
srchpath set <project path>
Where project path is the directory on the host machine where the complied VxWorks bootable image is saved.
load file vxworks t=0x10000
The option t=0x10000 tells the board where your image should reside in ROM.
The default for this value is hex 10000 but your should check your build
configuration in Tornado to be sure.
exec "<command file path>"
The biggest problem that we faced was errors in the VxWorks operating system and the Tornado integrated development environment. During the course of our project we found a few errors that were simply bizarre. For example, code in if statements would compile fine, but crash the server. If the developer entered blank lines between the braces in the if statements using the same code, everything worked fine. We also had an issue with data corruption when returning pointers of non-standard types. We implemented a linked list and while debugging we saw values being assigned correctly to pointers, but when the function ended the pointer was trashed. This was very frustrating and to get around this we had to implement long functions with no pointer manipulation externally.
The only reason that we came up with that these problems would occur is that the BSP is somehow generating bogus code for our board. It would be worth the while to follow up with WindRiver on what bugs are present in the BSP and what they are doing to fix them. Future groups should consider this.
Our hardware worked very well. The only implementation issue that we had was with a lack of memory. We wanted more memory initially so that we could server richer content in our application code, but we were only able to get 8MB total. This was fine for our purposes because we were merely implanting a framework for a real appliance, but in the future more features will require more memory.
Appendix – User’s Guide For Original Project
Scope:This supplement covers how to update, compile, load, and run a new VxWorks image on the project board.
webcomp –f filelist > webpages.c
srchpath set c:\projects\marapp\default
load file vxworks t=0x10000
The type of application can differ based on what you have modified, but in our code, the following sequence will take you through a normal situation.
The following outlines what to do in an emergency situation
The following outlines what to do for a simple diagnosis
The following outlines what to do for a simple diagnosis