Serial communication software (API) | Kickoff

Serial communication software (API)

9 May

Serial communication software (API): Let’s try out the various serial ports and see how they behave and what the differ- ences are to the TINI API. There are essentially three classes we are concerned with when programming the TINI serial ports.

• The obvious class is the javax.comm.SerialPort class that we used in Chapter 3 to communicate with the PC’s serial port.

Figure 9-21: com.dalsemi.com

• If you need more direct control over the TINI serial ports, you can use the com.dalsemi.comm.TINISerialPort class but you will give up portability. Your programs must be recompiled to run on a PC and may not work if you have used any methods specific to TINI.

• In addition to the javax.comm.SerialPort class, you need to be able to select and configure various options that are specific to TINI’s serial ports. You will find a collection of methods in the com.dalsemi.system.TINIOS class. The methods that you will probably be most interested in are:

•  enableSerialPort1( boolean ) – This method enables serial1 (and in doing that it disables the external TINI 1-Wire bus). The state of serial1 is preserved in TINI memory; this method only needs to be executed once after the firmware is loaded or the heap has been cleared.

•  setExternalSerialPortAddress( portnumber, address ) – The method sets the address for the external serial ports, serial2 and serial3. You only need to use this method if you install serial2  or serial3 at a location other than the default address. The address is preserved in TINI memory, so this method only needs to be executed once after the firmware is loaded or the heap has been cleared.

• setExternalSerialPortEnable(  portnumber,  boolean  ) – Call this method to enable or disable serial2 or serial3. The state of these ports is preserved in TINI memory until the heap is cleared.

• setExternalSerialPortSearchEnable(  bootlean  ) – This method tells the TINI firmware to look for serial2 and serial3 at boot time. The state of this setting is preserved in TINI memory until the heap is cleared.

• setRTSCTSFlowControlEnable(  portnumber,  boolean  )  – This method enables hardware flow control on the specified serial port. TINI only supports hardware flow control on one serial port at a time.

• setSerialBootMessageState(  boolean  ) – The method enables or disables boot messages to serial0. The state of these ports is preserved in TINI memory until the heap is cleared.

• getExternalSerialPortAddress(  portnumber  ) – Returns the memory map address of the specified serial port.

• getExternalSerialPortEnable(  portnumber  ) – Returns a boolean value indicating if the specified serial port is enabled.

• getExternalSerialPortSearchEnable(  portnumber  ) – This method returns a boolean value indicating if the firmware will search for the specified serial port on boot.

• getRTSCTSFlowControlEnable(  portnumber  ) – Returns a boolean value that indicates if hardware flow control is enabled on the specified port.

These are straightforward as to their function. The TINI API provides some addi-tional detail on each of these methods. Remember that before you can use serial1 you must call this method:

TINIOS.enableSerialPort1( true );

And before you can use serial2 or serial3 you need to enable them and set their address if you have placed them at some other address in memory than the default (0×380020 – 0×38002F)

TINIOS.setExternalSerialPortAddress( 2, 0×3800020 );
TINIOS.setSerialPortEnable( 2, true );

A serial example
Serial0

To test serial0 we will start by using the same SerialLoopTest.java program that we used in Chapter 3, without modification. Put your loopback plug on serial0, the same as you used on your PC’s serial port. Remember to use a cable that does not connect DTR or you will need to remove the solder jumper on J1 on the bottom of your TINI socket board. If you are using a Dallas Semiconductor socketboard and you leave the J1 jumper connected and your serial cable has the DTR line wired, your TINI will reboot (and then hang as the DTR line is pulled low) as soon as you connect the loopback plug. Compile SerialLoopTest.java for TINI and FTP SerialLoopTest.tini to your TINI. The program takes one command line param- eter, the name of the serial port to test. The SerialLoopTest.java is listed below for your convenience, but refer to Chapter 3 for a more detailed discussion.

Listing 9-1: SerialLoopTest.java

