ZOIS *
Technical Notes
ZOIS Technical Note TN-2009-10-01.
Author and Audience
A small program was written for a Mobile Phone using
the Java programming language as a test piece. This TN describes the
experience. A general knowledge of Java and UNIX style operating
systems is assumed. Written by Martin Sullivan[1],
ZOIS Limited, Cockermouth.
Abstract
It was decided to explore the programming of mobile devices and in
particular Mobile Phones using the widely available J2ME platform[2]. An existing Clock Application[3] designed to run on Java-enabled browsers was
chosen as a test piece. Problems were noted in the use of floating
point variables, multi-tasking and Internet communications, which were
overcome and are explained.
Introduction
|
| A screenshot of the ZoisClock midlet in the J2ME mobile phone emulator |
Java Virtual Machines (JVM) are now ubiquitous on Mobile Phones and machines of that ilk. They allow pre-compiled Java bytecode programs to run on these restricted platforms with a limit storage capacity and some Internet connectivity. It is thus possible to program the Mobile Phone to perform a wide variety of potentially distributed tasks. To practically explore how this was done a number a small program were written, with one in particular demonstrating a number of pit-falls that need to be know about if more complexed task-specific systems are to be written. The program written for this was a clock (ZoisClock), for the Author had already written just such a program as an Applet and was thus familiar with the source code. It would also give an indication of how difficult porting an existing Application would be.
In addition to simply displaying the time the ZoisClock gets the time from a time server remotely using the Internet and stores it as offset with respect to the Phones internal time.
The clock also provided a number of challenges both to be
explored on this limited platform.
Materials and Platform
The basic development platform was Emacs on Linux (the author is
over 50). The Java thus produced was compiled with the J2ME Wireless
Toolkit[4], rather than using odd libraries and a
complicated class-path. The J2ME WTK is documented elsewhere but
contains all that is necessary to produce working packaged Midlets as
such Java Byte Code programs for Mobile platforms are called. It also
contains an number of Phone emulators that allow testing and
experimentation of code without the necessity of physically installing
it on a Phone.
Method
Basic J2ME (as found on all J2ME Phones) conforms to the Mobile Information Device Profile (MIDP) 1.0[5] and Connected Limited Device Configuration (CLDC) 1.0[5] does not have floating-point types, a conclusion which is both strange and non-obvious, since even 70's-era programmable calculators had the ability to deal with numbers in the continuum. That needs to be re-iterated, Java on Mobile Phones doesn't have Floating Point. A Fixed-point decimal version of sine was therefore written following the algorithm found in a on-line Java based CS course[7].
The necessary calculations were performed in Java Here is the code use for calculating sine and cosine. The sine
function uses an algorithm that calculates successive terms in a
Taylor series based on the previous term. The calculation stops when
the term returns a value which is integer 0 in this system (actually
less than plus/minus 0.001 in real terms). Cosine is easily calculated
in terms of sine.
The ZoisClock midlet uses the Internet to ensure that the time it
returns is accurate. It uses the Phones internal clock and an offset
to calculate the true time. This fragment uses an RFC 686 time service
for simplicity and it is realised that this is now very much
depreciated in favour of NTP. The following is an idealise fragment,
the real code contains timeout handling, which here has been elided
for clarity.
The above fragment naively assumes no consequence for a protracted
Internet connection. In reality the acquisition of time from the
Internet requires that this code be run with in a separate thread of
control with an suitable mechanism that allows timeouts, lest this
thread run for ever. In the ZoisClock this is achieved by having two
threads using In normal Java programming environments such thread programming
would be relatively straight forward. The threads would coordinate
using In the above the This all makes for messy code with a variety of codependencies
between the two threads and the main body of the program. It appears
to work however, in a series of not very full artificial tests and
live.
Once an offset to the Phones internal clock has been acquired it
can be stored for future use, so that the ZoisClock is always
displaying an accurate time without reference to the Internet. The
J2ME Record Management Store system is a 'slotted' store
associated with a single Midlet (although that has evolved). The
individual records are enumerated and thus relatively sophisticated
list and tree like structures can be built, together with what looks
like an ISAM like direct access capability. For the ZoisClock however
a single record with a The chief finding when using this record store is that the initial,
the first record is enumerated as '1'. This was counter intuitive, for
most modern programming languages start array-like structures with
index '0'.
Debugging can proceed symbolically (using jdb) running the following
command:
As ever, the Internet is your friend, The User Interface (UI) Class
documentation is found on the Sun web-site[8] and a
restrictive set of OS Classes (CLDC 1.0) are found there[9].
There are many different platforms that constitute J2ME (now
apparently to be called JME) this has resulted in sites such as
MobileZoo[10] which aims to provide a break-down of
which phones do what. A set of related Midlets would result which
would have different levels of functionality and be targeted at
various phones. It would seem safe to assume, however, that one should
code to the absolute lowest common-denominator of platform and to use
'features' sparingly. A three year old S40 based 'smart' phone (Nokia
8260) only supports CLDC 1.0, with, of course a whole bunch of Nokia's
own extensions.
That there was no floating point representation was found out only
gradually, for the later versions of J2ME (MSA 1.0 for example) will
allow float/double, and thus programs using them will work in the
emulator. You'll also get quite a way down the build phase before you
see a whinge about floating point constants not being allowed. The
J2ME (CLDC 1.0) class java.lang.Math gives some clues, for it doesn't
have things like trigonometry and square-root in it. This leads you to
write buggy versions of sine and cosine functions before the penny
drops. It's worth noting that Java traditionally emulated Floating
Point operations, ignoring any standard hardware (and was therefore
slow)[11].
As the lack of floating point and accompanying mathematics has
caused problems to others who have therefore produced a floating point
Class (complete with a set of attendant mathematical functions). MathFP
seems to be the widest known[12]. It was
decided, however to implement a private solution which addressed only
the issues found in the ZoisClock.
After being challenged by a family member, Internet connectivity in
the form of a function button was added. This caused the Midlet to go
off and get the Internet time. A little calculation later and this
caused the displayed time to be adjusted (the real clock in the phone
could not be altered but the offset could be stored). Since the
acquisition of information from the Internet can take some time this
must proceed within a separate thread of control. Further to allow a
time-out, a another independent thread of control must be used. The
production of this new functionality proved challenging, the
java.lang.Thread package for this version of Java doesn't allow
cancellation, interrupt or stop. It was therefore necessary to have a
time-out thread which tried to force an I/O error to get an exception
thrown in the thread which does the actual network-read.
The clock was installed on the ancient Siemens SL55 Phone and found
to work after a fashion. So the conservative coding to old standards
was vindicated.
To get your version of the ZoisClock, download the following JAD and
JAR files into your Phone using either an off-line method such as
USB, Bluetooth or InfraRed or directly into the Phone using your
favourite mobile browser. Be warned that you'll almost certainly be
charged for the later, and some Phones will only support this method
(for example Samsung's). The whole thing is highly make and model
dependent so consult your documentation. Tradition has it that you
need both files, but in most instances the JAR is all that is
required. The ZoisClock Midlet has not been signed or obfuscated:
The format of JAD and JAR files, themselves, are explained
elsewhere[13].
References found in this section, and in particular the HTML links
were correct at time of writing (2009-12-01).
$Date: 2010/02/22 16:37:29 $
int,
with a fixed point notation that tripped over precision, anything more
than 3 gives problems with integer overflow (1000 == 1.0). This leads
to the following necessary assumptions Java int is really
16 bits (on J2ME MIDP 1.0 anyhow) and overflows are silently ignored
(including possibly setting the sign-bit). It's all very PDP-8
assembler mid-70s with a Object Oriented high-level veneer (
// Math class seems to be a problem on MIDP 1.0/CLDC 1.0, not only
// no PI, but also no sin() or cos(). And woopse, we don't have float
// nor double either, so lets do everything in fixed point decimal, 1000
// == 1.0 &c. Yes, I know about MathFP, but this is an intellectual
// challenge I can't ignore.
int sin (int x) { // compute the Taylor series approximation
x %= (2 * PI); // PI declared elsewhere to be 3141
int term = 1000; // ith term = x^i / i!
int sum = 0; // sum of first i terms in taylor series
for (int i = 1; term != 0; i++) {
term = ((term * x) / i) / 1000; // has to be phrased
// like this to preserve
// precision.
if (i % 4 == 1)
sum += term;
if (i % 4 == 3)
sum -= term;
} // for
return (sum);
} // sin
int cos (int x) {
x %= (2 * PI);
return (sin ((PI / 2) - x));
} // cos
long ticks = 0L;
int buff[] = new int[4];
int ix;
StreamConnection connection = null;
InputStream inputStream = null;
DataInputStream dataInputStream = null;
String timeServer = null
try {
timeServer = new String (getAppProperty ("TimeServer"));
} catch (Exception e) {}
// provide 'time' even if nobody else does
if (timeServer == null)
timeServer = new String ("home.zois.co.uk");
try {
connection = (StreamConnection) Connector.open ("socket://" +
timeServer +
":37",
Connector.READ, true);
// RFC 868, 'cos it's easy and it's TCP.
// Yep, should do it using NTP/SNTP, but
// so what ...
inputStream = connection.openInputStream ();
dataInputStream = new DataInputStream (inputStream);
// A 32bit unsigned number in NBO (most
// significant byte arrives first). We
// have to be circumspect about sign ...
for (ix = 0; ix < buff.length; ix++)
buff[buff.length - ix - 1] =
dataInputStream.readUnsignedByte ();
// for 32bit NBO read buff.lenght is 4
dataInputStream.close ();
inputStream.close ();
connection.close ();
} catch (Exception e) {}
for (ix = 0; ix < buff.length; ix++)
ticks += ((long) buff[ix]) << (ix * 8);
if (ticks != 0L) // got time
adjust = ticks
- SINCE_1900
- (System.currentTimeMillis () / 1000L);
// The following lines adjust the display
// suitably.
screen.notify ("Adj: " +
(adjust - screen.getAdjust ()) +
"s");
screen.setAdjust (adjust);
Thread. The first thread is relatively
conventional and, in essence, jackets the above code. The second
thread is started contemporaneously and executes
Tread.sleep to implement a delay, then forcing the first
thread to close.
Thread.cancel, the first cancelling the second when
it completed retrieving the time, the second cancelling the first
should a time-out occur. In this environment, however,
Thread.cancel is unavailable and threads are required to
cooperate with each other through the medium of intermediate common
variables. They can yield control through
Thread.yield calls. Since one of the threads will be running
independently, awaiting a response from the Internet at large, and not
able to periodically monitor some variable, it was decided to terminate
it by forcing an I/O exception artificially. The second timeout thread
then looks something like this:
public void run () {
for (int ix = 0; ix < timeout; ix++) {
try {
this.sleep (1);
} catch (InterruptedException ie) {
try {
connection.close (); // Force an IOException elsewhere
} catch (Exception e) {} // ignore it here.
} // try
if (timeout == 0)
return; // timeout cancelled
} // for
try {
connection.close (); // force an IOException, but ignore
// it here, right?
} catch (Exception e) {}
} // run
timeout variable is shared between the two
threads and can be set to zero to cause the timeout thread to
terminate early.
long clock adjustment was all that
was required:
void writeAdjustment (RecordStore adjustStore, long adjust) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
DataOutputStream outputStream = new DataOutputStream(baos);
try {
outputStream.writeLong (adjust); // Push the score into a
// byte array.
byte[] b = baos.toByteArray();
if (adjustStore.getNumRecords () < 1) // new store
adjustStore.addRecord (b, 0, b.length); // add
else
adjustStore.setRecord (1, b, 0, b.length); // update
} catch (Exception e) {
}
} // writeAdjustment
long readAdjustment (RecordStore adjustStore) {
if (adjustStore == null)
return (0L);
long suggested = 0L;
try {
ByteArrayInputStream bais =
new ByteArrayInputStream (adjustStore.getRecord (1));
DataInputStream inputStream = new DataInputStream (bais);
suggested = inputStream.readLong ();
} catch (Exception e) {
}
return (suggested);
} // readAdjustment
having run
jdb -connect com.sun.jdi.SocketAttach:hostname=localhost,port=5000
Project > Debug in ktoolbar, as the
controlling User Interface of the J2MEWTK is called. This seems to be
fragile and a lot of time is spent stumbling around in the debugger
trying to work out what it's doing, nothing new there then. Eventually
external test-harnesses and println were used to bag the
last faults, integer overflows, traditionally not something that
symbolic debuggers have excelled at.
Discussion
References
Break Frame *
E-mail Webmaster *
Copyright