Home : Course Map : Chapter 24 :
SNAP Processor Demo: Web Server
JavaTech
Course Map
Chapter 24

IntroEmbeddedJava
In Eng. & Sci
J2ME Overview
Real Time Java
Java Hardware
  Chips
  Cores
  Boards
Javelin Stamp
Javelin Programs
  
   Demo 1
   Listing
   Demo 2  
   Demo 3  

SNAP
   Demo 2
 
Performance
Embed Apps
Exercises

     About JavaTech
     Codes List
     Exercises
     Feedback
     References
     Resources
     Tips
     Topic Index
     Course Guide
     What's New

We have frequently referred to the benefits of custom client/server programs for embedded processors. Here we finally install a basic Web server in an embedded processor. In this case we use the SNAP board. The server can send web files as before but it can also present voltage readings taken from an analog-to-digital converter (ADC) on the board. The previous page describes the basics of programming the SNAP.

The program SnapAdcServer is quite similar to the MicroServer program described in Chapter 14, Tthe clients connect to the server via a socket provided by a ServerSocket. Each client is passed to an instance of a Worker class, which provides the client with a reading of a voltage in a HTML web page format.

Since the String class did not include the split() method that we used to parse the string messages in the Worker class for the MicroServer demo discussed in Chapter 14, we created our own simple split() method to carry out the parsing.

To obtain the ADC value the program uses the DataPort class in the com.dalsemi.system package. The system bus is mapped to memory so that by specifying a memory address a particular device can be accessed. This code in this Worker class uses:

DataPort p0 = new DataPort(0x380001);
// read ADC
int adcValue = p0.read();

This first creates the DataPort object for the address specified in the constructor and then reads the ADC value. The program combines the data reading with a hypertext header and footer code to create an HTML file with the data.

Another difference withthe Worker for the MicroServer is that the SNAP I/O package does not include the PrintWriter class so we use PrintStream instead. We flush the stream after each set of print methods to insure all data is moved from the internal buffers. We note that, like PrintWriter, the PrintStream methods don't throw IOException and instead the class offers the checkError() method, which returns true if an IOException occurred.

As we discussed in Chapter 14, you could modify this code to check for errors after every print invocation or put the print statements into utility methods that throw IOException as we did with the DataWorker class discussed in Chapter 15.

SnapAdcServer

import java.net.*;
import java.io.*;
import java.util.*;
import com.dalsemi.system.*;

/** Modified Version of MicroServer for the Imsys SNAP system. **/
public class SnapAdcServer {

  /** Start program with optional port number argument. **/
  public static void main (String argv[]) throws IOException {

    int port; // port number

    // Get the port number from the command line.
    try {
      port = Integer.parseInt(argv[0]);
    }
    catch (Exception e) {
      port = 2223; // Default
      System.out.println ("Use default port = 2223");
    }

    // Create a ServerSocket object to watch that port for clients
    ServerSocket server_socket = new ServerSocket (port);
    System.out.println ("Server started");

    // Loop indefinitely while waiting for clients to connect
    while (true) {

      // accept() does not return until a client requests a connection
      Socket client_socket = server_socket.accept ();

      // Now that a client has arrived, create an instance of our
      // Worker thread subclass to tend to it.
      Worker worker = new Worker (client_socket);
      worker.start ();
      System.out.println ("New client connected");
    }
  } // main
} // class SnapAdcServer

Worker

import java.net.*;
import java.io.*;
import java.util.*;
import com.dalsemi.system.*;

/** Threaded process to serve the client connected to the socket.**/
class Worker extends Thread {

  Socket fClient = null;

  String fWebPageTop =
   "<html>  <head> \n <TITLE>Solar Panel Voltage - ADC Readout</TITLE> 
   
 \n </HEAD>";

  String fWebPageBot = "</body> \n </html>";

  /** Pass the socket as a argument to the constructor **/
  Worker (Socket client) throws SocketException {
    fClient = client;

    // Set the thread priority down so that the ServerSocket
    // will be responsive to new clients.
    setPriority (NORM_PRIORITY - 1);
  } // ctor

