SIBO 'C' Software Development Kit GENERAL PROGRAMMING MANUAL Version 2.30 March 1, 1999 (C) Copyright Psion PLC 1990-98 All rights reserved. This manual and the programs referred to herein are copyrighted works of Psion PLC, London, England. Reproduction in whole or in part, including utilization in machines capable of reproduction or retrieval, without express written permission of Psion PLC, is prohibited. Reverse engineering is also prohibited. The information in this document is subject to change without notice. Psion and the Psion logo are registered trademarks, and Psion, Psion MC, Psion HC, Psion Series 3, Psion Series 3a, Psion Series 3c, Psion Siena and Psion Workabout are trademarks of Psion PLC. TopSpeed is a registered trademark of Clarion Software Corporation. IBM, IBM XT and IBM AT are registered trademarks of International Business Machines Corp. Microsoft and MS-DOS are registered trademarks of Microsoft Corporation. Apple and Macintosh are registered trademarks of Apple Computer Inc. VAX and VMS are registered trademarks of Digital Equipment Corporation. Brief is a registered trademark of Underware Inc. Psion PLC acknowledges that some other names referred to are registered trademarks. Contents 1 Installation .............csccsssssssscssscrssssceeeeseeeseeeseesseesssesseesseesseesseesseesseesseesseesceesceesseescesscsscesoseesoeees 1-1 Installation: :: i328 Assisi Aces whe chad Oks Ahsdoke sneha saniiin 1-1 Dif CtOry StEU Chute css 259s sie, Boost eek os shsg eats tess eth clees da Dies cos thes oT Dees ous hes eb Tset vous Teeneeeaav 1-2 Reconfiguring the TopSpeed project SysteM...........cssessecssseeesneecsseecsseeceseeeesaeessaeers 1-2 Customising the redirection file... eee eeeesesccssneeceneecseecsseecsseeeesseessaeecsaeesssneeessaes 1-3 2 A Brief Overview Of The SIBO SDK...............scsscsssssssssesesssesssessscsssesssessesesssessseessesssesssessoeees 2-1 Mantlal si as tcas crest a tacit a ptiteseder chai abste bei eiea ide ahr ianohii ast 2-1 WHEE TO SCALE sis ont 0k cee sat can abet ech veits es AlN oeuviuat ses alts cavvainases Ud oetitialens Gioia oe 2-2 The terms SIBO and EPOC explained ..........ceeceeceseseecsseessseeceseeeesaeeesaeecsaeeesseeessaes 2-2 Fatal programming errors (Pamics) .........ceseeeseeceseeessceeesseecsseecsaceceeecesaeeesaeesseessneeeeseaeers 2-3 Panic NUMDers :s..s:205 iors hess devas Gales eee eek bigs vaneiens ian Ghee 2-3 C++ and Object Oriented programming ...........eesceeseeceseeceseeesseeseeecseeeseseeeesaeessaeesseeesee 2-3 3 Building An Application ...............csscccssscssssccsscsssscsssssssssscsssecsssecsssssssssssssscnssscsessesssssssesseesees 3-1 INtroduchOti sais cei eh ab de ash kd Heh ah ee lg 3-1 Equipment required: :ctics 2 otesscvsthsce soba. cosa doee nesdussceusonasuestuaccavediseseassysoansibensseussaes 3-1 Whichfilesare needed 2.5. ccsscusi.5 coves cavsciestidebeccheves iol stebeset evveieh Steee sed seveted ees etlvber 3-2 Avfirst: éxample-applCattonicsssi.ci.tsiscssteasactealasieestesisceat le doenteaietenulads. agancdelasieesascaendst 3-2 A first look at projectiles o 525; ccissckeuei Seuscbehsiengotd Seubebetsaesaoch yuh veh sdebaten ouoh evshcgubeoeh Suenee 3-2 Creating: the ime filet:4 iain ohana lan ouB asian lanl 3-3 Copying the program to the target Machine ........ eee eeeeceeneeeeeeceeesseessseeessaeeesaee 3-3 Running the program on the target COMPULET........... ee eeeeeeeeneeeeneeceneeseaeessseeeeteeeesaee 3-3 Stepping through the program with the SIBO Debugger .......... eee eeeeeeseeeeseeeeeeeeenes 3-4 A PEIB version Of Hello Wotldssssis.scccbes.ceadeseseepiessc svda deste hiss apsviebe abtbies aeessarboeeeescbaae 3-4 PEIB- and ‘CLIB conitrasted oi. sc... 205 sicse eves cevetul sees teas caved ub steve neste. fel stevssustevbs felseeseesstyl 3-4 The-code for p hello. i drcssectssvestasscasseaiate adacteostea lareadaadenstestaseendsieasteataceenderioes eters 3-5 The epocinit statement in -pr files... eee eee eeseeesseeceseeesseeeeseeeesaeecsaeesseeesneessnaeeesaes 3-6 Housekeeping batch files and re-using project files... eee eeseeeseeceseeeeeeeeesseeesaeessneeeees 3-6 A general project file: unnamed. pF oe. eee eeeeeeeseeceseeesseesseeceseeeesaeeesaeessaeessseeeesaes 3-6 A batch file for test Compilation .......... eee eeeeeeseeesseecsneeceseeeesaeeesaeecsaeecsaeessneeeeteeeesaes 3-6 SOME COMPLICALLONS. os 2565 55h sete oks Fe heh ios Povk a gheties Soe Sivd ou gh adieba Sen usd bu gb ctuboveu dunk aubetedo tue 3-7 TSE versus ISCX i sssiostiss Mann eatin Aeniisscess teas dapbescrsp bate sapdasecesp hase aspbebs evades vundays 3-8 More complicated programming SeCtUPS ..........:.csscessseceseeceseeeceseeceaeecseecseaeeesaeecsaeessneeeees 3-9 Simple: PEIB: examples. sis.2ccasiasesetasicasagiasventaalateesbaadvestaasatessdawdoestestavesetaaateatagsgers 3-9 Moulti- file: prograinss.i sc castsisiceiiecigasl a sccbehicskpth auhcvelceeheoek Sheicvehjesbepehoigievesdestek sist 3-9 Graphics programs. ::..2.5:4 cp mstdceai Mapas dete Aeiiesicnipiensdapbeadseteti ss dngiescAeetise deeds 3-10 FAWIP progranns csc ossi0s cossccts tours cds Faveeubedevsesdsduyacad edu vse sdsdueaeevsdvetesds svneebsteesecosteensvbanes 3-10 Customised) libraries ¥s.::2)c<.t2s.ss555.92.diabateansaiste ddatpeatacisgeeleahe asibasounlastetestansendastoees 3-10 Applications containing assembler as Well aS Cu... eee eeeeceeseeceseeeesneeseeeesseersaeeseeeeees 3-11 Other advanced use of the project file SySteM..........esceesceeessceeesneeceseeceneeceseeeesaeessaeers 3-11 Greater control over the image file created... eee eeeeeseeesneessneeceeeeceeeesaeeesaeeesaeersneeenee 3-12 Priority, minimum heap, and version NUMDET............: ce eeeeeseesneeeeneeceneeceseeeseeeeneeeesaes 3-12 Use.OF Edumipiex rc. isiiit jf it ievieta Mis nhee Mi Ane oeiicciad sie eaten ile sed 3-12 Differences between .app files and .1mg files 0.0.0... eles eeeeeesneeeeneeceeeceeeeseeeeseeeesaes 3-13 Ad d=file ist si... ess Seeose ed Stbbe ous oP ysis saubease Sevseeesebsdis TeesesbeSas RIP Ivers thus nerve eres 3-13 Changing the set of add-files in an 1Mage......... eee eeeeeeeseeceseeeseecsaeecsseeeeseeeesaeeseaeers 3-14 Further uses of emake.exe ............ccccccceseeseccccccceeessseccccssseeeesseecccsssseueeseescessssueeeseeessess 3-14 GENERAL PROGRAMMING MANUAL ii 4 Notes On CLIB.............sccssssssscssscsssesssessserssesssesssesssesseesssssssesssesssesssesssesssesseesssessesseessseessesseeeseees 4-1 Functions missing from the MS-DOS JPIC library... eee eeeeeseeesseeeeseeeeeneeeeneees 4-1 TAS OR 5s deste ces; cass nevedeepavstbs sb eeagbassdact salscesodanpdhugasasevacespdensosbi cusses sosevehes Aantensseeraion tes 4-2 DIVE eset rt MM eR el oa NN oe ah oe te eee area ones ute aa PEG cara eset hs 4-2 File handle conversion routine............ceeseseseecsscecesceesseecseecseecsseeeesaeecsaeessneessseeeesaes 4-2 Phe Console: Channel. 22. cscs ices svadesessahpscossteg egebseey ages ced evebsdes seete dns esehstnpsaubeted oses step pee 4-3 MS-DOS ‘file names’.$3:.; ac.cseiyaieentiaelecnsie aie oui are ei ayia 4-3 Floating point emulator .......... ce eeeeeeeeesseecsscecsseeceseeeesneecsaeecsseeceseecesseecsaeecseessneeeesaes 4-3 Pate 80:s3isni this talest gain dain saad Palas ote Shaina osetia. 4-3 Building the CLIB library and header objects ............eeeeeeseeseseeceseeeeeeeeesseeesaeesseeeees 4-4 Cautionary Notes sssi.c.e i etiavien it ashe aoiaaiei ota bad ieee 4-4 5 Fundamental Programming Guide-lines ................cccssccssssseccsscssecssccecsssccecesseseesssccseesssceseeens 5-1 Tin tr OG UCHIOT os ek tes el iach i at wae cate cal ced ste cand eat see canned aenteat Si steee canta 5-1 Other related docuMeNntatiOn.......... ee eeseeeseecsseecesceeesseecsseecseeceseeeesaeessaeesseeseneeessaes 5-1 The source code for the examples ............eesceesecceseeeeseecseecsceseseeeesaeecsaeesseeesneeeesaes 5-2 User Anterface:. sii 2isi8 thas ets as bee avis lensed Avid dau esi tvico bei esiteda teh 5-2 A first look at multiple event SOUTCES......... cee eeseeeseeesseeeesceceeseeesaeecsaeecsseecseecesaeeesaeecsaeers 5-3 Remarks ‘On timers -.$:5. silts. oiel oo he Bled ea aed hie Band hao eetied 5-4 Remarks: on ke ypresses's:J.c5:33 sasiesidecvtsteAisiasihas beth Naidesddtedevid aioe dei Aenea ha 5-4 MO re Oi p1OWalt iss cos2o os sats Syceubsteus sab cdian cos vssisa Ans cous Avtsiba Aig eevadoreubs Ran eeiidawbonvs daads 5-4 Status words: the other side Of P_lOWa€It oo... eee eeeeeeseeceseeceseeeeseecseecseeseseeeesaeessaeers 5-5 Prioritisation Of CVENt SOULCES ........ eee eesecsseeesseeceseeeesseecsseecsseeceeeeesaeecsaeerseeesteeeesaes 5-5 VO devices ii ceneralicss, ateissi assess cast eA sisesiostsse Sh ssaveisndeesbesed stestoseepoasivaeensseeressi ha 5-5 The Console: device seccs2.es2.5 vege cuss sivedes Soves cuts Sesiel sake cavsebbesea savage cals cevaded Seats seitenusden Sinbely 5-6 How to‘Canicel::a thers ch sisiss-stssiacdticeassstacdeeledesetaatageetds tess eataosendadeasteaiagendaieaetens 5-6 Where to declare status WOrdS..........ccceescccseseessseecseecsneecsseecssaesesaeecsaeessaeeseeeessaeeesaes 5-7 A-first,look at ertorharidling 3: ).35c cenit dail endri ees eed e Baste 5-7 Brror handling in Events cin: coiscsess.basi.5 cats toons tsdhah eeisduose 0s bi bevadeesecus ds nsvetevsrDuteseiee 5-7 Fatal errors and non-fatal errors ..........eeeceeeseesseeesseecssceceececesaeeesaeecsaeessaeesseesssaeeesaes 5-8 When resources need to be tidied explicitly... eeeccesneeesneeesneeseseeseseeeesaeessaeers 5-8 Inter-Process Communication: Events2 and Subproc.........eeeeeeeseesseeeeseeceseeeeseeeesaeeesaeers 5-8 Acthird €vetit SOULCE ws c.65cistescd0s seuss eckeeebtee, Fei stvbs foibteestes stvie feb Tebslen sins Pevtdewsta ste de 5-8 How Events2 passes data to SUDPI0C........ eee eeseeeeseeeeseeceseeeesaeeesaeecsaeecsaeessneesesaeeesaes 5-9 The Code ti SUBProcis css sot cass cvs ssies Sab Lobe ewek Sheu pied Pedbewss Subd Lock Setacw es Seeeuoeh ocoenweh Sesooeh Senne 5-10 Mechanisms for inter-process COMMUNICATION .......... eee eeeeeeseeeseeeeeeeeseeeeaeessaeesseeeees 5-10 Debugging cooperating applications ........... cee eeeseecsseeeeseeeesseeesseecsaeecseecsseeeesaeeesaeers 5-11 Error Handling im Bvents2.5:.235 hss stds hcenkictessedealetentigiagsotesisceeidatsosanaaieasieatiaesneanenyiass 5-11 Socially responsible programming in Events2............:ecceesseeesseeeeseecsececeeeeeseeeeseeeesaes 5-11 Data received from:a-serial port s.s.s.5:.5 sts eiades his dacien aes eathisl asin An 5-11 Opening the:serial: Port cssis: yess ochisek saves cash cieised Stees eavlevesselstese cas ieves ced sesesw eevee aeeei ss 5-12 Active and inactive CVeNt SOUTCES 20... eeseeesseceseeeeseeeseeeesaeecsaeecsacecsseecseeeseeesnaeeesaes 5-12 Debugging applications with serial COMMS ............:esecesseceeseeeeseeeseecsneeeeseeeesaeessaeers 5-13 The tole:of: ptickles 2:8 wise aA inde iitha dade asada tshadea aes 5-13 Yielding CPU in compute-intensive programs ...........ssccseseeceseeceseceseeeeseeessaeecsaeessereeeenes 5-13 Tdl@:ObjecCtss. 2: ssesisscsscaseesteaissectagusaasd ataceas deters ncaisenndaseadeenesaat daha Moeetes etenhda Goeetdaa st cat 5-14 The meaning of calling p_1osignal......... ees eeeeeseecesneeeseeseeeesaeeceacecseeceseesseeseseeeesaes 5-14 One drawback of COMtiINUOUS ACtIVILY ...... eee eee eeeeeeeseeceeeeseeeesaeeceaeecsseecetersneeeenaeeesaes 5-14 Remarks On process PriOrities ........ ee eeseeeseecsseeeesceeesseecsaeecseeceseecesaeeesaeesseeesneeeesaes 5-14 The-call p-tOvyieldissisiss. sdasscessashassadaseteatastasiostatess tan caseendateestentassenda seasteaiaveendateastgas 5-14 Gremeral Perm ark o.ii61. 255s scis sh nahh a oest iocs disk Bevdeed Se ckbvad pes cbeesied hisheoui se sheteh el ouboe sereh erent oe 5-16 Multi-threadedness and multi-tasking... eee eeeesseeeseeeeseeeeseeeesseeseeeesaeessaeesseeeees 5-16 Subprocess or 1dlé: Object? «1.5. isseeestais bi steviesevich eistest tc ata aeons bees 5-16 Window redraws as an Vent SOUTCE....... ee eeesenecesneessneeseseeceseecsseecesaeessaecesseeesneeeesaes 5-16 The APPMAN and ACTIVE classes in OLIB .0......ceseeeeceessecesseeceneecseeeeeseeeesaeessaeers 5-16 CONTENTS 6 Copy-Protecting Softwar e...............scsscssccssscssssscssesssscscecssscesssscssesssscsssssscsscsssscssesssscssssssceseees On Tin tO Ct Oni aps fos oe dees teg shoes eiestene tee stcga estes See sata ig stes ott slong esac seep tene eset deestene eats 6-1 The freespace method s:.icisieiia ph eit ia. pei banning es 6-1 First generation copying methods......... ec eeeeeseesscesssceesseecesseeesaeecsaeecseecsseecesaeeesaeeesaeers 6-2 Preserving checksums :..3...2.:rvidiene aie kieran eh al nna eie 6-2 What kind of change should be made «0.0.00... eeeeeeeeesseeeeseessnceceseeeesaeecsaeessaeesseeeesas 6-2 Restricting the number of copies Made .......... ees eeseeeseeeeseceesseeesseecsseecsneeceseeeesaeessaeers 6-3 Low level SSD information’, « o::.06. 22st. he oes eho hk ee oe dhe eel ae eh ad ae 6-3 Copy-protection by changing the ROM 00.0... eescessecsseecsseeceseeeesaeeesaeecsaeecesaeeesaeessaeers 6-3 7 Compatibility: sccsscssccccsscsecccssssescestcsnsacsesssaassssssssssosvensseseveasdsocvansdsdevansdsentancsesssadessnosesessosnstesueseeg dL Initroduct On ¢::::.43. nA kee ius Lis Anh Aoh lhe Mon koh aah aae 7-1 What machine am I running ON? ............ceeecceeessceceeseceeesseneecessaseecessneecensaneesessnsesessnsesenses 7-1 iii CHAPTER 1 INSTALLATION The Psion SIBO 'C' Software Development Kit (SDK) enables you to develop applications in 'C' for the Psion SIBO family of hand-held and notebook computers: e the HC range of corporate handheld computers e the Series3 range of palmtop computers e the MC range of laptop mobile computers. The SDK is PC based - that is, you write and build your applications on a IBM PC or compatible and then run (or debug) the application on a SIBO computer. The SIBO SDK comes in three variants: Professional (Prof), Standard (Std), and Documentation (Doc). The Prof and Std variants contain differing amounts of the TopSpeed C Package (produced by the Clarion Software Corporation): e the Prof variant contains the complete TopSpeed C Package e the Std variant omits the TechKit and C Library Source Kit portions of the TopSpeed C Package. Parts of the TopSpeed C Package are required in order to build any SIBO application. These are the parts included in the Std variant of the SDK. The TopSpeed C Package may be used independently of the SDK to write C programs to run on IBM PCs and compatibles. All three variants of the SDK contain the same three volumes of SDK documentation, comprising 14 different manuals all told, together with associated software produced by Psion. This software incorporates libraries, header files, auxiliary programming tools, example programs, and much more besides. Installation There are three phases to installing the SIBO SDK: e installing the small code model of the TopSpeed C Package e installing Psion software and example programs ¢ customising the TopSpeed system using special Psion files. For information on installing the TopSpeed system, see the TopSpeed C documentation. (You may install other code models as well as the small code model, but they will not be used by the SIBO SDK). The Psion software consists of required parts and optional parts. For a full description of all the available files, see the read.me files in the root directories on the supplied disks. The files on the disks are in compressed ("zipped") form. The disks contain the pkzunzip program, which can be used to decompress ("unzip") the other files as they are copied. The installation procedure ensures that each group of files is copied to its correct directory. The read.me files on the disks specify which files are present in each group. GENERAL PROGRAMMING MANUAL Directory structure The TopSpeed software is usually located in a \fs\ directory tree. The Sibosdk software is usually located in a \sibosdk\ directory tree. There is no need for the \rs\ and \sibosdk\ directory trees to be on the same partition of your hard disk. Eg the TopSpeed system could be on drive c:, with the Sibosdk system on drive d:. Both the \ts\sys and \sibosdk\sys directories should be added to the MS-DOS path. Alternatively, you may copy the contents of \sibosdk\sys (with the probable exception of the ts.red redirection file - see Customising the redirection file below) to \ts\sys, in which case you will only need to add the \rs\sys directory to the MS-DOS path. Subdirectories under \sibosdk\ include: lib the location of standard libraries, startup objects, and some loadable device drivers (dynamic extensions to the SIBO operating system) include the location of header files sys the location of the SIBO Debugger and other miscellaneous programming tools pr the location of some standard project files demo the location of various standard demo programs s3atool Series 3a versions of an icon editor and the Spy application STC (not present in all versions) the location of the source code for the Clib (standard C) library hwdemo (optionally) the location of programs demonstrating use of the HWIF library hwifsre (optionally) the entire, buildable, source of the HWIF library, for interest and/or to allow the writing of extensions to HWIF wd (optionally) the source printer scripts of some WDR printer driver files Idd (optionally) the source code of some example device devices hemast (optionally) software allowing alternative versions of the HC rom to be built wkdemo (optionally) source code of example software for the Workabout fconv (optionally) software allowing the creation of file format conversion DYLs for Word oopdemo (optionally) the location of programs demonstrating the basic use of the Object Oriented Programming system (other directories contain more advanced examples) record (optionally) the source of the Object Oriented Series 3a Record application. This is buildable, provided that the \sibosdk\oop directory has also been installed The SIBO SDK requires between 3 and 6 Megabytes of disk space, depending on how much of it is installed. Reconfiguring the TopSpeed project system The Sibosdk software contains files, including tsprj.txt and tsmain.txt, that are replacements for files of the same name released by TopSpeed. The Sibosdk versions of the files allow the TopSpeed project system to handle the Epoc 1Mc system type, and the Sibosdk tools generally, in addition to the systems normally supported by TopSpeed. (See the following chapter for more details.) The Sibosdk versions should be copied, from \sibosdk\sys, over the TopSpeed versions in \ts\sys (as guided by read.me). Copies of the original TopSpeed files should be kept, with their extensions changed to .old (say). In case any specialised changes have already been applied to, say, your tsprj.txt and tsmain.txt files, you should re-apply these changes to the Sibosdk versions. 1 INSTALLATION In order for all these changes to have any effect, the TopSpeed tool tscfg has to be run: type cd \ts\sys to enter the appropriate directory type tscfg to invoke tscfg. Note that the replacement files are not the same as those supplied with versions of the SDK earlier than 2.0. You must therefore repeat the reconfiguration process, even if you are upgrading from a previous SDK version. Customising the redirection file The \sibosdk\sys directory contains the redirection file ts.red that allows the TopSpeed project system to find the SIBO SDK header files, library files, and other required files. When you invoke the project system to build an Epoc application it must be able to find this file. If there is no such file in the current directory, the TopSpeed system looks for this file in the directory containing the TopSpeed software itself (usually \ts\sys). So there are two options: e overwrite the TopSpeed ts.red file (in the \ts\sys directory) with the Psion ts.red file (in the \sibosdk\sys directory), and place a copy of the original TopSpeed ts.red file into the directory in which you are writing PC C applications (if any) ¢ copy the Psion ts.red file into the directory in which you are writing a SIBO application. The first option is more appropriate if you are writing more SIBO applications than PC applications, the second if you are not. The contents of the default ts.red file is basically as listed below. Again, note that the supplied file is different from the ts.red in earlier versions of the SDK. *.PR = .; C:\SIBOSDK\PR; * 7H = .; C:\SIBOSDK\INCLUDE; *,HPP = .; C:\SIBOSDK\INCLUDE; *,RH = .; C:\SIBOSDK\INCLUDE; ta = .; C:\SIBOSDK\INCLUDE; *.RG = .; C:\SIBOSDK\INCLUDE; *.XG = .; C:\SIBOSDK\INCLUDE; *.RSG = .; C:\SIBOSDK\INCLUDE; * INC = .; C:\SIBOSDK\INCLUDE; ee = .; C:\SIBOSDK\SRC; *.CPP = .; C:\SIBOSDK\SRC; *.CAT = .; C:\SIBOSDK\SRC; *.A = .; C:\SIBOSDK\SRC; *.,OBJ = .; C:\SIBOSDK\LIB; * LIB = .; C:\SIBOSDK\LIB; * HLP = C:\TS\DOC; For example, the meaning of the line *.H = .; C:\SIBOSDK\INCLUDE; is that any .h file referenced in the course of building an application should be searched for first in the current directory, then in the c.\sibosdk\include directory. To increase the search path for .h files, so that private .h files can be located from some other directory, just edit the ts.red file so that the line becomes, for example: baa! = .; ..\INCLUDE; C:\SIBOSDK\INCLUDE Note that the contents of this file assume that you have installed the Sibosdk system on your c: drive. If you have installed it on another drive you will have to edit ts.red to refer to the appropriate drive. 1-3 GENERAL PROGRAMMING MANUAL 1-4 CHAPTER 2 A BRIEF OVERVIEW OF THE SIBO SDK The SIBO SDK consists of a set of floppy disks containing the SDK software and a number of manuals describing the software and the Psion SIBO family of mobile and hand-held computers. The floppy disks contain the various tools, header files, libraries etc that are required to produce an image (img) file that will run on Psion SIBO machines. Manuals The SDK manuals supplement the TopSpeed manuals. In particular you are referred to the TopSpeed C Library reference for the description of standard C (CLIB) library functions. The SDK contains the following manuals: General Programming Manual HC Programming Guide Series 3/3a Programming Guide Workabout Programming Guide EPOC OSS System Services Additional System Information PLIB Reference Window Server Reference I/O Devices Reference The SIBO Debugger Hardware Reference Programming in HWIF This manual. It describes how to install the SDK, and how to build an application that will run on the SIBO machines. It also contains some notes on using the TopSpeed C Library reference manual, some discussion on how to copy protect software for SIBO computers, and a potentially very important chapter entitled Fundamental Programming Guidelines. Some documentation particularly oriented around the HC computer range. Some documentation particularly oriented around the Series 3 range of machines. Some documentation particularly oriented around the Workabout computer. Describes the software interrupt interface to the ROM-based system services. An appendix contains a complete listing of the EPOC service numbers. This will be of particular use to OPL and assembly language programmers who wish to make direct access to EPOC services. Describes the MCLink communications software, resource files, WDR printing, various file formats, how to write device drivers, and other miscellaneous topics. Describes the Psion PLIB library (this library provides the most direct access to the ROM based system services). Describes the window server library WLIB which implements a range of sophisticated graphics operations. Describes the interface to some of the Epoc device drivers, including those which access the serial and parallel ports. Describes how to use the SIBO Debugger to debug applications being developed for SIBO computers. Describes the basic hardware of SIBO computers. Describes the HWIF library (which contains support - mainly for the Series3 - for menus, dialogs, editors, and printing). 2-1 GENERAL PROGRAMMING MANUAL Object Oriented Programming Describes the development of applications using Object Oriented Guide techniques. Its introduction provides an overview of Psion's Object Oriented programming system and of the OLIB, HWIM, FORM and XADD object libraries. ISAM Reference Describes the ISAM dynamic library which provides Indexed Sequential Access management for large database files. OLIB Reference Describes the OLIB object library. FORM Reference Describes the FORM object library. HWIM Reference Describes the HWIM object library. XADD Reference Describes the XADD object library. Where to start There is a very large amount of information in these manuals - perhaps too much for any one person to keep it all in their head. However, few developers will need to make detailed reference to more than around half of the manuals. The manuals contain many cross references to sections where various topics are discussed in more detail. Use these cross references to help you find your way around the SDK documentation. The chapter immediately after this one is probably the best place to start. Alternatively, start reading the HC Programming Guide, the Series 3/3a Programming Guide, the Object Oriented Programming Guide, the Plib Reference manual - or anything that catches your eye as you flick through the pages. The terms SIBO and EPOC explained A SIBO machine is a battery-powered portable computer that is based on the SIBO architecture. This architecture is designed to minimise the size, weight and power consumption of the computer. The key components of the architecture are: e A sophisticated power management system that selectively powers subsystems under software control e Solid State Disks (SSDs) that provide fast low-power silicon-based mass storage with no moving parts e Asynchronous serial interface for peripherals running at high speed (Mega bit rates) e An 8086 class of processor (or any compatible processor such as an 80286) e Hardware protection of the system from aberrant processes (address trapping of out-of-range writes and a watch-dog timer on interrupts being disabled) e = Real-time clock e ROM-resident system software e Graphics LCD display e A touch sensitive digitising pad that provides a pointing device (used in some models) e ISDN combo sound system (used in some models). The hardware architecture is primarily implemented in custom ICs called ASICs. The SIBO architecture uses surface-mounted static CMOS ICs throughout. For further information see the Hardware Reference manual. The EPOC operating system, designed for the SIBO architecture, has the following features: e preemptive multi-tasking e MS-DOS-compatible file systems e installable file systems, including remote file access e asynchronous services e support for client-server architectures (used to implement system components such as the file server and window server) 2 A BRIEF OVERVIEW OF THE SIBO SDK ¢ acomprehensive I/O system with many built-in I/O devices e dynamically loadable device drivers e reentrant function library e multiple processes of the same program share a single copy of the code e support for object-oriented programming e code-shared dynamic link libraries. On SIBO machines, the system software resides on an in-built ROM. A version of the EPOC operating system also runs on a PC. See the Plib Reference manual for more details. Fatal programming errors (Panics) When the system detects a condition that it believes could only arise from a bug in a the application program, the system terminates the process with a "panic number" in the range 0 to 255 inclusive (where the system is said to "panic the process"). A panic is a fatal exception that causes the process to terminate immediately. There is no way for applications to avoid being terminated when a panic has been started. As well as protecting the system from defective applications, the panic system enforces a greater discipline on application code by terminating a process as soon as the condition is detected. Panic numbers Programming errors detected within different areas of the system code give rise to different panic numbers. The following table lists the possible panic numbers and the corresponding system code that can give rise to them. 0 to 80, and 255 The PLIB library 81 to 129 The Window Server library 130 to 160 The OLIB object library These panic numbers are described in more detail in the appropriate manuals. Panic numbers in the range 160 to 254 are used by code that is not resident in the ROM (such as the ISAM library). A given panic number may be used by more than one piece of code; such a panic may therefore have one of a number of causes. The only definitive way to discover the origin of such a panic is to make use of the SIBO Debugger to catch the panic and then trace it back to its source. C++ and Object Oriented programming This version of the SDK is compatible with TopSpeed C++ although, at the time of writing, the TopSpeed C++ package is not supplied by Psion as part of any variant of the SDK. Note that the kinds of classes, and the means of creating and accessing them, in C++ are quite different from those in the Psion Object Oriented programming system. Regardless of whether you use C or C++ to develop Object Oriented applications, if you wish to use Psion objects you must create instances of them and send messages to them by the mechanisms that are described in the Object Oriented Programming chapter of the PLIB Reference manual and the Object Oriented Programming Guide. If you intend to develop a SIBO application that uses only Psion objects, you may still use C++ as a "better" version of C, without making use of its Object Oriented aspects. You may, if you wish, use a mix of Psion and C++ classes, provided you make sure that you create and use instances of classes of each kind by the appropriate means. It is quite acceptable, for example, to use Psion classes for the application manager and user interface, but use C++ classes in the 'engine’ of an application. GENERAL PROGRAMMING MANUAL 2-4 CHAPTER 3 BUILDING AN APPLICATION Introduction The end result of developing a program to run on a SIBO computer is normally an image program, with characteristic extension .img. Essentially, .img files are to Epoc what .exe files are to MS-DOS. (Sometimes, the image file is given the extension .app instead. See later for the distinction between .img and .app forms of images.) Image files are actually produced via an intermediary .exe file by the operation of a tool emake.exe, though in practice this process is automated on behalf of the developer. The point is that the development cycle for .img files is basically the same as for .exe files in more traditional programming environments. The same compile-link-debug cycle exists in both cases. The program is written, compiled, and linked on the PC. These steps involve the TopSpeed compiler and linker, and TopSpeed project (.pr) files. These steps may also involve the full TopSpeed ts development environment, which is an Integrated Development Environment (IDE). Alternatively, developers may prefer a more traditional approach, involving their own favoured stand-alone text editor, and a batch-file mechanism for invoking the TopSpeed compiler and linker. Once linked, the program is transferred to the SIBO computer in one of three ways: e under the control of the SIBO Debugger e via a SSD written to by a PC SSD drive and then placed into the SIBO computer e via a serial link, using Comms software such as MCLink. A program running on a SIBO computer (though not one in its rom) can be debugged under the control of the SIBO Debugger running on a PC. If the program has been built under special conditions, source level debugging will be available; otherwise just machine-code level debugging. The remainder of this chapter gives more details on all the above points: e it introduces some particularly relevant aspects of the TopSpeed project file system e it describes some batch files that may be found useful when building applications e several example applications demonstrate the points made (all the example applications and associated files referred to in this chapter are optionally copied into \sibosdk\demo when the SDK is installed) Equipment required The following equipment is required in order to create an application that runs on a SIBO computer: e One target SIBO computer (HC, MC, or Series3) e One PC e The TopSpeed C development system on the PC e The Psion SIBO SDK software on the PC e One or other form of communication between the HC and the PC. 3-1 GENERAL PROGRAMMING MANUAL Around 5 to 7 Mbytes of PC hard disk is required to install the TopSpeed C development system and the Psion SIBO SDK software. There is no particular requirement for the PC to have extended memory. Development can take place on an XT, but a 486 machine with around 4 Mbytes of extended memory machine will obviously produce results more quickly. Which files are needed To build an application, the following files are required: e source files, such as .c and .h files e aproject file, with extension .pr e aredirection file, with name ts.red e libraries, with extension .lib. At the same time, various batch files (extension .bat) may be found useful. Additional files may be required for the development of applications with the aid of the Object Oriented system - see the Object Oriented Programming Guide for further details. There is no need to have a separate project file or redirection file for every single application. For example, ordinarily there will only be one redirection file on any one PC, shared between all applications written on that PC. One possible exception is in the case of developers who use the TopSpeed system to write PC programs as well as SIBO programs. A first example application The following discussion centres around a very simple "Hello World" program. The source C code is as follows: /* HELLO.C CLIB Hello World application bai A #include int main(VOID) { printf ("Hello World"); getchar(); return (0); } Evidently, the program prints the message Hello World onto the screen, waits for the ENTER key to be pressed, and then terminates. A first look at project files Before hello.c can be compiled and linked, a project file needs to be specified. In this case, the following (hello.pr) suffices: #system epoc img #model small jpi #compile hello #link hello The meanings of the last two lines of this file are obvious enough: the file hello.c should be compiled, and then the resultant object file linked to create hello.img. Note that in any case of ambiguity, the extension .c should be added to the name specified in the #compile statement. 3-2 3 BUILDING AN APPLICATION The first two lines in hello.pr are less obvious. Their meanings are as follows: #system epoc img The end outcome of the build is a .img file, as defined in the Epoc-customised part of the TopSpeed configuration (alternative #systems include dos and win) #model small jpi The code is to be compiled in small model (code and data segments each restricted to 64K), with the jpi (TopSpeed C) convention of using registers to pass parameters to subroutines. These two lines must be present in all project files used to build applications for SIBO computers. Other possible contents of .pr project files are discussed later in this chapter. Creating the .img file There are two ways a .pr file can be used to create a .img program: e inside the TopSpeed ts programming environment (see TopSpeed documentation for full details) ¢ outside the ts environment. For example, one reason for working outside the ts environment would be to allow the use of another text editor, such as Brief. The remainder of this programming manual describes use of .pr files outside of the ts environment. For the moment, simply type: tsc /m hello to have hello.c compiled and linked, with the end result (among other files) being hello.img. The significance of the /m parameter is that the project file is executed in "make" mode, with files not being recompiled or relinked needlessly. Copying the program to the target machine If your PC has a set of SSD drives attached, simply copy hello.img onto an SSD in one of these drives, and then insert the SSD into the target machine (the SIBO computer). Otherwise, you may wish to use MCLink as follows: ¢ connect the SIBO computer to your PC using a suitable cable e run the Link application on the target machine (type 1ink at the HC command line, click on the Link icon on an MC, or set Remote Link on in the System Screen of a Series3) e run MCLink on the PC (eg by typing mcurnx if \sibosdk\sys is on your path) e adjust the MCLink serial port and baud rate parameters if required e type copy hello.img rem::m:\hello.img to transfer the program to the m: drive of the remote machine (or copy the file to rem: :m:\img\hello.img on a Series3) For more details about the MCLink program, see the chapter Mclink, Mcprint, and Slink in the Additional System Information manual. (For example, that chapter explains how the whole process of running MCLink can be handled via time-saving batch files at the PC end of the connection.) Finally, another way the program can be transferred from the PC to the target computer is by using the SIBO Debugger, as discussed below. Running the program on the target computer The way the program is run on the target computer varies from computer to computer: e onan HC, simply type hello at the s prompt of the Command Shell e onan MC, use the Run menu command of the System application, and select hello.img ¢ ona Series 3 or Series 3a, the entry Hello will appear in the file list of the RunImg application when this list is next updated (assuming that hello.img has been copied into a \img\ top-level directory), so that hello.img can be run simply by positioning the highlight over Hello and pressing ENTER. 3-3 GENERAL PROGRAMMING MANUAL Stepping through the program with the SIBO Debugger In order to debug a program, there is no special need to copy it "by hand" onto the target machine. Just type \sibosdk\sys\sdbg hello (or equivalent) at the PC end, and ensure Link is running on the target computer. (These instructions assume that hello.img is in the current directory on the PC.) In due course, the debugging screen will appear on the PC. (When debugging a program running on an MC, the baud rate for the Debugger to use may have to be given explicitly - eg \sibosdk\sys\sdbg -b19200 hello.) Step through the program (use F8 or ALT+S) until it hangs (waiting for a key to be pressed on the target computer). Or simply run the program to completion (use F9 or ALT+R). In fact, if hello.img has been built as specified above, the debugging screen will come up in machine code level. In order to debug at the source code level, a slight change has to be made in the way hello.img is built: e = either a line #pragma debug (vid=>full) has to be inserted in the project file (before any instruction to #compile) e alternatively, a parameter /v2 can be added to the command line invoking the project file. Thus typing tsc /m hello /v2 at the PC command line builds a version of hello.img suitable for source level debugging. As before, just type \sibosdk\sys\sdbg hello but this time, the debugging screen by default starts in source level mode, and supports inspection of variables, etc. See the SIBO Debugger manual for more details. A PLIB version of Hello World PLIB and CLIB contrasted The above "Hello World" program uses the so-called CLIB library. CLIB is a version of the TopSpeed C library for the EPOC operating system. As such, it is a version of the standard ANSI C library. The functions in CLIB are described in the TopSpeed C Library Reference manual. Additional notes, including a list of the TopSpeed C library functions that are not implemented, may be found in the following chapter, Notes on Clib. The EPOC version of the TopSpeed C library supports the ANSI functions and most of the portable functions that are commonly supported by MS-DOS C libraries such as Microsoft C and Borland's Turbo C. The less portable functions such as those that access the BIOS and graphics functions are not included. The benefits of using CLIB are: e portability (existing C programs can easily be converted) e less to learn for programmers already familiar with standard C libraries. However, for many programs, developers are strongly urged to consider using not CLIB but PLIB - Psion's proprietary C library. Whilst PLIB differs from the ANSI standard in many places, there are good reasons for all these differences, so as to best take advantage of the Epoc architecture. In particular: e many of the ROM-based EPOC system services are not available from CLIB (eg asynchronous I/O, inter-process messaging, the window server graphics functions) e executables are larger in CLIB and the process takes a larger data segment. The executables are larger because, although CLIB uses the ROM-based system services wherever possible, it is still a much "thicker" library than PLIB. The data segments also tend to be larger because the various CLIB subsystems typically require large static buffers and tables. 3-4 3 BUILDING AN APPLICATION See the Introduction chapter of the PLIB Reference manual for more details. In fact, unless you are using the in-built user interface object dynamic libraries (accessed using object- oriented programming), you can freely mix PLIB calls with CLIB. Experienced C programmers can, if they wish, initially use the more familiar CLIB functions and regard PLIB and WLIB (the window server library) as they would regard non-portable components of any C library. It is worth converting completely to PLIB and WLIB when the desirability of making efficient use of memory outweighs the benefits of portability and familiarity. The code for p_hello.c The code for a PLIB version of the above program hello.c is contained in the file p_hello.c: /* P_HELLO.C PLIB Hello World application ef #include GLDEF_C INT main(VOID) { p_printf ("Hello World"); p_getch(); return (0); } and a corresponding project file p_hello.pr would be #system epoc img #set epocinit=iplib #model small jpi #compile p_hello #link p_hello The following differences will be noticed between hello and p_hello: e the PLIB program uses a Psion-proprietary header file (plib.h in this case) e the PLIB program uses Psion-proprietary function calls (p_xxx functions) e the PLIB program links with a different library (this is one effect of the epocinit line in the project file - discussed further below). To build p_hello.img, just type either tsc /m p_hello Of tsc /m p_hello /v2 (the latter producing a version supporting source-code debugging). As a result of the differences between hello and p_hello, a substantially smaller .img file is produced (try it and see). The reason for the remarkable codesize improvement of the PLIB program is that, as mentioned earlier, the functions in the PLIB library provide only very thin shells over functionality that is present in the ROM of the SIBO computer. PLIB programs make better use of the SIBO ROM software than do CLIB programs. Being tailored to the particular needs of SIBO computers, PLIB evolved with very different constraints and objectives from standard C libraries. In many cases, PLIB functions can be claimed to "improve" upon the specification of their nearest CLIB equivalents. The difference in size between CLIB and PLIB programs is not always so remarkable as in the above example - it depends on the number and types of library function calls made. Indeed, it is perfectly possible to write some parts of an application using CLIB, and others in PLIB. This fact considerably simplifies any process of converting a previous large programming project from one computer system to the SIBO SDK system. Whilst it is possible to avoid PLIB entirely, this is not recommended. Time spent gaining familiarity with the functions in the PLIB library should prove an excellent investment, aiding the production of leaner and more powerful applications. In any case, familiarity with PLIB is a pre-requisite for accessing many other parts of the SIBO ROM software - such as the enhanced graphics facilities of the Window Server. 3-5 GENERAL PROGRAMMING MANUAL The epocinit statement in .pr files In p_hello.pr, the command #set epocinit=iplib sets the value of the project macro %epocinit. Note that this command must precede the #mode1 command in any .pr file. This command serves two purposes: it specifies whether you are using the CLIB or PLIB startup object files, and it specifies the stack size for the .img file produced. The allowed values of sepocinit are: iclib CLIB startup, 8k stack (recommended size when using CLIB startup) iclib4 CLIB startup, 4k stack iclib2 CLIB startup, 2k stack iplib PLIB startup, 4k stack (recommended size when using PLIB startup) iplib8 PLIB startup, 8k stack iplib2 PLIB startup, 2k stack If sepocinit is not set then it defaults to iclib (as in hello.pr). You must use the CLIB startup object files if you are writing a program that includes any CLIB library I/O functions. It is, however, possible to use many CLIB library functions (for example, the memory allocation functions) in conjunction with the PLIB startup. If you do not use any CLIB library functions then you should always use the PLIB startup. See the Introduction chapter in the PLIB Reference manual for more about startup object files. Housekeeping batch files and re-using project files A general project file: unnamed.pr Clearly, a project file such as p_hello.pr can be used, with only nominal changes, for a wide range of other similar programs. Consider the related project file, unnamed.pr: #system epoc img #set epocinit=iplib #model small jpi #compile %main #link %Smain in which the only difference from p_hello.pr is that references to p_hello have changed into main. Any batch file that invokes unnamed.pr has to set the value of smain as a parameter to tsc. For example, tsc /m unnamed.pr /smain=%1 with the TopSpeed /s construct being used to set the value of main to the variable passed into the batch file. A batch file for test compilation A programmers’ text editor usually has some means to compile or "test compile" a source file, from inside the editor. Many programmers find this a considerable boost to productivity. For example, Brief supports compilation on the ALT-F10 hot key, with the way the compilation is done being determined by an MS-DOS environment variable: e = during autoexec.bat (or a batch file called therein), set the value of bcc, eg to !"cc.bat %s" e the effect of ALT-F10 while editing a .c file would then be to run the batch file cc.bat, passing the basic name of the file (ie less the path and extension) into the batch file e the leading exclamation mark specifies that compiler warnings should be reported, as well as errors. 3-6 3 BUILDING AN APPLICATION The TopSpeed ts integrated development environment naturally possesses an equivalent mechanism, but some users may prefer to use an independent text editor. Accordingly, one suggestion is that there should be a file cc.bat in the local directory (or in the path), with the following contents (or equivalent): tsc %1.c /fpunnamed The meaning of the /fp construct is that the specified project file should be used (in this case, unnamed.pr). Given that there is no /m in this command (nor any /1), the specified project file is invoked in so-called "compile" mode: nominated files are compiled, without any files being linked. Further, the compilation always takes place, without any calculation of whether an object file is already "up-to-date". Once all the required C source files in a project have been successfully compiled, the programmer can exit the editor, and then "make" the project in the normal way: e no time will be wasted in recompiling files unnecessarily e a.img file will be produced (if the make is successful). The cc. bat file used for test compilation could be accompanied by a make.bat file that invokes the project file in "make" mode. Some complications There are a couple of shortcomings with the above batch file cc. bat: e it takes no account of whether files should be compiled with full debug information ¢ it takes no account of a possible specialised .pr file: the project file unnamed.pr is hard-wired. It does not take too much imagination to come up with a more general scheme - as is embodied in the batch files cc.bat and make.bat actually shipped with the demo files p_hello.c etc: e atest should be made for the existence of a project file with name 31. pr e attention should be paid to the value of an environment variable for whether to generate full debugging information. The batch files supplied assume that the required debug status is stored in an environment variable %4pivids. This should have one of the values v2 (for full debug information) or vo (for no debug information). However, cc.bat and make.bat each call a subsidiary batch file, checkvid.bat, which ensures that %jpivias does indeed exist and has one of these values. The value of s jpivids is itself expected to be set up by calling the final batch file in the suite: vid.bat. Typing vid on at the MS-DOS command line has the effect of setting sjpivids to v2, whereas typing vid off sets $jpivids to vo. Typing via by itself echoes the current vid setting. 3-7 GENERAL PROGRAMMING MANUAL The contents of these four batch files are as follows: (vid.bat) @echo off goto X%1X :Xv0X :Xoff£X set jpivid=v0 echo VID is now OFF goto :end :Xv2X :XonX set jpivid=v2 echo VID is now ON goto :end 2XX call checkvid goto Sjpivid% :v0 echo VID is OFF goto end :v2 echo VID is ON send (checkvid.bat) @if not "Sjpivids"=="v2" set jpivid=v0 (co batt) @echo off call checkvid if exist %1.pr goto custom tsc %1.c /fpunnamed /%jpivids goto end :custom tsc %l.c /fp%1 /%jpivids send (make.bat:) @echo off call checkvid if exist %1.pr goto custom tsc /m unnamed.pr /smain=%1 /%jpivid% goto end :custom tse /m %1.pr /smain=%1 /%jpivid% send Naturally, there is considerable scope for further personalisation and enhancement of these batch files, if desired. One final refinement would be to use the MS-DOS prompt command to change the prompt to reflect the current value of vid. For example, prompt $p_%jpivid%s$sg (The reason it is generally important to keep track of whether full debugging information is being generated is that significantly larger .img programs can result in this case.) TSC versus TSCX All the examples of compiling and linking that have been given so far use the TopSpeed tsc command. This command does not make use of expanded memory and may cause problems, particularly when linking large applications. Most of the batch files supplied with the SDK to compile, link or make executables use the tsc version. If this causes difficulties on your PC, you may find that replacing tsc with tscx (which uses expanded memory) in these batch files will cure the problem. 3-8 3 BUILDING AN APPLICATION More complicated programming setups The remainder of this chapter makes no mention of programming technique or programming concepts within the SIBO SDK system (see the later chapter Fundamental Programming Guidelines for that). Rather, it continues to explain more details of the mechanics of building applications of various sorts. Simple PLIB examples The following four programs all use the default project file, unnamed.pr, and each consist of only one source module: p_search searches a specified text file for a given piece of text p_prndir prints specified directory listings to the screen p_dlist lists all current "devices" (ie local and remote disk drives) Pp_comp compares two specified files, to see if they match. For example, to build a version of p_dlist.img suitable for source-level debugging, just type vid on make p_dlist To exit any of these programs which repeatedly request user input, simply press ENTER on an empty input line. Note: these programs are all restricted to so-called console i/o: e no attractive graphics e limited support for the user editing data entered previously. Additionally, they pay no attention to the actual size of the screen on individual SIBO computers. Whilst the data they display fits well enough on the large screen of MC computers, the display is less suited to the smaller screens of HC or Series3 computers. Simple modifications can make amends in this last regard. But for enhanced graphics output, use of Window Server functions is needed. Finally, these programs are all single-threaded, ie each has only one event source (the keyboard). At the same time, they contain no asynchronous i/o. (The vital topics of multi-threaded programming and asynchronous i/o are two of the central themes of the chapter Fundamental Programming Guidelines.) But despite their limitations, these four programs will hopefully be found useful for the purpose of acquiring familiarity with .pr project files and with the SIBO SDK system generally. There is no need to worry unduly over their detailed content; however, taking the time to build them and then improve them could well turn out a very rewarding exercise (eg in making the transition from CLIB to PLIB). Multi-file programs For a program with more than one source file, the corresponding .pr needs but a slight modification. For example, suppose a program triple has three source files: triple.c itself, utils].c and utils2.c. A suitable project file triple.pr would be system epoc img set epocinit=iplib model small jpi compile triple compile utils1l compile utils2 link triple The effect of the final #1ink statement is actually as follows: e link together all the files listed with #compile statements e link also the relevant startup module and standard libraries 3-9 GENERAL PROGRAMMING MANUAL e link also any object files or libraries specified by any #pragma link statements (see below for examples) e give the final executable the name specified in the #1ink statement. Note in particular there is no need for the name specified by the #1ink statement to match the name of the .pr file, nor the name of any of the individual files linked together. Graphics programs Programs which interact directly with the Window Server can produce a large variety of impressive graphics effects - icons and bitmaps, shapes and areas, mixed fonts and styles, scrolling and animation, information messages and alerts, and so on. These programs can operate with .pr files of exactly the same form as described earlier in this chapter. For example, the file unnamed.pr can continue to be used, unchanged, for any simple single-module Window Server program. Parts of the Window Server library, wlib.lib, are automatically linked in as required, without any change being required in the .pr file: there is no need to ask for wlib.lib explicitly. The source modules will, of course, have to change in the following aspects: e calls to Window Server functions gxxx or wxxx will be included e the Window Server header file wlib.h will have to be #included. For more details, including some introductory Window Server programs of the "Hello World" variety, see the Window Server Reference manual. HWIF programs Developers writing for the Series3 can take advantage of the additional menu and dialog functionality (amongst other features) of the HWIF library, to create applications very similar to those built into the rom of the Series3. See the Programming in HWIF manual for full details, including a suite of example programs. Project files for these programs need to include the line #pragma link (hwif.lib) since the HWIF library is not one of those that are automatically searched at link time. Customised libraries Developers may wish to collect various utility routines, or other subsets of code, into their own libraries, which can in due course be linked into different programs. Possibly, developers may wish to distribute their libraries in object form (./ib files), and not in source form. In such a case, there is likely to be at least two different .pr files: one controlling the creation of the .lib file, and one that, later, joins the ./ib file into a required application program. For example, suppose that modules utils/.c and utils2.c are to be compiled and linked into a library called utils.lib. This can be accomplished by means of the following project file: #system epoc img #set epocinit=iplib #model small jpi #compile utilsl #compile utils2 #dolink utils.lib Note the following points: e the command #dolink is used rather than #1ink, to stop the TopSpeed system attempting to link in a startup object too (not to mention other standard libraries) e the extension .1ib explicitly given overrides the default .img that would otherwise be assumed on account of the statement #system epoc img. 3-10 3 BUILDING AN APPLICATION A project file to produce an application tutils, say, that made use of functionality in utils.lib, could then be as follows: #system epoc img #set epocinit=iplib #model small jpi #compile tutils #pragma link (utils.1lib) #link tutils with utils.lib being searched for along the path specified in the redirection file ts.red. Applications containing assembler as well as C In principle, it is perfectly possible for an application to include assembler source modules, as well as modules written in C. For example, if an application contains two source files, cfile.c written in C and afile.a written in assembler, the following could appear in the project file: #compile cfile #compile afile The TopSpeed system will automatically run the appropriate "compiler" for each specified type of file - ie compiling the .c file and assembling the .a file. However, programmers should note that there are various rules that must be adhered to in writing assembler modules for Epoc programs. See the /ntroduction chapter of the PLIB Reference manual in the first instance. Note: the TopSpeed system will give an error message, and terminate, if there are two possible files each candidates as the source for of a #compile statement - for example, if the files cfile.a and cfile.c both exist in a directory. As another example, if a directory contains files query.c and query.rc, the statement #compile query will again result in an error - since the TopSpeed system regards the .rc file as a possible source file too. All these cases can be circumvented by giving the extension explicitly in the #command statement - eg #compile query.c. Other advanced use of the project file system The TopSpeed documentation describes many possible ways to exercise further control over the process of building program files. One general piece of advice should, however, be borne in mind: while learning to program within the SIBO SDK system, please accept the default configuration proposed by Psion. Only attempt to refine this configuration once your program is already clearly working. Otherwise, it may prove difficult to determine whether some unexpected program behaviour is due to a coding mistake, or to some unexpected side- effect of a proposed "optimisation" of the build configuration. In any case, optimisations resulting from careful choices of PLIB or WLIB (etc) functions, are likely to prove more significant than any that can easily be achieved by tweaking the SIBO version of the TopSpeed build configuration. It is also generally a bad idea to ignore warnings from the compiler and linker (except where explicitly mentioned in the SDK manuals). Rather than discounting these warnings as "quirks" of the system, they should all be analysed and dealt with. In particular, don't be too hasty to disable "inconvenient" compiler warnings. Note that the SIBO SDK build configuration is actually defined in two different parts: e in the file tsprj.txt which has to be "compiled" (using tscfg) before being used e in the file stdepoc.h which is always the first include file in any source module. As mentioned in the chapter on /nstallation, the file tsprj.txt released as part of the SIBO SDK modifies and extends the one released by Clarion themselves, by adding in details specific to the SIBO SDK system. GENERAL PROGRAMMING MANUAL Greater control over the image file created This section explains some of the SIBO add-ons to the TopSpeed project file build system. It also covers standalone use of the tools edump.exe, emake.exe and eremake.exe: e edump.exe provides key information about the contents of an image file e emake.exe is the underlying tool which creates image files e eremake.exe can be used to alter some of the "additional" contents of image files. Priority, minimum heap, and version number Three project file variables can be used to override various defaults otherwise used when a .img file is created: sversion sets the version number of the .img file, which otherwise defaults to 0x100f spriority sets the initial priority of the program, which otherwise defaults to 0x80 sheapsize sets the initial and minimum heap of the application, which otherwise defaults to 0x80. The application version number can be read by various pieces of software, for example the Application Info command of the System application on MC computers. For more about legal version numbers, see the section on p_version in the PLIB Reference manual. The initial process priority may occasionally need to be specified explicitly, eg for an application that is part of a suite of cooperating applications. See the section on p_setpri in the PLIB Reference manual and also the section Priority changing in the chapter General Window Server Functions in the Window Server Reference manual. The value of sheapsize is the one that applications are most likely to wish to alter, since this has significance for error handling (see the chapter Fundamental Programming Guidelines later in this manual): e the value of sheapsize is in paragraphs, eg 0x80 means 0x800 bytes ie 2 Kbytes e the operating system will refuse to start an instance of the application if this amount of free heap space cannot be found for it e once started, the application will never have its heap shrunk below this value. The default values for these variables can be overridden in either of two ways: e aline such as #set heapsize=0x180 can be added into the project file e the parameter /sheapsize=0x180 can be added to the end of the tsc command invoking the project file (this is evidently the same syntax as in the /smain=%1 in the supplied batch file make.bat). Use of edump.exe The tool edump.exe can be used to verify the values of the above three variables (amongst others) for a specified .img file. For example, typing edump p_hello results in output such as EDump V2.02F (03/10/90) Copyright (C) Psion PLC 1989 LOC: :D:\SIBOSDK\DEMO\P_HELLO.IMG IMAGE file data Image version = 200F Code Segment = 01D0 (bytes) Initial IP = 0000 Stack = 1000 (bytes) Data = 0040 (bytes) Heap = 0800 (bytes) Data Segment = 1840 (bytes) Initialized data = 0030 (bytes) Code checksum = DA14 Data checksum = OBF7 Code Version = 100F Priority = 0080 Header size = 0040 (bytes) Dyl count = 0000 Dyl table offset = 00000000 Image file size = 00000240 (bytes) where the default values of "Heap", "Code version", and "Priority" can all be seen. 3-12 3 BUILDING AN APPLICATION Deleting p_hello.img and rebuilding it via the command tsc /m p_hello /sversion=0x110b before running edump again yields identical output, except that the "Code version" line changes. Differences between .app files and .img files Strictly speaking, there is no real difference between image files with extension .img and those with extension .app. For example, although the System applications on the MC and on the Series3 usually expect to install .app files, they will also, if requested, install suitable .img files. However, by convention a .app file contains one or more extra so-called add-files embedded within it, in addition to the core .img file itself. These files may include: e a.pic file providing the icon for the application e a.rsc or .rzc file providing the resource file for the application e a.shd file providing the shell data for the application (only for Series3 applications). As such, a .app file is simply a .img file which has some associated files conveniently built into it. A significant advantage of a .app file is that a user cannot inadvertently sabotage the operation of the program by copying the .img file itself from one drive to another, but neglecting to copy one of the associated files. Add-files can be added into the .img file automatically, via the operation of emake.exe, at the time the .img file is itself created. What controls the set of add-files used (if any) is the presence or absence of a suitably named add-file list (.afl) file. Add-file lists An add-file list (afl) file is a text file containing from one to four filenames. For example, the contents of a file tele.afl could be: tele.pic tele.rsc tele.shd When any .pr project file is invoked that leads to the building of tele.img, the existence of a file tele.afl is checked for. If such a file is found, the files listed therein are combined with the core .img file to form a larger .img file as output. By convention, .img files that contain embedded add-files are renamed to .app files (though no such renaming takes place automatically). The inclusion of these embedded files can be confirmed by running the tool edump.exe as follows. Typing edump tele.app might yield EDump V2.02F (03/10/90) Copyright (C) Psion PLC 1989 LOC: :E:\SIBOSDK\HWDEMO\TELE.APP IMAGE file data Image version = 200F Code Segment = 1EDO (bytes) Initial IP = 0000 Stack = 1000 (bytes) Data = 0690 (bytes) Heap = 0800 (bytes) Data Segment = 1E90 (bytes) Initialized data = 03C0 (bytes) Code checksum = 33DF Data checksum = 3033 Code Version = 100F Priority = 0080 Header size = OOFO (bytes) Add 1 offset,len = 0040 (bytes), 0074 (bytes) Add 2 offset,len = 00C0O (bytes), 0000 (bytes) Add 3 offset,len = 00C0O (bytes), O02E (bytes) Dyl count = 0000 Dyl table offset = 00000000 Image file size = 00002380 (bytes) For the moment, the interesting data here is contained in the three lines of the form: Add n offset,len 3-13 GENERAL PROGRAMMING MANUAL These give the offsets within the combined .app file to the embedded add-files. In this case, three of the add-file slots are used; in general, any number from zero to four could be used. For more discussion about various possible add-files, see the Series 3/3a Programming Guide. A similar technique, using a DYL file list in a file with a .dfl extension, may be used to build any number of dynamic library (DYL) files into an application. This topic is described in more detail in the Object Oriented Programming Guide. Changing the set of add-files in an image The tool eremake.exe can be used to change the set of add-files built into an image file, without needing to run the TopSpeed project system again, and without needing to have any files to hand apart from the original image file. That is, image files can be remade with new add-file contents, without the earlier .exe, .obj, or .c files being present. One common use of eremake is to convert eg an English language version of an application into a specified alternative language version. See the chapter Resource Files in the Additional System Information manual for a general discussion of applications that can run in more than one language. For example, suppose that an application Query has all its language text isolated in a resource file query.rzc, which is one of the original add-files for the application. More precisely, suppose that the original contents of guery.afl are query.pic query.rzc query.shd Suppose further that a French version of the resource file is produced: frquery.rzc, say. Then a new .afl list should be created, frquery.afl say: query.pic frquery.rzc query.shd and eremake.exe should be invoked as follows: eremake -afrquery -o..\french\query.app query.app For a full list of possible parameters to eremake.exe, simply type eremake by itself. Note that eremake.exe can be used to alter the priority, minimum heap, or version number of an image file. In the above case, the "output" file ..\french\query.app is created by "remaking" query.app with add-files listed in frquery.afl. In this example, the files guery.pic and query.shd from the original version are also used for the French version. Clearly, these could be changed too, if required. Further uses of emake.exe The actual conversion from .exe form into .img form is handled by the Psion-proprietary tool emake.exe, according to the command #run "emake —-b %af1l% -otname% -s -v%version% -p%priority% -hsheapsize% -%epoctype% Sname%S.exe" in the file tsprj.txt. For a full list of possible parameters to emake.exe, just type emake by itself. Note in particular that emake can produce other forms of final output, apart from .img files. This is determined by the sepoctype variable in the above command, which by default takes the value t1. Other possible values are t2 through +4: tl makes an image file, with characteristic extension .img t2 makes a logical device driver, with characteristic extension .ldd t3 makes a physical device driver, with characteristic extension .pdd t4 makes a dynamic library, with characteristic extension .dyl. Logical and physical device drivers are further discussed in the Writing Device Drivers chapter in the Additional System Information manual. Dynamic libraries are discussed in the Object Oriented Programming chapter of the PLIB Reference manual, and in the Object Oriented Programming Guide. 3-14 CHAPTER 4 NOTES ON CLIB This chapter provides some additional information about the implementation of CLIB, the version of the TopSpeed C library for the Epoc operating system. It need be read only by developers who wish to use CLIB (for example, to port existing code from another program). Developers who stick to PLIB can skip this chapter entirely. The difference between PLIB and CLIB is explained in the previous chapter. Functions missing from the MS-DOS Jpi C library The following functions are not included in the EPOC version of CLIB because they rely on the IBM PC hardware, far or huge pointers, or direct MS-DOS functions calls. For many of the missing function calls there is an equivalent function or set of functions which may be called from either PLIB or WLIB. absread _arc bdos biosdisk biosmemory _bios_disk _bios_memsize _bios_timeofday _clearscreen ctrlbrk delay _dosbeginthread _dosfreestack dos creat _dos_findnext _dos_getdiskfree _dos_getftime _dos_keep _dos_setblock _dos_setfileattr dos. setvect _expand execve farcoreleft farrealloc _ffree _fheapwalk _fmsize _frealloc _getbkcolor getcurdir getdta _getfillmask _getlogcoord getpsp abswrite at bdosptr biosequip biosprint _bios_equiplist _bios_printer Jochain intr convertcoords _cube _directwrite _dosendthread _dos_allocmem _dos_creatnew _dos_freemem _dos_getdrive _dos_gettime _dos_open dos_setdate _dos_setftime _dos_write execle execvpe farfree fcalloc _fheapchk _floodfill _FP_OFF freemem getcbrk _getcurrentposition getfat _getimage _getphyscoord gettime allocmem Awaited bioscom bioskey biostime _bios_keybrd _bios_serialcom change country Delay _displaycursor dosexterr ados_close _dos_findfirst _dos_getdate _dos_getfileattr _dos_getvect dos read _dos_setdrive _dos_settime _ellipse execlpe farcalloc farmalloc _fexpand _fheapset _fmalloc _FP_SEG geninterrupt _getcolor getdfree getfatd _getlinestyle _getpixel gettext 4-1 GENERAL PROGRAMMING MANUAL _gettextcolor gettextinfo _gettextposition getvect getverify _getvideoconfig halloc _harderr _hardresume _hardretn hfree hide highvideo hmemccpy hmemchr hmemcmp hmemcpy hmemicmp hmemset hrealloc info Init intdos intdosx ioctl keep _lineto Lock locking lowvideo mktemp MK_FP movedata movetext _moveto ncalloc_ _ms_cursor _ms_getpage _ms_getsensitivity _ms_reset _ms_setdouble _ms_setmickeys _ms_setrange _ms_driversize _ms_getpress _ms_getstatus _ms_restoredriver _ms_setgraphcursor _ms_setpage _ms_setsensitivity _ms_getmotion _ms_getrelease _ms_lightpen _ms_savedriver _ms_setinterrupt _ms_setposition _ms_settextcursor _ms_swapinterrupt _ms_updatescreen normvideo nosound Notify obsucredat _outtext palettecolor palettecolorused paletteopen parsfnm peek peekb _pie poke pokeb _polygon putbeneath _putimage putontop puttext randbrd randbwr readbufferln _rectangle _remapallpallete _remappallete _selectpalette SEND _setactivepage _stbkcolor setblock setcbrk _setcliprgn _setcolor setdta setftime _setfillmask setframe _setlinestyle setlogorg setpalette setpalettecolor _setpixel _settextcolor _settextposition _settextwindow settitle setvect setverify _setvideomode _setviewport _setvsualpage snapshot sound spawnle spawnlpe spawnve spawnvpe StartProcess StartScheduler StopProcess StopScheduler tempnam textattr textbackground textcolor textmode tmpnam top Unlock use used WAIT window windowclose windowopen _wrapon _wrbufferlin int86x int 86x is implemented by exactly the same code as int 86, ie the values in the segment registers struct are ignored. This is because in the pure small model ps=zs=ss and hence there is never any need to change the values in the segment registers. intr As for int86x above, the values in the segment registers are ignored. File handle conversion routine void *getRealHandle(int handle); Returns a PLIB file handle, given a CLIB file handle. Returns nut if the handle is not currently allocated. 4-2 4 NOTES ON CLIB The console channel Programs built with the CLIB start-up module automatically open a console channel. The channel is also automatically assigned to stdin, stdout and stderr, unless they have been redirected. It may prove useful to get the actual PLIB handle for the console channel. This can be achieved by either calling getRealHandle(fileno(stderr)) or by referencing the global _winHandle as follows: extern void *winHandle; You can prevent the automatic opening of a console channel by defining the function p_xwind in your code, as in the following example: extern void *winHandle; void p_xwind (void) { winHandle=(void *)1; } int main (void) { return (0); } You should ignore the warning, given during the linking of your program, that the symbol _p_xwind is duplicated. If you use this technique your program should not, of course, make any reference to stdin, stdout or stderr, unless you have redirected them. Setting winHandle to | (an illegal value for a handle) will guarantee that any such reference will fail with a panic. MS-DOS file names Applications written for the Epoc O/S should in general avoid making any assumptions about file names (see the Files chapter in the Plib Reference manual) and should use p_fparse and p_chdir to manipulate file names and navigate directory paths. However the Loc: : file system on all SIBO machines is totally MS-DOS compatible. Thus CLIB supports the TopSpeed STD C library functions findfirst, findnext, getcwd, etc which rely on MS-DOS naming conventions. However if an attempt is made to use these functions on other filing systems, such as rem: :, the routines will return an error. Floating point emulator As the SIBO architecture does not allow for an 8087 maths coprocessor, all floating point is performed by software emulation of the 8087. Normally the emulator code would be linked in with your program for MS-DOS exe's, but under Epoc O/S the emulator is provided by an LDD called SYS$8087.LDD in \sibosdk\lib\. Any programs requiring the emulator will automatically load the LDD and free it again when it is no longer required. This has the advantage of saving about 8K of code from your program and allows the LDD to be shared by multiple processes. The C startup module (see r_emul.a) will look for the LDD in the directory in which your program was executed. If it is not found the it will use the environment variable ems (remember to use capitals for the name as environment variables in Epoc O/S are case sensitive). Panic 80 An application which terminates with a "panic 80" before it even starts has almost certainly failed to locate SYS$8087.LDD. There are three steps that can be taken to avoid the panic: move a copy of the LDD into the directory where the program will execute from set the environment variable ems appropriately (eg using a short program) rewrite the program so that it does not require the use of the LDD. See the Floating Point chapter of the Plib Reference manual for some more details. GENERAL PROGRAMMING MANUAL Note that floating point instructions can easily be generated unexpectedly (eg to push or pop floating point registers) if the recommended build configuration pragmas are "improved" in any way - resulting in panic 80s "out of the blue". If in doubt, inspect the object code using the SIBO Debugger (or use the TopSpeed disassembler, tsda). Building the CLIB library and header objects To build the CLIB library you must have purchased the Professional variant of the SIBO SDK. This version includes the C Library Source Kit and the corresponding EPOC CLIB Library Source. Since some of the EPOC CLIB source modules are written in C++, you will also need to have separately purchased TopSpeed C++. Simply startup TS in the SRC directory of SIBOSDK. Select CLIB as the project file and then MAKE the project. The libraries and objects will be generated in the SRC directory and need to be copied into the LIB directory. There is a batch file IVST.BAT which will do this for you. Note that, in addition to the CLIB library, there is also an RLIB component. This contains elements that are common between CLIB and PLIB. The source code modules for PLIB and WLIB are currently in Turbo Assembler format and are not buildable using the TopSpeed assembler. They have not been included in this release of the SDK. The vast majority in any case are simple shells which just juggle registers. Cautionary note It is advisable to tread cautiously when changing the library, and under no circumstances should the pragmas be changed in either TSPRJ.TXT or STDEPOC.H. CHAPTER 5 FUNDAMENTAL PROGRAMMING GUIDE-LINES Introduction In some ways, this chapter may be viewed as being among the most important in the whole of the SDK. Follow the Guide-lines here and your programs have a good chance of possessing the following qualities: user responsiveness users will not be kept waiting impatiently if they want to interact with an application whilst it is busy - eg to cancel some operation part-way completed error robustness data will not suddenly be lost when run-time errors occur such as shortage of system memory (bear in mind that such errors are almost inevitable on a multi-tasking computer, when the system memory can become unexpectedly used up by other applications) architectural robustness changes in user requirements or in implementation tactics should not lead to the whole code becoming unmaintainable. Of course, practice of standard general programming principles - such as modular programming, data hiding, egoless programming, designing prior to coding (not to mention adequate requirements specification prior to design), and a structured approach to validation and testing - all have important roles to play in the production of quality SIBO applications. But there are additional programming principles that have particular importance within the SIBO environment, and it is these that this chapter addresses. These principles should complement the ones good programmers from other backgrounds already practice. Incidentally, just as the merits of the above-mentioned "standard" programming principles are not always immediately obvious (data hiding is a good example), but rather have to be learned, so it is with some of the principles outlined in this chapter. Their importance has become clear to the programming team at Psion only gradually, over several years’ experience. It is understandable that experienced programmers from other backgrounds may wish to rush over this chapter, believing its contents to be inapplicable to them, but that would almost certainly be a mistake. Again, there is of course no substitute for a wide-ranging knowledge of which library functions are available. Developers wishing to produce quality applications will naturally have to spend some considerable time familiarising themselves with the contents of the reference manuals within the SDK, so as to be able to spot the right function to use in any particular coding situation. This knowledge cannot be acquired simply by assenting to the set of programming principles covered in this chapter. But conversely, wide knowledge of the set of available function calls is insufficient, by itself, to produce programs with the traits listed at the start of this chapter. Other related documentation Applications which are multi-lingual (eg which present English language messages on an English language computer, French language messages on a French language computer, and so on) pose their own set of programming problems. These are discussed in the course of the Resource Files chapter of the Additional System Information manual. (Resource files are a tool of particular importance for multi- lingual applications.) Note that these problems are shared between applications which are actually multi- lingual and those that are potentially multi-lingual: it is better to design support for multi-linguality in from the start, than trying to add it on afterwards. GENERAL PROGRAMMING MANUAL Graphics programming has its own particular set of do's and dont's, in order that (for example) flicker- free redrawing and automated screen update take place. These are discussed at various places in the SDK, for example, in the Window Server Reference manual, and also in the Programming in HWIF manual. Avoidance of excessive RAM usage, and also of "stack windup", are also of considerable importance within the SIBO architecture. Specific advice on these regards are scattered throughout the SDK; the present brief note simply has the purpose of drawing attention to the topic. Finally, the task of designing the user interface (menus, dialogs, and so on) is another that poses its own special problems - programmers who labour under the misapprehension that user interfaces are "easy" to design almost invariably produce poor user interfaces. Guide-lines on these matters may be found within the object oriented documentation parts of the SDK. The source code for the examples The bulk of this chapter consists of a lengthy analysis of a suite of example programs. These build in four stages - Events, Events2, Events3, and Events4 - to a program that can simultaneously process: e keyboard input e the expiry of a timer e reports of the completion of a sub-process e data received from a serial port whilst all the time carrying on some compute-bound activity "in background" At any given moment, the program cannot predict which of its five possible "event sources" will be the next to require CPU. As such, the program amply demonstrates the three vital themes of multi- threadedness, asynchronous i/o, and yielding CPU: e = multi-threadedness means that more than one set of activity takes place simultaneously within the program, with each different flow of activity being handled by its own "thread" of code e¢ — asynchronous i/o means that the queuing of a read request (or write request) on an i/o channel is separated in code from the completion of that request e yielding CPU means that lengthy calculations are broken down into subcomponents that are executed separately, with gaps in between so that some more urgent event source can be attended to, if necessary. Although the program itself has limited practical use, it demonstrates the basic architectural principles that all sophisticated Epoc programs are bound to have to consider. The source code for these four stages of Events can be installed from disc (SIBOSDK\DEMO), together with that of an associated "sub-process" application, Subproc. Readers are urged to take the time to build these applications and to experiment with them, in particular trying out some of the suggestions made in this chapter for how these programs could be modified. User interface The user interface of these example programs has deliberately been kept spartan. All screen drawing is to a "console terminal" that is 25 characters wide and 9 characters deep. These decisions have the advantage that: e the program works equally well on all different SIBO computers (even on the HC, where the screen is smallest) ¢ considerations about interfacing with the Window Server - necessary in order to achieve more graphically appealing displays - can be postponed while focusing instead on multi-threadedness, asynchronous i/o, and yielding CPU. Various examples of Window Server programs demonstrating multi-threadedness (et al) can be found within the SDK. For example, the Writing Software for the HC chapter of the HC Programming Guide discusses an application called Gauge, that will in fact run happily (with only minor adjustments) on a Series 3. Again, the Programming in HWIF manual contains a large set of example programs, all of which interface with the Window Server. 5-2 5 FUNDAMENTAL PROGRAMMING GUIDE-LINES A first look at multiple event sources The main routine in Events is as follows (the individual calls made, including the Plib calls, are discussed below): GLDEF_C VOID main(VOID) { OpenConsole(); DrawBorder() ; OpenTimer () ; timint=10; QueueTimer (); QueueKey () ; FOREVER { p_iowait (); if (keystat!=E_FILE_PENDING) { if (key. keycode==W_KEY_ESCAPE) p_exit (0); if (key.keycode>='1' && key.keycode<='9') SetTimInt (2* (key. keycode-'0')); QueueKey () ; } else if (timstat!=E_FILE_PENDING) { if (counter++==MAX_COUNT) counter=1; DisplayCount (); QueueTimer (); } } Schematically, the code is as follows: GLDEF_C VOID main(VOID) { INITIALISE (); QueueTimer () ; QueueKey () ; FOREVER { p_iowait (); if (keystat!=E_FILE_PENDING) { PROCESS_KEY () ; QueueKey () ; } else if (timstat!=E_FILE_PENDING) { PROCESS_TIMER() ; QueueTimer(); } } in which it is clear that the program has two event sources - keypresses and the expiry of a timer. What the program actually does is to update a numeric count (displayed on the screen) regularly, on a timer. The rate at which the timer fires is determined by which keys the user presses: e it starts off firing once every second e if the user presses the 2 key, the timer changes to firing once every 2/5 of a second (so that the numbers tick over more rapidly) e if the user presses the 9 key, the timer changes to firing once every 9/5 of a second (so that the numbers tick over more slowly) GENERAL PROGRAMMING MANUAL and so on. Further, every time a numeric key is pressed, the existing timer request is cancelled, and the timer reset - so that pressing repeatedly on keys such as 8 and 9 can have the effect of "stalling" the counter altogether. The program exits in response to the ESC key being pressed. All other keys are ignored. Remarks on timers One simple approach to programming with delays is to call a function such as p_sleep, which effectively suspends the application for a specified amount of time. This approach could be adopted in Events, were it not for the fact that, when the application is suspended, it cannot respond to a keypress. The keypress will only be received when the application "wakens up" again. Now this might not be too much of a loss for very small time delays, but it is of course unacceptable for longer delays. For example, a program might wish to perform some housekeeping or maintenance once every twenty four hours - or simply update the display in a dialog once every two seconds, whilst allowing the user to cancel out of the dialog at any time. That is, whilst routines such as p_sleep certainly have a role to play, they cannot handle all timer requirements in programs. A next possible approach would be to design a routine which, when called, suspended the application until the specified time elapsed or a keypress is received - whichever happens first. Indeed, there is a call with just this specification in the Opl programming language (pause when used with a negative time delay). Actually, this routine would satisfy the requirements of Events perfectly. However, it has the severe drawback of lack of architectural openness. That is, suppose the application has to be modified at a later date, to be able to respond to another sort of event source - eg the arrival of data at a serial port, or an interprocess message from another application. Alternatively, the application may need to carry on some continuous activity, whilst waiting for the timer to expire. In either case, a more general approach is required. This more general approach is the mechanism by which the queuing of a timer is separated, in code, from the completion of the timer. In the above code, the timer is queued by the call queueTimer, whereas the completion of the timer occurs within the p_iowait call. (See later for the details.) This kind of code separation between the queuing of a request and the completion of the request is known as asynchronous - because there is no automatic synchronisation of the two phases (as occurs, for example, in a call such as p_sleep). Remarks on keypresses A routine such as p_getch is to keypresses what p_sleep is to timers - in both cases, the program is effectively suspended until the request is completely satisfied. Just as there is a place for p_sleep in programming, so also there is a place for p_getch. However, each is generally inappropriate when there is more than one event source current - as here. So the call p_getch is split into two parts: the request for a keypress to be delivered, inside the call Queuekey, and the delivery of the keypress - inside p_iowait. More on p_iowait The call p_iowait is where the application gets suspended, while it waits for the completion of some or other event. But whilst p_sleep only returns when the associated timer expires, and p_getch only returns when a keypress is delivered, p_iowait returns when any known event has completed. Of course, sometimes the application won't get suspended at all when it calls p_iowait - on account of a queued request already having completed. For example, during the time Events is inside the code PROCESS_TIMER, the user may have pressed a key, in which case the subsequent call to p_iowait will return immediately (not that the application needs to worry about this, however). The way p_iowait works is by consulting the value of the i/o semaphore for the process. Each process has an i/o semaphore assigned to it. These semaphores are maintained in the private data space of the operating system. An i/o semaphore commonly has its value changed in either of two ways: e it is decremented whenever a call to p_iowait is made e it is incremented whenever some piece of software "signals" the application. 5-4 5 FUNDAMENTAL PROGRAMMING GUIDE-LINES For example, whenever a timer expires, the operating system timer device signals the application which owns the timer. Again, whenever the Window Server delivers a keypress to an application, it signals that application. In general, the completion of any i/o request always involves the application being signalled. The i/o semaphore of an application initially has the value zero. A call to p_iowait only returns when the i/o semaphore is non-negative. Given that the call to p_iowait starts by decrementing the semaphore, the call will return only when "something has happened". For more details about p_iowait and i/o semaphores in general, see the Plib Reference manual. Note that the SIBO Debugger has a menu command (Process Status) which displays the value of the i/o semaphore of a process (amongst other information). The Spy application discussed in the Series 3 Programming Guide has a similar feature, which allows the i/o semaphores of all different running processes to be viewed simultaneously. Status words: the other side of p_iowait When a program returns from a call to p_sleep, it knows that it is a timer that has expired. Likewise, when a program returns from a call to p_getch, it knows that a keypress has been delivered. However, when a call to p_iowait returns, no such information is immediately available. All the application knows at this point is that some event has completed - not which event. In general, the task of determining which events are indeed ready to be processed involves two factors: ¢ knowing which event sources are active - having had requests made on them e knowing which of this subset have completed their requests. For the moment, the first of these points can be ignored (but see later), with attention given to the notion of the status word of an asynchronous request: e when the request is made, an address of a status word is specified (recall that a "word" is two adjacent bytes) e when the request is made, the value E_rFILE_PENDING gets written to this word e when the request completes, a value other than &_FILE_PENDING is written to this word (the actual value varying depending on the type of asynchronous request) Writing to the status word takes place just before the i/o semaphore for the application is signalled. Both these steps are integral to the SIBO mechanism of p_iowait. All this explains the code in Events immediately after the call to p_iowait: the different status words are polled in turn, in order to find one whose value is no longer E_FILE_PENDING. Prioritisation of event sources Note that the order in which the status words are polled implicitly prioritises the different event sources. For it is possible for more than one asynchronous event to have completed; in this case, the first one of the two polled will be the one which gets the first response. Note in particular that the order in which events are processed need bear no direct relation to the order in which the events actually completed. An event source lower down the priority listing can be "locked out" by rapidly firing event sources higher in the listing. In fact, code can often be written which depends on this prioritisation - so that a lower priority event source is only serviced when all higher priority event sources have quietened down. I/O devices in general In this example, keypresses are delivered by the console device. Likewise, timer expiry is handled by the timer device. The console device and the timer device are both instances of general so-called i/o devices, all of which possess a common interface: e before using an i/o device, an application has to open a channel to it © once opened, various services can be requested via the channel e these services can all in principle be requested either synchronously or asynchronously e if an i/o device channel is no longer needed, the resources it consumes (eg memory) can be released by closing the channel. GENERAL PROGRAMMING MANUAL Channels to i/o devices are opened by means of the p_open call, in which the 1/o device has to be specified by name. Another parameter to the p_open call also defines where the handle of the channel will be written. The handle returned by p_open can then be used to request other services from the i/o device. It can also be passed as a parameter to p_close, to close the channel down again. The way synchronous requests are made, via an i/o channel, is to use a p_iow call (or a convenience routine that layers over this). Asynchronous requests are made using a p_ioa (or p_ioc) call. For example, the call to position the console cursor, inside the routine write in events.c, is as follows: P_POINT pos; WORD func; pOS.xX=X; Pos.y=y; func=P_SCR_POSA; p_iow4 (conH, P_FSET, &func, &pos) ; This is a synchronous call because there is no point in calling it asynchronously: the effect of this call (setting the cursor position) is always (virtually) immediate: there is no scope for any extended delay as it is carried out. On the other hand, the code for queuekKey is LOCAL_C VOID QueueKey (VOID) { p_ioa4 (conH, P_FREAD, &keystat, &key) ; } which is clearly asynchronous. (The 'a' in "p_ioa" stands for asynchronous.) By chance, it turns out that these two calls to p_ioa and p_iow have the same number of parameters. This, however, is only the case because the P_FREAD request requires one less parameter than the P_FSET request. In general, an asynchronous request always has one more parameter than the corresponding synchronous request - namely the status word, whose address has to be passed in the asynchronous case. For more on the p_io? functions (including the significance of the numeric suffices to the function names), see the Plib Reference manual. The console device The Events application uses the console device - as opposed to just making calls like p_printf - for two reasons: e as discussed already, the console device supports an asynchronous version of p_getch e the console device supports repositioning of the cursor position - which fact is relied upon heavily in the application. For a full specification of the console device, see the corresponding chapter in the //O Devices Reference manual. How to cancel a timer The code inside cancelTimer merits some attention: LOCAL_C VOID CancelTimer (VOID) { p_iow2 (timH, P_FCANCEL) ; p_waitstat (&timstat) ; } First, the P_FCANCEL service is requested. This is itself a synchronous request, completing at once. However, the way the generic service P_FCANCEL works in device drivers is never to retract the earlier request, but rather to precipitate its completion. It cannot retract it in general because it may already have completed by the time the p_FcANCEL request is made: e if the request has already completed, the p_rcaNncEL does precisely nothing e if the request is still outstanding, it is completed forthwith, with the value E_FILE_caANcEL being written to the status word, and with the application being signalled (on account of the fact that the earlier request has now completed, albeit precipitously). 5-6 5 FUNDAMENTAL PROGRAMMING GUIDE-LINES In either case, the application will be signalled - either before the p_rcanczg , or after it. Accordingly, this signal has to be "processed" (or "used up"). This is the purpose of the subsequent call to p_waitstat. For more details about p_waitstat, see the Plib Reference manual. Omitting to call p_waitstat after making a p_FCANCEL request is a common error. The result of this error is that the next call to p_iowait will return at once, even though none of the remaining active event sources is ready to deliver an event. For more details about the timer device in general, see the chapter Time, Timers and Dates in the Plib Reference manual. Where to declare status words On the subject of common programming errors in conjunction with asynchronous i/o, perhaps the most common one has yet to be mentioned. This is the mistake of declaring status words on the stack of some routine which will have returned long before the asynchronous request completes. The status word will now be a piece of random data - perhaps on the stack of another routine - and random damage can ensue when it is in due course written to. Status words should always be declared either in static data (as in Events), or in a control block allocated from the heap. A first look at error handling Every time a function call is written into a SIBO program, the programmer should consider the question: could a run-time error occur in the middle of this function? And if so, what would happen? Chief amongst these possible errors is lack of memory. This can occur in three different ways: e the application has reached the limit of its 64k data segment e the application is using less than 64k itself, but there is no system memory available for it to be given more heap space e another program with which the application is cooperating runs out of memory. Other errors that need to be considered include: e resources not being available because another application is already using them (eg serial port or sound device driver, or even a file that is currently open by another application) e disk-based errors such as disk full, disk corrupt, or disk removed e the unexpected disappearance of the remote filing system (rem: :) e comms failures such as serial overrun, parity error, or line failure. These errors cannot be dismissed with the philosophy that, in an ideal world, they will not happen. Instead, they can and will happen, despite the best endeavours of the programmer. SSDs becoming full up, comms cables being removed, or a file already being open by another program, are all problems that arise naturally in the operation of a SIBO computer. Whatever the cause of a run-time error, applications should take every care that no data entered by the user is lost. Another requirement - to avoid parts of memory being permanently tied up for no purpose - is that partly assembled data constructs which cannot be completely assembled, owing to a run-time error at a later stage, should be carefully disassembled again. Error handling in Events Looking at the source code in events.c, it is clear that three different types of error are considered: e failure to open the timer device e failure to open the console device e failure to set the size of the console screen. GENERAL PROGRAMMING MANUAL None of the other function calls have any possibility of run-time error, as can be verified by considering them all individually. (In fact, considering every call individually for possibilities of run-time error has to be the norm when developing applications.) It is worth considering the above three possible errors in a little more detail. For example, opening a timer can fail for two reasons: e lack of memory for the timer control block in the application data space e lack of memory in the operating system dataspace for the real timer entry. Now whilst an application may be able to ensure that the first possibility never arises - by means of setting its minimum heap appropriately - it can never be sure of preventing the second case. The number of timers allocated in operating system dataspace depends not on circumstances within the original application, but rather on what other applications have done. If other applications running simultaneously happen to make heavy use of timer resources, the operating system may not be able to set aside the one timer channel requested by Events. Should this occur, the code in openTimer and Check ensure that a suitable error message is passed back to the user. The user can then take action to shut down some of the other applications running simultaneously on the computer, before trying to start Events again. The case of the channel to the console device is similar. This time, it is resources of (for example) the Window Server which may be unable to meet the request made. Likewise when the console window is sized (at which time various arrays or back-up bitmaps need to be allocated). Fatal errors and non-fatal errors The three possible errors in Events are all treated as being fatal: the application initialisation fails, so the application terminates. This kind of action makes good sense for errors during the initialisation of an application, but cannot on the whole be tolerated for errors during the main phase of an application (ie after the initialisation is complete). By this time, the user may well have committed some data into the application, which would be lost if the application suddenly terminated. In these cases, a retry philosophy is much more appropriate: the application cleans up any interim semi- allocated resources, "rolls back" to its previous good state, and presents an error message informing the user what has happened. It is up to the user to try to correct the error condition, and then re-initiate the previous action. When resources need to be tidied explicitly It may be noted that there are no calls to p_close in events.c. These calls are unnecessary in this program, because the channels are automatically closed, by the operating system, when the application exits. This situation must be contrasted carefully with that when a resource (such as a channel to an i/o device) is used transiently by an application. In this case, it must be freed as soon as it is no longer needed. Inter-Process Communication Events2 and Subproc Events2 extends the functionality of Events by supporting the facility to launch a sub-process. A sub- process is automatically started during program initialisation, and once it has terminated, the user can press ENTER to re-launch it again. The sub-process mimics the carrying out of some extended activity. When it finishes, it signals the fact of its completion to Events2, together with an "answer", which Events2 displays on the screen. This answer has in fact been calculated from a parameter passed by Events2 to Subproc on the command line. Subproc and Events2 therefore carry out a restricted form of inter-process communication, and thereby illustrate some of the multi-tasking possibilities in writing software for SIBO computers. A third event source Events2 remains alert to the possibility of a signal from Subproc, even though it is busy responding to timer events and keyboard events. Events2 manages this via a straightforward extension of the architecture in Events: one more "event source" is added into the picture. 5-8 5 FUNDAMENTAL PROGRAMMING GUIDE-LINES Thus there is one more status word - substat - and one more test in the main loop in main: else if (substat!=E_FILE_PENDING) Report Sub () ; That is, whereas main used to poll up to two status words, on returning from a call to p_iowait, it now polls up to three status words: subst at in addition to keystat and timstat. However, this new event source differs from the previous two in that it is not an i/o device. There is no p_ioa call to request notification from Subproc; rather, the corresponding "queue" call is p_1ogona. In the line of code p_logona (pid, &ésubstat) ; the calling application (Events2) is requesting asynchronous notification of the eventual termination of the process identified by pia. This notification consists of two parts (now familiar): e avalue other than &_FILE_PENDING is written into substat e the application is signalled (so that its i/o semaphore increments). How Events2 passes data to Subproc Events2 passes its original data to Subproc via the command line. In any case like this, there has to be an agreement between the two processes as to the format of the command line. Here, the protocol is established in the shared header file subproc.h, which defines the following struct: typedef struct { HANDLE pid; VOID *poff; ULONG data; } SUBPROC_CL; The members of this struct serve the following purposes: pid identifies the process which launched Subproc (ie Events2) poff an address within the dataspace of Events2 where Subproc should in due course write back the "answer" it discovers data _ the original seed data for Subproc to operate with. The following code sets up this struct and creates and runs Subproc: LOCAL_C VOID LaunchSub (VOID) { HANDLE pid; SUBPROC_CL cl; TEXT subname [P_FNAMESIZE]; p_fparse ("subproc.img",DatCommandPtr, &ésubname[0],0); cl.pid=p_getpid(); cl.poff=(&answer) ; cl.data=p_date(); if ((pid=p_execc (&subname[0],&cl,sizeof (cl) )) <0) { p_notifyerr(pid,"Failed to launch subprocess",0,0,0); return; } p_logona (pid, &substat) ; p_presume (pid) ; } The variable answer is a static. Clearly, it would be a significant error to include it on the stack of LaunchSub, since this stack will have unwound before answer gets written to (by Subproc). As can be seen, in this example, the data value passed to Subproc is just the current time/date, as returned by p_date. GENERAL PROGRAMMING MANUAL Note the call to p_fparse, which calculates the presumed full pathname of subproc.img, under the assumption that this is in the same directory as events2.img. (The full path of events2.img is written to DatCommandPtr by the operating system, when Events2 starts running.) For more on the operation of p_logona, see the Plib Reference manual. The code in Subproc The code in subproc.c is very straightforward: #include #include #include #include #include "subproc.h" GLREF_C TEXT *DatCommandPtr; GLDEF_C INT main(VOID) { TEXT *pb; SUBPROC_CL *pcl; UWORD answer; WORD logstat; pb=DatCommandPtr+p_slen(DatCommandPtr) +1; if (*pb!=sizeof (SUBPROC_CL) ) return (E_GEN_ARG) ; pcl=(SUBPROC_CL *) (pbt+1); if (!p_logona(pcl->pid, &logstat) ) { answer=(UWORD) (p_randl (&pcl->data) % (2*60*32) ); p_sleept (answer) ; if (logstat<0) p_pcpyto (pcl->pid, pcl->poff, &answer, sizeof (UWORD) ) ; } return (0); } The way Subproc mimics performing a lengthy calculation is simply to call p_sleept, for some random period up to two minutes in duration. Note that Subproc exits at once if the command line passed to it is not of the expected type. On most SIBO computers, the result of an application calling p_exit with a negative value is a Notifier reporting the abnormal exit. Note too that just as Events2 asynchronously logs onto Subproc, Subproc logs onto Events2. However, this is for a different reason. Namely, Events2 might terminate in the meantime, while Subproc is busy "calculating". In this case, a non-negative number will be written into logstat. If Subproc ignored this fact and proceeded regardless to p_pcpyto data into the process currently having identifier pc1->pia, in all probability the call would fail - process identifiers take a long time to get re-used, and the operating system would ignore the p_pcpyto on account of a non-existent pid being specified. But there is always an outside chance that the pia will indeed be re-used by the time Subproc has completed - in which case the p_pepyto could cause random damage to a blameless application. The reason there is a test on the result of the p_logona call in Subproc is to guard against the rare case of Events2 exiting even before Subproc reaches the p_logona call. Mechanisms for inter-process communication The above mechanism is a very simple illustration of a form of IPC (inter-process communication). Epoc supports a considerable range of IPC services, chief amongst them being IPC messaging. Messaging also involves the same principles of status words, synchronous or asynchronous requests, and signalling an application. In some cases, one process will signal another one explicitly, using the function p_iosignalbypid; in other cases, the signalling is performed by the operating system, say in response to a p_mfree call in an application (indicating that the message sent has been processed). See the Plib Reference manual for more details of these different forms of IPC. 5-10 5 FUNDAMENTAL PROGRAMMING GUIDE-LINES Debugging cooperating applications One method of debugging the interaction between Events2 and Subproc is as follows: e leave both image files in the same directory on the PC e in that directory, type sdbg events2 to start debugging Events2 e place a breakpoint on the p_logona call in events2.c e run Events2 until it reaches this breakpoint e note incidentally that the p_fparse call in Launchsub automatically deduces that since Events2 has been launched from a remote directory (ie on the PC), Subproc should also be launched (if possible) from this same remote directory e when the Debugger breaks at the p_logona call, the code and data segments for Subproc will already be created (by virtue of the prior p_execc call) e refresh the main list of remote processes; select Subproc and break into it (use the Break Into menu command) e scan to the beginning of main in subproc.c and set a breakpoint there e issue the Apply Breakpoints menu command (whence the windows will go blank) e switch back to the window debugging Events2 and step over the p_presume call e this will have the effect of starting the execution in Subproc - in which case the breakpoint in main will be reached. Debugging now continues, with two different debugging windows - one for Events2, and one for Subproc. Error handling in Events2 The call to p_execc in Events2 can fail for a variety of reasons - chief amongst them lack of system memory. Note that Events2 does not treat this as a fatal error; rather, the error is reported to the user, and the program carries on (taking care to leave the internal variable subexist set correctly). The user has the opportunity to respond to the message by freeing up some system memory, and then pressing ENTER to make another attempt to launch Subproc. Socially responsible programming in Events2 There is one more change between events.c and events2.c, which actually corrects a bug deliberately left in Events. This change is the addition of a call to p_unmarka at the start of main. If a SIBO computer is left switched on while Events is running, it will fail to auto-switch-off subsequently. This is because of the regular timer activity in the program, which keeps resetting the inactivity counter of the computer. Suppose that the user turns the computer off explicitly. However, if an alarm rings at some stage, Events will start running again, and if the user is not at hand to notice the alarm, the result will soon be flattened batteries - regardless of the auto-switch-off setting. (Try it and see.) However, the addition of the call to p_unmarka prevents any activity within Events2 from resetting the inactivity counter. As a result, Events2 is much more socially responsible than its precursor. See the Plib Reference manual for more details on p_unmarka. Data received from a serial port Events3 extends the functionality of Events2 by including yet another event source: data received from a serial port. Characters are read one at a time from the serial port and, if they are printable, they are echoed onto the screen. For background information on the serial port, see the Serial Port chapter of the I/O Devices Reference manual. 5-11 GENERAL PROGRAMMING MANUAL Opening the serial port The serial port is an i/o device: before services such as P_FREAD can be requested from it, a suitable channel has to be opened. The contents of the openSer routine in events3.c are as follows: LOCAL_C VOID OpenSer () { INT ret; ret=p_open(&serH, "TTY:B",-1); if (ret<0) ret=p_open(&serH, "TTY:A",-1); if (ret<0) { p_notifyerr(ret,"Opening serial port",0,0,0); serH=0; } } If the attempt to open "TTyv:8B" fails, an attempt is made to open "TTy:A" instead; only if both attempts fail is this fact reported to the user. Typical reasons for it being impossible to open a serial port are that port already being in use (eg by Link software) or the port not being physically present. In contrast to the retry mechanism for launching Subproc which is built into Events3, there is no corresponding retry mechanism for opening the serial port. A trivial amendment could be made to allow this. Active and inactive event sources Events3 adds this fourth event source to the bottom of the prioritised list in main, which now has the following schematic form: GLDEF_C VOID main(VOID) { INITIALISE(); QueueTimer (); QueueKey (); LaunchSub () ; QueueSer(); FOREVER { p_iowait (); if (keystat!=E_FILE_PENDING) { PROCESS_KEY (); QueueKey (); } else if (timstat!=E_FILE_PENDING) { PROCESS_TIMER() ; QueueTimer (); } else if (subexist && substat!=E_FILE_PENDING) Report Sub (); else if (serH && serstat!=E_FILE_PENDING) { p_tickle(); DisplaySerChar (); QueueSer (); } 5-12 5 FUNDAMENTAL PROGRAMMING GUIDE-LINES Note however that the test for whether to call Report sub has changed its form slightly. No longer is it sufficient just to poll substat; it is also necessary to check on the current value of subexist: e subexist is set to TRUE When Subproc is successfully launched e¢ subexist 1s set back to FALSE whenever it is discovered that Subproc has completed e thus the only time the value of substat should be polled is when subexist iS TRUE. Without this double check, a variety of bugs can be demonstrated - all of which stem from serial port events being misinterpreted as reports of Subevent completing. Similarly, for the sake of correctness, the value of serx should be tested before going on to poll serstat: serH is 0 if it has proved impossible to open a serial port. (Actually, no immediate harm will ensue if the check on serH is omitted, given that this is the last of the event sources in the priority list.) The reason no corresponding checks are required for the keyboard and timer event sources is that these event sources are always active: e the program terminates at once if it proves impossible to open a channel to these devices e every time an event is delivered from these sources, another request (for yet another event) is issued straightaway. The variables serx and subexist in Events3 play the role of what are sometimes called active words for their event sources - complementing the roles of their status words: e active words have to be set and cleared by the application itself e status words are written to by system software; generally, application software only reads the values of status words ¢ active words are set when a request is made; status words are set when a request completes. One other possible advantage in maintaining active words for event sources is to avoid making the mistake of sending a Pp_FCANCEL request to an i/o channel which has not had a read request made on it. Some i/o devices panic the application if this happens. Debugging applications with serial comms Programs involving serial comms are inevitably harder to debug than without serial comms. This is because the Debugger itself uses up one serial port on the computer. In general, Events3 will be unable to open any serial port currently being used by Link software (such as the SIBO Debugger). One possibility, however, is to use say port a to debug the application, and send serial data to the application via port B. The role of p_tickle Whenever serial port data is received by Events3, a call is made to p_tickle to reset the inactivity counter. This prevents the computer from auto-switching off part way through processing an incoming stream of serial data. Note that there is no requirement to make a corresponding call whenever a keypress is received, since the operating system does this automatically. Finally, it would of course be an error to make this call whenever the timer expires - since this would keep the computer permanently switched on. Note that some early versions of the Epoc operating system may fail to support p_tickle (versions prior to 2.11). Yielding CPU in compute-intensive programs Events4 adds in yet another type of event source - one that is subtly different from all the others so far introduced. This is an event source which is always ready to run immediately. However, it is deliberately located in a low position in the priority listing, to ensure that other event sources are processed preferentially. 5-13 GENERAL PROGRAMMING MANUAL A real-life example of such an event source would be a recalculation computation in a spreadsheet, or a reformatting calculation in a word processor. Again, a long file operation - such as building the index of a DBF file - should also be broken up into chunks, so as to let the application to respond to other event sources in the meantime. Finally, a game may think indefinitely until such time as it is told to stop. In Events4, this continual "thinking" is simulated by continually adjusting the display of part of the boundary of the console window. The constant visible change is meant to reflect constant internal activity. Idle objects Event sources such as just discussed are sometimes referred to as idle objects. The meaning of the name is that they only get a chance to run when the application is otherwise idle. For example, if an application is busy responding to keypresses, it is certainly not idle, and so any idle objects have no opportunity to run. On the other hand, this name is of course potentially misleading, since the activity represented by the idle object is anything but idle. The meaning of calling p_iosignal The contents of the "queue" routine for the idle object in Events4 is just the single line p_iosignal(); Since there is no genuine i/o connected with an idle object, there is no system software that automatically signals the application when the i/o has completed. That is why the "queue" routine itself calls p_iosignal. At the same time, it might be thought that this routine should write to a status word. Actually, however, there is no point in doing so: what matters is simply that the event source is active; in that case, it is automatically ready to deliver an "event" (ie to take more CPU). Just as some event sources have no need to maintain an active word (since they are always active), others (ie idle objects) have no need to maintain a status word, since whenever they are active, they are ready to deliver an event. One drawback of continuous activity Interestingly, Events4 has re-introduced the "stay awake" bug that Events2 managed to fix from Events. This fact can easily be verified by user experimentation. The call make to p_unmarka is now ineffective since, as is explained in the Plib Reference manual (section on p_unmarka), it is the sys$null process which administers the auto-switch-off, yet it will have no opportunity to run if any other applications are continually running. The point is that the priority of sys$null is lower than that of any other process. One possible solution here is to call, say, p_sleept (2) every so often, to try to allow sys$null to run. However, this too will fail in the rare case when there are two similarly anti-social applications running simultaneously on the SIBO computer. Even if they both call p_sleept periodically, there is little chance of them both sleeping at the same time - which would be required in order for sys$null to run. A better solution is to call p_allowoff from time to time. By doing so an application assumes responsibility for performing the auto-switch-off that would otherwise be done by sys$null if it had an opportunity to run. Remarks on process priorities The above problem of preventing the SIBO computer from auto-switching off is not the only potentially deleterious side-effect of continuous activity. Just as continuous activity within Events4 prevents sys$null receiving any CPU, so too will any other lower priority processes be locked out. As it happens, Subproc and Events4 both run at the same process priority - the default of 0x80. (See the chapter Building an Application for details on how process priorities are initialised.) However, suppose the process priority of Subproc were lowered to say 0x70. In that case, continuous activity within Events4 would mean that Subproc, although launched, would never receive any CPU. Thus Events4 would perpetually display the message "Subp launched", but never the completion message "Subp slept xxx ticks". The solution here is that any process about to become computationally intensive over a long period of time should consider lowering its process priority, say to 0x70 - using the call p_setpri. For some related discussion, see the section on wStartCompute in the Window Server Reference manual. 5-14 5 FUNDAMENTAL PROGRAMMING GUIDE-LINES The call p_ioyield One more potentially surprising fact about continuous activity within a program ought to be mentioned. Clearly, not every program needs to be structured with an asynchronous event processing loop as in the Events programs. Whilst such a loop is undoubtedly the correct architecture for a larger program, other simple programs may have alternative structures. For example, Subproc makes no call to p_iowait - nor does it need to, being purely single-threaded. Again, the example Plib programs discussed in the chapter Building an Application (eg p_hello, p_comp and p_prndir) likewise survive without an asynchronous event processing loop, since they are likewise single-threaded. However, there may be a temptation for programs to use the following semi-asynchronous mechanism, in order to be able to respond to keypresses (say) whilst being mainly dedicated to some continuous activity: ¢ continue processing queue an asynchronous request to receive a keypress e start the continuous activity e every so often, test to see if the status word is still z_F1LE_PENDING e if it is, continue processing In other words: FOREVER { QueueSer (&keystat) ; while (keystat==E_FILE_PENDING) MoreProcessing(); ProcessKey(); } However, this program may totally fail, with keystat never changing from B_FILE_PENDING. The reason for this is rather complicated, but it is worth understanding. It has to do with what happens when an asynchronous event completes. This completion often involves two distinct phases: e the completion itself happens on an interrupt ¢ an interrupt service routine runs, and the i/o device changes some of its internal variables to record this fact e however, the i/o device generally cannot write to the associated status word during the interrupt service routine itself e this is because there are strict rules on what can and cannot be done within an interrupt service routine (see the chapter Writing Device Drivers in the Additional System Information manual for more details) e instead, the i/o device relies upon its so-called wait handler routine to be called, so that it can finish the job of completing the request - writing to the status word and signalling the application e these wait handler routines only have an opportunity to run inside the call p_iowait (or equivalent). In other words, the description given earlier in this chapter of the functioning of p_iowait was incomplete in one important respect: not only does this routine take note of the value of the i/o semaphore for the application, and suspend the application so long as this remains negative; it also gives all i/o device channels in the application an opportunity to run their wait handlers. 5-15 GENERAL PROGRAMMING MANUAL Accordingly, the earlier code has to be changed into FOREVER { QueueSer (&keystat) ; while (keystat==E_FILE_PENDING) { MoreProcessing(); p_iosignal(); p_iowait (); } ProcessKey (); } which is in fact much more in line with the main routine of the Events4 application discussed. For convenience, the single call p_ioyie1d can be used with the same effect as p_iosignal followed by p_iowait. Note incidentally that it is a rare application that needs to actually write a wait handler; there is of course no need to write a wait handler routine just because an application involves asynchronous i/o. General remarks Multi-threadedness and multi-tasking For the sake of clarity, the two different notions of multi-tasking and multi-threadedness ought to be compared and contrasted: e multi-tasking involves two (or more) different processes; multi-threadedness involves two (or more) event sources within one process e the operating system takes care of multi-tasking automatically, on behalf of applications; multi- threadedness requires conscious effort from an application e §=multi-tasking is pre-emptive in that a process with a higher priority that is ready to run will always displace a lower priority process that is running e multi-threadedness is non pre-emptive in that an event source with a higher priority has to wait until a lower priority event source voluntarily gives up CPU, before being able to run. Subprocess or idle object? In the design of large systems, there is considerable scope for decision-making on whether to assign compute-intensive tasks to idle objects within an application, or to a subprocess of the application proper. Some factors that may be considered in making such a decision are: e having two different processes automatically allows a total combined dataspace greater than 64k e asubprocess need not worry unduly about creating "holes" ("fragmentation") in its allocator heap, since these will all vanish when the subprocess terminates (when its entire heap vanishes); however, if an idle object is transient and terminates well before the overall application finishes, any fragmentation it creates in the allocator heap may have a more damaging long-term effect (see the chapter Memory Allocation in the Plib Reference manual) e an idle object is much more tightly bound to the main program than is a subprocess ¢ communications between a subprocess and the main program have to be much more formalised than is the case with an idle object e an idle object can draw to the same windows on the screen as the main application, but not so for a subprocess (except in the case of the MC - see the function wAttachToclient in the Window Server Reference manual). 5-16 5 FUNDAMENTAL PROGRAMMING GUIDE-LINES Window redraws as an event source Up till now, one very important event source has not been mentioned in this chapter. This is the event of a window requesting itself to be redrawn. (In fact, the request originates from the Window Server.) These events do not occur when using console i/o, nor when using windows with back-up bitmaps: windows are automatically redrawn by the Window Server in these cases. However, high quality applications undertake window redrawing by themselves, so as to avoid the large ram overheads of the back-up bitmaps. (See the Introduction chapter of the Window Server Reference manual.) Such applications must remain responsive to redraw events at all times - otherwise their screen will remain blank if they are suddenly task switched into foreground, or if an overlapping menu or dialog window is removed. This is all the more reason for these applications to adopt the sort of general event processing architecture outlined in this chapter. The APPMAN and ACTIVE classes in OLIB The appman and active classes in olib.dyl provide system support for object-oriented applications e representing their event sources (each event source is represented by an "active object") e prioritising these event sources ¢ maintaining active and status words for each event source e calling p_iowait at appropriate times e ensuring that all event sources are properly polled. At the same time, the appman class ("appman" is short for "application manager") provides an automated mechanism for error handling, as well as handling the interface to resource files (see the Resource Files chapter in the Additional System Information manual). These topics are further discussed in the Object Oriented Programming Guide. In addition, the appman and active classes are documented in the OLIB Reference manual. 5-17 GENERAL PROGRAMMING MANUAL 5-18 CHAPTER 6 CoPyY-PROTECTING SOFTWARE Introduction This chapter considers various mechanisms to "copy-protect" software written for SIBO computers. Possible goals of copy-protection include: e software should be able to run, only from the original SSD it is supplied in e — software should be able to run, only on one particular computer e first generation copies should be allowed, but not second generation copies (ie direct copies make from the original SSD would run, but not copies of these copies) e possibly, the number of first generation copies allowed could be limited. These different goals vary in their applicability to the different computers in the SIBO range. For example, software that disallowed even first generation copies would be very unwelcome on the Series 3, because it prevents consolidation - the process whereby users copy more than one different application onto the same SSD. It is unlikely that such software would sell at all well. On the other hand, this kind of strict copy protection makes more sense for the HC, and for corporate ("Vertical") programs generally. At the same time, software developers may wish to apply differing amounts of sophistication in their copy protection schemes - some being willing merely to frustrate the casual would-be copier, and some being determined not to allow copying at all (if possible). This chapter does not favour one copy protection method over all others. Rather, it simply hints at various different possibilities. Software developers may find it convenient to mix and match the different proposals made, as well as others (along the same lines) that they can think of themselves. By the very nature of the subject, too much documentation would be self-defeating. Once any algorithm to implement copy protection becomes widely known, methods to defeat this algorithm may be developed and circulated. | ic I a The free space method This method aims at strict copy protection: the software will only run if it is on the original SSD. This simple yet effective method turns one of the commonly debated ‘disadvantages’ of using Flash storage into an advantage. The method is based around the fact that when a file is deleted from a Flash SSD it remains on the pack taking up space but is no longer practically accessible. Assuming that an application master pack contains a deleted file, if someone were to copy this pack using the usual copy from the root including subdirectories, the resulting copy of the master pack will differ fundamentally: the deleted file no longer exists. This in turn means, rather conveniently, that the amount of free space on the pack will be different. Given the above you can then hard-code into your application a check to see if the figure for space on the pack matches the figure you expect: if it does then all well and good; else, do not allow the software to run. GENERAL PROGRAMMING MANUAL The way to find the amount of free space on an SSD is to call p_dinfo. For example, a program that prints the amount of free space on the disk the program was launched from: #include #include #include GLREF_D TEXT *DatCommandPtr; GLDEF_C INT main(VOID) { P_DINFO dinfo; p_dinfo(DatCommandPtr, &édinfo) ; p_printf ("Free space is %lu",dinfo.free); p_getch (); return (0); } First generation copying methods Methods that allow first generation copies to run, but not second generation copies, rely on a separate "AppCopy" program being provided on the master SSD, in addition to the program itself. First generation copies can only be made using the AppCopy program. Copies made using ordinary Copy commands will fail. Further, AppCopy will refuse to copy first generation copies into second generation copies. Essentially, AppCopy does not make an exact copy, but changes some of the bytes in the application program. This can be done, even on Flash SSDs, provided: e the original values of the bytes are all oxrft's e the bytes are adjusted one at a time (assuming that a complete copy has already been made, and that this complete copy has to be altered). The last point is most important; the Flash filing system tests for the special case of only one byte being written, and in this case, alters the physical byte on the SSD. In other cases, the physical structure of the file is significantly changed. Preserving checksums Note that in adjusting bytes in a program file, care has to be taken not to disturb the code or data checksums (as reported eg by the tool edump.exe). Otherwise, the operating system will refuse to run the program, believing it to be corrupt. The checksums can be preserved in either of two ways: e provided enough bytes are changed, the checksum can be left the same as it was originally e rather than changing the program part of the image file, one of the add-files inside the image file should be changed (see the chapter Building an Application for details of add-files). In general, the second method is preferable. What kind of change should be made The change made to the program file has two purposes: e the file is now recognisably a first generation copy e the change contains data somehow allowing this first generation copy to run, in a way preventing a straight copy of this file from running on another computer. Possible ideas on this second point include: e information from an environment variable specially created on the target computer (secretly and with a random value), by the AppCopy program e the date the copy was made (so that the copy will "expire" after a certain length of time) e details about the low-level structure of the SSD (see below). 6 COPY-PROTECTING SOFTWARE To make the mechanism less obvious to a casual browser, any information from say an environment variable ought to be stored in the file encrypted in some way. Restricting the number of copies made In order to restrict the number of first generation copies ever made to eight, say (which would not be unreasonable), certain bytes in the master copy of the program could be changed. As above, these bytes would start with the value oxf£, and would have to be written one at a time. The documentation for the product would have to state clearly that AppCopy could only be used eight times. This would have the effect of making the owner of the software most wary against making cavalier bootleg copies. This method will of course only work if the SSD containing the original copy can be written to. This will be impossible for OTP (One Time Programmable) or masked ROM SSDs. In this case, information about the number of first generation copies made could be stored in another environment variable, though of course this method would be easier to subvert. Low level SSD information Each SSD contains a so-called "unique ID" which can be used to identify it. Another potentially very useful piece of information would be the physical pack offset of the start of a nominated file on an SSD. An AppCopy program could create a small file on the target SSD, and then delete it, before copying the program file across. The physical pack offset of the start of the program file could then be written into the program file (possibly in encrypted form), for the program to check when it starts to run. Alternatively, information could be read from the deleted file. These types of information can be read by use of the p_locreadpda function, described in the Files chapter of the PLIB Reference manual. Copy-protection by changing the ROM In the case of the HC, it is possible to use the tool romwrite.exe to overwrite portions of a file custom$.dat in the ROM of the HC. See the chapter Introduction to the HC in the HC Programming Guide for details of the operation of romwrite.exe. Programs can then check that they are running on a given specified HC. To read the contents of custom$.dat, just open the file as normal, specifying the full path name rom: :custom$.dat. One other possibility is to change the contents of the ROM more radically, eg placing certain software into the ROM, with a program on an SSD refusing to run unless this software is present in the ROM. For more details, again see the HC Programming Guide. GENERAL PROGRAMMING MANUAL 6-4 CHAPTER 7 COMPATIBILITY Introduction The vast majority of existing software will, in principle, run on all machines in the SIBO range, provided that the display can accommodate itself to the different screen sizes. For details of the differences between SIBO machines see Writing Software for the HC in the HC Programming Guide and the Series 3 family compatibility section of the Series 3 Programming Overview chapter in the Series 3/3a Programming Guide manual. What machine am I running on? Most SIBO machines can be distinguished by their screen sizes, as determined by the return value from a call to p_geticda. The possible return values for existing SIBO machines are as follows: E_LCD_640_400 (0) E_LCD_640_200_SMALL (1) E_LCD_160_80 (4) E_LCD_240_80 (5) E_LCD_480_160 (11) E_LCD_240_100 (12) E_LCD_240_160 (14) a 640x400 pixel display as on the MC 400 a 640x200 pixel display as on the MC 200 a 160x80 pixel display as on the HC a 240x80 pixel display as on the Series 3 a 480x160 pixel display as on the Series 3a and Series 3c a 240x100 pixel display as on the Workabout a 240x160 pixel display, as on the Siena This will distinguish all machines except the Series 3a and Series 3c, which have screens of the same size. These two machines can be distinguished by means of a call to the function p_returnexpansionportinfo, present in machines with EPOC version 3.90F or later, as in the following example code fragment. GENERAL PROGRAMMING MANUAL UINT lcdtype; UINT version; UINT port; lcdtype=p_getlcd(); if (lcdtype==E_LCD_480_160) { /* S3a or S3c */ version=p_version(); if (version>=0x390F) { /* safe to call p_returnexpansionportinfo */ port=p_returnexpansionportinfo() if ((port & 0x0700)==0x0300) { /* must be S3c */ } else { /* must be S3a */ } } else { /* EPOC version less than 3.90, } else { /* machine determined by LCD type */ } ’ so must be S3a */ INDEX .afl files add file lists, 3-13 add file lists - changing, 3-14 .app files versus .img files, 3-13 .dfl files add file lists for DYLs, 3-14 .dyl files building with emake.exe, 3-14 .img files applications, 3-1 control over, 3-12 creating, 3-3 versus .app files, 3-13 Idd files building with emake.exe, 3-14 .pdd files building with emake.exe, 3-14 .pic files application icons, 3-13 .pr files application project files, 3-1 project files - a first look, 3-2 sc files resource files - application, 3-13 zc files resource files compressed, 3-13 .shd files shell data files, 3-13 ACTIVE class remarks on OLIB, 5-16 add file list application, 3-13 application - changing, 3-14 application DYLs, 3-14 application a first look at .img files, 3-3 add file lists, 3-13 add file lists - changing, 3-14 add file lists for DYLs, 3-14 app files vs img files, 3-13 batch files - housekeeping, 3-6 building, 3-1 building - introduction, 3-1 building - more complex example, 3-9 building - more complex example PLIB, 3-9 building - multi-file, 3-9 building - with assembler, 3-11 building emake.exe, 3-14 building eremake.exe, 3-14 copy protection see copy protection, 6-1 debugging on SIBO system, 3-4 file - control over, 3-12 file transfer to SIBO system, 3-1, 3-3 graphics and, 3-10 heap size - minimum, 3-12 Hwif - building, 3-10 icon files, 3-13 information from edump.exe, 3-12 multi-tasking - remarks on, 5-16 multi-threaded - remarks on, 5-16 priority - control over, 3-12 resource .rsc files, 3-13 resource files .rzc compressed, 3-13 running on SIBO system, 3-3 shell data files, 3-13 version number - control over, 3-12 application development C SDK equipment required, 3-1 C SDK files for oop, 3-2 C SDK files required, 3-2 first example, 3-2 fundamental guide-lines, 5-1 applications .img files, 3-1 APPMAN class remarks on OLIB, 5-16 assembler applications - containing, 3-11 asynchronous I/O programming, 5-2 auto-switch-off p_unmarka, 5-14 SYS$NULL - chance to run, 5-14 background processing programming example, 5-2 batch files application housekeeping, 3-6 compilation, 3-6 compilation complications, 3-7 build C SDK configuration files, 3-11 GENERAL PROGRAMMING MANUAL building C applications, 3-1 applications - control over, 3-12 applications - more complex example, 3-9 applications - more complex example PLIB, 3-9 applications - multi-file, 3-9 applications - with assembler, 3-11 applications introduction, 3-1 applications with graphics, 3-10 applications with Hwif, 3-10 manuals - Topspeed C, 2-1 C SDK C++ build configuration files, 3-11 configuration file tscfg compiler, 3-11 configuration file tsprj.txt, 3-11 configuring the redirection file, 1-3 configuring the Topspeed project system, 1- 2 directory structure, 1-2 documentation version, 1-1 equipment required, 3-1 files required, 3-2 files required - oop, 3-2 installation, 1-1 installation phases, 1-1 manuals, 2-1 manuals - where to start, 2-2 overview SIBO system, 2-1 professional version, 1-1 SIBO software, 1-2 small model code, 1-1 standard version, 1-1 Topspeed C, 1-1 Topspeed software, 1-2 variants of, 1-1 object oriented programming and, 2-3 cancelling timers in general, 5-6 Clarion Software Topspeed C, 1-1 CLIB console device I/O, 4-3 DOS file names, 4-3 file handle conversion, 4-2 floating point emulator, 4-3 floating point emulator - panic 80, 4-3 int86x implementation, 4-2 intr implementation, 4-2 library - building, 4-4 missing DOS functions, 4-1 notes on, 4-1 CLIB & PLIB contrasted, 3-4 code size application CLIB, 3-5 application PLIB, 3-5 compatibility software on SIBO systems, 7-1 compilation batch file complications, 3-7 batch files, 3-6 optimisation warning, 3-11 TSC vs TSCX, 3-8 compute intensive application CPU yielding, 5-13 configuration file C SDK tscfg compiler, 3-11 C SDK tsprj.txt, 3-11 configuration files C SDK build, 3-11 console device implementation in CLIB, 4-3 in general, 5-6 cooperating applications debugging, 5-11 copy protection first generation copy method, 6-2 free space method, 6-1 introduction, 6-1 low level SSD method, 6-3 mechanisms, 6-1 ROM changing method, 6-3 CPU intensive yielding in applications, 5-13 CPU yielding compute intensive applications, 5-13 programming, 5-2 customised libraries, 3-10 debugging applications - on SIBO system, 3-1, 3-4 cooperating applications, 5-11 serial port comms applications, 5-13 device driver LDD - building with emake.exe, 3-14 PDD - building with emake.exe, 3-14 devices I/O in general, 5-5 directory structure C SDK, 1-2 documentation C SDK - where to start, 2-2 documentation sources programming, 5-1 DOS functions CLIB - missing functions, 4-1 DYL add file lists into application, 3-14 building with emake.exe, 3-14 dynamic library DYL - building with emake.exe, 3-14 edump.exe application information, 3-12 utility program, 3-12 emake.exe application building, 3-14 application conversion, 3-1 utility program, 3-14 EPOC explained, 2-2 epocinit project file statement, 3-6 eremake.exe application building, 3-14 utility program, 3-14 error handling a first look, 5-7 events and, 5-7 resource tidying, 5-8 errors panic number ranges, 2-3 panics explained, 2-3 events active and inactive sources, 5-12 ACTIVE class - remarks on, 5-16 APPMAN class - remarks on, 5-16 idle objects, 5-14 multiple source examples, 5-3 p_iosignal - function of, 5-14 prioritisation of sources, 5-5 window redraw - remarks on, 5-16 example code detecting which SIBO system, 7-1 fatal program errors panics explained, 2-3 file handle conversion in CLIB, 4-2 file names DOS implementation in CLIB, 4-3 file transfer applications - to SIBO system, 3-1 applications to SIBO system, 3-3 floating point emulator - panic 80 in CLIB, 4-3 emulator in CLIB, 4-3 fundamental guide-lines programming, 5-1 graphics applications and, 3-10 heap size minimum, 3-12 hello world application - PLIB first example, 3-4 application first example, 3-2 Hwif application building, 3-10 I/O devices in general, 5-5 INDEX icon files application, 3-13 IDE Topspeed Integrated Development Environment, 3-1 idle object contrasted with sub-process, 5-16 idle objects events, 5-14 p_iosignal - function of, 5-14 image file control over, 3-12 include file stdepoc.h, 3-11 installation C SDK, 1-1 int86x implementation in CLIB, 4-2 inter-process communications in Events2 - and Subproc, 5-8 mechanisms, 5-10 intr implementation in CLIB, 4-2 IPCS in Events2 - and Subproc, 5-8 mechanisms, 5-10 key presses remarks on, 5-4 keyboard input programming example, 5-2 LDD building with emake.exe, 3-14 libraries customised, 3-10 library building CLIB, 4-4 CLIB missing DOS functions, 4-1 CLIB notes on, 4-1 machine detecting which SIBO system, 7-1 manuals C SDK, 2-1 Topspeed, 2-1 multi-tasking applications - remarks on, 5-16 multi-threaded applications - remarks on, 5-16 programming, 5-2 object oriented programming C++ and, 2-3 Psion C approach, 2-3 optimisation compilation warning, 3-11 p_hello.c source code, 3-5 p_iosignal function of, 5-14 iii GENERAL PROGRAMMING MANUAL p_iowait remarks on, 5-4 status words - declaring, 5-7 status words - remarks on, 5-5 p_ioyield remarks on, 5-14 p_tickle function of, 5-13 p_unmarka auto-switch-off, 5-14 panic 80 floating point emulator - CLIB, 4-3 panics explained, 2-3 number ranges, 2-3 PC C programs, 1-1 PC based development, 1-1 PDD building with emake.exe, 3-14 PLIB hello world application example, 3-4 PLIB & CLIB contrasted, 3-4 priorities processes - remarks on, 5-14 priority application - control over, 3-12 process priorities remarks on, 5-14 program file transfer to SIBO system, 3-3 program errors panics explained, 2-3 program size application CLIB, 3-5 application PLIB, 3-5 programming asynchronous I/O, 5-2 console device I/O in general, 5-6 CPU yielding, 5-2 documentation sources, 5-1 error handling - a first look, 5-7 error handling - in events, 5-7 error handling - resource tidying, 5-8 events - prioritisation of sources, 5-5 events multiple source examples, 5-3 example of background processing, 5-2 example of keyboard input, 5-2 example of serial port data input, 5-2 example of sub-process completion, 5-2 example of timer expiry, 5-2 fundamental guide-lines, 5-1 I/O devices in general, 5-5 introduction - example source, 5-2 introduction to, 5-1 introduction to events - example apps, 5-2 key presses - remarks on, 5-4 multi-threaded, 5-2 p_iowait - remarks on, 5-4 p_iowait remarks on, 5-4 p_iowait status words - declaring, 5-7 p_iowait status words - remarks on, 5-5 p_ioyield - remarks on, 5-14 PC based development, 1-1 semaphore I/O, 5-4 timers cancelling in general, 5-6 timers remarks on, 5-4 user interface - simple examples, 5-2 programs .img files, 3-1 project file a first look at .pr files, 3-2 advanced use, 3-11 application project .pr files, 3-1 epocinit statement, 3-6 reusing - general, 3-6 resource files application .rsc files, 3-13 application .rzc compressed, 3-13 screen sizes detecting which SIBO system, 7-1 table of for SIBO systems, 7-1 segment registers small code model, 4-2 semaphore I/O remarks on, 5-4 serial port comms debugging, 5-13 data reception of, 5-11 opening, 5-12 serial port data input programming example, 5-2 shell data files application, 3-13 SIBO explained, 2-2 systems family, 1-1 SIBO SDK see C SDK, 2-1 SIBO systems screen size table, 7-1 software compatibility, 7-1 what machine, 7-1 small code model segment registers, 4-2 small model code C SDK, 1-1 software compatibility across SIBO systems, 7-1 copy protection introduction, 6-1 copy protection mechanism, 6-1 stack size default, 3-6 specifying, 3-6 INDEX status words declaring - p_iowait, 5-7 stdepoc.h include file, 3-11 sub-process contrasted with idle object, 5-16 sub-process completion programming example, 5-2 SYS$NULL chance to run auto-switch-off, 5-14 timer expiry programming example, 5-2 timers cancelling in general, 5-6 remarks on, 5-4 Topspeed Integrated Development Environment, 3-1 Topspeed C Clarion Software, 1-1 library reference, 2-1 package, 1-1 ts.red file C SDK redirection file, 1-3 TSC vs TSCX contrasted, 3-8 tscfg configuration file compiler, 3-11 tsprj.txt configuration file, 3-11 user interface programming examples, 5-2 utility program edump.exe, 3-12 emake.exe, 3-14 eremake.exe, 3-14 version number application - control over, 3-12 versions C SDK, 1-1 what machine detecting the SIBO system, 7-1 window redraw event source - remarks on, 5-16 window server WLIB library introduction, 3-5 WLIB introduction, 3-5 yielding CPU programming, 5-2