OPL programming guide

Welcome to the programming guide of OPL, the programming language for EPOC and Symbian OS. I will explain things carefully for you, and therefore this tutorial is aimed at complete beginners in programming.

Programming environment

So you could start programming OPL, you must have an environment, where you can run your code. You have two choices: the device itself (e.g. Nokia 9300) or the device's emulator for Windows (comes with the SDK). The emulator on Windows doesn't run at the same speed as the device, so especially when making games, the results can vary very much between the emulator and the device.

1. Installing onto the device
- download the latest OPL programming kit from http://opl-dev.sourceforge.net/opldev.html
- read the readme file in the ZIP archive and follow the instructions

2. Installing onto the emulator
- get the device's SDK from Forum Nokia and install it
- download the latest OPL programming kit from http://opl-dev.sourceforge.net/opldev.html
- read the readme file in the ZIP archive and follow the instructions

Now your programming environment is ready, so you can start programming.

A few instructions

I'll give you little hint, which makes the programming on the emulator faster: don't write your code on the emulator, but open a text file and save it to "C:\Symbian\7.0s\S80_DP2_0\epoc32\wins\c\" or equivalent in your own SDK. Write or copy-paste your code into this file, and open it every time in the emulator's OPL text editor by pressing CTRL + SHIFT + I simultaneously. This trick shows to be very handy before long, because you can't copy-pastetext from Windows into the emulator.

Compiler, which I will be using universally in the text, is a "robot", which interprets the OPL language into machine code (...01101011100...), which the device understands.

I will be using the user interface Series 80 v2.0 in my examples, so the screenshots are taken from its emulator.

The word printing I use, when a code shows something on the screen, e.g. text.

The word procedure I will also use - don't get blurred from it - it means a basic element of the programming language - a PROC chunk (which can be used multiple times in the code), which ends in a ENDP command.

You can stop an OPL program running on the emulator by pressing CTRL + ESC buttons simultaneously, and SHIFT + ESC on the device.

The first program - printing text onto the screen

Let our program be an easy and simple code block, which shows a text string "Hello, world!" on the screen (a classic programming example):

PROC HelloWorld:
  PRINT "Hello, world!"
  PAUSE 40
ENDP

To translate the program you must open a program called TextEd or Program on the emulator or phone, write the code into the text area and press the "Translate" button (or the button combination CTRL + L)

A screenshot of the program:

Let's examine the code.

  • the PROC, short for procedure, in the first row tells the compiler that the program begins here. HelloWorld: tells the program's name (the colon comes always after the program's name).
  • the PRINT in the second row is a command, which prints (obviously) any text string onto the screen. The text must be inside quotation marks to show on the screen.
  • PAUSE 40 tells the program to pause for two seconds. One PAUSE unit is 1/20 seconds.
  • ENDP, short for end procedure, tells the compler that this is the end of the procedure.

Now you have seen how programming in OPL works in practice. That code chunk is still only a beginning of what you can do with OPL. So follow this guide.

The second program - variables

Although the word variable may sound a little boring, it is one of the basic things in programming. A variable is a particle, which can be used to store data, and its value can be modified.

So this wouldn't go too theoretical, let's get our hands dirty: we'll do an addition calculation with variables and print it onto the screen.

PROC Variables:
  LOCAL A%, B%, C%
  A% = 10
  B% = 8
  C% = A% + B%
  PRINT C%
  PAUSE 40
ENDP

Screenshot:

Now we have somewhat more complex code in front of us, but it's nothing, as we will go through it carefully.

  • the first row is old news.
  • the second row gets interesting. LOCAL tells the compiler that the variables after it (A%, B%, C%) are local for this procedure. So they only work in this procedure, not in any other. LOCAL's opposite is GLOBAL, whose variables work in all procedures.
  • I'm sure you are now wondering what the percent marks are for in front of our variables A, B and C. Well, they signify the marginal of how big numbers can be stored into the variable. The % mark means that the variable can hold an integer between numbers -32768 - 32767. We can therefore save a maximum number of 32767 into the variables with the % mark.
  • the third and fourth rows are for saving values into the variables. In OPL, saving and modifying values is this easy.
  • The fifth row does the addition calculation of the variables A% and B%, and saves the result into the variable C%.
  • The sixth row prints the C% variable's value onto the screen (18, if I calculated right). So the PRINT command can print also values of variables, but then they can't be inside quotation marks. We examined the other rows already.

All %-ending variables are for storing integers between -32768 - 32767. But what if we want to store bigger values into the variables or even letters? Then we just use a different ending sign than %. Below is a table of all OPL's variable types.

VariableMarginalEnding signElse
Small number-32768 - 32767%An integer
Large number-2147483647 - 2147483648&An integer
Floating point number2,2250738585072015E-308 - 1,7976931348623157E+308NothingA decimal number
Character stringAll letters, numbers and special signs.$Can hold up to 255 characters.

But if a floating point number can be used to store integers also, then why shouldn't we use always floating point numbers. Well, because a floating point number uses a lot more memory than a small number. For example, if you want to store human age values into a variable, you should use small number variables. Let us look into this subject in the next code block. The program 2½ follows.