  /**
    *  This thread receives a message from the client that will
    *  request ADC.html with voltage data or a standard web page file.
    *  The ADC information is obtained via the SNAP DataPort.
    *  The web page files are found relative to the directory location
    *  of this code.
   **/
  public void run () {
    boolean read_adc = false;
    try {

      BufferedReader client_in = new BufferedReader (
        new InputStreamReader (fClient.getInputStream()) );

      // Now get an output stream to the client.
      OutputStream client_out = fClient.getOutputStream ();

      // Use PrintStream for SNAP output
      PrintStream pw_client_out = new PrintStream (client_out);

      // First read the message from the client
      String client_str = client_in.readLine ();
      System.out.println ("Client message: " + client_str);

      // Split the message into substrings.
      String [] tokens = split (client_str);

      // Check that the message has a minimun number of words
      // and that the first word is the GET command.
      if ((tokens.length >= 2) &&
           tokens[0].equals ("GET")) {
         String file_name = tokens[1];

        // Ignore the leading "/" on the file name.
        if (file_name.startsWith ("/"))
            file_name = file_name.substring (1);

        // If no file name is there, use index.html default.
        if (file_name.endsWith ("/") || file_name.equals (""))
            file_name = file_name + "index.html";

        // Check for a request for the ADC reading.
        if (file_name.endsWith ("adc.html")) read_adc = true;

        // Check if the file is hypertext or plain text
        String content_type;
        if (file_name.endsWith (".html") ||
            file_name.endsWith (".htm")) {
              content_type = "text/html";
        }
        else {
           content_type = "text/plain";
        }

        // Now either read a file from the disk and write it to the
        // output stream to the client or send the ADC reading if that
        // is requested
        try {
          // Send the header.
          pw_client_out.print ("HTTP/1.0 200 OK\r\n");

          if (read_adc){
              pw_client_out.print ("Server: ReadADC 1.0\r\n");
              pw_client_out.print ("Content-length: " + 500 + "\r\n");
              pw_client_out.print ("Content-type: "
                                   + content_type + "\r\n\r\n");
              pw_client_out.print (fWebPageTop);
              // Connect to ADC.
              DataPort p0 = new DataPort (0x380001);//DataPort.CE3);
              // read ADC
              int adc_value = p0.read ();
              pw_client_out.println ("ADC = " + adc_value);
              pw_client_out.println (fWebPageBot );
              pw_client_out.flush ();

          }
         
else { // Or just send a requested file

              // Open a stream to the file. Remember that by this point
              // all the text except for the file name has been stripped
              // from the "request" string.
              FileInputStream file_in = new FileInputStream  (file_name);

              // Send the header.

              File file = new File (file_name);
              Date date = new Date (file.lastModified ());
              pw_client_out.print ("Date: " + date + "\r\n");
              pw_client_out.print ("Server: MicroServer 1.0\r\n");
              pw_client_out.print ("Content-length: "
                                   + file_in.available () + "\r\n");
              pw_client_out.print ("Content-type: "
                                   + content_type + "\r\n\r\n");
              pw_client_out.flush (); // For PrintStream with SNAP


              // Creat a byte array to hold the file.
              byte [] data = new byte [file_in.available ()];

              file_in.read (data);     // Read file into the byte array
              client_out.write (data); // Write it to client output stream
              client_out.flush ();     // Remember to flush output buffer
              file_in.close ();        // Close file input stream

          }
        }
        catch(IllegalAddressException err) {
          // If no such file, then send the famous 404 message.
          pw_client_out.println (
             "ADC readout failure - Illegal Address Exception" );
          pw_client_out.println( fWebPageBot );
          pw_client_out.flush ();// For PrintStream with SNAP

        }
        catch (FileNotFoundException e) {
          // If no such file, then send the famous 404 message.
          pw_client_out.println ("404 Object Not Found" );
          pw_client_out.flush (); // For PrintStream with SNAP
        }

      } else {
        pw_client_out.println ("400 Bad Request");
        pw_client_out.flush (); // For PrintStream with SNAP
      }
    }
    catch (IOException e) {
      System.out.println ( "I/O error " + e );
    }

    // Close client socket.
    try {
      fClient.close ();
    }
    catch (IOException e) {
      System.out.println ("I/O error " + e );
    }

  } // run


  /**
    * Since the platform may not include the J2SE 1.4 String class with
    * the split() method, we provide a substitute. This method returns an
    * array with the tokens in the string parameter that are separated by
    * blank spaces.
   **/
  String [] split(String source_string) {

    // First get rid of whitespace at start and end of the string
    String string = source_string.trim();
    // If string contains no tokens, return a zero length array.
    if( string.length () == 0) return (new String [0]);

    // Use a Vector to collect the unknown number of tokens.
    Vector token_vector = new Vector();
    String token;
    int index_a = 0;
    int index_b = 0;

    // Then scan through the string for the tokens.
    while(true){
      index_b = string.indexOf (' ', index_a);
        if (index_b == -1) {
            token = string.substring (index_a);
            token_vector.addElement (token);
            break;
        }
        token = string.substring (index_a, index_b);
        token.trim ();
        if (token.length () >= 1)
            token_vector.addElement (token);
        index_a = index_b + 1;
      }

    // Copy elements into a string array.
    String [] str_array = new String[token_vector.size()];
    for( int i = 0; i < str_array.length; i++)
         str_array[i] = (String) (token_vector.elementAt(i));
    return str_array;

  } // split

}// class Worker

 

 

 

References and Web Resources

 

 

Latest update: Dec. 15, 2004

  
  Part I Part II Part III
Java Core 1  2  3  4  5  6  7  8  9  10  11  12 13 14 15 16 17
18 19 20
21
22 23 24
Supplements

1  2  3  4  5  6  7  8  9  10  11  12

Tech 1  2  3  4  5  6  7  8  9  10  11  12
Physics 1  2  3  4  5  6  7  8  9  10  11  12

Java is a trademark of Sun Microsystems, Inc.