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
|