Guide to Running Tynamo™ from Flash

It is possible to use the Tynamo™ server as the main user application in flash, replacing Slush. This is one of several ways of increasing the reliability of your TINI server.

This guide discusses the procedures for placing the Tynamo™ server into flash, but does not discuss techniques for including additional material, such as web pages, images, or other files. Please contact us if you would like more information on this subject.

It is emphasized that this guide discusses only one of many ways flash can be utilized for your application. For example, Slush can still be included in addition to your own program code. There are many alternative possibilities.

Limitation of this Guide

Because this guide does not discuss how to include static files, the steps presented here require that your server relies only on servlets for its content.


There are four sections:

  1. Application Entry Point,
  2. Build Configuration,
  3. Discussion, and
  4. Additional Suggestions

And one appendix:

  1. Startup.java Source

Application Entry Point

First, your server will need a class that serves as the main entry point to the application since Slush is no longer present. Appendix A lists source code for a sample main class that can be used as a starting point for your own custom setup.

Save this in your source path as Startup.java. For example, if you keep your source in a directory named src/ in your project directory, then save this file as src/Startup.java.

[Top]


Build Configuration

Add Startup.java to your src.files setting in build.properties, and make sure its parent location is added to the src.paths list. For example, if your source is located in the src/ directory, then make sure src is in src.paths. In other words, add this source file to your build in the usual manner.

Next, make these changes to build.xml:

  • Change the value of the tini.useFlashFormat property to "yes",
  • Change webserver.mainClass to "Startup", and
  • Change webserver.outputFile to "webserver.tbin".

– If you are running a '390-based TINI system and if you have enough flash to hold the generated TBIN file, then change tini.useTargetAddress to "0x70100" as well.

You may wish to copy the build.xml file to your project directory before making any changes, as outlined in step three of the Decoupling Your Project guide.

Build the server as usual, and a webserver.tbin file that is suitable for uploading to your TINI instead of Slush will be created in the current directory. This is the only file needed for the webserver.

[Top]


Discussion

This section explains some of the ideas presented here in more detail.

Other Solutions

It was mentioned briefly at the beginning of this document that this guide discusses only one of many ways to utilize flash for your application.

For instance, the "main" code presented here performs some simple system initialization, stores a few important configuration files, and then starts the server. The system initialization could be skipped, and Slush could be started after the server is started. Then, the benefits of Slush can be utilized.

The important thing to note is that you are not restricted by the approach presented here. In other words, "Decide what you need, and then put it there." There is a range of options.

Source Code

The Startup.java code deserves some explanation. It is divided into three parts that:

  1. Initialize the system,
  2. Store files into the filesystem, and
  3. Start the webserver.

The system initialization code first sets the default streams to the serial port in order for you to see what happens when the system starts. For example, when JavaKit is used, you will be able to see startup messages. The same thing is done at startup in Slush:

if (TINIOS.isConsoleOutputEnabled()) {
    com.dalsemi.system.Debug.setDefaultStreams("serial0", 115200);
}

Then, the filesystem is set so that each reboot will cause everything to start from a clean slate. This can improve performance at runtime since the system doesn't have to perform certain consistency checks:

TINIOS.disablePowerFailRecovery();
TINIOS.blastHeapOnReboot(TINIOS.BLAST_ALL);

Finally, the network parameters are set. Be sure to set these to your own values.

After this, files needed by the webserver are stored in the filesystem with the call to storeFiles(). Remember that we have set the system up so that it starts from a clean slate every time it reboots, so the files must be restored each time as well. Please consult the Suggestions section for a few more ideas on how to store files in flash.

The webserver is then started by setting up the mail handler (whose most likely use is for mailing the log files), then reading the configuration file, and finally starting the webserver thread. Some comments are included that explain how to shut down the server with a call to shutdown().

The Build Script

There are a few modifications to be made inside the build.xml script. These tell the build process to write out a file suitable for uploading with JavaKit, and to use the new Startup class for the main entry point instead of the usual com.qindesign.tini.http.Main class.

Because we are replacing slush, some of the work done to initialize the system has to be done ourselves. Replacing the webserver.mainClass property tells the TINIConvertor program to set this as the main entry point when the system is started.