import java.io.*;
import java.util.*;
import javax.comm.*;
import com.dalsemi.system.*;
import com.dalsemi.comm.*;
public class SerialLoopTest implements Runnable,
SerialPortEventListener {
static CommPortIdentifier portId;
static Enumeration portList;
static InputStream inputStream;
static OutputStream outputStream;
static SerialPort serialPort;
Thread readThread;
static String message2send = “Hello Port!”;
static String messagereceived;
static byte[] inbuf = new byte[20];
int i = 0;
static String portname;
public static void main(String[] args) {
// check out the command line args
if (args.length < 1) {
System.out.println( “Specify a port! (COM1 or /dev/ttyS0
or something).” );
return;
} else {
portname = args[0];
System.out.println( “Testing port: “ + portname );
}
try {
// Get the ID of this port
portId = CommPortIdentifier.getPortIdentifier(portname);

// Is it a serial port?
if (portId.getPortType() != CommPortIdentifier.PORT_SERIAL) {
System.out.println( “Port is not a serial port”);
return;
}
}
catch(NoSuchPortException e) {
System.out.println(“No Such Port!”);
return;
}
catch (Exception e) { System.out.println(e); }
SerialLoopTest tester = new SerialLoopTest();
}
public SerialLoopTest() {
try {
serialPort = (SerialPort) portId.open(“SimpleReadApp”, 2000);
}
catch(PortInUseException e) {
System.out.println(“Port In Use.”);
return;
}
catch (Exception e) {
System.out.println(e);
return;
}
try {
inputStream = serialPort.getInputStream();
outputStream = serialPort.getOutputStream();
}
catch (IOException e) { System.out.println(e); }
try {
serialPort.addEventListener(this);
}
catch (TooManyListenersException e) { System.out.println(e); }
// Turn on some notifiers so we can catch them with an event listener.
serialPort.notifyOnDataAvailable(true);
serialPort.notifyOnCTS(true);
serialPort.notifyOnDSR(true);
// We don’t really need to set the port parameters for a loop back test
// but if you did, this is how you would.
try {
serialPort.setSerialPortParams(19200,
SerialPort.DATABITS_8,
SerialPort.STOPBITS_1,
SerialPort.PARITY_NONE);
serialPort.setFlowControlMode(SerialPort.FLOWCONTROL_NONE);
}
catch (UnsupportedCommOperationException e) {
System.out.println(e);
}
readThread = new Thread(this);
readThread.start();
public void run() {
// send characters out the port
try {
}
catch (IOException e){ System.out.println(e); }
System.out.println(“Flipping  RTS…”);
serialPort.setRTS( ! serialPort.isRTS() );
System.out.println(“Flipping  DTR…”);
serialPort.setDTR( ! serialPort.isDTR() );
try { Thread.sleep(1000); } catch (Exception e) { }
serialPort.removeEventListener();
serialPort.close();
System.out.print( i + “ bytes read from port “ + portname + “. “ );
if (i<1) {
System.out.println( “Maybe something is not working.” );
}
else { System.out.println();
}
public void serialEvent(SerialPortEvent event) {
// determine whuch event has happened
switch(event.getEventType())                                          {
case SerialPortEvent.BI:
case SerialPortEvent.OE:
case SerialPortEvent.FE:
case SerialPortEvent.PE:
System.out.println(“Some status line changed.”);
break;
case SerialPortEvent.CD:
System.out.println(“Status line CD changed.”);
break;
case SerialPortEvent.CTS:
System.out.println(“Status line CTS changed.”);
break;
case SerialPortEvent.DSR:
System.out.println(“Status line DSR changed.”);
break;
case SerialPortEvent.RI:
System.out.println(“Status line RI changed.”);
break;
case  SerialPortEvent.OUTPUT_BUFFER_EMPTY:
System.out.println(“Buffer  Empty”);
break;
case  SerialPortEvent.DATA_AVAILABLE:
byte[] readBuffer = new byte[20];
try {
while (inputStream.available() > 0) {
int numBytes = inputStream.read(readBuffer);
i += numBytes;
messagereceived = new String(readBuffer);
System.out.println(“Read: “ + messagereceived);
}
}
}
catch (IOException e) { System.out.println(e); }
break;
}
}
}

Compile the program:

C:\> javac -bootclasspath                          %TINI_HOME%\bin\tiniclasses.jar
-d bin src\SerialLoopTest.java
C:\> java                                          -classpath c:\opt\tini1.02d\bin\tini.jar;. BuildDependency
-p                                                 %TINI_HOME%\bin\owapi_dependencies_TINI.jar
-f bin
-x                                                 %TINI_HOME%\bin\owapi_dep.txt
-o bin\SerialLoopTest.tini
-d %TINI_HOME%\bin\tini.db

Run the program on TINI and observe the results:
TINI />java SerialLoopTest.tini serial0
Testing port: serial0
[ Sat Jan 01 00:00:00 GMT 2000 ]   Message from System: Serial server stopped.
Flipping RTS…
Flipping DTR…
Read: Hello Port!
11 bytes read from port serial0.
TINI />
[ Sat Jan 01 00:00:00 GMT 2000 ]   Message from System: Serial server started.

Notice the output. When we access serial0, the TINI OS automatically stops the serial server and then restarts it when we are done. Also notice that we didn’t receive the RTS and DTR events as we did in Chapter 3. This is simply because serial0 does not support hardware flow control.

Let’s try a real example where we send meaningful characters to a serial device and read back meaningful characters. We will be reading data from a digital multimeter. This program is not much more complicated, but it does show more of the methods for controlling the serial port. The meter expects us to talk to it at 2400 baud using 7 data bits, 2 stop bits and no parity (we know this because we looked in the manual for the meter). To have the meter take a measurement and send back the data we first send it a “D”. The meter then replies back with 14 bytes of ASCII information (which is more or less what is on the meter display). Also, because the meter is configured as a DCE and so is serial0, we will need a null modem adapter.

Listing 9-2: MeterReader.java

import java.io.*;
import java.util.*;
import javax.comm.*;
import com.dalsemi.system.*;
import com.dalsemi.comm.*;
public class MeterReader {
static CommPortIdentifier portId;
static SerialPort serialPort;
static String portname;
//static Enumeration portList;
static InputStream inputStream;
static OutputStream outputStream;
static String message2send = “D\r”;
static String messagereceived;
public static void main(String[] args) {
// check out the command line args
if (args.length < 1) {
System.out.println(   “Specify   a   port!   (COM1,   /dev/ttyS0   or   something).”   );
return;
} else {
portname = args[0];
System.out.println( “MeterReader. Using “ + portname );
}
int times=1; // number of readings to take
if (args.length>1 ) {
times = (byte) Integer.valueOf(args[1]).intValue();
}
// Is this a valid Serial port?
try {
// Get the ID of this port
portId = CommPortIdentifier.getPortIdentifier(portname);
// Is it a serial port?
if (portId.getPortType() != CommPortIdentifier.PORT_SERIAL) {
System.out.println( “Port is not a serial port”);
return;
}
}
catch(NoSuchPortException e)
{
System.out.println(“No Such Port!”);
return;
}
catch (Exception e) { System.out.println(e); }
// Open the port, set parameters
System.out.println( “Configuring port…” );
try {
serialPort = (SerialPort) portId.open(“MeterReader”, 1000);
serialPort.setSerialPortParams(2400,
SerialPort.DATABITS_7,
SerialPort.STOPBITS_2,
SerialPort.PARITY_NONE);
serialPort.setFlowControlMode(SerialPort.FLOWCONTROL_NONE);
}
catch(PortInUseException e) {
System.out.println(“Port In Use.”);
return;
}
catch (UnsupportedCommOperationException e) {
System.out.println(“Port option unsupported.”);
}
catch (Exception e) {
System.out.println(e);
return;
}
// Set input & output streams
try {
inputStream = serialPort.getInputStream();
outputStream = serialPort.getOutputStream();
}
catch (IOException e) { System.out.println(e); }
System.out.println( “Reading …” );
byte[] readBuffer = new byte[20];
int numBytes = 0;
for( int i = 1; i<=times; i++ ) {
// Send the command text
try {
outputStream.write( message2send.getBytes() );
Thread.sleep(500);
numBytes = inputStream.read(readBuffer);
messagereceived = new String(readBuffer);
System.out.println( “Meter:(“ + numBytes + “) “ +
messagereceived);
}
catch (IOException e) { System.out.println(e); }
catch (Exception e) { System.out.println(e); }
}
serialPort.close();
}
}

Notice that we need to set the serial port to the proper parameters (baud rate, databits, stopbits, and parity). While some devices are fairly tolerant of miss-set stop bits, the receiving UART will not be able to synchronize with the serial data if the baud rate is improperly set.

serialPort = (SerialPort) portId.open(“MeterReader”, 1000);

serialPort.setSerialPortParams(2400,
SerialPort.DATABITS_7,
SerialPort.STOPBITS_2,
SerialPort.PARITY_NONE);
serialPort.setFlowControlMode(SerialPort.FLOWCONTROL_NONE);

The program loops for the specified number of readings, each time sending a “D” to the meter and then reading back the reply from the meter.

for( int i = 1; i<=times; i++ ) {
// Send the command text
try {
outputStream.write( message2send.getBytes() );
Thread.sleep(500);
numBytes = inputStream.read(readBuffer);
messagereceived = new String(readBuffer);
System.out.println( “Meter:(“ + numBytes + “) “ + messagereceived);
}
catch (IOException e) { System.out.println(e); }
catch (Exception e) { System.out.println(e); }
}

Compile the program:

C:\> javac -bootclasspath     %TINI_HOME%\bin\tiniclasses.jar
-d bin src\MeterReader.java
C:\> java                     -classpath c:\opt\tini1.02d\bin\tini.jar;. BuildDependency
-p                            %TINI_HOME%\bin\owapi_dependencies_TINI.jar
-f bin
-x                            %TINI_HOME%\bin\owapi_dep.txt
-o bin\MeterReader.tini
-d %TINI_HOME%\bin\tini.db

then FTP it to your TINI. In this case we need to stop the serial server before we run the program. If we don’t, then it won’t work (when the program sends the first “D” to the meter, the TINI OS sees outgoing data so it stops the serial server but then that “D” is lost so the meter never replies with data and our program waits forever). The program takes two command line parameters: the name of the serial port that the meter is connected to and the number of readings to take. Run the program.

TINI /> downserver -s
Warning:   This will disconnect users on specified servers.

OK to proceed? (Y/N): y
[ Sat Jan 01 00:00:00 GMT 2000 ]   Message from System: Serial server stopped.

TINI /> java MeterReader.tini serial0 5
MeterReader. Using serial0
Configuring port…
Reading …
Meter:(14) DC                                                                            05.09                                                        V
Meter:(14) DC                                                                            05.10                                                        V
Meter:(14) DC                                                                            05.10                                                        V
Meter:(14) DC                                                                            05.09                                                        V
Meter:(14) DC                                                                            05.09                                                        V
TINI /> startserver -s
[ Sat Jan 01 00:00:00 GMT 2000 ]   Message from System: Serial server started.

The program took five readings of 14 bytes each. In this case we were reading a DC voltage of 5.09 volts (the output of the TINI power supply). Notice we restarted the serial server when we were done.

Serial1
We can run the same two examples on serial1 that we just tested on serial0. To do this we must first add a line driver to serial1, add the optional 1K resistor between the EN2480 pin on the TINI stick and ground to disable the 1-Wire driver, and add a “fake” DTR signal to the serial1 connector. This particular meter (as with many serial devices) expects to see the DTR line high before it will communicate with a com- puter. So we need to connect pin 4 of the serial1 to Vdd (basically we are saying to any serial device that TINI is always ready to communicate). For the serial line level shifter we used a MAX232 but just about any serial level shifter should do. We chose this one because it does not require external capacitors for the charge pump (to provide ±10 volts).

You should be able to rerun both SerialLoopTest.tini and MeterReader.tini on serial1 with the exact same results. You will not need to worry about stopping the serial server for this port but you must enable serial1 first. Since the same CPU pins control both the external 1-Wire bus and the serial1 port, we will need to indicate to TINI that we want to use the serial port and not the 1-Wire bus. You can do this by adding the following line to both programs (someplace in the program before actually trying to open the serial port):

TINIOS.enableSerialPort1( true );

Before you modify the programs to enable serial1, try running either program on TINI and specifying serial1 just for fun. You should see the exception java.io.IOException: Could not write to serial port.

Since the state of the serial1 port enable is preserved in TINI memory, we can write a separate program that enables and disables serial1 (and even serial2 and serial3 if we need them) so that our original program does not have to be modified. Why would we want to do this? Without these TINI specific additions to enable serial1 (and we will need similar ones for serial2 and serial3) our programs so far have been 100% non- TINI specific. The MeterReader.java and SerialLoopTest.java program will run on a PC just as well as on TINI by telling it to read from COM1 (Windows) or \dev\ttyS0 (Linux).

Here is a program that runs on TINI that changes the serial1, serial2 and serial3 settings in TINI memory so that you don’t need to modify your programs to enable these ports.

Listing 9-3: serialports.java

import java.io.*;
import java.util.*;
import javax.comm.*;
import com.dalsemi.comm.*;
import com.dalsemi.system.*;
import com.dalsemi.onewire.*;
import  com.dalsemi.onewire.adapter.*;
public class serialports {
static CommPortIdentifier portId;
static SerialPort serialPort;
static DSPortAdapter myPortAdapter = null;
// Tell me the command line options
public static void usage() {
System.out.println( “serialports -enable [123] -disable [123] “ );
System.out.println( “                                                                    -search -nosearch -query” );
}
// Query the serial ports, report what we find
public static void query() {
boolean isonewire = false;
// The only way to check if serial1 enabled is to open it and
// catch an exception if there is one.
System.out.print( “serial1: “ );
try {
myPortAdapter =

OneWireAccessProvider.getAdapter(“TINIExternalAdapter”,
“serial1”);
myPortAdapter.freePort();
System.out.println( “enabled for 1-wire communication” );
isonewire=true;
}
catch (Exception e) {
System.out.println( “disabled for 1-wire communication” );
isonewire=false;
}
if (!isonewire) {
System.out.print( “                                            “ );
try {
portId = CommPortIdentifier.getPortIdentifier(“serial1”);
serialPort = (SerialPort) portId.open(“port enabler”, 1000);
serialPort.close();
System.out.println( “enabled for serial communication” );
}
catch (Exception e) {
System.out.println( “disabled for serial communication” );
}
}
// Checking serial2 and 3 is easy
System.out.println( “serial2: “
+ (TINIOS.getExternalSerialPortEnable(2) ? “enabled” : “disabled”)
+ “, address 0x”
+ Integer.toHexString(TINIOS.getExternalSerialPortAddress(2)) );
System.out.println( “serial3: “
+ (TINIOS.getExternalSerialPortEnable(3) ? “enabled” : “disabled”)
+ “, address 0x”
+
Integer.toHexString(TINIOS.getExternalSerialPortAddress(3)) );
System.out.println( “Search for ports on boot “
+   (TINIOS.getExternalSerialPortSearchEnable()  ?  “enabled”   :  “disabled”  )  );
}
// set if TINI should search for ports on boot or not
public static void searchOnBoot( boolean search ) {
System.out.println( “search on boot “ + (search ? “enabled” :
TINIOS.setExternalSerialPortSearchEnable(search);
}
// enable/disable serial ports.
public static void enableSerial( char port, boolean state ) {

switch (port) {
case ‘1’:
System.out.println(  (state  ?  “enabling”  :  “disabling”)   +  “  serial1”);
TINIOS.enableSerialPort1( state );
break;
case ‘2’:
System.out.println(  (state  ?  “enabling”  :  “disabling”)   +  “  serial2”);
TINIOS.setExternalSerialPortEnable(2,state);
break;
case ‘3’:
System.out.println(  (state  ?  “enabling”  :  “disabling”)   +  “  serial3”);
TINIOS.setExternalSerialPortEnable(3,state);
break;
default:
System.err.println(“invalid port” + port);
break;
}
}
public static void main(String[] args) {
String arg;
char flag;
String ports_on=””, ports_off=””;
int i=0;
// Check out all of the comamnd line args and process each as we
// find them.
while (i < args.length && args[i].startsWith(“-”)) {
arg = args[i++];
if (arg.startsWith(“-s”)) {                                                      // s for search
searchOnBoot(true);
}
else if (arg.startsWith(“-n”)) {                                                 // n for nosearch
searchOnBoot(false);
}
else if (arg.startsWith(“-q”)) {                                                 // q for query
query();
}
else if (arg.startsWith(“-e”)) {                                                 // e for enable
if (i < args.length) {
// the the port numbers if any
ports_on = args[i++];
for (int j = 0; j < ports_on.length(); j++) {
flag = ports_on.charAt(j);
enableSerial( flag, true );
}
}
else {
System.err.println(“-enable requires a port”);
}
}
else if (arg.startsWith(“-d”)) {                   // d for disable
if (i < args.length) {
// the the port numbers if any
ports_off = args[i++];
for (int j = 0; j < ports_off.length(); j++) {
flag = ports_off.charAt(j);
enableSerial( flag, false );
}
}
else {
System.err.println(“-enable requires a port”);
}
}
else {
System.out.println( “Don’t understand “ + arg );
}
}
}
}

This TINI utility program takes several possible parameters:

-e [1][2][3]  to enable any of the serial ports 1, 2 or 3 (or any combination).
-d [1][2][3]  to disable any of the serial ports 1, 2, or 3 (or any
combination of ports).
-s                                                                                to tell TINI to search for serial2 and 3 on boot.
-n                                                                                to tell TINI not to search for serial2 and 3 on boot.
-query                                                                            to query the current settings.

As you study the program, you will see that main() method simply parses the command line and calls the appropriate methods depending on what is specified. There are four helper methods: usage(), query(), searchOnBoot( boolean state ), and enableSerial( char port, Boolean state ). The usage() method simply reports the command line options if you don’t provide any. The query() method reports back what TINI thinks the current serial port settings are. The searchOnBoot( boolean state ) method either enables or disables searching for serial2 and 3 on boot. The enableSerial( char port, Boolean state ) method enables or disables the specified serial port. All of this is straightforward use of the methods in the com.dalsemi.system.TINIOS class with the exception of how we determine if serial1 is enabled or not. The com.dalsemi.system.TINIOS class, does not provide a method for querying the status of serial1 but we know that if it is not enabled we get an exception when we try to open it. Actually there are two ways to get an exception: opening serial1 for 1-Wire communication when it is enabled for serial communication, or opening and accessing it as a serial port when it is disabled for 1-Wire communication. The method first tries to open serial1 as a 1-Wire port adapter. If we succeed, we know serial is not enabled as a serial port. If that method does cause an exception, then we know serial1 is enabled for serial port communica- tion.

Compile this program:
C:\> javac -bootclasspath                                                                 %TINI_HOME%\bin\tiniclasses.jar
-d bin src\serialports.java
C:\> java                                                                                 -classpath c:\opt\tini1.02d\bin\tini.jar;. BuildDependency
-p                                                                                        %TINI_HOME%\bin\owapi_dependencies_TINI.jar
-f bin
-x                                                                                        %TINI_HOME%\bin\owapi_dep.txt
-o bin\serialports.tini
-d %TINI_HOME%\bin\tini.db

So now we are ready to test out serial1. Put the loopback plug on serial1 and try the SerialLoopTest.tini and MeterReader.tini programs.

TINI /> java SerialLoopTest.tini serial1
Testing port: serial1
java.io.IOException: Could not write to serial port
Flipping RTS…
Flipping DTR…
0 bytes read from port serial1. Maybe something is not working.
TINI />

See, it didn’t work. We didn’t enable serial1 for serial port communications. Run the serialport.tini program to enable serial1 and try again.

TINI /> java serialports.tini -e 1
enabling serial1
TINI /> java serialports.tini -q
serial1: disabled for 1-wire communication
enabled for serial communication
serial2: disabled, address 0×380028
serial3: disabled, address 0×380020
Search for ports on boot enabled
TINI />

With the serial port now enabled we should be successful running both SerialLooptest.tini and MeterReader.tini and telling them to read from serial1.

TINI /> java SerialLoopTest.tini serial1
Testing port: serial1
Flipping RTS…
Flipping DTR…

Read: Hello Port!
11 bytes read from port serial1.
TINI />
TINI /> java MeterReader.tini serial1 5
MeterReader. Using serial1
Configuring port…
Reading …
Meter:(14) DC                             05.03   V
Meter:(14) DC                             05.03   V
Meter:(14) DC                             05.03   V
Meter:(14) DC                             05.02   V
Meter:(14) DC                             05.03   V
TINI />

No surprises: the same results as with accessing serial0, and the best part is that we didn’t need to modify our original program to use serial1.

328-Serial2 and serial3

Random Posts

Comments are closed.