M I D l e t P a s c a l
Advanced features

Custom library units

MIDletPascal does not provide functions that access the complete MIDP API. However, if you need to call a MIDP API function that is not supported by MIDletPascal, you don't need to wait for the next version of MIDletPascal. You can extend the MIDletPascal functionality on your own by creating a library unit.

A library unit is used from your MIDletPascal program just like any other unit. To use the unit, write


uses unit_name;

at the beginning of your program. To call a function or procedure that is located inside the unit, write

procedure_name(parameters...)

If more units define the same procedure_name, use the following syntax to resolve ambiguity:

unit_name.procedure_name(parameters...)

The differences between library units and regular units are the following:

·library units are written in Java, not MIDletPascal  
·library units reside in {app_install_path}\Libs directory, not your project's directory  
·library units can only contain functions and procedures, not types or variables  
·functions and procedures that reside in library units can only work with the following data types: integer, string, image, recordStore and command  

So let's write a simple library unit. You must have Sun Java Development Kit and Sun Wireless Toolkit installed on your computer to be able to compile the library units (both can be freely downloaded from java.sun.com). Let JDK register environment variables during the install process. In the following code we will assume that Wireless Toolkit is installed in c:\wtk21\ directory.

Create the directory for your library unit, c:\MyLib. In this directory, create three subdirectories: src\, tmpclasses\ and classes\. In subdirectory src\ create the file Lib_mylib.java with the following contents (Java is case-sensitive unlike Pascal!):


// library unit class MUST NOT be contained in any package!!!

// class name must be prefixed with Lib_ and all letters except 
// the starting L must be lowercase
public class Lib_mylib
{
  // all functions must be static, and all letters in the
  // function name must be lowercase
  public static int square(int val)
  {
    return val * val;
  }

  public static int count_numbers(String text)
  {
    int count = 0;
    int i;
    for(i = 0; i < text.length(); i++)
    {
      if ((text.charAt(i) >= '0') && (text.charAt(i) <= '9'))
        count ++;
    }
    return count;
  }
}



To compile the file, open command prompt window, enter the directory c:\MyLib\src, and type (in a single line):

C:\MyLib\src>javac -g:none -classpath 
c:\MyLib\tmpclasses;c:\WTK21\lib\midpapi20.jar;c:\WTK21\lib\cldcapi10.jar
-d c:\MyLib\tmpclasses Lib_mylib.java

The position to c:\MyLib directory and enter the following command:

C:\MyLib>c:\WTK21\bin\preverify.exe -classpath          c:\MyLib\tmpclasses;c:\WTK21\lib\midpapi20.jar;c:\WTK21\lib\cldcapi11.jar 
-d c:\MyLib\classes Lib_mylib

The file Lib_mylib.class found in c:\MyLib\classes directory is a library unit file that will be used by MIDletPascal. Copy in to c:\Program Files\MIDletPascal2\Libs\ directory.

Now you can use the library unit in your MIDletPascal project:


uses MyLib;

var idx : integer;
begin
  ShowForm;
  
  idx := FormAddString('5 squared is: ' + MyLib.square(5));
  
  idx := FormAddString('There are ' + 
                       MyLib.count_numbers('a0b2c') + 
                       ' numbers in ''a0b2c'' ');
  Delay(5000);
end.




Let's say that you want to create a library unit with the functions vibrate and flash_backlight. MIDP API functions for vibrating and flashing are called on the MIDlet's Display object. To retrieve the Display object from your library unit, use a little trick: create another file in c:\MyLib\src directory, name it FW.java, and enter the following code into the new file:

import javax.microedition.midlet.*;  
import javax.microedition.lcdui.*;
  
public class FW extends MIDlet
{
  public static FW fw; // the active MIDlet object
  public Display display; // the current display object
  public static Displayable CD; // the current Displayable object

  public void startApp()
  {}

  public void pauseApp()
  {}

  public void destroyApp(boolean unconditional)
  {}
}