[Top]


Additional Suggestions

This section presents some additional ideas on how to store files in an alternative way, such that they are available at startup.

Store Files as Strings

It is possible to store all files as string data in fields in a class. The plain text files could stay as they are, and the binary files could be Base64 encoded.

The disadvantages to this approach include a slightly longer startup time, and classfile size limitations. The startup time would be affected because each string would have to be extracted and written to a file. The size limitations in TINI are currently 32k for converted classfiles and 64k for arrays. This would limit the data that can be stored per class, although this limitation could probably be worked around with a more elaborate file extraction mechanism.

Store Files in Flash

It is possible to store arbitrary data in flash using either a native TLIB library or a raw TBIN file. Both of these approaches require you to devise a storage scheme for the files and a way to access the flash memory.

The TLIB format, however, is also limited to 64k by the TINI firmware.

Retrive Files from the Internet

At server startup, either inside the main entry point, or in the initialization code of a servlet, a connection could be made to a host somewhere on the Internet that contains the latest version of your files.

Protocols such as FTP or HTTP allow you to retrieve these files in a straightforward way.

[Top]


Appendix A — Startup.java Source

import com.dalsemi.system.TINIOS;
import com.dalsemi.tininet.TININet;

import java.io.*;
import java.net.URL;
import java.net.URLStreamHandler;
import java.net.URLStreamHandlerFactory;
import java.util.Properties;

/**
 * Demonstrates how to start the server from flash.
 *
 * @author Shawn Silverman
 */
public class Startup {
    /**
     * Application entry point.
     */
    public static void main(String[] args) throws IOException {
        // Set the System streams to serial0

        if (TINIOS.isConsoleOutputEnabled()) {
            com.dalsemi.system.Debug.setDefaultStreams("serial0", 115200);
        }

        System.out.println();
        System.out.println("      --= System starting =--");

        System.out.print("Disabling power fail recovery......");

        // Doing this will speed up the program since it's running from flash

        // It is okay to call this because we are also blasting the heap

        TINIOS.disablePowerFailRecovery();

        // Blast the memory on reboot

        TINIOS.blastHeapOnReboot(TINIOS.BLAST_ALL);

        System.out.println("[DONE]");

        // Set up the network
        // You can configure other things here such as the mailhost

        System.out.print("Configuring network................");
        TININet.setIPAddress("eth0", "192.168.0.7");
        TININet.setSubnetMask("eth0", "255.255.255.0");
        TININet.setGatewayIP("eth0", "192.168.0.1");
        TININet.setPrimaryDNS("192.168.0.1");
        System.out.println("[DONE]");

        System.out.print("Storing files......................");
        storeFiles();
        System.out.println("[DONE]");

        System.out.println();

        // Load the properties file

        System.out.print("Loading web server properties...");
        Properties props = new Properties();
        String propsFile = "/web/bin/webserver.props";
        try {
            FileInputStream in = new FileInputStream(propsFile);
            props.load(in);
            try { in.close(); } catch (IOException ex) { }
        } catch (FileNotFoundException ex) {
            System.err.println("File '" + propsFile + "' not found.");
            System.exit(1);
        }
        System.out.println("done.");

        // Set up our "mailto" handler, if needed
        // The ability to mail the logs depends on this, for example

        URL.setURLStreamHandlerFactory(new URLStreamHandlerFactory() {
                public URLStreamHandler createURLStreamHandler(String protocol) {
                    if ("mailto".equalsIgnoreCase(protocol)) {
                        return com.qindesign.protocol.mailto.Handler.instance;
                    }
                    return null;
                }
            });

        // Start the webserver

        System.out.println("Starting web server...");
        com.qindesign.tini.http.HttpServer server =
                new com.qindesign.tini.http.ServletHttpServer(props);
        new Thread(server).start();

        // Now other tasks can be performed here
        // The server can be shut down with "server.shutdown()"
    }

