Initialization and Configuration of TINI & Java Communications API for Real-Time Embedded Networked Applications Vincent A Akpan*, Reginald O A Osakwe** Abstract This article addresses the challenges in installing, initializing and configuring TINI for real-time embedded networked applications. A simple technique for installing Java communications API for accessing communication ports for direct interfacing to legacy systems as well as an efficient technique for the initialization and configuration of the TINI’s serial and Ethernet ports for real-time online datalogging capabilities over a network are presented. The techniques proposed in this article are implemented to demonstrate and validate the proposed schemes. Finally, all the Java programs developed to implement and demonstrate all the techniques proposed in this article are presented.
Keywords: Java communications API, Networking, Online datalogger, Real-time embedded system, TINI (Tiny InterNet Interface), TINI SDK (software development kit).
Introduction The unstoppable expansion of the Internet has been witnessed within the last few years. The proliferation of the Internet and Web Access has occurred at a phenomenal rate to permeate the societies within which it operates. It has allowed the sharing of ideas, collaboration and the exchange of services and information. Furthermore, the proliferation of the Internet has encouraged traditional engineering schools to introduce teaching programs and to conduct research topics that involve the interfacing of engineering applications to the Internet. The unstoppable expansion and proliferation of the Internet are added values to the world of control engineering where they provide Web-based interfaces to many types of devices. Nowadays many devices do not have this interface implemented and even the suitability of making this interface internal could be discussed in terms of cost, security and efficiency. Hence, it is very interesting to have a small, low cost, external component to increase the functionality for a wide range of control devices. The Tiny InterNet Interface (TINI) developed by Dallas Semiconductors incorporated meets all the above requirements.1 The TINI card was designed to give a voice on the network to many types of devices: from small sensors and actuators to factory *
automation equipment and legacy hardware. TINI has a built-in Java runtime environment. Java was primarily designed and introduced to facilitate real-time embedded systems development and not the Internet itself.2 However, Java was not commonly used for embedded systems,3 but today the relative cost of programming rises compared with hardware costs, so better use of cost-effective hardware/software programming boards with full support for Java such as the TINI are needed. This situation fits perfectly with the Java philosophy.2 One of the novelties provided by TINI is the support for Point-to-Point Protocol (PPP) communication.4 The Point-to-Point Protocol (PPP) provides IP packet transport over a serial link. The serial link can be a direct serial connection using a serial cable, a connection using a modem and telephone lines, or a cellular handset using wireless technologies. Being a point-to-point protocol, PPP does not distinguish between client and server operations. For the purposes of this application note, a peer that requires a remote peer to provide authentication and provides an IP address to the remote peer is known as a server. Whereas, a peer that does not require a remote peer to authenticate and accepts an IP address is known as a client. On
Department of Physics Electronics, The Federal University of Technology, P.M.B. 704 Akure, Ondo State, Nigeria. Department of Physics, The Federal University of Petroleum Resources, P.M.B. 1221 Effurun, Delta State, Nigeria. Correspondence to: Mr Vincent A Akpan , Department of Physics Electronics, The Federal University of Technology, P.M.B. 704 Akure, Ondo State, Nigeria. E-mail Id:
[email protected] **
© ADR Journals 2015. All Rights Reserved.
Akpan VA et al.
2
TINI, the PPP physical interface is a serial port, which can be connected to a modem and allows the use of the Public Switched Telephone Network (PSTN) for global access to the TINI. However, the use of a modem is not required. Devices such as cellular phones and PDAs with PPP support can be connected to a TINI with the proper serial cable. The major challenge in the development of a TINI-based application is on the initialization and configuration of the TINI as well as setting up the Java communication application programmer interface (API) for direct interfacing to the outside world via serial ports. These challenges are due to the pieces of software tools that must be properly installed, initialized and configured to facilitate the programming of the TINI board model. The solutions to these challenges amongst others are the main objectives of this article. The article is organized as follows. Section 2 presents and discusses on the hardware/software requirements, initialization and network configuration for the development of TINI as a legacy system. Section 3 is devoted to the TINI’s serial port configuration for communication to the outside world. The article concludes in Section 4 with some recommendation and future directions. All the programs required to demonstrate the techniques presented in this article are provided in the appendix.
The TINI: Hardware/Software Requirements, Initialization and Network Configuration The TINI (Tiny Internet Interface) Platform Tiny Internet Interface (TINI) is a platform developed by Dallas semiconductor to provide system designers and software developers with a simple, flexible, and cost-effective means to design a wide variety of hardware devices that can connect directly to corporate and home networks. The platform used in this project is the TINI Board Model (TBM) 390. The TBM 390 is a combination of a small but powerful chip-set and a java programmable runtime environment. The chip-set provides processing, control, device-level communication and networking capabilities. TINI’s networking capability extends the connectivity of any attached device by allowing interaction with remote systems and users through standard network applications. The TINI hardware consists of a microcontroller, flash ROM and static RAM. The flash memory stores TINI’s runtime environment and it maintains the memory content even in the absence of system power; it is reprogrammable. The static RAM contains the system data area as well as the garbage collected heap from which all java objects are allocated. It also stores all file system data. Figure 1 is an illustration of a full-featured TINI hardware implementation.5
Figure 1.A full-featured TINI hardware implementation
J. Adv. Res. Netw. Comm. Engi. 2015; 2(2): 1-26.
3
Akpan VA et al.
Figure 2.(a) Top view of the TBM 390 TINI board model, (b) bottom view of the TBM 390 TINI board model and (c) The complete E10 socket with the TINI board model
Figure 3.The TINI runtime environment
J. Adv. Res. Netw. Comm. Engi. 2015; 2(2): 1-26.
Akpan VA et al.
he circuitry performs two functions. First, it keeps the clock running in the absence of main power (Vcc), ensuring that an accurate time can always be read from the clock. The lithium cell alone performs this task. Also the lithium cell in conjunction a small chip known as an SRAM non-volatizer, maintains the contents of the state RAM in the absence of main power. The TBM 390 is a compact (31.8mm x 102.9mm) 72–pin SIMMM board. It is an Ethernet-ready hardware implementation and supports all the functionality shown in fig. 2. It requires only a single+5V power supply.
The TINI Board Model The board model 390 (TBM 390) is a complete TINI hardware reference design that is currently available with either 512 kilobytes or 1 megabyte of non volatile, static RAM. It is also available as a 72 – pin SIMM module and the TINI employed in this project is a 512-kilobyte of NVSRAM. The top and bottom view of the TBM390 as well as the E10 socket with TINI board are shown in fig. 2 (a), (b) and (c) respectively. The E10 socket board shown fig. 2(c) is aimed at aiding the application development process. It provides the following physical connectors: 1). 72–Pin SIMM Connector: the SIMM connector accepts the TINI board shown in fig. 2(a) and (b). 2). 9–Pin Female DB9 Connector: this connector provides a limited DCE (Data Communication’s Equipment) serial port using a straight-through serial cable. This port is typically used for loading the run time environment and bootstrap application. Hardware handshake lines are not supported. 3). 9–Pin Male DB-9 Connector: this connector provides a DTE (Data Terminal Equipment) serial port for straight–through connections to DCE devices such as analog modems. Most TINI applications that control serial devices use the DTE port. In this case TINI is the DTE device, replacing all hardware handshake lines except DSR (Data Set Ready) and RI (Ring Indicate). 4). RJ45: The RJ45 connector accepts a standard 10Bax-T Ethernet cable providing connectivity to an Ethernet network. Use a straight-through cable for connecting TINI directly to a PC or Workstation. 5). RJ11: the connector provides access to the 1-Wire network using standard telephone cable.
4
6). Power Jack: the E10 accepts a regulated+5V DC power supply. The E10 also provides integrated circuit and discrete components foot prints to support additional I/O option such as parallel, CAN and additional Serial Ports.
The TINI Runtime Environment Providing hardware essentials for developing embedded network devices is only half of the job. A large amount of software is also required to free application developers from having to worry about the details of creating layers of infrastructure to provide support for executing multiple tasks, network protocol stacks, and an application programming interface. A well-defined runtime environment that provides all of these features allows the developer to focus primarily on the details of the application. For this reason a runtime environment was developed from the beginning as an integral part of the overall platform. The software that comprises TINI’s runtime environment can be divided into two categories: native code executed directly by the microcontroller and an API interpreted as bytecodes by the Java Virtual Machine. Application code is written in Java and utilizes the API to exploit the capabilities of the native runtime and the underlying hardware resources. It is also possible to write native libraries that can be loaded from within an application to meet defined real-time requirements. A graphical representation of the runtime environment is shown in fig. 3. Java programs running on TINI are mostly defined in applications and not applets. They are stand-alone programs that begin execution from a “main” method with the following signature. public static void main(String[] args) Also, unlike applets, they have no “sandbox” restrictions. On TINI, Java applications have full privileges and access to all system resources, even more so than on other platforms that support a Java runtime environment. This is particularly important for embedded applications because they are closely coupled with physical devices. Also, unlike other Java platforms, on TINI there is usually no system administrator to perform configuration and maintenance. This means that the application is responsible for configuring as well as controlling the entire system. For these reasons an application that controls an embedded system must have complete access to even low-level functionality provided by the OS (operating system).
J. Adv. Res. Netw. Comm. Engi. 2015; 2(2): 1-26.
5
Development Platform Requirements The development platform refer to the computer used for creating, building, and loading TINI applications and can be connected to TINI using Ethernet and/or a serial cable. This development platform will usually be referred to as the “host”. In this project TINI will be developed on Windows XP operating System although any other operating system is still alright. To load TINI’s runtime environment, the host must have an RS232 serial port. The host must have a Java development kit (JDK) bundled with NetBeans® integrated development environment (NetBeans® IDE), Java communication application programming interface (Java Comm API) and TINI software Development Kit (TINI SDK) software correctly installed. Amongst the three software installed, it is important to understand the contents of the TINI SDK files since it forms TINI’s major software. These files include: 1). README.txt: the README.txt file is located in the root of the SDK hierarchy. It contains detailed instructions on how to install the TINI runtime environment, booth the TINI system, and initializes its network settings. It also contains references to other documents in the SDK that further describe the process of creating a full development environment. 2). Tini.jar: The jar file is located in the bin directory and includes two important utility programs: Javakit and TINIConverter. The Javakit utility manages the firmware-loading process and performs other system maintenance tasks. It can also be used to run slush user sessions over a serial connection. The TINIconverter utility takes the class files in an application as input and generates a binary image suitable for execution on TINI. 3). Tiniclasses.jar: The tiniclasse.jar file is located in the bin directory and contains all of the class files in TINI API. In this sense, it is similar to the rt.jar file distributed with Sun’s JRE, JDK and SDK. This file must always be included as the first file in the classpath when compiling applications for TINI. 4). Tini.db: The tini.db files are an ASC11 file that contains information about API class files. This file is used by TINIConverter along with the class files in your application to produce a binary image suitable for interpretation by TINI’s JVM (Java Virtual Machine).
J. Adv. Res. Netw. Comm. Engi. 2015; 2(2): 1-26.
Akpan VA et al.
5). Tini.tbin: The .tbin extension is short for “TINIbinary” and is the default extension used for binary images that are targeted for execution from the flash ROM. The tini.tbin file is located in the bin directory and contains the binary image of TINI’s runtime environment. It is a combination of the native operating system and the API. This file must be loaded before any java applications can be executed. 6). Slush.tbin: The slush.tbin file is located in the bin directory and contains the binary image of the user shall be known as slush.
Configuring the Java Communications API The installation and configuration of the Java Communications API presents several challenges for communication with serial ports on Windows environment. Here, we present a simple but excellent technique to install the Java Communications API correctly on a window system machine. Note that the following files are the core of the Java Communications API, and they are very important to have them installed on the development platform (host computer) for the proper development and operation of the embedded system (TINI). These file are: 1) Comm.jar, 2) win32com.dll, and 3) javax.comm.properties. For the JDK to recognize the serial ports on the embedded system (TINI), it is important to properly place these files in the right folders on the development platform (host computer) at the following location: %Java_HOME% = the location of the JDK directory. For completeness, we show how to locate the JDK directory as shown in the following 8 stepwise procedures: 1). Click on Start; 2). Click on Search; 3). Click on For Files or Folders; 4). On the left hand side, click on All Files and Folders; 5). Type in jdk* in the textbox under All or part of the file name; 6). Click Search; 7). Look for yellow icon that looks like a folder; 8). Double click on the folder to open the JDK folder. comm.jar is be placed in: %JAVA_HOME%/lib %JAVA_HOME%/jre/lib/ext win32com.dll is placed in:
Akpan VA et al.
6
%JAVA_HOME%/bin
Load Complete
%JAVA_HOME%/jre/bin
Loading file
%windir%System32
Please wait. …(Esc to Abort.)
javax.comm.properties is placed in:
Load Complete
%JAVA_HOME%/lib
The above simple procedures were employed for the proper installation and configuration of the Java Communications API which established the communication between the TINI board and the development platform (host computer).
These files were rather large and at Javakit’s default serial data rate of 115,200 beeps, loading tini.tbin and slush.tbin took couple of minutes. The binary image that comprises TINI’s runtime has been load. Before the system is booted for the first time, the heap must first be initialized. At the boot loader prompt, type “BANK 18” and hit Enter. This selects the loader 64k portion of TINI’s heap. Next type “FILL 0” and hit Enter.
Loading the TINI Runtime Environment
> BANK 18
Installing the runtime environment in the TINI board consists of two steps: 1). Loading tini.tbin and slush.tbin and 2). Initializing the heap. Both steps require the use of the javakit utility. Javakit runs on the host and communicates with TINI’s bootstrap loader over an RS232 serial port using the Communication API. Javakit is a sing based GUI utility and it is launched with the following command:
> FILL 0
c:\jsdk4.1.2\bin\javaw-classpath c:\tni1.02\bin\tini.jar javakit.
------ TINI Boot -----------
Once successfully launched a window is displayed using the “Port Name” drop down selection box, COM1 is chosen and “Open Port” is clicked which changes to “Close Port”. Next the “Reset” button is clicked and the TINI’s loader generates a prompt as shown below:
API version 8009
%JAVA_HOME%/jre/lib
TINI loader 05 –05 –05 17:45 Copyright © 2000 Dallas Semiconductor. All rights reserved. > Automatically, the TINI’s loaders attention has been captured and the runtime binaries can be loaded. Firstly, “load file” is selected from the file menu. Using the directory drop box, the bin directory in the TINI SDK hierarchy is selected and the file named tini.tbin and slush.tbin and the “open” button is clicked. The Javakit window displays the following statements: Loading file: c:\tini1.02\bin\slush.tbin Please wait. …(Esc to Abort.)
:
c:\tini1.02\bin\tini.tbin
This rather cryptic two-step sequence fills the low 64k of heap with 0s, forcing the 0s to initialize the heap, file system, and all other persistent setting. To exist the serial loader and boot the TINI for the first time type “EXIT” at the prompt and text generated by the operating system (OS) early in the boot process:
TINI OS 10.2
Copyright © 1999 – 2001 Dallas Semiconductor Corporation After a couple of seconds the system boots completely and the following prompt is displayed by slush: Hit any key to login After pressing a key, slush prompts for the user login name Welcome to slush (version 1.4.2) TINI login: Here, the username used is root and the password is tini.
Configuring the Network Network configurations can be set by using the slush command ipconfig. The ipconfig command provides several options that allow for complete control of all important network parameters. Ex-
J. Adv. Res. Netw. Comm. Engi. 2015; 2(2): 1-26.
7
Akpan VA et al.
ecuting ipconfig with no parameters display the following current network settings:
[-d]
use DHCP to lease an IP address.
[-r]
release currently held DHCP IP address
[-x]
show all interface data.
TINI /> ipconfig Hostname
:
Current IP
:
Default Gateway
:
TINI [- h xx.xx.xx.xx]
Subnet Mask
:
Ethernet Address Primary DNS
:
[-C] flash
commit current network configuration to
[-D] flash.
disable restoration of configuration from
[-F]
don’t prompt for configuration.
00:60:35:00:10:bb
:
Secondary DNS
:
DNS Timeout
:
DHCP Server
:
DHCP Enabled Mailhost
set mailhost
0 (ms)
:
False
TINI /> ipconfig – a 192.168.0.15 255.255.255.0
:
Restore from Flash
If there is a DHCP available on the network, then the –d option can be used to dynamically obtain an IP address and subnet mask as well as several other network parameters, depending on the configuration of the DHCP server. For static network configuration, the IP address and the subnet mask have to be set to a minimum.
:
Not committed
Since the runtime have just been installed and the heap cleared, nothing but the Ethernet address and default host name, TINI, have been configured. The Ethernet address is an IEEE registered MAC id to avoid any possible collision on an Ethernet Network. It is read from the read-only memory of a 1–wire chip on the TINI board and is not user configurable. Thus, using the help command, a list of option’s supported by ipconfig can be obtained. TINI /> help ipconfig Ipconfig [options] Configure or display the network settings
Warning: this will disconnect any network user and reset all network servers. OK to proceed? (Y/N) :y. [Saturday February 9 14:52:46 GMT 2013] message from system: Telnet Server started. [Saturday February 9 14:52:46 GMT 2013] message from system: TFTP Server started. The new setting’s was tested by “pinging” the TINI board from the host machine by using the ping command and slush automatically start Telnet and FTP servers after setting the network information. At this point a Telnet session can be established with TINI, using the host’s Telnet client.
[- a xx.xx.xx.xx] set IP address. Must be used with the –m option.
C:\>telnet 192.168.0.15
[-n domainname] set domain name
Connecting to 192.168.0.15….
[- m xx.xx.xx.xx] set subnet mask. Must be used with the – a option
Welcome to slush (version 14.2)
[- g xx.xx.xx.xx]
set gateway address
[- p xx.xx.xx.xx]
set primary DNS address.
[- s xx.xx.xx.xx]
set secondary DNS address
[-t dnstimeout] backoff/retry)
set DNStimeout (set to for
J. Adv. Res. Netw. Comm. Engi. 2015; 2(2): 1-26.
-M
TINI login: root TINI password TINI/> Once connected, slush prompts for a user name and password. The telnet session can be killed by using the exist command.
Akpan VA et al.
8
To extend TINI’s reach beyond its physical network, the IP address of the default gateway (or router) address is set using –g option and the IP address of the DNS server is also set using the –p option. Running the following command from the serial session adds the default gateway and DNS server’s IP address to the current network configuration.
Subnet Mask
:
DNS Timeout
:
TINI/>ipconfig –g 192.168.0.1 –p 192.168.0.2
DHCP Server
:
Naming: this will disconnect any connected network users and reset all network servers.
DHCP Enabled
Ethernet Address Primary DNS
[Saturday February 9 15:02:53 GMT 2013] message from system: FTP Server stopped. [Saturday February 9 15:03:00 GMT 2013] message from system: Telnet Server stopped. [Saturday February 9 15:03:00 GMT 2013] message from system: Telnet Server started.
00:60:35:00:10:bb
:
Secondary DNS
Mailhost
OK to proceed? (Y/N): y
:
: 0 (ms)
:
False
:
Restore from Flash :
Not committed
All these must remain active because they will be used to run all the programs in this study.
Program Execution Techniques and Testing of the TINI
Note that if the FTP and Telnet servers are running slush stops then, before changing the requested network setting. After aborting any active FTP or Telnet sessions, the new network parameters are set and the servers are restarted. The new settings can both be tested by pinging the host machine on another network, using the host’s name as opposed to its IP address.
At this point the runtime environment has been loaded and the TINI have been configured for network operation, and the interaction with the runtime is also possible using slush. Slush via a Telnet session will be used to run all the programs (applications), display any output, interact with the file system and control process. The following five (5) steps are typically employed to develop and test application on TINI: 1). Create the source file, 2). Compile the source file, 3). Convert the class file, 4). Load the converted image and 5). Run the converted image.
TINI/> ping www.ibutton.com
Step 1: Create and save the source file
[Saturday February 9 15:03:01 GMT 2013] message from system: FTP Server started.
Got a reply from www.ibutton.com/198.3.123.121
node
www.
Sent 1 request(s), got 1 reply(s) Next is to log out of the serial session and close the Javakit. Interaction with TINI is now possible and running Java programs over the network using the host’s Telnet and FTP clients. Starting a new Telnet session and running the ipconfig with no parameters give the following output. Welcome to slush (version 1.02) TINI /> ipconfig
Program 0 Blinky program for testing the TINI import com.dalsemi.system.BitPort; class Blinky { public static void main(String[] args) { BitPort bp Port(BitPort.Port3Bit5);
=
new
Bit-
for (;;) {
Hostname
:
Current IP
:
Default Gateway
Create and save a file ending with the .java extension containing the source code given in the Program 0 below:
TINI
// Turn on LED bp.clear();
:
// Leave it on for 1/4 second
J. Adv. Res. Netw. Comm. Engi. 2015; 2(2): 1-26.
9
Akpan VA et al.
try {
Connected to 192.168.0.15 Thread.sleep(500);
220 Welcome to Slush. (Version 1.4.2) Ready for user login.
} catch (InterruptedException ie) {} User (192.168.0.15: (none)): root // Turn off LED bp.set(); // Leave it off for 1/4 second try {
331Root login allowed. Password required Password: 230User root logged in ftp >
Thread.sleep(500); } catch (InterruptedException ie) {} }
After successfully establishing a connection and logging in to slush, the Blinky.tini is now transferred to the TINI’s file system. First type “bin” at the FTP prompt to ensure that the binary image is not altered during the actual file transfer.
} ftp>bin }
200 Type set to Binary
Step 2: Compile the Source file Compile Blinky.java to a class file, using the Java SDK and change to the directory that contains the first created file and the following command is executed:
Transfer Blinky.tini, using the put command. Finally, close the FTP session by typing bye or quit at the prompt. ftp> bye
Javac Blinky.java
221 Goodbye
If the compilation completes successfully, a new file named Blinky.class will be created in the current working directory.
Configuration of successful file transfer can be checked by using the ls –l command at the slush prompt in the telnet session.
Step 3: Convert the Class File
TINI/> ls –l
To convert Blinky.class to a binary image that can be executed on TINI, the TINIconverter supplying the three mandatory command line parameters is run: input file or directory (-f), API database (-d), and output file (-o).
Total 3 drwxr – x 1 root ruary 9 14:45 rwxrruary 9
Admin
1 root admin 15:45 Blinky.tini
2
Saturday Feb-
171 Saturday Feb-
java – classpath c:\tini1.02\bin\tini.jar TINIconverter –f Blinky.class – d c:\tini\tini1.4.2\bin\tini.db -o Blinky.tini
drwxr – x February 9
Running this command produces a Binary output file named Blinky.tini.
The file Blinky.tini now appears in the root directory of the file system and has the same size that was listed during the FTP transfer.
Step 4: Load the Converted Image Using the FTP client provided with the Operating System to connect to TINI and transfer the binary image, generated in the previous step, to the TINI file system. C:\tini1.02\Blinky > ftp 192.168.0.15
J. Adv. Res. Netw. Comm. Engi. 2015; 2(2): 1-26.
1 root 14:45
admin etc
3
Saturday
Step 5: Run the converted Image Run the application using the Java command at the slush prompt. TINI /> java Blinky.tini & TINI />
Akpan VA et al.
Looking at the TINI board, the status LED (D1) blinked about once per second. It will continue to blink until the process is killed. To kill a process from slush, type “kill” command specifying the process id on the command prompt. To identify the process id, the PS command is used. TINI /> PS 3 processes 1: Java GC (Owner root) 2: Init (Owner)
10
streams for reading data from and writing data to the underlying physical port. CommPort objects cannot be created directly using the new operator. Rather, they are created by involving the open method on a CommPort Identifier object. The CommPortIdentifier class manages access to the ports exposed by the platform’s physical port drivers. It also provides a mechanism for notifying applications when port ownership status changes. This can be useful when multiple applications need to share a single port like on TINI.
The PS command shows the total number of processes and hits each process id followed by its name. Killing filename is achieved by:
An enumeration of CommPortIdentifier for all communication ports supported by the system can be obtained by invoking the getport Identifiers method. The portlister in Program 1 gets an enumeration of all Commport objects on the system and displays their names.
TINI /> kill 4
Program 1: PortLister
TINI />PS
import java.util.Enumeration;
2 Processes
import javax.comm.CommPortIdentifier;
4:Blinky.tini (Owner root)
1: Java GC (Owner root)
class PortLister {
2: Init (Owner) Note that killing and immediately restarting the same process does not give the process its former id; rather the process id is incremented by 1.
public static void main(String[] args) { Enumeration ports = CommPortIdentifier.getPortIdentifiers(); while (ports.hasMoreElements()) {
TINI’s Serial Port Configuration The sheer number of devices that uses serial ports as a means for communicating with other electronic devices is staggering. These include everything from very well known examples like personal computers and modems to manufacturing and industrial automation equipment. In fact, for many, a serial port provides the sole mechanism of communicating with the outside world. For this reason bridging the communication gap between serial-only devices to networked host is one of the most popular applications of TINI technology. The Java communications API has been defined by Sun Microsystems as an extension to the Java Platform. The API is defined and partially implemented in the Javax.com package. The platform specific portion of the communication API implementation exists in the com.dalsemi.comm.package. SerialPort is a subclass of the abstract class CommPort. CommPort provides a fairly generic abstraction of a communications port. It provides methods for configuring port settings and acquiring
System.out.println(((CommPortIdentifier)(ports.nextE lement())).getName()); } } } The output of PortLister when executed on TINI shows that four serial ports are supported by the system. They are named serial0 through serial3. TINI /> java PortLIster.tini Serial0 Serial1 Serial2 Serial3 After having the CommPortIdentifier object, open is invoked to obtain the CommPort object. Another
J. Adv. Res. Netw. Comm. Engi. 2015; 2(2): 1-26.
11
setting that must be configured before beginning serial data transfer is the flow control mode. Flow control is a mechanism that allows a receiver to tell the sender to pause when its internal receive data buffer is close to full. The Java Communications API supports the notion of receive time-outs and thresholds. Receive time-outs and thresholds allow the application to control blocking reads on serial port InputStream objects. As a summary, the javax.comm package provides a standard way to use communication ports under Java.6 The basic sequence of steps that you'll use to open an input stream on a serial port is: 1). Create a CommPortIdentifier object that names the serial port (for the TINI this is serial0) by calling the static method CommPortIdentifier.getPortIdentifier. 2). Use the object's open method to create a SerialPort object. 3). Use setSerialPortParams to set the SerialPort's baud rate and other parameters. 4). Call getInputStream to return an InputStream object that refers to the port. This InputStream object is like any other. In fact, for debugging purposes, it might be necessary to replace the serial port code with is=System.in; which allows the use of standard input stream as a source for input (so characters can be entered from the SLUSH terminal or a Telnet session). After both the port and the socket are ready, a while loop reads characters from the port and sends them to the socket. On receipt of an end-of-line character, the program flushes the socket so that the remote computer receives frequent updates.
Serial Port Events The communication notifies of interesting serial port events, such as state changes in the modem control lines and when data, is available. On TINI, the events are propagated by a daemon thread listens for state charges in the serial port drivers. The daemon thread is created when the first event listener is registered using the argument Listener passed to method addEventListener requires an instance of a class that implements the SerialEventListener interface. The CTSMonitor shown in Program 2 listens for changes on the CTS (Clear To Send) line. During Construction CTSMonitor creates and opens a SerialPort object that encapsulates serial0.
J. Adv. Res. Netw. Comm. Engi. 2015; 2(2): 1-26.
Akpan VA et al.
It then adds itself as an even listener and requests notification for CTS change events. The TINI runtine environment supports up to four serial ports. The serial ports are designated serial0 through serial3. The UARTS used by serial0 and serial1 are integrated within TINI’s microcontroller. For this reason they are termed “interval” serial ports. The UARTS used by serial2 and serial3 require a dedicated external dual-UART chip. These are referred to as “external” serial Ports. First serial1 is by default dedicated to the task of communicating with the external 1 – wire line driver. If a particular TINI hardware implementation does not require the use of the external 1-wire adapter, serial1 can be reclaimed for use of with a general purpose serial Port. To override serial1’s default usage, an application must invoke the enableSerialPort1 method defined in the TINIOS class. If serial1 on the IBM390 is used, then there is need to disable the DS2480 1-wire driver and this is accomplished by grounding theEN2480 signal (pin 26 of the SIMM connector). TiniTerm’s constructor and main method shown in Program 3 ties together much of the functionality provided by the Comm API. The baud rate must be specified on the command line. The TiniTerm program reads characters from the console (System.in) and writes the same characters to a serial. Data flow in the other direction is also supported. The main method simply creates and starts a now thread that blocks waiting for console input. The getCommPortIdentifier method of class CommPortIdentifier is used to obtain a CommPort object representing the port specified by name to the TiniTerm’s constructor catches each checked exception that can be thrown during initialization displays an appropriate error message. The constructor invokes the getInputStream and getOutputstream methods on the SerialPort object to acquire streams for receiving data from the transmitting data to the underlying serial port. The TiniTerm’s run method is shown in program 4.
Program 4: TiniTerm’s run method // Return as soon as any bytes are available // (i.e. don't wait for line termination) ((SystemInputStream) System.in).setRaw Mode(true); while (true) {
Akpan VA et al.
12
try { byte
b
=
(byte)
Sys-
tem.in.read(); if (b == (byte) '~')
is requested whenever data is received on the serial port. SerialEvent invokes the getEventType method on the SerialPortEvent object. The SerialEvent method is shown in Program 5. If the data rate selected is 115, 200 bps, then the TiniTerm can be started in the Telnet session using the following command
break; // Send the byte out the serial port
TINI/> java TiniTerm.tini 115200 It should be noted that the application is launched as foreground process (i.e. in and at the end of the command line). This is important because background process cannot read from System.in. For background process, System.in is fed from a com.dalsemi.comm.NullInputstream.
sout.write(b); } catch (IOException ioe) { ioe.printStackTrace(); }
A Serial to Ethernet Converter
} } In Program 4, the first thing the run method does is cast System.in to a SystemInputStream and set its mode to “raw” using the setRawMode method. However, the key may have be hit before the data typed is transmitted to the remote terminal or echoed to the console. The only escape from the run method is to type the tilde (~) character at the prompt. TiniTerm implements SerialPortEventListener, which means it must provide an implementation for the SerialEvent method and in this case notification
Serial Device
When TiniTerm is run, it takes console input System.in, which received data typed from a Telnet session. The characters typed at the Telnet prompt ultimately wind up as network data traveling over a TCP connection. The point here is making a bridge between a serial device and another host on an Ethernet network. The big difference is that SerialEthernet is designed for communication with serial devices that transfer potentially large amount of information with relatively little decay between characters. This is as opposed to TiniTerm that only needed to perform well enough to keep up with a human typist. The SerialToEthernet application reads data from an attached serial device and writes it to a network server and vice versa as shown in fig. 4.
TINI Serial 0
eth 0
Network
Server
Figure 4.Serial to Ethernet bridge data flow
Since both serial and network I/O are potentially full duplex the serial port flow control mode is set for RTS and CTS flow control. This will protect the serial receive buffers of both TINI and the attached device from overflow under a potentially heavy load the constructor acquires an InputStream and an OutputStream for reading from and writing to the serial port. The SerialtoEthernet program is shown in Program 6.
After completing the serial port configuration; a connection is established with the network server, and input and output streams are obtained for data transfer to and from the server. Finally, the constructor starts three new threads of execution. Their tasks are: SerialRead which reads from the serial port writes to the socket; SerialWriter which reads from the socket, writes to the
J. Adv. Res. Netw. Comm. Engi. 2015; 2(2): 1-26.
13
serial port; and the SerialToEthernet which provides periodic statistical updates. The program for the SerialtoEthernet run method for the maintenance thread shown in Program 7 writes the total number of bytes received from the serial port and the total number of bytes received from the network to the console (System.Out) and sleeps for about a minute. The process is repeated as long as running is true and vice versa. SerialToEthernet contains two inner classes: SerialReader and SerialWriter. Each implements the runnable interface so that they can each run as separate threads of execution. This prevents either of the threads from having to block while the other is performing serial or network data transfer. This helps achieve the goal of high-speed, full duplex I/O. The inner class SerialReader in Program 8 creates a byte array of the specified size that serves as a reusable buffer for serial received data. The run method enters a loop that reads data available from the serial port’s InputStream and immediately writes that data to the socket’s OutputStream. The Inner class SerialWriter is shown in Program 9. SerialWriter’s run method enters a loop that reads data available on the socket’s InputStream and immediately writes the data to the Serial Port’s OutputStream. It also maintains a single 1024-byte buffer that is (re)used for moving data from the socket to the serial port. SerialWriter’s job is just a bit less complicated than that of serialReader as it does not need to be concerned with receive time-outs and thresholds. If the remote server closes the network connection, the socket’s InputStream read methods return –1. When this occurs, running is set to false and the maintenance thread is interrupted. This will cause all three threads to eventually fall out of the run methods, and the application will terminate.
Conclusion The challenges encountered during the installation, initialization and configuration of the TINI for real-time embedded networked applications have
J. Adv. Res. Netw. Comm. Engi. 2015; 2(2): 1-26.
Akpan VA et al.
been critically examined with profound solutions. The article also presented a simple technique for installing Java communications API for accessing communication ports for direct interfacing to legacy systems which poses several challenges especially for TINI developers and hardware engineers. To establish a direct interface for communication between the TINI and the outside world; the article has proposed, implemented and demonstrated an efficient technique for the initialization and configuration of the TINI’s serial and Ethernet ports for real-time embedded network application. For completeness, the article also presents all the Java programs used to implement and demonstrate the techniques proposed herein. As a future work, the techniques proposed in this work can form the foundation for deploying the TINI for two projects, namely: 1) efficient networking of TINI for real-time online datalogging applications over Ethernet and serial communication interfaces; and 2) real-time embedded system for online pressure and temperature measurement, monitoring and control of fluid flow in a pipe.
References 1. Dallas Semiconductors Inc. (Maxim Integrated Products). Tiny Internet Interface (TINI) and IBUTTONS. Available from: http://www. ibutton.com. 2. Roussel G, Duris E. Java et Internet Concepts et Programmation. Vuibert, 2000. 3. Sun. Java Web Site-useful for updated documentation. Available from: http:// java.sun.com. 4. Shillewar SS. Using TINI point-to-point protocol (PPP). Oriental Journal of Computer Science & Technology 2011; 4(1): 153-58. 5. Loomis D. The TINI TM Specification and Developers Guide. Dallas Semiconductor Corporation, Addison Wesley, Upper Saddle River, New Jersey, U.S.A., 2001. 6. Williams I. The TINI internet interface: A tiny board with big possibilities. Dr. Dobb’s Journal Oct 2000: 1-7. Available from: http://collaboration.cmc.ec.gc.ca/science/rpn/b iblio/ddj/Website/articles.
Akpan VA et al.
14
APPENDIX A Java programs for the initialization and configuration of TINI & communications API for real-time embedded networked applications:
Program 0: Blinky program for testing the TINI import com.dalsemi.system.BitPort; class Blinky { public static void main(String[] args) { BitPort bp = new BitPort(BitPort.Port3Bit5); for (;;) { // Turn on LED bp.clear(); // Leave it on for 1/4 second try { Thread.sleep(500); } catch (InterruptedException ie) {} // Turn off LED bp.set(); // Leave it off for 1/4 second try { Thread.sleep(500); } catch (InterruptedException ie) {} } } }
Program 1: PortLister import java.util.Enumeration; import javax.comm.CommPortIdentifier; class PortLister { public static void main(String[] args) { Enumeration ports = CommPortIdentifier.getPortIdentifiers(); while (ports.hasMoreElements()) { System.out.println(((CommPortIdentifier)(ports.nextElement())).getName()); } } }
J. Adv. Res. Netw. Comm. Engi. 2015; 2(2): 1-26.
15
Akpan VA et al.
Program 2: CTSMonitor import java.io.IOException; import java.util.TooManyListenersException; import javax.comm.*; import com.dalsemi.system.TINIOS; class CTSMonitor implements SerialPortEventListener { SerialPort sp; CTSMonitor() throws NoSuchPortException, PortInUseException { // Specify a timeout value of at least a few seconds before failing on 'open' attempt. // This allows another process (probably slush) to relinquish port ownership. sp = (SerialPort) CommPortIdentifier.getPortIdentifier("serial0").open("CTSMonitor", 5000); try { // Enable the use of hardware hanshake lines for serial0 TINIOS.setRTSCTSFlowControlEnable(0, true); } catch (UnsupportedCommOperationException usce) { // Won't happen on serial0 } try { sp.addEventListener(this); sp.notifyOnCTS(true); } catch (TooManyListenersException tmle) {} } public void serialEvent(SerialPortEvent event) { switch (event.getEventType()) { case SerialPortEvent.CTS: System.out.println("CTS change, new value="+event.getNewValue()); break; default: } } public static void main(String[] args) { try { CTSMonitor cm = new CTSMonitor(); try { Thread.sleep(Long.MAX_VALUE);
J. Adv. Res. Netw. Comm. Engi. 2015; 2(2): 1-26.
Akpan VA et al.
16
} catch (InterruptedException ie) {} } catch (Exception e) { System.out.println(e.getMessage()); e.printStackTrace(); } } }
Program 3: TiniTerm import java.io.*; import javax.comm.*; import java.util.TooManyListenersException; import com.dalsemi.shell.server.SystemInputStream; class TiniTerm extends Thread implements SerialPortEventListener { private SerialPort sp; private InputStream sin; private OutputStream sout; private TiniTerm(String portName, int baudRate) throws NoSuchPortException, PortInUseException, UnsupportedCommOperationException, IOException { try { // Create SerialPort object for specified port sp = (SerialPort) CommPortIdentifier.getPortIdentifier(serial o).open("TiniTerm", 5000); // Configure port for 8 databits, 1 stop bit and no parity checks sp.setSerialPortParams(baudRate, SerialPort.DATABITS_8, SerialPort.STOPBITS_1, SerialPort.PARITY_NONE); } catch (NoSuchPortException nsp) { System.out.println("Specified serial port ("+portName+") does not exist"); throw nsp; } catch (PortInUseException piu) { System.out.println("Serial port "+portName+" is in use by another application"); throw piu; } catch (UnsupportedCommOperationException usc) { System.out.println("Unable to configure port:"+portName); throw usc;
J. Adv. Res. Netw. Comm. Engi. 2015; 2(2): 1-26.
17
Akpan VA et al.
} try { // Get input and output streams for serial data I/O sin = sp.getInputStream(); sout = sp.getOutputStream(); } catch (IOException ioe) { System.out.println("Unable to acquire I/O streams for port " + portName); throw ioe; } } public void run() { try { // Add 'this' object as a Serial port event listener // and request notification when receive data is available sp.addEventListener(this); sp.notifyOnDataAvailable(true); } catch (TooManyListenersException tml) { tml.printStackTrace(); System.exit(1); } // Return as soon as any bytes are available // (i.e. don't wait for line termination) ((SystemInputStream) System.in).setRawMode(true); while (true) { try { byte b = (byte) System.in.read(); if (b == (byte) '~') break; // Send the byte out the serial port sout.write(b); } catch (IOException ioe) { ioe.printStackTrace(); } } }
J. Adv. Res. Netw. Comm. Engi. 2015; 2(2): 1-26.
Akpan VA et al.
18
public void serialEvent(SerialPortEvent ev) { switch (ev.getEventType()) { case SerialPortEvent.DATA_AVAILABLE: try { int count = sin.available(); if (count > 0) { byte[] buf = new byte[count]; count = sin.read(buf, 0, count); System.out.write(buf, 0, count); } } catch (IOException ioe) { // Drain it } break; default: // Ignoring any unexpected events break; } } public static void main(String[] args) { if (args.length != 1) { System.out.println("Usage: java TiniTerm.tini data_rate"); System.exit(1); } try { TiniTerm term = new TiniTerm("serial0", Integer.parseInt(args[0])); term.start(); } catch (Exception e) { System.out.println(e.getMessage()); e.printStackTrace(); } } }
J. Adv. Res. Netw. Comm. Engi. 2015; 2(2): 1-26.
19
Akpan VA et al.
Program 4: TiniTerm’s run method // Return as soon as any bytes are available // (i.e. don't wait for line termination) ((SystemInputStream) System.in).setRawMode(true); while (true) { try { byte b = (byte) System.in.read(); if (b == (byte) '~') break; // Send the byte out the serial port sout.write(b); } catch (IOException ioe) { ioe.printStackTrace(); } } }
Program 5: SerialEvent import java.io.*; import java.util.*; import javax.comm.*; …….. public void serialEvent(SerialPortEvent event) { switch(event.getEventType()) { case SerialPortEvent.BI: case SerialPortEvent.OE: case SerialPortEvent.FE: case SerialPortEvent.PE: case SerialPortEvent.CD: case SerialPortEvent.CTS: case SerialPortEvent.DSR: case SerialPortEvent.RI: case SerialPortEvent.OUTPUT_BUFFER_EMPTY: break; case SerialPortEvent.DATA_AVAILABLE:
J. Adv. Res. Netw. Comm. Engi. 2015; 2(2): 1-26.
Akpan VA et al.
20
byte[] readBuffer = new byte[20]; try { while (inputStream.available() > 0) { int numBytes = inputStream.read(readBuffer); } System.out.print(new String(readBuffer)); } catch (IOException e) {} break; } } }
Program 6: SerialToEthernet import java.net.*; import java.io.*; import javax.comm.*; import com.dalsemi.system.TINIOS; class SerialToEthernet extends Thread { // Use a 1K buffer for serial data receive private static final int INPUT_BUF_LEN = 1024; // Serial port and associated streams private SerialPort sp; private InputStream spin; private OutputStream spout; // Socket and associated streams private Socket s; private InputStream sin; private OutputStream sout; private volatile boolean running = true; private int serialTotal = 0; private int networkTotal = 0; private SerialToEthernet(String server, int port, int speed) throws Exception { // Create and initialize serial port sp = (SerialPort) CommPortIdentifier.getPortIdentifier("serial0").open("SerialToEthernet", 5000);
J. Adv. Res. Netw. Comm. Engi. 2015; 2(2): 1-26.
21
Akpan VA et al.
// Enable the use of hardware hanshake lines for serial0 TINIOS.setRTSCTSFlowControlEnable(0, true); // 8 data bits, 1 stop bit, no parity sp.setSerialPortParams(speed, SerialPort.DATABITS_8, SerialPort.STOPBITS_1, SerialPort.PARITY_NONE); // Require RTS/CTS flow control from both serial channel endpoints sp.setFlowControlMode(SerialPort.FLOWCONTROL_RTSCTS_IN | SerialPort.FLOWCONTROL_RTSCTS_OUT); // Initialize serial port input and output streams spin = sp.getInputStream(); spout = sp.getOutputStream(); // Set a 100 millisecond receive timeout sp.enableReceiveTimeout(100); // Set the receive threshold equal to buffer length sp.enableReceiveThreshold(INPUT_BUF_LEN); // Connect to network server s = new Socket(server, port); sin = s.getInputStream(); sout = s.getOutputStream(); // Create and launch Serial -> Ethernet thread (new Thread(new SerialReader(this, INPUT_BUF_LEN))).start(); // Create and launch Ethernet -> Serial thread (new Thread(new SerialWriter(this))).start(); // Launch maintainence thread super.start(); } public void run() { while (running) { try { Thread.sleep(60000); } catch (InterruptedException ie) {} System.out.println("Bytes received from serial:"+serialTotal); System.out.println("Bytes received from network:"+networkTotal); } try {
J. Adv. Res. Netw. Comm. Engi. 2015; 2(2): 1-26.
Akpan VA et al.
22
// Close serial port and associated streams sp.close(); spin.close(); spout.close(); // Close socket and associated streams s.close(); sin.close(); sout.close(); } catch (IOException e) {} } private class SerialReader implements Runnable { private byte[] serBuf; private Thread maint; private SerialReader(Thread maint, int size) { serBuf = new byte[size]; this.maint = maint; } public void run() { while (running) { try { // Read all available data in serial input buffer int count = spin.read(serBuf, 0, serBuf.length); if (count > 0) { // Blast serial data to network server sout.write(serBuf, 0, count); serialTotal += count; } } catch (IOException ioe) { // Trouble communicating with server System.out.println(ioe.getMessage()); ioe.printStackTrace(); running = false; maint.interrupt(); break; }
J. Adv. Res. Netw. Comm. Engi. 2015; 2(2): 1-26.
23
Akpan VA et al.
} } } private class SerialWriter implements Runnable { private byte[] ethBuf = new byte[1024]; private Thread maint; private SerialWriter(Thread maint) { this.maint = maint; } public void run() { int count = 0; while (running) { try { // Read all available data from network server count = sin.read(ethBuf, 0, ethBuf.length); if (count > 0) { // Write data received from network out serial port spout.write(ethBuf, 0, count); networkTotal += count; } else if (count == -1) { running = false; maint.interrupt(); } } catch (IOException ioe) { System.out.println(ioe.getMessage()); ioe.printStackTrace(); running = false; maint.interrupt(); break; } } } } public static void main(String[] args) { if (args.length != 3) {
J. Adv. Res. Netw. Comm. Engi. 2015; 2(2): 1-26.
Akpan VA et al.
24
System.out.println("Usage: java SerialToEthernet server server_port ser_speed"); System.exit(1); } try { // Intialize serial port and connect to network server new SerialToEthernet(args[0], Integer.parseInt(args[1]), Integer.parseInt(args[2])); } catch (Exception e) { System.out.println(e.getMessage()); e.printStackTrace(); } } }
Program 7: SerialToEthernet’s run …….. private volatile boolean running = true; private int serialTotal = 0; private int networkTotal = 0; ……. public void run() { while (running) { try { Thread.sleep(60000); } catch (InterruptedException ie) {} System.out.println("Bytes received from serial:"+serialTotal); System.out.println("Bytes received from network:"+networkTotal); } try { // Close serial port and associated streams sp.close(); spin.close(); spout.close(); // Close socket and associated streams s.close(); sin.close();
J. Adv. Res. Netw. Comm. Engi. 2015; 2(2): 1-26.
25
Akpan VA et al.
sout.close(); } catch (IOException e) {} }
Program 8: SerialReader ……… private class SerialReader implements Runnable { private byte[] serBuf; private Thread maint; private SerialReader(Thread maint, int size) { serBuf = new byte[size]; this.maint = maint; } public void run() { while (running) { try { // Read all available data in serial input buffer int count = spin.read(serBuf, 0, serBuf.length); if (count > 0) { // Blast serial data to network server sout.write(serBuf, 0, count); serialTotal += count; } } catch (IOException ioe) { // Trouble communicating with server System.out.println(ioe.getMessage()); ioe.printStackTrace(); running = false; maint.interrupt(); break; } } } }
J. Adv. Res. Netw. Comm. Engi. 2015; 2(2): 1-26.
Akpan VA et al.
26
Program 9: SerialWriter …….. private class SerialWriter implements Runnable { private byte[] ethBuf = new byte[1024]; private Thread maint;
private SerialWriter(Thread maint) { this.maint = maint; } public void run() { int count = 0; while (running) { try { // Read all available data from network server count = sin.read(ethBuf, 0, ethBuf.length); if (count > 0) { // Write data received from network out serial port spout.write(ethBuf, 0, count); networkTotal += count; } else if (count == -1) { running = false; maint.interrupt(); } } catch (IOException ioe) { System.out.println(ioe.getMessage()); ioe.printStackTrace(); running = false; maint.interrupt(); break; } }
J. Adv. Res. Netw. Comm. Engi. 2015; 2(2): 1-26.