PROC Variables2:
  LOCAL HouseAge%, HousePrice&, HouseHeight, HouseName$(5)
  HouseAge% = 38
  HousePrice& = 135000
  HouseHeight = 5.5
  HouseName$ = "Smith"
  PRINT "House's age:",HouseAge%,"y"
  PRINT "House's price:",HousePrice&,"$"
  PRINT "House's height:",HouseHeight,"m"
  PRINT "House's name:",HouseName$
  PAUSE 40
ENDP

Screenshot:

This one left us a lot of information to analyse.

  • in the second row the variables get defined. The last one, HouseName$, is a little weird: why is there a number 5 inside parentheses? It belongs to OPL's normal variable defining rules, and it has to be after every string variable ($). The number inside the parentheses tells how many characters the variable can store up to. Here we have 5 inside the parentheses, so we can store up to five characters into the variable HouseName$, which is the amount of letters in the name "Smith."
  • the rows 3-6 store the values into the variables.
  • the rows 7-10 print the texts inside quotation marks and every variable value onto the screen. The rest is explained before.

Now we have used all of OPL's variable types. I can quickly tell you that if you want to modify the variable's value, then just write a new row identical to those where the value is saved into the variable. You can change the variable's value as many times as you wish.

The third program - user's keyboard input

A vital part of a mature program is interactivity. What kind of e.g. a game would be if a user couldn't do nothing by pressing buttons or by moving mouse? The game would just go forward with its own pace or be stuck in one place all the time. The player would lose his interest in a short while.

Let's build a program where the user can input the data of his own house. Finally the program prints the data onto the screen.

PROC Interactivity:
  LOCAL HouseAge%, HousePrice&, HouseHeight, HouseName$(50)
  PRINT "House's age:",
  INPUT HouseAge%
  PRINT "House's price:",
  INPUT HousePrice&
  PRINT "House height:",
  INPUT HouseHeight
  PRINT "House's name:",
  INPUT HouseName$
  CLS
  PRINT "House's age:",HouseAge%,"y"
  PRINT "House's price:",HousePrice&,"$"
  PRINT "House height:",HouseHeight,"m"
  PRINT "House's name:",HouseName$
  GET
ENDP

A screenshot of my own values:

Once again, we have some new commands in the code.

  • I put the maximum string length of HouseName$ to 50, because I don't think there is a longer house name.
  • the INPUT here is the central command. With it we can take data out of user via his keyboard. We have only one variable with the INPUT command, and its value is given us by the user.
  • CLS is a command which clears the screen.
  • GET command waits for the user to push a button, and after that the program continues to run. We have nothing below the GET command now, so the compiler goes straight to ENDP command, which ends our program.

I'll have to tell you that the INPUT command doesn't work on S60 phones at all.

Now we have got very good knowledge on how to make interactive programs, but how about graphics? Let's move on.

The fourth program - loading an image

One of the basic elements of today's programs is graphics. I can't name any Windows program that has no image file. So images are pretty important pieces of a program, although they are not compulsory.

I will load a 640 x 200 pixels large image file onto the S80 v2.0 emulator's screen. The image is in MBM format, which is the EPOC's and Symbian OS's native image format. You can download it here. A quick guide follows, which teaches you to convert images from BMP to MBM with a Windows command line tool called BMCONV.

  • download BMCONV here.
  • open the Command prompt in Windows (Start -> Programs -> Accessories -> Command Prompt)
  • navigate to the folder where your BMP file is located (with cd command, e.g. cd Images (cd.. leads you one folder back)).
  • write BMCONV [image file].mbm /c[bit amount][image file].bmp.
    For example, the command could be the following: BMCONV Image.mbm /c12Image.bmp. The bit amount tells the color depth (e.g. 12 bits would be 2^12, which is 3096 colors).
  • if the command returns "Success", the conversion went OK, and now you have an MBM file in your folder.
PROC ImageLoad:
  LOCAL Image%
  Image% = gLOADBIT("C:\Image.mbm")
  gUSE 1
  gAT 0,0
  gCOPY Image%,0,0,640,200,0
  gCLOSE Image%
  GET
ENDP

Screenshot:

This time we have some difficult commands - five of them! How could we figure these out?

  • the second row defines the Image% variable, which holds the image.
  • the third row saves the value of Image.mbm into the variable Image%. gLOADBIT command is used to load the image's data. The image must be in MBM format in order to load successfully.
  • gUSE 1 means that the following graphic commands are aimed at the current window on the screen.
  • gAT 0,0 tells the compiler where the drawing of the image begins on the screen: 0,0 gives the values x = 0 and y = 0, which is the upper left corner of the screen.
  • gCOPY Image% copies the loaded image (Image%) onto the screen. A bunch of numbers follow this command, and I'll explain their meanings below.
    - 0,0 marks the spot where we begin to copy the image inside the image. We start from the upper left corner of the image, so we give the parameters x = 0 and y = 0.
    - 640,200 tells where we stop copying the image, inside the image. Our image's size is 640 x 200 pixels, and we want to copy the whole thing, so we give the parameters x = 640 and y = 200. Therefore the copying of Image.mbm stops at the pixels 640 x and 200 y.
    - The last number, 0, tells that the image is set onto the screen (e.g. 1 would tell that the image gets cleared from the screen).
    - This command might sound and seem a bit difficult, so below is a help imageI have drawn, which helps you understand this command better.
  • gCLOSE Image% closes the image from the memory, so it won't reserve memory in the RAM any more. It's copied into the memory and that way onto the screen, and it's not needed any more. Thus it can be closed.