    /**
     * Store the data for the configuration files.
     */
    private static void storeFiles() throws IOException {
        // Create the necessary parent directories

        if (!new File("/web").mkdir()
              || !new File("/web/bin").mkdir()
              || !new File("/web/logs").mkdir()
              || !new File("/web/http-root").mkdir()) {
            throw new IOException("Error creating directories");
        }

        // Store /web/bin/webserver.props

        FileOutputStream out = new FileOutputStream("/web/bin/webserver.props");
        out.write(("server.port=80\n"
                  + "server.bufferSize=1024\n"
                  + "server.mimeTypesFile=/web/bin/mimeTypes.props\n"
                  + "server.rootDir=/web/http-root\n"
                  + "server.sendServerHeader=true\n"
                  + "server.shutdownEnabled=true\n"
                  + "server.shutdownPasswordFile=/web/logs/shutdown.pwd\n"
                  + "servlet.propsFile=/web/bin/servlets.props\n"
                  + "servlet.reloadingEnabled=true\n"
                  + "server.log.logFile=/web/logs/webserver.log\n"
                  + "server.log.transferLogFile=/web/logs/transfer.log\n"
                  + "server.log.stackTraceEnabled=true\n")
                  .getBytes());
        out.flush();
        out.close();

        // Store /web/bin/servlets.props

        out = new FileOutputStream("/web/bin/servlets.props");
        out.write(("default.mapping=/\n"
                  + "default.class=com.qindesign.servlet.DefaultServlet\n"
                  + "default.initParams=canBrowseDirs=true\n"
                  + "default.loadOnStartup=true\n"
                  + "RequestInfo.mapping=/servlet/RequestInfo/*\n"
                  + "RequestInfo.class=com.qindesign.servlet.example.RequestInfoServlet\n"
                  + "AuthExample.mapping=/servlet/AuthExample\n"
                  + "AuthExample.class=com.qindesign.servlet.example.AuthExampleServlet\n"
                  + "TiniInfo.mapping=/servlet/TiniInfo\n"
                  + "TiniInfo.class=com.qindesign.servlet.example.TiniInfoServlet\n"
                  + "LogViewer.mapping=/servlet/LogViewer\n"
                  + "LogViewer.class=com.qindesign.servlet.example.LogViewerServlet\n"
                  + "OneWireServlet.mapping=/servlet/OneWireServlet\n"
                  + "OneWireServlet.class=com.qindesign.servlet.example.OneWireServlet\n"
                  + "OneWireServlet.initParams="
                        + "familyCode10=TemperatureInclude,"
                        + "familyCode21=TemperatureInclude,"
                        + "familyCode05=SwitchInclude,"
                        + "familyCode12=SwitchInclude,"
                        + "familyCode1f=SwitchInclude,"
                        + "familyCode29=SwitchInclude,"
                        + "familyCode20=FamilyCode20Include\n"
                  + "OneWireServlet.loadOnStartup=true\n"
                  + "TemperatureInclude.mapping=\n"
                  + "TemperatureInclude.class="
                          + com.qindesign.servlet.example.TemperatureInclude\n"
                  + "SwitchInclude.mapping=\n"
                  + "SwitchInclude.class=com.qindesign.servlet.example.SwitchInclude\n"
                  + "FamilyCode20Include.mapping=\n"
                  + "FamilyCode20Include.class="
                          + com.qindesign.servlet.example.FamilyCode20Include\n")
                  .getBytes());
        out.flush();
        out.close();

        // Store /web/bin/mimeTypes.props

        out = new FileOutputStream("/web/bin/mimeTypes.props");
        out.write((".class=application/java-class\n"
                  + ".css=text/css\n"
                  + ".gif=image/gif\n"
                  + ".htm=text/html\n"
                  + ".html=text/html\n"
                  + ".ico=image/x-icon\n"
                  + ".jar=application/java-archive\n"
                  + ".java=text/x-java-source\n"
                  + ".jpeg=image/jpeg\n"
                  + ".jpg=image/jpeg\n"
                  + ".jnlp=application/x-java-jnlp-file\n"
                  + ".js=application/x-javascript\n"
                  + ".pdf=application/pdf\n"
                  + ".png=image/png\n"
                  + ".ser=application/x-java-serialized-object\n"
                  + ".txt=text/plain\n"
                  + ".xml=text/xml\n"
                  + ".zip=application/zip\n")
                  .getBytes());
        out.flush();
        out.close();
    }
}

[Top]