Then add the two functions into Lib_mylib.java:

public static void vibrate(int duration)
{
  FW.fw.display.vibrate(duration);
}

public static void flash_backlight(int duration)
{
  FW.fw.display.flashBacklight(duration);
}



Compile the two files:

C:\MyLib\src>javac -g:none -classpath 
c:\MyLib\tmpclasses;c:\WTK21\lib\midpapi20.jar;c:\WTK21\lib\cldcapi10.jar
-d c:\MyLib\tmpclasses FW.java

C:\MyLib\src>javac -g:none -classpath 
c:\MyLib\tmpclasses;c:\WTK21\lib\midpapi20.jar;c:\WTK21\lib\cldcapi10.jar
-d c:\MyLib\tmpclasses Lib_mylib.java

And preverify the library unit file:

C:\MyLib>c:\WTK21\bin\preverify.exe -classpath          c:\MyLib\tmpclasses;c:\WTK21\lib\midpapi20.jar;c:\WTK21\lib\cldcapi11.jar 
-d c:\MyLib\classes Lib_mylib

Once again, copy the Lib_mylib.class from c:\MyLib\classes\ directory into
c:\Program Files\MIDletPascal2\Libs directory.

Now you are ready to use the new functions in your MIDletPascal program:


uses MyLib;

var idx : integer;
begin
  MyLib.vibrate(1000);
  MyLib.flash_backlight(1000);
  Delay(5000);
end.



Final note: functions vibrate and flashBacklight are MIDP2.0 compatible. Older phones that support MIDP1.0 will crash if you try to execute the sample program. To avoid the possible crash, add exception handler to your library unit functions:

public static void vibrate(int duration)
{
  try
  {
    FW.fw.display.vibrate(duration);
  } catch (Exception e) { }
}

public static void flash_backlight(int duration)
{
  try
  {
    FW.fw.display.flashBacklight(duration);
  } catch (Exception e) { }
}






Build configurations


Imagine that you are developing a professional MIDlet game and two mobile operators buy that game from you. Each of the operators wants that his logo is displayed when the game starts. The obvious solution is to develop a game, and, when a game is finished, create a new MIDletPascal project, copy the code from the original project and only change the logo image.