Below is a help image for the gCOPY command. We ensuingly want to copy an area from the image, which starts from the pixels 120 x and 20 y, and stops at the pixels 463 x and 153 y. The image below shows the area inside a box. Your duty is to make a gCOPY command out of this, and the answer lies below the image.

The answer is: gCOPY Image%,120,20,463,153,0. If you knew this one, you're skilled. The boxed area looked like this when it would be copied onto the screen (and the gAT command's parameters were 0,0):

It might take some time for you to learn how to load an image, just like in my case. Finally you will learn it, when you have written the code a few dozen times.

The fifth program - conditional statements

Our fifth program deals with conditional statements - the basis of artificial intelligence. Conditional statements grant the possibility of choices for the program's user. The user might want e.g. go playing or read the instructions. This is where the conditional statements enter the stage.

The artificial intelligence works e.g. like this, written in pseudocode:

IF UserPressing = Game
StartGame:
BUT IF UserPressing = Instructions
Instructions:
ELSE
AskNewPressing:

Let's make an OPL program, which asks for your opinion about Coca-Cola and Pepsi.

PROC ConditionalStatements:
  LOCAL Pressing%
  PRINT "Which one do you prefer: Pepsi or Coca-Cola?"
  PRINT "Press 1, if you like Pepsi more and 2, if Coca-Cola."
  PRINT ""
  Pressing% = GET
  IF Pressing% = 49
    PRINT "So Pepsi is for you."
  ELSEIF Pressing% = 50
    PRINT "Coca-Cola. Good choice."
  ELSE
    PRINT "Not selectable."
  ENDIF
  GET
ENDP

A screenshot of my Coca-Cola positive selection:

So, now we have managed to make a simple conditional statement program. It works like a charm. Let's analyse the code, shall we?

  • a local variable Pressing% is introduced, which is for storing the keyboard pressing value (1 or 2).
  • the fifth row acts as a line breaker.
  • the sixth row is important - there we set the keyboard pressing value into the Pressing% variable. So GET command can be harnessed this way.
  • the seventh row starts the conditional statement. So if Pressing%'s value is 49 (read on), the text "So Pepsi is for you" is printed. The value 49 is the character code of keyboard number 1 in S80 devices.
  • the ninth and tenth rows mean: but if the value of Pressing% is 50, print: "Coca-Cola. Good choice." In S80 devices the keyboard number 2's character code is 50. You can look for more character codes from the table in the bottom of this page.
  • the rows eleven and twelve can be translated into English like this: "in any other case print "Not selectable.""
  • the thirteenth row's ENDIF ends the conditional statement.

Other things related to OPL

Here was the tutorial so far. I'm sure you will get started with this guide, and you might get some ideas from it. If this tutorial shows some popularity, I will gladly write more about this subject. Below are coincidental things about OPL.

  • draw the code in when needed. Usually the rows after conditional and loop statement (IF, ELSEIF, ELSE, DO, WHILE) and PROC commands get drawn in.
  • in OPL the command for graphics begin with the letter g, for example, gLOADBIT.
  • when you program in OPL and learn new things about it, you will learn a new language more easily - e.g. C++ has variables and conditional statements as well. Although OPL is a dying programming language, learning it isn't vain.
  • the OPL guru Ewan Spence has written a book about OPL. Its name isRapid Mobile Enterprise Development for Symbian OS: An Introduction to OPL Application Design and Programming.
  • there is a very good freeware text editor named OPeLo made for OPL. You can download it here.

Character codes of S80 devices

CharacterSHIFT + characterCode (character)Code (SHIFT + character)
Enter(nothing)13(nothing)
Esc(nothing)27(nothing)
Space(nothing)32(nothing)
Backspace(nothing)8(nothing)
0=4861
1!4933
2"5034
3#5135
4¤52164
5%5337
6&5438
7/5547
8(5640
9)5741
.:4658
,;4459
-_4595
+?4363
*(nothing)42(nothing)
aA9765
bB9866
cC9967
dD10068
eE10169
fF10270
gG10371
hH10472
iI10573
jJ10674
kK10775
lL10876
mM10977
nN11078
oO11179
pP11280
qQ11381
rR11482
sS11583
tT11684
uU11785
vV11886
wW11987
xX12088
yY12189
zZ12290

More character codes can be found with this piece of code (you can exit the program by pressing Esc).

PROC CharacterCodes:
  LOCAL Pressing%
  DO
    Pressing% = GET
    PRINT Pressing%
  UNTIL Pressing% = 27
ENDP