However, it is possible that a mobile operator tests your game and finds a bug. Now you have two projects where you have to fix the bug (you may fix the bug in one project, and then copy-paste the changes, but this copy-paste process may generate more bugs if you don't do it carefully).

Another similar situation may occur if your MIDlet must be optimised both for devices with 128x128 display and 220x160 display. You would create two projects, one for devices with smaller, and the other for devices with larger display. Both MIDlets would only differ in image resources and a bit of drawing code.

To avoid creating multiple projects, MIDletPascal offers build configurations. You can define multiple build configurations in your MIDletPascal project. When you build your MIDlet, you select which build configuration should be used. You can specify which resources will be included in which configurations and some parts of the source code can be compiled only for specific build configurations.

Use of build configurations will be described in a simple MIDlet application. We want to create a MIDlet that will display an image in the center of the screen. We want to have two version of a MIDlet. The first version will display black & white image, while the other version will display a color image on a MIDP2.0 full-screen canvas.

Using build configurations you can also specify which kind of rela number support you need in your application. Fixed-point arithmetic is fast, doesn't take up a lot of JAR space, but its precision is very low. Floating-point arithmetic is slower than fixed point, takes much more JAR space, but is very precise.

Let's start by creating a new project, Configs. After the project has been created, select Project -> New image resource… and add a new image called bw_img.png (make the size of the image 50x50). Draw something on the image (using black color), and save the image. Then add the new image, color_img.png, and draw something on it using more colors. Save that image.

After we have created required images, we are ready to set up the build configurations. Select Properties tab located at the bottom of the left sidebar. One build configuration already exists, and it is called Default. Rename that build configuration to be called BlackWhite. Leave all other properties untouched. Now press the New button located at the bottom of the sidebar. A new build configuration will appear in the list. Change its name to Color, its MIDlet type to MIDP2.0 Fullscreen and its MIDP version to MIDP2.0. Save all changes to your project.#bc

Configs1

Finally you are ready to edit the source code. First write the code that will display black & white image:

var img: image;
begin
    img := LoadImage('/bw_img.png');
    DrawImage(img, 
             (GetWidth – GetImageWidth(img))/2,
             (GetHeight – GetImageHeight(img))/2
             );
    Repaint;
    Delay(5000);
end.



The line with the call to LoadImage should be different for the second build configuration. MIDletPascal uses preprocessor statements to define which parts of code should be compiled for a given build configuration. The preprocessor statements available are:
·{$ifdef build_configuration_name}  
·{$ifndef build_configuration_name}  
·{$else}  
·{$endif}  

The modified code that works with both build configurations looks like this:

var img: image;
begin
    {$ifdef BlackWhite}
    img := LoadImage('/bw_img.png');
    {$else}
    img := LoadImage('/color_img.png');
    {$endif}

    DrawImage(img, 
             (GetWidth – GetImageWidth(img))/2,
             (GetHeight – GetImageHeight(img))/2
             );
    Repaint;
    Delay(5000);
end.



To determine which configuration will be built, use the drop-down menu next to the build button:

Configs2

Finally, we don't want to have bw_img.png in Color build configuration and vice-versa. Select back the Files tab, and in the files list, select the bw_img.png. A list with all available build configurations appears. Uncheck the Color checkbox:

Configs3

Then select the color_img.png and uncheck the BlackWhite configuration.





Debugging

MIDletPascal IDE currently does not support standard debugging. MIDletPascal, however, provides two procedures that can help in debugging your program. Both of these procedures write some text to the standard output. The standard output is availabe only when the application is run in the emulator; when the application is run on the device, there is no output.

You must set up your emulator to display the standard output. If you have installed Wireless Toolkit, do this as follows: open Configure -> Program options… menu, then select Emulator menu entry, click on Add… button and enter Debug emulator as emulator name and
C:\WTK21\bin\emulator.exe -Xdescriptor %JAD%  
as the command string.

The first procedure is Debug; it takes one string parameter. This procedure simply writes the given string to the standard output.
The second procedure is Assert and it takes a boolean value as the parameter. If that value is false, the procedure will write something like this to the standard output:


Assertion failed at: Tetris.mpsrc:162

Take a look at a simple program that uses these two procedures:

begin
  Debug('Some text');
  Assert(false);
end.



When you want to run your MIDlet application in debug mode, select Debug emulator as current emulator and run the application. A console window with the standard output will appear together with the emulator window:

Debugger


Resources

Resources are files that are included in your applications JAR file together with the executable code. Resources are usually images or music files. Sometimes it is useful to include a custom resource file into your project – for example, if you develop a dictionary application, you don't want your program to be full of if-then statements:

  if englishWord = 'fish' then italianWord := 'pesce';
  if englishWord = 'dog' then italianWord := 'cane';



This is a very bad aproach for two reasons: the size of your application will be very large, and the size of your application will be very large (this is not a typo; I want to underline that the applications size will be large).

Instead, you can create a file, dictionary.txt, which will contain one word per line like this:


fish
pesce
dog
cane


and add this file as a resource into your project. The function that translates the word would be coded like this:

function EnglishToItalian(englishWord: string): string;
var italianWord : string;
    res         : resource;
    line        : string;
    pos         : integer;
begin
  res := OpenResource('/dictionary.txt'); // the name is case-sensitive!
  
  if (ResourceAvailable(res)) then
  begin
    repeat
      line := ReadLine(res);

      if line = englishWord then
      begin
        italianWord := ReadLine(res);
        break;
      end;
      else
        line := ReadLine(res); // skip over italian word 
      
    until length(line) = 0;
  end;

  englishToItalian := italianWord;
end;