ADDITIONAL SYSTEM INFORMATION 


Version 2.00 


December 21, 1993 


(C) Copyright Psion PLC 1990-93 


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 and 
Psion Series 3a are trademarks of Psion PLC. | 


TopSpeed is a registered trademark of Clarion Software Corporation. M, 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 
A IVICUINK:  MICDIINt;-GNG SNK vcsissscssccasncscdececeu cease ovcenveuieve css ecueedudciiessneidcrecdeewencs 1 
VIGIIIIKOXG yccecuscccasasacezediwaanerew nodes seaatani oes ousescaiencannandessaaevdocancautesecseeises 1 
Commands provided in MCLINK..............ceccccscccscccccscccccccscscccccsscssecccees 1 
MCLINK and single floppy disk drive PCS ..............ccccccccssccsccscccscccceccess 2 
Exiting the MCLINK program ............ccccccccccccccscescccsscccsccesscccessovesecccees 2 
Display the version Of MCLINK ..............ccccccccsccescccvccccceccsseenccsesssceccers 2 
MCLINK file-handling Commands. ............cscccccccscsccscsscsscssccscesccscscccecesccececs 2 
HUIGS ON: TIEMAMES 5 suisse eevesseecoradisbicai conc ceeaiebiededanssacatesadentesescieneeeek 2 
NLR cerca oc ewemiocsnt acto ance Neate saw ce dea mane naka welde ona anteducumcedsauaicecieielse ont benceaees 3 
COPY aaiiadteiicatiaiencae lunes cso cs Monnens sonee arctan naneeaten age iannend awe a 3 
RENAME coscinececead cs eae tenscvwvscsesuiaincadse utaeoet Solanueswaesaaneoue nae ees 4 
EE iE acces itcacidio ae swetaetaontaddaenwasoeias ces cee ueanten semaalen sanubaw Mie cenGee leas eeeees 4 
BVI DUR eo tessastcicoacaing eatavenadeaceu ee uncanaie suse pademnacea chan aaoneeaceeere ceed eects 4 
Changing MCLINK communications SettingS..............ccccccscscscscscscccscscsecececs 4 
Options for the SET Command ...............ccccscccccccsscccssccscesccccceccceccceccecs 4 
Serial port and Baud rate Options ............c.cccccccsscssccscccsccscccccecccecccsececs 5 
MIOGEM OPTIONS hsiscssceseshaec cant dav sencasvs cous autacadecuaevedeisantatenias eoeeeeeiedates 5 
Examples of the SET command 
Advanced use Of MCLINK.............c.cccscccccscceccccnccssscsescccsssseccvessecsvecevccencs 5 
Running programs remotely on the MC, HC or Series 3............cccccccsecccs 5 
MICLINK batch files ...............cccccccscccscsccccssccccscsssscecceccsccsssceecseccsveecess 6 
MCLINK command line processing..............ccccscscsssccscsccsccccecsccscecescecess 6 
Invoking MCLINK inside an MS-DOS batch file .................cccccsccecsccscceces 6 
MICLINK and MOdeMS .............ccccccccccsccscscsccsccsccsceccsccecescccecescescevecesescccess 6 
MCLINK as a PC file server via the phone System. ............scccccccsceccesscces 7 
MCLINK and modem Baud ratesS.............cccccccccscsccsccccesccccscccesccccccssecess 7 
Link on the MC/HC as a requestor via MOdEM.............sccsccsccscecscescecccces 7 
Link and Modem Baud rates. ............ccesscccsscccsccscessccecceesccesceccseves ere 8 
Link/MCLINK with MNP ..............cccscscscsccscsccsccssscsccsctecessescsceescscescesces 8 
Examples with modems. ............cccccccccsscssecsccccccscsscsscescceccceeccecceccecsesecccecs 8 
Using a Dacom QuadPlus MNP 5 compressing modem...............scecceseees 8 
Using an Amstrad SM2400 moder. .............ccececessccssescesssccccscsccccecceccs 8 
Using a Dowty Quattro SB2422...............cccccsccccsnccsccssccccccececcccccvecccess 9 
Using a WorldPort 1200 pocket Modem. ...........ccssceccccsccecccccscccscceccccecs 9 
An HC with a Psion Quad modem ..............sccscscscecccccccceccccccccccececccecees 9 
An HC with the Amstrad SM2400 modem ...............ccsccsccscecccceccecceccecs 9 
IVIGDEING- OXG se scecsressiacecaassewcineroiswateastcusssaousaseecate ain eeGaigontanmuceteadaventienat: 9 
USING -MICPRINE vvtauisscomadccsuacrencoss sean wdasanseceeutaonuseeataedia ake coveuumeewad 9 
EXITING MICPRING 25 cevscecasccancsdesctus boveareviccets eeceanuiedosstantdea ndencecatannecins 9 
Printer Configuration On the MC ..............cccccccsccscscccccesccsccsccccesccscceecces 10 
Printer configuration On the Series 3............ccccecsccscsccecccacsssccsccscescceaces 10 
PAlAMPELOIS 5.0555 cds ccccae saeuaaenwse caw tasson sense wale dese omer ueceessc2 seven aieawed vacation suiek 10 
The <prdev> parameter .............cccccsccscccsccccsccsscccceccceseccccuceececesevucess 10 
The -C<poOrt> parameter .............cccccccccccscccsccsccsccnccessctsccsceccccececeucess 10 
The -t<timeout> parameter.............cccccccccccccsccssccccccccccesceccceccecescceecss 11 
ENG = DAFAMEER oii coescs teins acacnsicsewrvecsnssidalsceobicasctwuduesdecewesleisaesececetors 11 
SHIA O XC esis ieeeend arcs oceciidastavcbated dbaeetiubaes een eoedaaceeenveuki cate weduGlasaaieadacecs 11 
A RESOUCE FUCS vce oa casters csoens a dunciscnntedavauaaspuesxdaauianSnesadneswaniieasWenieapentteaewenedonecs 13 
MICFOGUGTION iescesecaie awossse eects odale ices watcsaacassnsRacbensantes vecsaue usa Oeaecied aeseewenas 13 


ADDITIONAL SYSTEM INFORMATION 


rr reser ssh se ress nna eremmeeee 


Format of Sibo resource fileS.............cccsccecenccccccccccccs : 


isiehuce na aeeecaadecusnaidmsseate 15 
The format Of .rsc fil€S............cccccsseccsecessccesceeces | Sesh aeiiniaanastaesasee cia 15 
Some strategies for reading .rSc fileS..............scccsseccecsscscscececscscscscsasess 15 
Example of reading resource files directly............. hehe wedencuvmeuaciatewsinues 16 
Using the rscfile Class in Olib..............:sccccsecccscscccscecscecccscscsceceseccscssccseeees 16 
Basic services of the rscfile claSs..............cseceseees | atoatealeiactecie See teatmt aati 16 
Reading compressed resource files with the rscfile Class .............ccceceeees 17 
Initialising an rscfile ODjeCt.............ccccseesecsecscseees Pere ree ree 17 
Which header files are needed ................cccceccecccsceccccssccsscsccscescccccsceees 18 
Run-time errors with the rscfile ClaSs.............ccccccdecssceccescsessscsccsscnsceccs 18 
Possible errors during initialisation ...............cccccccqcscccssccsscsecsccsaccessenccs 18 
Errors during rs_read Or rs read DUf............cscsscscdscsecscecetescsscnssceseecaes 18 
How rscfile errors are reported .............cscesseseeeees d eusigulee se sa beamquabeeua sears 19 
Dealing with errors in rs_read or rs read Duf.............c.ccscscscssscncnceesceees 19 
Advice on where to locate resource fileS ...............ccccdecescccccccccccccccssecccccecs 21 
Mono-lingual applications ..............cccessccccescccvssccdescccccccccccescsccccscceececs 21 
Multi-lingual applications ...............ccccccncccccccccesncsecccccccsaccecsssssccscecesess 21 
Copying of applications ...............cccccccesscccssceeccess Siicatacsaronteee eres 22 
General comments on multi-lingual applications..............csccccsscsssesscccscesceecs 22 
The basic principle of independence of code from resource file .............. 22 
Careful design of screen layout ...........cccccccessccccccercccscceccceccsccesccecsences 23 
Codesize problems. ...........sscsscsscssssscsscscscscoesenees shorty Dating TectatSoeectacan: 23 
Varying KEVYDOAlGS viessisciside cake tices ened ice dikcwks aidesecdeceseedoxwca veweuceieens 23 
CONCIUSION aise Sec cctyatiwreestcocascsiice soi uadotessiadononeseeke UL cbaduadingniemaeeeea mannan: 23 
Creating .rsc files USING FCOMP.EXE...........ccecccccsceeesecs i alerhcsaseianaieta bse alesis aia oleeecies 23 
GONGFateG <fS0 THES 6s 6ciaccesieciieacetdontetsecinaieewsuseoaeesbeescaveceusuaantedanusccese 24 
The syntax of the rcoMp COMMANG.............cccccccccccccvcccccsccccecccccccoeeeecs 24 
Include files within a resource SCTipt ............cccceee: Dolged dee cube ee enoe ane 25 
Conditional compilation in resource files ............... a Seian muueeetsaooneuaucassees 25 
Contents of .rss fileS .............cccccecccccccscccevevcccccsovenece Mera oeisatnnamoe kata euaet ences 25 
Declaring STRUCTS ...........cccccccccvccccccreccsscccccscees po auimataiesdeevaeeesenesses 26 
Possible member types in STRUCTS............cccccsscepccsceccccccecssescccscceececs 26 
Declaring RESOURCES .................ccecesccscceccecceees Wire ates mate alee fae aate etal 27 
Declaring the values of sub-STRUCTSs................00 Daeiteas sreicnadiacauewtacenes 27 
Leading byte and word length values..................8. : SE ET Cee eT ee 28 
Arrays Within resource fileS ............cccccccccccccccccccuhecccccccccccccccccceccecececs 29 
Creating SYSTEM resource fileS ...........ccccsscccseeees Dacia deals unease ausewarereasins 30 

| 
3 WDR Printing...............c.:ccsccecssecesccccscseocseccosesccseceeceeeeens heed entree ees: 31 
INFOGUCUON i ssies ise ecatesh insets condateddanenaeseteaentee Ceessaseeees | ssp ctsalanebe reson eeeuuateniss 31 
Creating .wdr files .............cccccccscccscceccccccccccesccecs oat saseauestebbess sheneetadcel 31 
The WDR printing environment variables............... Det Ort heals ewan ecee coin 31 
A note on reading environment variables .............. U creaepdieniiales atusenese tens 32 
Overview of the contents of a .wdr file.............cccceeees Heath acta cioumaeeceubasemacas 32 
Deciphering general. wr ...........cccccccccsscsccescccsesess pedessingcaciant seuveaassasaeads 33 
TNE NEAGEF TESOUICE wisccva cesses scar siesensicencauisuerssssacieleuvia censuses eseevsseceuwades 33 
TNE COMMANAS FESOUICE...........cccessccccscvccevccscesecs Temes aes sebecamentaa wean ens 34 
Model rOSOUrCeS........cccsccvecscesscccesccccccscccccssceceeses | sia atatnensoiceaateoseee aoe 34 
TYDCTACE FESOUICES ei iisteeresdobaccelodaracsekcadsSdcesesases sexhlvsneveniecericaeeene ees 35 
Translates reSOUMCES ..........ceccesccccscccesccecscsesscesses ee ne rere 35 
Summary of resource types in a .wdr file.............. Lacouanet aa weedeecewensveuee: 35 
More details on the contents Of .wWdr fileS ............ccsccesecvccvscccecsccseccsccesenecs 36 
POSSIDIC WOl-TAQS aise is sccias seas insascanciseendeadiiaeusernie facut beg cemanrovaceaseueanns 36 
The notion of “printer models” ...........scssccssssesceees b wslagdaeseacuaberius seventies 36 
Overview of the different Command StringS...........1....cecccsesesssseeeeecesees 36 
Special characters in COMMANA StringS ...........scccecsescscsccccscscscsacscscsceees 37 
The MOVE_RIGHT commands..............ccceccscseeseees omens svaptaeeneestasame nan: 37 
PRIMO UNITS csciigencescoowaesteinte dexter cicie eer edeawcasuce Leiioduiitaia wou aust Sune ou sean 37 
Possible model-flags ............ccecccccescccescccccccscccvecs ces aeons vas: 38 
Typefaces and fonts .........cccesccccccccccccccccccccsccesecs | sac cg Ghi tieanonmecaeeuseas 38 
TY DETACE NUMDELS ses ccsianvnictiacsienscetawvceGolacccssuedewns mensenaaaesabencnedseeaesenes 38 


CONTENTS 


Possible typeface-flags ............cccccccsceccccccccceccseccceccesescsssavescececesseereccs 39 
FICIGIIES OF TONTS ot saa ssicaties sesisadd vo vawsntaidee nod dowd aca wus ceaenoens savesenensaeeeaawa gaa 39 
Widths of characters in fonts.............ccccccccssccccccscccccccescccecescescsececsccees 39 
Creating .wdr fileS USING WOtraN.eXe ...........cccccccsccscccccccccsscescescescesccsevecsces 40 
Contents OF .Wd FileS .............cccccscccacsccsssccescecsceccccceecseccccccceeccccseseceecs 40 
Acceptable syntax within a COMMANDS resource definition.................. 41 
Acceptable commands within a TRANSLATES resource definition........... 41 
Acceptable commands within a WIDTHS resource definition .................. 42 
Acceptable commands within a TYPEFACE resource definition ............... 42 
Acceptable commands within a MODEL resource definition.................... 42 
Allowed typeface NUMDETS. ..............ccccesscscescscscecscscscuctacecsescceccesseceeces 43 

BM: (DBP TOS iso scios dace ei obece cons dadciadeducecaataaesdocbsa scacncweGastecwawodedenecenetoledednn staal 45 
IPIRFOGUCTION sae cpio sca seaticore i seubauncsacuae suatiieetacasaccacee he baSaake aa iweteekavocsesacden 45 
Basic structure of DBF files................ccccscsccscecccscccccscccccceccecceccencevccnccecccece 45 
The Standard header...............cccsscsccscscccsccecscecccccccceccccteccccccevccecccecccece 46 
The extended header ...............cccscssssccsccsccccccsccccescecceccceccceccevcceccceccces 46 
The field information reCord...........cccscsccccscecceccecsccccccecceccencecevceccecceeces 46 
The format of all reCords............ccccscscscscscecessscssescccesescvcecceceusecececceccce 46 
DGICTE TECOLOS ends cusacveysewascasGacaisceeuhddeeuad menses ote esboscene nn irwelndddoweunelns 47 
DESCTIPTIVE FECOFS ...........cecccccnccceccscsccccsccsceccececsccecscccccececceccecceeceeces 48 
More On type 1 records ...........ccecccscscccsccesccccscssecececccecescccscececscceeecece 48 
The Series 3 Database ...............ccccsccscscscecccccescccceccceccccerecececccececcecccceccece 48 
Field information record ...........ccccscscscsccecscsccscecsevccecsceccecccececceccececcece 48 
EXtGnded NGAGel ais ceescncs daidacdasicucdastebel eis eausewseoeeieandosseuues vassceareeicieewence: 48 
DESCHPUVE TECONG ixesitsscencaascnscawesecsawdsnedeedoamuccdeniebeShodeGiadooeteccaeieelcun 48 
Flags options for the Series 3 Database ................cccccecscecccccceccecesecececs 50 
EPYOG™ VO CONGS oanaseitten see cicsacnsssvanians dalmancwicn Suneasasleanei esa cchunetheen cect 50 
Continuation Sub-fields ...............ccccecsssscscscecscascececcccecececscscecsceccccecece 50 
The Series 3 Agenda ...............ccsccssscsssscsscscsscscscvscesescecsrecceuscececercececececes 50 
Field information reCord ............cecscscscscscscsctecscscscccccecscececccceccocececcecccs 50 
Extended Neader ..............cscsscscscscsccscscsccscscscscscoscecescccceeeececeecesecececess 50 
D@SCIIPLIVE FECOIE ...4.ccceacessecvcccsnoseccvaesesdseescescsdcvecceectsechcccdececdacececcecc 51 
TYPE: T GOCONOS ses iies te see neat oatsGsanesu aa chons uestncebeddadeuboudatecidocucunchichenwene 51 
Calculating with AlarmTime.............ccccscsscsscscescscesscccsccccscescececececceccces 51 
The text Of AN APPOINTMENT ................cccscscscscecscscecccccccececccececcccececcccee 52 
TODO MOINS oes esi on sicisg shen su siaccuedet <i cs sdeundaawannedenfascensevese deaeadnueceuh cowie 52 
FREDCOE ILONNS ssiciati sate tagbasdaavasens casceicdauccsedseee hws iasnes os bireaaceiaanei Beaton: 52 

5 Series 3a Agenda File Format ..................cccsccossccsscoccccsscccscccscceccoccecccoccocceccess, 55 
HITE OGUCTION ices pcsiredtiedccpiandews decwenineeRediediadudelaisawededivabeansheercaddduoetedacs beets coeav: 55 
Basic structure of Agenda files..............cc.cccscscsveccccscoscccececececscececccccececces, 55 
The standard header................cccccoccecscsscscscecscsscscececceceecececceccececececess 55 
The extended header ...............cccccsscsssscscscecscscssevcccccceececcescecccccecceces 56 
TMG Gata TOCONGS 3iiciassiecss secs szacceuedcossavevwsuedeasieaceedesk deaveecseoe ek sioles csevune 56 
RECONG:  VDES sgsts crepe iscaies ube, ease addiaaesademesanteeudsbantudenteeeairboas aabistuecutienin: 56 
Type O - deleted record ..............ccsessossscrensncesccccaescscssssearsovessecescassessceecs 56 
Types 1 to 4 - Entry reCOrds ..............scccsscscscscscecccccscccccececececscececcecececccces 57 
NCEY GOtAIS TONG uj sicsonsisescooccsenea iewsstbuaecatese tstenciesuidusSecnetcexcxeh maceausve 57 
ING THO: THONG sees cat ncrsic dames Goes da eandin ccaeonewodadeiaecidensiastemiuekeoieecodeecn 59 
TEINS: ALANNA TIONG: eeserisascenenctandealtiadautwievouraa be oiasansc ees uecabieciecs ccceatamisoeaneies 60 
WRNEANEMO HONG saccc essa sicessc¥salaovdevech wvpasheudands saccclnd decals @eeek hee oe 60 


ADDITIONAL SYSTEM INFORMATION 


A rei ei Stns ern wnt i= acpbnets 


Type 5 - repeats ............cccsccccscscscsccccscscescececcscvaveces Lace tatedueteaetadycsou 60 ~~ 
Type 6 - anonymous data ssteaesesseneseneanenessenessseenesnsspenessseansssseaceneneaneneaee 62 
Types 7 and 8 - reServed. ............ccsccssscscscssccscsccssscscccsccecececcecevscccceseevececs 62 
Type 9 - to-do list information ...........ccccsccscesccccscsaces L Bduateeeinacamnecan ie cette 62 
Types 10 to 14 - descriptive records ..........ccscecscscsees | siieielaseesiwateaeneiaetnodes 62 
Type 10 - styles descriptive record...........ccccssscsceceees , bee titsuayatetaecasecnentanened 63 
Type 11 - to-do manager descriptive record............00. dente temalinaeGacomsueshaunesene 63 
Type 12 - frequently changing data descriptive record ................cssecccceseeees 63 
Type 13 - general descriptive record..............cs.cssseees de duet oasatcn Some saieninns 63 
Diamond list setup field ............ccccccccccssccccsseaceecs dea aetna aeudodetescetuorses 64 
Day entry defaults field ...............ccccecceseccccsccscces d Sue tenaneunnguiMemmeus ents 64 
Anniversary entry defaults field ...............cccccccccccccscccscccsccccsccecscssccesens 65 
General defaults field ..............ccccceccceccccccssccccesecs hte decssudoiuateecacieewauns 65 
Day VIEW SEttINgS Field..............cccccesccecccccccccccccedescccceccccceusscesseescsesacs 66 
Week view Settings field.................ccscccccccccscccecesccccccccsseccsssccscsscoesecs 66 
Year view settings field ..............cscscecssscevcsccccececs  SadalaenledreWauw cases tonsuadds 66 
To-do view settings field ................cccccceccscccecceees ieaciaseaseaeeeud cas weamoutes 66 
Anniversary view Settings field ..............cccccsccssscssesscsscsessccscescssssscesens 67 x 
List view Settings field ..............cccccescescccsccscesceecs Lace cwentinoeuasuiosmauac seas 67 : 
Type 14 - print setup descriptive record...............scsee ne wadhawieatsea eoaeawanceeeues 67 
Type) 10 Weal sccucs0d scocacitenntevssdbesevasineuctieseecseest Besteip setae seta eetiaiont 67 
: 
6 Word Processor File Format ................cccceccecceccccccccccesceees bs siavsatcuesuedaeasutaneucncte 69 
The document header............cccecceccccceccccescccccccvccscece GLa lout seedeonneecseemecie: 69 
FRECOPG TV DCS ois Gees csiiss re can cheeses ane een ca maeaiw esa eeivanaad cy axcincen eden aeiaee dese onawer 70 
The options data record (type 1, length 10) .......... Hatta darias tas dian ate oy heat se 70 
Printer-related data record (type 2, length 58) .......  ominigdiidaguiteennamersiiedmens 70 
Printer model data record (type 3, variable length)..,.............ccscecsscssceees 72 
Page header record (type 4, variable length).......... Pawbawsbaeneanewa sank Gueecees 72 
Page footer record (type 5, variable length)........... Dood alot aa aisoseacanecuans 72 
Style data record (type 6, length 8O)............sesceses Ls aaaeecaesamicn moanoemasanues 73 
Emphasis data record (type 7, length 28).............. Oats a vesnaccaananseaouetonst 74 
Document text record (type 8, variable length) ...... pacbniciettadotnnenvauanamaeaeet 74 
Document index record (type 9, variable length) ....,.......:sssscsssessereeseeees 75 
| _ 
| a 
7 Writing Device Drivers .............cccccscssscsscscoscescsccccsccscceccechecssccccsccecaccececcescovees 77 
IATHOCUICTION ices os bicesbct casas ccevalestiensconwneeeecbesseeeesaaes Lassteascccesevesecasseeceeees 77 
The location of device Grivers..........ceccrecccccsscsceees Po Salinuwncacunet smaesnaas Sonne 78 
Device Driver NOMOS oxic scsccesesicnds scscoset an slekwrnseduos wsassecandesecd eds sestansnens 78 
Device Driver Chantel ..............ccccccceccccscsccesccces preseeeeeneeneeeenseenerenens 78 
Searcning fOr PODS 4 sscei chia cine cortsecccesGace ts ousactsesecewses cet ieisuesadeeuaudses 79 
Device Driver Hierarchies And Attached Drivers...........cccsccccccccccesscseeees 79 
Interrupts and Interrupt Service ROutines..............ccecescceecccesscccscsceccscescesnees 80 
Device Driver 1/O Semaphore Waithandlers............; So vuladsnbaweetureteaueneaive 80 
Loadable Logical Device Driver Structure...............0.66. (hates loaianeeca emieassengaes 81 
Single Code SEQMent...........ceccccccecsccccerevecsscessces I aohicais omsawamaeaiagauicsece 81 
WHE LIDEAT SUC TUG eid cesaccaticwasevidcweccnduadinse et ecdeaas ote sew veesineeseewmaieoseess 81 
Mandatory LDD Functions. ................ccccccccccceccccncccucccscsccccccsccccssccsscecs 82 
DevFuncinstall ...........ccsccceccecccccecvcccccssccseccccsececs i eokcepaley Gace easeanmawenseeae 82 
De@VFUNCREMOVE .........cccsccvssccccceccceccscccccccecccececs daa Merl eeuecstnucmecdaes 83 
DEV EUMCHOING vices caiisssactensncdecccueeavtusananeetaesnceaneceusonedeceedeanausbexsasisueatas 83 
DOVEUNCRESUIMNG oxi icdsccaeae ecu ticsccticecenaddncc ceca canes sanaioenecaeacesseesieesaens 85 
DOEVEUNCRESCE ioscsnecs ccausatenesscsecsvecsuedeuon cccauasencue. ccutes chinese veceuremsenees 85 
DO VUNG OTIS sacivcr sed scrcenncrnstatscd acuaa casewabacssencae oi oneevanaw een cause sce eeuces 86 
DEVFUNC ODEN sedéciiesssechsscstcecoctescstecscaavesccuwienteesss Janecasceesceescenrenenssoeses 87 
DEVFUNCSIPAlLe GY oiccseicsiesccavsscsicvexcecoseia pedonweredocsdeess sees ee cues cveesescsanne’ 89 


1V 


CONTENTS 


Loadable Physical Device Driver Structure..............ccsccecscceccscceveccccvccscccetees 90 
SINGIG COGE SOOMENE sissscccasescecessc sense dedaseaedelncetessiwaeidoncedevencecansaumsaves 90 
TRE LIBENt SH&UCTUTE sick odeveciasbiead vodienciindeiveeaasaantebseandeecdiaerssseawens 90 
Mandatory PDD FUNCTIONS .............cccccccesnccccecccccveccsecevscccsccccosccecececccce 91 
DeVFUuNCIAStallPDD ices csecescocsesca casas se cdaccees ceive vensasis bie eSnkersbowandcniadeeeck 91 
DevEuncReEmovePDD & s isiccescsccencscacadis cas scccsd scene dGebdiesalesbcsvadenccccsoncsveree 92 
DEVFUNCOPENPDD igi ve sds noses ieickiionsedsccdoss re seeabsiacdanenacsesesacinaseweschcakeetens 93 
DEVEUNCStrategy POD sive eccsccrecheand phase ites hace ida dedoasbaneieteadeceniaceneact 93 

8 Example Device Drivers ...............ccccccccccesccccsecccccccccccccccccccscccccccccssconsccccsscccess 95 

An Attached Device Driver Example ...............ccccccccccccccccsccecesccsccecscscccssscees 95 
"ENG GOVICE: TaDIG cincs oickis sa cciecescicadiwccunsieces cake ecudveatinaneawebenisercansarteaans 95 
The lnstall: FUMCHHON wocesissickcsticecssavcbivevesndesecsiddcevel deeds deovecsenevasceesaccs cok 95 
“ERG REMOVE: FUNCUION visiecdesideisStewhdiscueeedestiesin dh beaeiavecoue ence ueaaverceeeaees 95 
ENG FIOM 'FUNCHON 6c.i dee oeidicitecascuwasineanceeacaecsariiedusateabiosdencanes tear Secciaoobeek 95 
The RESUME FUNCtion ...........ccccccccccccccccccccccccccccsccsevcctccvecececccceccscscecce 95 
UNE: RESCUE. FUNCTION sods coniwaceccusesscibactenennsaxncicsovneronsusacetuaciceiesvonutesebee 95 
“EMG? URITS FURCHON ices ioiscicic cis cocceedeutinc atecediowidudeddacdansdeebecineece eowenekes 96 
PNG ODEN: FUN CtOMsces seis cece cess. cdscadascemeceranecovesuslnieses aa cade ccsdelioncamiaends 96 
THE Strategy FUNCHON 55sses ccs: cscseerckseweieediovesccinwcwedOinacendevennoueteeeecanedeks 96 
The Wait Handler Function .............ccsecccccccsssccccsccccevcccccecccncscncucccccesecs 96 

Non Interrupt Based Sound Drriver................ccccoccsccscsccsscsccsccccceseeccscsesseecce 97 
NING GOVICE TaDIe ieead si cceivakenececassvecavcewsndsveasececacnesdeus seauacerin na cenaerdsaceses 97 
Whe: INStalll PUM Cti OM aceesca dis oisesecrrsacowsesien tenet ucecicaieeaweaee saecowneueenePake 97 
The Remove Function ..............ccccccsccoseccsccssccesecccsscccccccccececccccecccseeeccs 97 
AMO IGIG FUNCUON i scs'iccccardententiwakiocdecasdansessncndetaweain 4 dole bond soaskaconeen kee 97 
The Resume Function ............cccccccccccescsccscccsccccccesccccecccecssceccccveccsceeccs 98 
The Reset Function ............ccccccscscscccccscccsccssccccccescsccccceeccccecccsseccseccces 98 
PNG URNS FUNCTION vsscsiscsiccsnccosseeisees tb Secdeeigecionn beiieec ues hae sacs saedbaieaeecs 98 
The Open Function. ...........ccccccccccccccccccscsccecvssescscsscesesccescsscesvevececsevecs 98 
The Strategy Function ..............ccccccccccesscsscsccsccssccccccccecceesecccecccesccccces 98 
The Wait Handler Function ...............cccecsccccsccecsccccccccccccccccccccccceececeuecs 98 
EX€rciSiINg the VECtOIS .........cccccecescccsccecccccccscencsccccsasessvececscesceccscccesess 99 

Interrupt Driven Sound Driver..............cccccccssccsccccccceccccccccccccccccccevecceeseveees 99 
THO GOVICE TAD a cect st ca vecatiee tes vues wercancesshanecnsaheaeehcenelsossueueiedonieiesnk 99 
THe Install FUNCHON sco srins ea cend iccdcdscaiea deh eacsechedaccowastchceveeoukevouesns 99 
The Remove FUN ction.............cccscccccesccnsssccssccscescecceccseccccccecceseceecceveees 99 
The: Old Pun CuO eseescceekirciiteatclicaseis a cncsbeieeacecasccannee hedegiawctawokeidenoeass 100 
The Resume Function ..............cccccscccscccsccccccsccceccsscccscescccceccescccecccenccs 100 
THE RESET FUNCTION svi sicc ds ioveseie dein avowecaddewceewdinnteulseecbosceieeesvecacleoxeucdouuns 100 
EMG UNitS FUNCTION sescGcocensasideccstieatawiednnd scons vucaciuacw ded cave nee nciead a veeeghas 100 
THE OPO FUN CON ii sceceic cicwiwsde vase eis cues eadsina does odes dacebedesedceeveaseniiaesie 100 
The Strategy FUNCTION ..............cccceseccccccscccccccscsscccccccccceccceseeceecesceecees 100 
The Wait Handler Function .................csccsccscscccccsccccscccccecccecceccecceccences 101 

9 PCMCIA cards and SSDs ..............cccccceccsccscccccccccccccccvccesceccccceccecccenccccecccececece 103 
Mobility and robuStness................sccscssccsscsscsscescescecccsccccsccccscccecscccseecs 103 
SIZE CONSIDEFATIONS ............ccccccccsccsccacccsccccscccsceccecceeteccccsceecsecseecceece 103 
Different standards for different PUrPOSES. ..............cccceccccccscceccceccceccecce 103 
FIOU INSOPLION uicedees casi cocccaveceeeaend ade Seckcnesy we neatceeeok Seesaw one ees cc 104 
FlaSN: THING SVStOMNS 2 ve scwcusascscusmersawsconssaadaesausseedinverenweneetdextselebeneeeeees 104 
COSt GCONSIGElALIONS veiccs cssccced cncks cack buewtndaes eiancaseesesenaicevebavelsolovavaxbeeds 104 
Architectural OPENNESS ............ccccccccccccsccccccecccssccsccscssncceccecccscececsecces 104 


tee 

7 ' 

ce a 

s 
Fe 
5 
a 

“ 

. 


CHAPTER 1 


NMICLINK, MCPRINT, AND SLINK 


The directory \sibosdk\sys contain the following programs (amongst others), all of which can be run on a 
PC connected to a SIBO computer: 


mcelink. exe a program allowing file transfer and remote file access between the PC and the 
SIBO computer 
slink. exe a "no frills" server-only version of mclink.exe, which may run on PCs or PC- 


lookalikes that cannot run mclink 
meprint. exe a program for printing "through" a PC to an attached printer. 


Basic information on connecting a PC with either an MC computer, a Series 3 computer (see note 
below), or an HC computer, is given in, respectively, the MC Operating Manual, the Series 3 User 
Guide (see note below), and the Introduction chapter of the HC Programming Guide (part of this SDK). 
The information in this chapter gives some more advanced details on the above three programs. 


Note: throughout this chapter a reference to the Series 3 machine is taken to include both the Series 3 and 
Series 3a machines unless explicitly stated otherwise. 


De Aha aes Ae ah NS ee ee ee a 
~ Mclink.exe 


MCLINK requires MS-DOS version 3.2 or above. MCLINK is unlikely to run inside "DOS emulations" 
provided by other operating systems (though it happily runs inside MS-DOS tasks inside MicroSoft 
Windows). 


If you experience any problems running MCLINK on your PC, you should experiment with reduced 
contents of autoexec. bat and config.sys files. Serial mouse cards may be particularly prone to interfere 
with the operation of MCLINK. 


If all else fails, you may wish to use the alternative SLINK program, also supplied on the PC MCLINK 
disks. 


Note that, by default the HC and Series 3 run at 9600 Baud, the MC and Series 3a at 19200 Baud. When 
a PC running MCLINK is connected to an MC, either the PC or MC end will in general have to be 
changed to enable a link to be established. 

Commands provided in MCLINK 


When you start up the MCLINK program, the lower window contains a $ prompt. At this prompt you 
can enter various commands. These commands cover: 


# file-handling 

= changing the communications settings 
® exiting the MCLINK program 

®# displaying the version of MCLINK 


® running programs on the remote computer. 


ADDITIONAL SYSTEM INFORMATION : 


For all these commands: 


= the command can be abbreviated, to a minimum of the first two letters, eg DE for DELETE, RE for 
RENAME, CO for CoPY, and SE for SET | 


= CTRL-C stops the command (though in multiple file operations, some files may already have been 
copied, deleted etc, before the command is stopped). 
MCLINK and single floppy disk drive PCs 


If your PC has only one floppy disk drive (currently referenced as "A:"), and you mistakenly enter DIR B: 
while in the MCLINK program, the program will be halted by MS-DOS, requesting you to insert a disk 
into B:. 


To avoid this, use the MS-DOS aAssicn command before running the MCLINK program, like this: 


ASSIGN B=A : 


Then DIR B: will be read as DIR A: and the program will not be halted. See your MS-DOS manual for 
further details of the ASSIGN command. | : 


Exiting the MCLINK program 
Type EXIT to return to MS-DOS. } 
| 
Display the version of MCLINK : 
Type VER to display the version number. | 
ne ee 


MCLINK file-handling commands 


For file transfer operations between a PC and a SIBO computer, you would normally use the File 
Manager on the MC or various file options on the Series 3. For certain| purposes, however, you might 
choose to use the file-handling commands within MCLINK on the PC instead. 

Rules on filenames 


In order to make full use of the file-handling commands of MCLINK, various rules about filenames need 
to be appreciated. 


In MCLINK the syntax of full filenames on the PC, MC, HC or Series 3 is: 
filing system: :device:\directory\sub-directory\file.extension | 


This is very similar to MS-DOS, except for the <filing system prefix. 


If you do not specify a filing system in a file specification, LOC:: is presupposed. 
In MCLINK on the PC, <fiting system is 
® LOC:: for files on the PC (local) 
= REM:: for files on the MC, HC, Series 3 or Series 3a (remote). 


On the MC, HC or Series 3 the situation is reversed, with Loc:: for files on the MC, HC, Series 3 or 
Series 3a, and REM:: for files on the PC. 


Note that for all MCLINK file management commands: 
= if no directory is specified, the current directory is assumed 


= if no device is specified, the current device is assumed 
= if no filing system is specified, the PC is assumed. 


When specifying a directory or sub-directory in the file-handling co ds, make sure to add a \ onto 
the end of the directory name. Otherwise the directory name will be taken as a filename. So: 


COPY A:\*.* REM::\LETTERS is wrong - it would try to copy the files in the root directory of A: 
to the file LETTERS ! 


| 
| 
I 


i 
| 


+) 


1 MCLINK, MCPRINT, AND SLINK 


COPY A:\*.* REM::\LETTERS\ is right - it would copy the files on A: to the directory LETTERS. 


Syntax: DIR filespec 


The directory specified may be on the remote or local filing system - eg DIR A:\LETTERS\ looks in 
directory LETTERS on the disk in drive A: of the PC, DIR REM::A:\NOTES\ looks in the NOTES directory on 
the SSD in drive A: of the remote machine. 


Use wildcards to list only certain files - eg DIR *.TXT to list just the .TxT files in the current directory. 
When you get a directory listing with the DIR command, the following file information is given: 
ws file name and extension 
= date and time when the file was last modified 
= size of file in bytes 
and a combination of these indicators as appropriate: 
Mod file has been modified since last backed up 
Rdo read-only file 
Sys system file 
Hid hidden file 
Example: CLIENTS.DBF 14/01/90 09:54:23 544 Mod RdO 


. 
oaataleaca tates ite Cate Selesere” ea otatatateetetetetetaate! cat aeatatataetetetel 


ecified dev 


Syntax: COPY filespec1 filespec2 


Optional flags: 
-j include sub-directories: If there are any files copied from subdirectories they are placed in 
directories below the current directory, to reflect the source directory structure 
-m modified files only, eg COPY REM::A:\*.* -i -m copies all modified files in all directories 
of the SSD in drive A: on the remote machine to the PC. 
Examples: 
COPY REM::M:\*.TXT \BACKUP\ would copy all the .TxT files from the internal disk of the remote 


machine to the BACKUP directory on the PC 


COPY \SMITH\*.DOC REM::A:\LS\ | would copy all the .p0c files from the SMITH directory on the PC 
to directory LS on the SSD in drive A: of the remote machine. 


If you do not supply a complete destination name, the root directory and/or default disk on the remote 
machine is assumed, and the source filename is used as the destination filename. Eg 


COPY \HOME\SECURE .TXT REM: :M: 
would copy SECURE.TXT to the M:\ directory on the remote machine, giving the file the name SECURE.TXT. 
If you do not supply a complete source name, the current device/directory is assumed. Eg 

COPY *.TXT REM::M:\ 
agg files from the current directory on the PC to the root directory of the remote machine's internal 


Note: if you are transferring a lot of small files to the Series 3, it is a good idea not to stay in the Series 3 
System Screen. This could take longer than usual because the System Screen would continually update its 
file lists as files arrived. In extreme cases, with lots of very small files, the file transfer could even fail. 
So press an application button, such as the TIME button. 


ADDITIONAL SYSTEM INFORMATION 


Syntax: RENAME filespeci filespec2 | 

You can rename a file in any directory on any drive on the PC, MC, HC or Series 3. For example 
RENAME DETAILS.DOC DETAILS2.DOC | 
RENAME REM::M:\CLIENTS.DBF REM::M:\BUSINESS .DBF 

You can rename more than one file at a time. For example 
RENAME REM::M:\*.TXT REM: :M:\*.DOC | 

You cannot rename a file across directories or devices. Thus 
RENAME REM::M:\LETTER1.TXT REM::B8:\LETTER2.TXT 


would give an error. Instead, copy the file to the new name and destination then delete the old file. 


Syntax: DELETE filespec | 
Optional flag: 


-i delete files of the same name in sub-directories, eg DEL *.1XT -i would delete all .1xT files 
in the current directory and in any sub-directories of the current directory. 


You can delete files from any directory on the PC, MC, HC or Series 3, 
You can delete more than one file at a time by using wildcards. | 


You cannot delete directories with this command. 


Syntax: MKDIR directory 


Makes a subdirectory of the current directory. 
You can make directories on any drive of the PC, MC, HC or Series 3. 


You can make more than one subdirectory at a time - eg MKDIR \HOME\LETTERS makes the subdirectory 
\HOME\LETTERS and also the intermediate subdirectory \HomE (if it does not exist). 


Changing MCLINK communications settings 
The SET command in MCLINK allows you to: | 

= use either of the PC's serial ports : 

= change the Baud rate which the PC uses | 

= use a modem (see later in this chapter for more details of using MCLINK over a modem) 
The SET command creates a new MCLINK.TRM in the current directory to hold the new settings. The 
next time you run MCLINK from this directory, these settings will be loaded again. 
Options for the SET command | 
Following the SET command you can specify a variety of options. For apote 
SET -p1 -b9600 selects com1, 9600 Baud : 
SET -p2 -b9600 selects com2, 9600 Baud | 
The full range of options for the SET command includes -p, -b, -m, -n, and -c. 


These options are also available as parameters to the command line for MCLINK (see later), but in this 
case, no permanent record of the options are made in any .7RM file. 


| 
SEES 
4 | 


() 


1 MCLINK, MCPRINT, AND SLINK 


Serial port and Baud rate options 
The SET options -p1 or -p2 select COM1 or COM2. 


The option -b followed by a number sets the Baud rate. You will need to set the Baud rate on the MC, 
HC or Series 3 to match that on the PC. 


IMPORTANT: In general you should specify both -p and -b, or neither. If you specify just one, the other 
is reset to MCLINK''s internal default value. The internal default for the Baud rate is 19200. (By default 
MCLINK runs at 9600 Baud since when starting up it looks for a file called MCLINK.TRM which is built 
in to MCLINK.EXE. This file sets the PC to COM1 at 9600 Baud.) 

Modem options 


The SET options -m or -n specify that you are using a modem (as described in more detail later in this 
chapter). 


The option -m means wait for a call; MCLINK will establish the speed to use to the modem. 


The option -n followed by a number causes MCLINK to dial the number. The modem is assumed to 
conform to the Hayes command set. Here you can if you wish specify the speed for MCLINK to use, 
with -b. For example: -b2400 -n314159 dials 314159 at 2400 Baud. 


The option -c<string> will cause <string> to be transmitted to the modem to configure it before 

waiting/dialling: 

SET -cATMO turns off the modem speaker 

SET -cAT\N3 sets a Dacom modem to MNP fallback mode. 

Note that the AT is optional in these commands. Multiple strings can be transmitted. For example, 
SET -cMO -c\NS 


Examples of the SET command: 


SET -b1200 1200 Baud 

SET -p2 -m waits for a call using the modem in port 2 (Com2) 

SET -p1 -b2400 -n314159 modem connected to port 1 dials the phone number 314159 
SET -cm0 turns off the modem speaker. 


Advanced use of MCLINK 


Running programs remotely on the MC, HC or Series 3 
The syntax 
RUN <program name>, <program command line> 
causes the named program to be run on the remote computer, with the specified command line. 


The program is assumed to exist in the default directory of the remote machine or the root directory of 
any drive on the remote machine. Otherwise the ROM of the remote machine will be searched for the 


program. 
The program command line is as required by the program being invoked. 
For example, 

RUN CLOCK.IMG 
will run a copy of CLOCK.IMG on the remote machine. 


As an accelerator for running a copy of the remote shell program on HC machines the '!' command is 
equivalent to typing RUN SYSSSHLL. 


For example: 


! DIR 


ADDITIONAL SYSTEM INFORMATION 
Ee get gd a eRe can SR ee cn mf eee ng ee ee ee ee eee ee oe 


will run a copy of the SYS$sHLL program passing an initial command line of DIR. See the HC 
Programming Guide for further information on commands available to the SYS$SHLL program. 


MCLINK batch files : 
MCLINK can read a text file containing multiple commands: | 
= Any line in the file containing a '!' is assumed to be a comment line and is ignored. 
# Any blank line is ignored. 


= You may specify almost any MCLINK command, although some may be meaningless in this 
environment - DIR, for example. 


= The SET command should not be used. 


To invoke, a batch file, type the 'a' character immediately followed by the name of the text file 
containing the commands. For example, if the file SEND_ALL. TXT contains the following lines: 


! Sends all text files to the remote machine after 
! creating the correct directory, then exits 

MKDIR REM: :M:\NOTES\ 

COPY *.TXT REM: :M:\NOTES\ 

COPY *.DOC REM::M:\NOTES\ 

EXIT 


then entering @SEND_ALL.TXT at the '$' prompt will cause the \NOTES\ directory to be created in the internal 
memory of the remote machine, all the .TxT and .poc files in the — directory to be copied to this 
directory, then MCLINK to exit. 


MCLINK command line processing 


MCLINK understands a command line entered when running MCLINK fn the MS-DOS prompt. The 
command line may take the form of the parameters to the SET command, a filename assumed to be a 
configuration file, or the @ command to run a sequence of commands. | 
| 
Examples: | 
MCLINK -p2 -b9600 will run MCLINK using port 2 at 9600 Baud. No .7RM file will 


be created, unlike using the SET command, and any future running 
of the MCLINK program will not use these parameters. 


MCLINK S3SETUP will run MCLINK forcing it to use the file S7SETUP. TRM as the 
initial configuration file. This file would typically have been 
created by a previous use of the SET command within MCLINK. 


MCLINK @SEND_ALL.TXT will run MCLINK and cause the initial commands to be read 
from the file SEND_ALL.TXT. MCLINK will wait until a 


connection to the MC, HC or pie 3 has been established before . 


running any of the commands. 


Invoking MCLINK inside an MS-DOS batch file 
Perhaps the most convenient way to automate a regular MCLINK task iB via an MS-DOS batch file. 


For example, a batch file SEND_ALL.BAT could contain the single line 
MCLINK @SEND_ALL.TXT 

in which case the contents of SEND _ALL. TXT would be performed — by typing 
SEND_ALL 

from the MS-DOS command line. 


MCLINK and modems | 


A PC running MCLINK can use one modem at one end of a telephone line to connect to an HC or MC 
computer attached to another modem at the other end of the telephone line. 


| 
(est —— - etisechlenennseecetnasacinutetewsernet ive aseeineeermnascie 
6 


‘a 


1 MCLINK, MCPRINT, AND SLINK 


Modem communication of this sort is possible only for MC and HC computers. The 3 Link software for 
the Series 3 does not have any built-in modem support for communicating over a telephone line to a PC 
running MCLINK. (The kMD: device driver is not present in the ROM of the Series 3.) To communicate 
over a modem using a Series 3, use the Script language instead (which is included with the 3 Link 
software for the Series 3). 


MCLINK as a PC file server via the phone system 


When used as a PC file server via the phone system, MCLINK assumes that your modem follows CCITT 
tules and regulations concerning the RS232 signals - ie 


= The modem drives DSR when powered up, never drops DSR and does not use DSR for any sort 
of handshaking. If the modem is physically removed, MCLINK detects this as the DSR signal 
disappears. If DSR is not driven MCLINK will not talk to the modem as it does not think it is 
there. 


= The modem responds to the DTR signal in the following manner - when MCLINK drives DTR 
low, (off, inactive) the modem should reset itself - ie disconnect if online etc and eventually 
enter its command mode. When MCLINK is exited, it drives DTR low to disconnect any calls 
currently connected. When MCLINK is started up it drives DTR low for 2 seconds to try to 
force the modem into its command mode, at its default settings. 


s The modem only drives DCD when it is on line to a remote modem, and drops DCD when the 
connection with the remote modem is lost. 


When MCLINK is asked to communicate with a modem it sends the 'AT' command string to the modem 
at the following Baud rates: 300, 600, 1200, 2400, 4800 and 9600. It monitors the response to sending this 
command, and sets itself to the highest speed at which an "ok" reply was received. 


MCLINK then sends the following command stream to the modem to configure it: 
#ATX4EOSO=1" if the modem's maximum Baud rate was 2400 Baud or above 
“ATX1E0SO=1" otherwise. 


MCLINK then reads the user command configuration strings passed to it and sends them to the modem. 
All commands sent to the modem are checked for validity by waiting for the modem to respond to the 
command sent. If the '0K' response is received the command worked, otherwise an error is reported. This 
will result in MCLINK re-starting. 


NOTE: If the user command stream contains any form of reset, then the auto answering of calls should 
be re-enabled explicitly. 


MCLINK and modem Baud rates 


When MCLINK displays the status message Waiting for an Incoming Call the Baud rate displayed will be 
the fastest Baud rate that MCLINK found the modem supported. Setting the Baud rate is really a 
meaningless exercise since the Baud rate at which the modem connection is made is determined by the 
Baud rate of the dialling modem (originator) and not the modem accepting the call. _ 


If MCLINK detects the fastest Baud rate its modem can handle is 2400 Baud or above, it assumes that the 
modem has the ability to provide a constant speed interface - ie the modem does not change to the 
originator's Baud rate as soon as a connection is established. All modems that can handle Baud rates of 
2400 and above must have the constant speed interface since this is the way in which MNP throughput is 
normally achieved. 


If the fastest Baud rate is below 2400 Baud then MCLINK will set the connection Baud rate to that 
reported by the modem when it connects - ie the modem is assumed to change to the originators Baud 
rate and MCLINK will follow it. Modems in this class will not support any form of data 
compression/correction since a higher Baud rate than the connection Baud rate is required to achieve data 
compression. 


Link on the MC/HC as a requestor via modem 


(This section closely matches the corresponding section above for MCLINK.) 


When used on the HC or MC as a requestor via the phone system, Link software on the HC/MC assumes 
the modem follows CCITT rules and regulations concerning the RS232 signals - ie 


« The modem drives DSR when powered up, never drops DSR and does not use DSR for any sort 
of handshaking. If the modem is physically removed, Link detects this as the DSR signal 
disappears. If DSR is not driven Link will not talk to the modem as it does not think it is there. 


7 


ADDITIONAL SYSTEM INFORMATION 


= The modem responds to the DTR signal in the following manner - when Link drives DTR low, 
(off, inactive) the modem should reset itself - ie disconnect if online etc and eventually enter its 
command mode. When Link is exited, it drives DTR low to disconnect any calls currently 
connected. When Link is started up it drives DTR low for 2 seconds to try to force the modem 
into its command mode, at its default settings. ! 


= The modem only drives DCD when it is on line to a remote modem, and drops DCD when the 
connection with the remote modem is lost. 


When Link is run it sends the 'AT' command string to the modem at the following Baud rates: 300, 600, 
1200, 2400, 4800, and 9600. It monitors the response to sending this command, if it sees an 'OK' it assumes 
the modem can be driven at that Baud rate. 


Link then sends the following command stream to the modem to confi it: 
"ATX4EQSO=1" if the modem's maximum Baud rate was seh Baud or above 


"NATX1EOSO=1" otherwise. 


Link then reads the user command configuration strings and sends the to the modem. All commands 
sent to the modem are checked for validity by waiting for the modem to respond to the command sent. If 
the '0K' response is received the command worked, otherwise an =a reported. This will result in 
Link re-starting. 


Link and modem Baud rates 


Link will send the dial string to the modem at the Baud rate specified from the Link dialog, or in the case 
of the HC at the Baud rate specified in the command line. If no Baud rate is specified, the fastest Baud 
rate that the modem responded to (see above) is used. By sending the dial string at the specified Baud rate 
the particular type of Vxx connection will be established - eg at 2400 a V22bis, at 1200 a V22, and at 
300 a V21 connection. Note that a V23 (1200/75) connection cannot be) used. 


Note: if you want to use your HC as the file server and the PC as the requestor, swap the above 
instructions for 'MCLINK’ and ‘Link’. 


| 
Link/MCLINK with MNP | 


If you have MNP modems do not be surprised if the data transfer rate een your PC and MC/HC is 
lower. This is because of the way MNP works. 


Typically it is not worth having MNP enabled. The protocol used by Link and MCLINK is based 
heavily on the MNP protocol, ie it provides an error free connection hone the PC and HC. 


Examples with modems 


The first four examples below focus on a PC with MCLINK as a file server. The last two examples focus 
on an HC with Link software. | 


For more information on any of the configuration strings see the appropriate modem manuals. 


| 
Using a Dacom QuadPius MNP 5 compressing modem 


Run MCLINK with the following command line: 
MCLINK -C&F&C1&D3\N3\J1S0=1 | 
Alternatively, you could set up a. 7RM file, eg QUADPLUS.TRM and type 
MCLINK @QUADPLUS.TRM | 
or call the .7RM file MCLINK.TRM and just type 


MCLINK 


Using an Amstrad SM2400 modem 

Run MCLINK with the following command line: 
MCLINK -m 

a ————=—— ae a ——————— ae ee ee pe ee eee 

8 


1 MCLINK, MCPRINT, AND SLINK 


Using a Dowty Quattro SB2422 
Run MCLINK with the following command line: 


MCLINK -m 


Using a WorldPort 1200 pocket modem 
Run MCLINK with the following command line: 


MCLINK -m 


An HC with a Psion Quad modem 
Run Link with the following command line: 
LINK -n<the phone number> -c\n0 
This talks to all of the above PC file server configurations. 


An HC with the Amstrad SM2400 modem 
Run Link with the following command line: 


LINK -n<the phone number> 


DR Ta cP Oy CO eer A a ee ee 
Micprint.exe 


MCPRINT allows an MC, HC, or Series 3 (or any other serial-printing device) to print to a printer 
which is connected to an IBM PC/XT/AT or compatible. The PC must have a free serial port which is 
used to connect to the MC/HC/Series 3. The printer may be connected to a parallel or serial port on the 
PC. 


Even if you can link the MC/HC/Series 3 directly to the printer, there may be reasons why it is more 
convenient to use MCPRINT: 


= The printer is shared by other PCs - either using a multi-port printer buffer or a local area 
network - and it would be unreasonable to connect it directly to the MC/HC/Series 3. 


= You do not wish to disturb the connection between the PC and the printer. 
= You have already set up the serial connection to use MCLINK for file transfer to the PC. 


= When your PC is connected to more than one printer, you can select which one the 
MC/HC/Series 3 will use. 


Note: it is also possible to print via MCLINK to a printer attached to your PC. To do this, set your 
MC/HC/Series 3 to print to a file, and give the printer device on REM:: (such as REM::LPT1) as the “file” to 
use. This method may be slower than using MCPRINT - especially when printing "justified" text from 
the Word Processor on either computer - and will only work reliably on version 3.0 or above of 
MCLINK. However, MCLINK can correct transmission errors, whereas MCPRINT can only report 
them. Such errors may occasionally be caused by PC add-ons, such as some network card drivers. 


Using MCPRINT 


Physically connect the MC/HC/Series 3 to the PC exactly as for MCLINK. If the printer is connected to 
LPT1, and MC/HC/Series 3 is connected to COM1, you can now run MCPRINT on the PC by typing: 


MCPRINT 


If LPT1 and Com‘ are not the ports used, parameters are required, as described below. 


Exiting MCPRINT 
To exit MCPRINT, press CONTROL-C. 


ADDITIONAL SYSTEM INFORMATION 


Printer configuration on the MC 


On the MC, select Print Setup from the Options menu in the System <e lication to display the Printer 


dialog. Set one of the configurations to output to Serial. You don't no y have to click on the SET 
SERIAL... button to change any of the Serial options because MCP uses the default settings. 


Once the current configuration has been set to Serial, you print as if the printer was directly connected to 
the MC - by selecting the Print menu item in any application which can print. As far as the MC software 
is concerned, it is printing to a Serial printer. | 

Printer configuration on the Series 3 


On the Series 3, select the Printer setup option from the Special menu in the System screen. In this 
dialog, set the Printer device line to Serial. You don't normally have to change the Serial characteristics 
(it displays a subdialog when you press TAB) because MCPRINT uses the default settings. 


You can now print as if the printer was directly connected to the Series 3 - by selecting the Print option 
in any application which can print - including the built-in Word r, Agenda, Database, and 
Program editor. (Remember first to use the Print setup options in these|applications, to tell the Series 3 
about the type of printer and the page layout desired.) As far as the Series 3 software is concerned, it is 
printing to a serial printer. 
Parameters 
MCPRINT takes the following parameters: 

<prdev> -c<port> -t<timeout> -q 
all of which are optional. To be reminded of these parameters, type: 


MCPRINT ? 


The <prdev> parameter 


<prdev> is the print device name, as for the MS-DOS PRINT command. If omitted, the default is LPT1 (the 
MS-DOS name for the first parallel port). 


For example, to print to LPT2, type: 
MCPRINT LPT2 


If the PC is a station on a local area network, LPT2, LPT3 etc may be to redirect output to remote 
printers attached to the network server. 


The <prdev> parameter may specify any suitable output device. If you have a printer connected to a 
second serial port on the PC, you can use: 


MCPRINT COM2 


In this case, you should have previously used the MS-DOS ModE command to set the serial parameters to 
be used between the PC and the printer. 


You can also print to a file on the PC using, for example: 
MCPRINT PRINT.LIS 
Note that PRINT.LIS will be overwritten each time you print. 
To test the connection without wasting paper, type: 
MCPRINT CON 


CON is the MS-DOS name for the console (screen). When you then print! from the MC/HC/Series 3, you 
should see the output appear on the screen of the PC. 


The -c<port> parameter 


<-c> is the serial port on the PC to which the MC/HC/Series 3 is connected. If omitted, the default is 
port 1, which corresponds to com1. If the MC/HC/Series 3 is connected to the PC's second serial port, 


type 
MCPRINT -C2 


10 


1 MCLINK, MCPRINT, AND SLINK 
a ee 
The -t<timeout> parameter 


<timeout> is a number of seconds. This parameter is provided for use on local area networks where it is 
necessary to close and open the print device between each print job. It is used to specify an inactivity 
ee in seconds. If there is no printing for this period, the print device is automatically closed. For 
example: 


MCPRINT LPT2 -T5 
will close the print device after 5 seconds of inactivity. 


If the parameter is omitted, the print device is not automatically closed. You don't have to specify a time- 
out, as you can close the print device manually by pressing any key on the PC keyboard. Exiting 
MCPRINT will also close the print device. 


The MC/HC/Series 3 are multi-tasking - while one application is printing, you can carry on with 
something else. However, the background printing can be held up at times, depending on the processing 
requirements of the work you are doing. This can fool MCPRINT's inactivity time-out into thinking that 
the printing has finished, causing it to prematurely close the print device. If you experience this problem, 
consider increasing the time-out, or convert to closing the printer device manually by pressing a key on 
the PC keyboard. 

The -q parameter 


This parameter suppresses status messages (the 'q' stands for "quiet"). 


ure ceran e  sete  e F g t te  N  e  e 
Slink.exe 


SLINK is a “no-frills” server-only version of MCLINK.EXE. However, it may run on “PC"s which are 
less than 100% PC-compatible and cannot run MCLINK, and it may run in combination with other 
software which conflicts with MCLINK. 


By default, SLINK uses the com1 port, at 9600 Baud. You can specify on the command line the Baud rate 
and the serial port to use. These are in the same format as in the SET command in MCLINK. For 


example: 
SLINK -p2 -b9600 


This sets SLINK to use com2. Note that, as with the SET command in MCLINK, -b9600 is used in this 
example to keep the Baud rate at 9600. 


If you just type SLINK -p2 this will reset the Baud rate to the internal default of 19200. 
Press Q to quit SLINK. 
SLINK has no support for modems. 


11 


ve 
4 


‘ 

a a 
(8 

t 

oe 
caer) 
+ 
te 


CHAPTER 2 


RESOURCE FILES 


This chapter covers a range of related topics: 
= reasons programmers might consider using resource files 
= the format of Sibo .rsc resource files 
= the Olib rscfile class that can be used to read resource files 
= the Sibo resource compiler tool, rcomp.exe, that can be used to create resource files 
= general considerations about multi-lingual applications. 


Although the topics are all related, it is by no means necessary to read and understand all the sections in 
this chapter, just in order to understand one of these sections. 


ye Ns ee he 
Introduction 
There are two main reasons why a programmer may wish to use resource files: 


= Having data in a resource file, rather than as part of the program itself, cuts down on the size of 
the data segment required by the program, and thus makes more efficient use of RAM. 


= Resource files make it easier to write applications that can run in more than one language (eg 
English, French, German...). 


Text strings are a simple but important example of data that can be stored in a resource file. Suppose a 
program contains lines of code such as 


winfoMsg("Starting calculation"): 
and 


wSetBusyMsg("Scanning"); 


D.yh 


or even 
P_printf("%d items found",num); 


The dataspace of this program, when compiled and linked, would contain the three strings "Starting 
calculation", "Scanning", and "%d items found" - a grand total of some 45 bytes (note that a terminating 
zero is stored for each string). A larger program may have many times this number of data strings; up to 
2k would not be uncommon. Now this data would be permanently loaded into RAM all the time the 
program is running. As a result, 2k less space would be available to the ordinary data of the program - 
such as cells in a spreadsheet, or text in a word processor - thus reducing the amount of such data that the 
program can accept before giving an “out of memory" error. Moreover, the operating system would be 
more likely to refuse to load and run the program, on account of insufficient memory being available to 
start it. 


Next consider how the problem worsens for a program that is to be translated into more than one 
language. Either the program has to carry the data for all the different target languages, with a choice 
being made at run time between the various different possibilities: 


13 


ADDITIONAL SYSTEM INFORMATION 


if (language==LANG_ENGLISH) 
wSetBusyMsg("Scanning"); 

else if (language==LANG_FRENCH) 
wSetBusyMsg("Parcourt") > 

else if (language==LANG_ GERMAN) 
wSetBusyMsg("Suche") > 


or else the code will have to be recompiled each time for a new lan e. But this latter approach makes 
the problem of maintaining code much harder; each different change to the code, such as a bug fix, 
will have to be propagated to all the different language versions. At the same time, the job of the 
translator is not helped by the text to translate being all mixed up with the rest of the code, whilst if the 
translator works on a separate list of text strings, there is the risk of ription errors when the 
separate lists are merged back into the code. 


For reasons such as these, serious programming in any system (Sibosdk or otherwise) frequently adopts 
one or other resource file approach for text strings and other data items. The strings "Starting 
calculation", "Scanning", "Xd items found", and so on, are kept in a file, not as part of the 
dataspace of the program, and are loaded into RAM only when they are needed. 


Thus the above call 
wWInfoMsg("Scanning"); 

would be replaced by a call such as 
InfoMsg(RESOURCE_SCANNING); 


where RESOURCE_SCANNING is a symbolic constant (#define) giving the inde of the text string "Scanning" in 
the resource file. (The exact meaning of the index varies between different resource file schemes. See 
below for the meaning in Sibo resource files.) | 


The contents of the routine InfoMsg would be something like 


LOCAL_C VOID InfoMsg(INT index) 
{ 
TEXT buf [60] ; 


LoadResourceString(&buf [0] , index); 
wInfoMsg(&buf [0] ) > 
> : 


and in turn LoadResourceString would read data from the appropriate feource file. 


At the initialisation of the program, the name of the appropriate resource file would be determined, once 
and for all, by reference to the current language (as obtained by a call to p_get language). 


Some uses of resource files on Sibo computers 


Each of the built-in or bundled applications on the MC and Series3 ranges has its own resource file, in 
which are kept menu and dialog data, as well as more basic text strings The dialog data can contain 
numerical layout information and numerical flags customising ee within dialogs. 


Since the text strings and dialogs used by these different applications often overlap, there is also a so- 
called system resource file, where common items are kept. Thus an ication loads data at various 
times from each of two different resource files - its own application resource file, and the system one. 


The .wdr printer driver files used by the printer subsystem in form. dyl (as on the Series3 - see the WOR 
Printing chapter in this manual for more details) are also resource files, ;with the data items consisting of 
escape sequences, font width tables, and other printer data. 


Finally, low-level error messages are defined in another file in the ROM, sys$ctry.cfo. This file also 
contains the keyboard layout tables, the fold tables, and other standard text such as the names of the days 
of the week. See the Config Files chapter for more details. 


14 | 


2 RESOURCE FILES 


i ca ee SNR Re eet ge Se Se Dn gd 
Format of Sibo resource files 
There are in fact three kinds of Sibo resource files: 
= .cfo files, which are language configuration files (sometimes just called config files), with 
sys$ctry.cfo being the principle example 
=  .rsc files, which are standard resource files 
=  .rzc files, which are Huffman compressed versions of .rsc files. 


Access to the data in .cfo files is via Plib functions such as p_errs, p_gettext, and p_nmmon, as described 
in the Plib Reference manual. 


Data in .rsc and .rzc files can be accessed using the functionality of the rscfile class in olib.dyl, as 
described later in this chapter. 


The. Sibo resource compiler, rcomp.exe, can be used to create instances of .rsc files from plain text input 
known as resource scripts, which typically have extension .7ss. This process is also described later in 
this chapter. However, the format of .rsc files (described immediately below) is so straightforward that 
programmers could easily create their own tools for producing customised .rsc files. 


Unless explicitly stated to the contrary below, the remainder of this chapter focuses exclusively on the 
.rsc type of resource files. 


The format of .rsc files 


A standard resource file just containing the three strings "Starting calculation", "Scanning", and "%d 
items found", has the following contents (when dumped): 


0: 31 00 08 00 53 74 61 72 74 69 6e 67 20 63 61 6c 1...Star ting cal 
10: 63 75 6c 61 74 69 6f 6e 00 53 63 61 6e 6e 69 be culation .Scannin 
20: 67 00 25 64 20 69 74 65 6d 73 20 66 6f 75 Ge 64 g.4d ite ms found 


30: 00 04 00 19 00 220031 00 = Veep MSD vs 
This conforms to the pattern: 
<header><resources><index table> 
where: 
<header> is always four bytes long, with the first word giving the file offset of the start 
of the index table, and the second word giving the length (in bytes) of the 
index table 
<index table> is a sequence of words, the first giving the file offset of the start of the first 
resource, the second giving the file offset of the start of the second resource, 
and so on, up to the last word, which gives the file offset of the end of the last 
resource (which is also the beginning of the index) 
<resources> are a series of variable length data items, whose contents can have any form. 


Some strategies for reading .rsc files 
Clearly, one way to implement a routine such as LoadResource is essentially as follows: 


GLDEF_C VOID LoadResource(UBYTE *pb, INT index) 


{ 

ULONG fpos; /* file offset */ 

UWORD tmp[2]; /* section of index table */ 

fpos=ixpos+(( index-1)*2); /* position into the index table */ 
p_seek(fcb,P_FABS, &fpos); 7 
p_read(fcb,&tmp [0] ,4); /* read two words from index table */ 


p_seek(fcb,P_FABS, tmp[0] ); 
p_read( fcb, pb, tmp[1]-tmp [0] ); 
> 


where: 


= feb is the file control block of the open resource file 


ADDITIONAL SYSTEM INFORMATION | 


= xpos is the value of the first word in the resource file (ie the be offset of the beginning of the 


index table), and has been read into memory during program initialisation, for the sake of 
efficiency 


a Se une cere oe ee et urce, 2 for the second resource, 
and so on | 


= the code would need modifications to cope with possible error values returned by the p_seek or 
p_read calls (further discussed below). 


This strategy relies on a value of ixpos being stored in program memory. Another strategy would be to 
store the entire index table in memory - and this is the reason why the length of the index table is 
recorded as the second word in the resource file. However, in practice there is no observable speed 
degradation on account of reading index table data from the file every time a resource has to be loaded, 
and so the earlier scheme is generally to be preferred - in view of the lesser demand it places on RAM 
usage. 


Example of reading resource files directly | 


See the file readrsc.c in \sibosdk\demo for an example of how to read ne contents of a resource file 
directly (i.e. without using the services of the rscfile class). 


This example code assumes that the resource file is embedded in the applicstion’s program (.app) file. 
Thus, when used in an application, the name of the resource file should be specified on the second line of 
the application's .a/l file. 


To use the example code, you must create a resource file with its first two resources both being short text 
strings. Any additional resources are not read by the supplied code. 


Using the rscfile class in Olib | 


| 


Although it is possible, along the lines discussed above, to read .rsc resource files using ordinary Plib 
function calls, there are various reasons for instead using the functionality of the rscfile class in 
olib. dyl: 


= Using the rscfile class avoids needing to remember any details of the format of .rsc files 


= The rscfile class also contains considerable logic, hidden from the casual user, to decode .7zc 
Huffman compressed resource files - so that a decision can be taken at a later stage, to use .rzc 
format files instead of .rsc format, without any need to alter or recompile existing code 


ws The rscfile class automatically takes care of locating resource files suitably embedded in a .img 
file - see below for more details | 


= The interface to the rscfile class clarifies and documents all possible error conditions that 
need to be catered for 


» Learning about the rscfile class is a useful step along the rou | to learning about Psion's 
proprietary object-oriented programming system - since this stem makes heavy use of the 
rscfile class. 


Basic services of the rscfile class 


Before the functionality of the rscfile class can be used in a program, an instance of this class needs to 
be created and initialised. This is dealt with below. 


The outcome of the initialisation is a handle, rather like a handle to a file control block or to other 1/o 
device control blocks. Subsequent rscfile services are directed via this handle. 


The most primitive rscfile service is to load a resource, specified by index number (starting at 1 for the 
first resource), into a supplied buffer. This is the rs_read_buf service. [In this case, it is assumed that the 
caller has supplied a sufficiently long buffer. 


Sometimes, however, it is more appropriate for the rscfile class to all | te a cell of sufficient length, for 
the resource to be loaded into. This typically applies when a resource can have variable length, and 
when the resultant alloc cell will have some permanence. The rs_read service fulfils this requirement. 


16 


» 


2 RESOURCE FILES 


As an example of the rs_read_buf service, consider the following routine InfoMsg: 


LOCAL_C VOID InfoMsg(INT index) 
{ 
TEXT buf [60]; 


p_send4(rcb,0_RS_READ_ BUF, index, &buf [0] ); 
winfoMsg(&buf [0] ); 
> 


with rcb being the handle of a suitably initialised rscfile object. 


As an example of the rs_read service, consider loading some menubar data in from a resource file. For 
Hwif programs, this data is (in part) in the form of an H_MENU_DATA struct. The address of this struct has 
to be written to the static _mdata (of type H_MENU_DATA*) whose existence the Hwif library presupposes. In 
that case, the following call might be made during the initialisation of an Hwif application: 


p_send4(rcb,0_RS_READ,MENU_DATA_INDEX,& mdata); 
where MENU_DATA_INDEX is a symbolic constant giving the index of the appropriate resource. 


Note that although the calling interface to rs_read_buf and rs_read may look similar, they require 
different types for the penultimate parameter: 


= rs_read_buf requires a parameter such as a TEXT* or a UBYTE*, ie with one level of indirection 
from the actual loaded data 


= rs_read requires a parameter such as a TEXT** or a UBYTE**, ie with two levels of indirection from 
the actual loaded data. 


Barring run-time errors (discussed below), the calls rs_read_buf and rs_read both return the length of the 
resource read. Note that in the case of a (zero-terminated) string, this length includes the length of the 
terminating zero, since that is part of the resource too. 


Reading compressed resource files with the rscfile class 


If a Huffman compressed resource file, typically with extension .rzc, is substituted for a standard 
resource file (typically having extension .rsc), there is no need to alter or recompile in any way 
application code making use of the rscfile class. The interface remains exactly the same. 


The only point possibly worth mentioning is that the lengths returned by rs_read and rs_read_buf are the 
length of the resources once decompressed, and not the length of the compressed resources on file. 


Initialising an rscfile object 


The following code can be used to create and initialise an rscfile object providing access to a resource 
file with name rscname (assumed to be a full path name): 


VOID *InitRcb( TEXT *rscname) 
{ 
HANDLE OlibCat; 
VOID *rcb; 
INT ret; 


Pp_findtibC"OLIB.DYL",&0libCat); 
reb=p_newlibh(Ol ibCat,C_RSCFILE); 
if (reb) 
{ 
ret=p_entersend3(rcb,O_RS_INIT, rscname); 
If (ret<0) 
p_exit(ret); 
> 
return(rcb); 
> 


For overtly object oriented programs, the lines 


p_findlib("OLIB.DYL",&0libCat); 
rcb=p_newl ibh(OlibCat,C_RSCFILE); 


17 


ADDITIONAL SYSTEM INFORMATION 
a 


can be replaced by a line such as 
reb=p_new(CAT_HWIF_OLIB,C_RSCFILE); | 


with the category number CAT_HWIF_OL18 being replaced by the suitable pomenre to olib.dyl from the 
native category. 


For Hwif programs, the line 


rcb=p_new(1,C_RSCFILE); 
can be used instead, taking advantage of the fact that the value of the (normally hidden) symbolic 
constant CAT_HWIF_OLIB is 1. 
Which header files are needed 


The symbolic constants C_RSCFILE, O_RS_READ, O_RS_READ_BUF, and O_RS_INIT, are defined in the object- 
oriented include file appman. g. 


Duplicates of these definitions are given in the special SDK file rscfile.xg. 
The value of 0_DEsTROY (defined in olib.g) is 0. (See below for use of 0| DESTROY.) 


Run-time errors with the rscfile class 


Broadly speaking, there are five kinds of run-time error that can arise with resource files: 


1 there is insufficient memory to create or initialise the rscfile object 


2 the resource file cannot be found (when the program starts) 
3 ‘the data in the resource file is bad 
4 the SSD containing the resource file is removed or cannot be accessed 
5 there is insufficient memory to load a specified resource. 


Of these possibilities, the third is regarded simply as a programming error. Thus if some data in what 
should be the index table part of the file effectively says that a certain resource has length 5398 bytes, 
whereas the file itself is smaller than this size, the rscfile object will panic the application (with panic 
number 141). 


Otherwise, errors 1 and 2 can occur when initialising a rscfile object, whereas error 4 and 5 can occur 
when subsequently using the object. 


Possible errors during initialisation 


The only reason the calls p_newl ibh or p_new in the above routine InitRcb will fail is on account of lack of 
memory. Applications can choose to discount this possibility if their minimum heap is appropriately 
calibrated - see below. | 


The call to rs_init can fail with file-based errors on account of the filename in *rscname. The most 
pertinent possibility (assuming that a well-formed name has been ) is that the specified file does 
not exist. Applications could guard against this by checking on the existence of the file prior to calling 
InitReb. If the file does not exist, the user can be notified, and the "T exited. 


Errors during rs_read or rs_read_buf 


The only errors that an application should in practice worry about, for he rs_read and rs_read_buf 
services, are the fourth and fifth in the above list. 


Running out of memory can occur only in the case of rs_read - when it is impossible to allocate a call 
from the heap large enough to load the resource into. The implementation of rs_read_buf is guaranteed 
never to fail with out of memory. 


If calls to rs_read are made during program initialisation only, it may well be legitimate to ignore the 
possibility of out of memory errors in this case too - provided the decl minimum heap of the 
application is large enough. The point is that only memory in the dataspace of the application has to be 
allocated - not any memory in another process such as the File Server (see the chapter Fundamental 
Programming Guidelines in the General Programming Manual for related discussion). 


However, applications calling either rs_read or rs_read_buf ought always to consider the possibility of 
the user removing the SSD containing the resource file. What will happen in this case is as follows: 


| 
18 


- 


2 RESOURCE FILES 


= suppose the user removes the relevant SSD, not realising (or forgetting) that the program may 
wish to access data on it 


= the application makes a call to rs_read or rs_read_buf 


= system code, detecting that the file is missing, presents a Notifier requesting the user to replace 
the SSD; this Notifier has two exit options: Retry and Fail 


= the user ought to replace the SSD and select Retry; however, it is possible that the Fail option 
will be selected 


= in this case, an error such as E_FILE_ABORT will be generated. 


How rscfile errors are reported 


The rscfile services rs_read and rs_read_buf do not return any error values; instead, they internally call 
p_leave. 


Applications performing sophisticated error handling, using p_enter, should be sure that p_send calls to 
rs_read or rs_read_buf are (ultimately) enclosed in some call to p_enter - otherwise any errors will result 
in their application being panicked, with panic number 47. 


Applications not wishing to use p_enter should replace the above calls to p_send with calls to 
p_entersend, as follows: 


ret=p_entersend4(rcb,O_RS_READ_ BUF, index, &buf [0] ); 
and 
ret=p_entersend4(rcb,O_RS_READ,MENU_DATA_INDEX,& mdata); 
Possible values of ret that can be returned are as follows: 
positive value the length of the resource loaded (no error has occurred) 


negative value an error has occurred: either E_GEN_NOMEMORY for out of memory, or some other 
value in case the resource file could not be accessed. 


Note incidentally that the complications over possible errors while reading resource files are by no means 
exclusive to the .7sc format of resource files. An application could devise its own format of data file, 
and its own library of routines to extract data from these files, but these routines would have to cope with 
all the same error possibilities as for the rscfile routines. That is, the error possibilities stem not from 
the rscfile class, but from the notion of resource files itself. 


Dealing with errors in rs_read or rs_read_buf 


(This section should be skipped on a first reading.) 


There follows a more detailed example of how to deal with possible errors during an rs_read call. The 
case for rs_read_buf is similar, albeit simpler (since there is no possibility of an out of memory error in 
this case). 


19 


ADDITIONAL SYSTEM INFORMATION 


LOCAL_C VOID ReadResource(VOID *ppcell,INT index) 
{ 
INT ret; 


FOREVER 

{ 
ret=p_entersend4(rcb,0_RS_READ, index, ppcell); 
if (ret>=0) 

return; 

while (ret<0) | 

{ 
if (ret==E_GEN_NOMEMORY) 

{ 

*ppcel l=NULL;/* signal failure to caller */ 

Tel lNoMemory(); 

return; 

> 
wsAlertW(WS_ALERT_CLIENT,O,ReplaceDisk,0); 
p_send2(rcb,0O_DESTROY); 
FOREVER 

{ 

rcb=p_newlibh(Ol ibCat,C_RSCFILE); 

if (reb) 

break; 

Tel lNoMemory(); 

> 
ret=p_entersend3(rcb,0_RS_INIT,rscname); 
> 


> 


as follows: 


One way to implement the routine Tel \NoMemory - which must never al run out of memory - would be 
LOCAL_C VOID Tel lNoMemory(VOID) 
{ ! 
TEXT buf [40]; 
p_errs(&buf [0] ,E_GEN_NOMEMORY ) ; 
wsAlertW(WS_ALERT_CLIENT,0,&buf [0] ,0); | 
> 


The way ReadResource works, in cases when the user has removed the lo and has refused to replace it, 
is to present another alert, wait for the user to respond (by pressing ESC), and then try to re-~make the 


connection with the resource file. For this purpose, various statics are : 

OlibCat The value of the category handle of olib.dyl, as returned by the earlier call to 
p_findlib | 

rscname The full path name of where the resource file/should be 

ReplaceDisk Text that might read, in English, "Replace the application disk”. 


Clearly, for multi-lingual applications, the string ReplaceDisk must itself be read from a resource file. 
Since the channel to the application resource file is broken at this stage, |it may be necessary to read in 
this text during program initialisation. ! 


Standard practice for applications on a Series3 is to bracket calls to wsAlertW with increments and 
decrements to the reserved static DatLocked: 


DatLocked++; 
wsAlertW(...); 
DatLocked--; 


Incidentally, the error handling mechanism described above is implemented automatically for object 
oriented programmers who use the appman class and its methods am_load|resource and am_res_buf to 

data from resource files (except that the error recovery code in appman is even better, in that it caters with 
the case of the SSD being removed from one drive and replaced in another). 


20 


2 RESOURCE FILES 


orn me a ee en ag ry ee en ee ae ae ee | 
Advice on where to locate resource files 


Mono-lingual applications 


In the case of a mono-lingual application, the safest place to locate a resource file is within the image file. 
The rscfile class will find any resource file in the second of the four possible add-file slots in an image 
file. 


For example, if the application is called archive.app and the resource file is called archive.rsc, an add- 
file list archive.afl should be created, with the following contents: 


archive.pic 
archive.rsc 


where archive. pic will be placed in add-file slot 1, and archive.rsc in add-file slot 2. 


The named files will be added to the resultant image file, whenever this is made, just by virtue of the 
existence of an .ajl file with the same basic name as the image file. 


In this case, the appropriate name to pass to rs_init is simply DatCommandPtr (recall that a zero-terminated 
string giving the full path name of the image file is placed at this reserved static, by the operating system, 
when the process is started): 


p_entersend3(rcb,0_RS_INIT,DatCommandPtr); 


Not only does this scheme have the advantage of simplicity, it also prevents accidents if users copy the 
main image file to an SSD, but neglect to copy the associated resource file. 


For a multi-lingual application, the above continues to apply in any case when a different .img file is re- 
made (using the tool eremake) for each new language version. (For more details about eremake, see the 
chapter Building an Application in the General Programming Manual.) 


However, for multi-lingual applications in which the resource data for more than one language is shipped 
together, the resource files must in general be separate from the main .img file. (There is no scope for an 
indefinite number of add-files.) The documentation for the application should emphasise to users that if 
the .app file (or the .img file) is copied from one SSD to another, for consolidation purposes, then 
appropriate .7sc (or .rzc) files should also be copied. 


Multi-lingual applications 


One scheme that has much to recommend it is to rename the resource files as follows: 


archivO2.rsc for a French language resource file 
archiv03.rsc for a German language resource file 
archiv18.rsc for a Dutch language resource file 


and so on (for an application archive. app), where the numbers at the end of the filename are the language 
codes of the target languages, listed in the documentation of p_get\anguage in the Plib Reference manual. 


These files should be located in a sub-directory underneath the directory containing the application 
program file. The name of this subdirectory should be the same as the basic name of the program file. 
For example, if the full pathname of the program file is \app\archive.app, the full pathnames of the 
resource files should be \app\archive\archiv??.rsc. Again, resource files used by a program with full 
pathname \img\backup.img should be located as \img\backup\backup??.rsc. 


Then code to determine the name of the resource file, suitable to the language of the computer at run 
time, could be as follows: 


ADDITIONAL SYSTEM INFORMATION 


TEXT *FindRscName(VOID) 
€ 
LOCAL_D TEXT RscNameBuf [P_FNAMESIZE]; 
TEXT *RscName; 

P_INFO f; 


RscName=(&RscNameBuf [0] ); 

p_atos(RscName, "\\app\\archive\\archivz02d.rsc",p_ get Llanguage()); 

p_fparse(RscName,DatCommandPtr ,RscName, NULL); 

if (p_finfo(RscName, &f)<0) | 
p_scpy(RscName,DatCommandPtr); | 

return(RscName) >; 

> 


Note the check on the existence of the first filename generated by this routine; in case the language as 
returned by p_get language is not supported by the application, the routine defaults back to whatever 
resource file is built into the application. 


Copying of applications 


The above recommendation for where resource files should be located conforms to the important general 
rule that if users wish to copy an application \path\name. ext from one SSD to another (say from drive a: 
to drive b-), all they need to do is type 


copy a:\path\name.ext b:\path\name.ext | 
copy a:\path\name\*.* b:\path\name\*.* 


in which case (assuming the application is not copy-protected!) all the files required or presupposed by 
the application will be transferred. | 


General comments on multi-lingual applications 
It is a common programming error to design an application too closely around the text of one language 


(eg English), and to discover only at some late stage that various tions made fail when the 
application is translated into another language. 


For example, if the English text "weekly" is to be read into some resource, it may be tempting to write 
some code as follows: 


TEXT buf [8]; 


| 


p_entersend4(rcb,O_RS_READ_BUF ,WEEKLY_INDEX, &buf [0] ); 


However, when the application is translated into German (say), with the entry for "Weekly" in the 
resource file being changed into "Wochentlich", the new application most likely crash when the above 
code is run. The reason is that the buffer of eight bytes, which was long enough to contain the text 
MWeekly", is not long enough to contain "Wéchentl ich". | 


Better therefore to decide in advance what a reasonable limit on the translation of this term should be, 
and use that as the size of the buffer in the code (not forgetting to oe the translators what the limit 
iS). 


The basic principle of independence of code from resource file 


One basic guideline is that the code itself should not have to be altered, just because a new translation has 
been undertaken. The original code should be general enough to start with. 


The main problem with allowing code to change at a later date, to simplify the task of translators, is that 
it is often difficult to foresee the side-effects of such a change. In practice, the most intense testing an 
application receives is just prior to its launch in the original language; if changes are made at a later date, 
these may introduce bugs which slip through subsequent testing, on t of that testing being less 
severe. 


For this approach to work, a special test plan has to be devised, focussing on the purely language 
dependent parts of the application. This test plan should include means |of loading, one by one, all the 
resources from the resource file, and displaying them on the screen for validation. 


22 


2 RESOURCE FILES 


Provided changes made in response to problems thrown up by this test plan are restricted to the resource 
files themselves, there can be some confidence that the original intensive testing still holds good. But if 
code has to be changed, there is the risk of regression - something that used to work now no longer 
works. 


Careful design of screen layout 


Design of screen layout is another area where things can go unexpectedly wrong when the contents of a 
resource file is changed. 


In some cases, screen layouts which (just) work in one language, become untenable in another language, 
because there simply is no acceptable way of translating the text on the screen and still fitting within the 
allowed display area. For this reason, displays which are already cramped in the original language 
should be avoided: if they are cramped in one language, they will likely become "grid locked" in some 
other language, with slightly longer words. 


Even if there is ample room in some screen display, care should be taken to calculate various dimensions 
dynamically, ie at run-time, using the widths of the actual characters used, rather than statically (ie at 
compile-time). 


Codesize problems 


For related reasons, an application which, together with its resource file, only just fits on an SSD of a 
certain size (say 128k), will be unlikely to fit on a similarly-sized SSD when the resource file has been 
translated into another language. 


Of course, as with the other problems above, it is always possible to insist that a sufficiently brief 
translation be found, but this can result in abbreviations the user is likely to consider ridiculous. It is far 
better to include some “spare” in the original budget, to allow for some measure of growth as the 
translation takes place. 


Varying keyboards 


As well as the text of messages varying from one language to another, it is also possible for the keyboard 
layout to alter. This does not just mean changing from QWERTY to AZERTY, but changes in which characters 
can be typed in combination with various modifiers. 


For example, an application in one translation may define the hot-key PSION+/ as the accelerator for 
some menu command. However, a foreign language keyboard may move the / key into a place where it 
cannot be pressed in conjunction with the PSION modifier. Thus on the Series3 keyboard, PSION together 
with some keys changes the characters delivered, into altogether different ones. Therefore, the 
accelerator would have to alter to some other keypress. 


Something else that may have to change, on account of the keyboard changing, is references to the 
keyboard within eg Help text (or inside “Action buttons"). For example, the DELETE key may become 
the EFF key in a different language variant. 

Conclusion 


The possible problems of multi-lingual code form another item in the list of things that need to be 
constantly under background consideration as an application is written. 


The discipline of separating text into a resource file is a vital step in the right direction, but by itself, it 
does not guarantee that all related problems will be solved. Every time text is used in an application, the 


writer must ask the question: not what is the length of this text, but what might the length of this text be 
in some foreign translation - and what would the consequences of that be? 


CA a 9 A npn VO ae ee enn 
Creating .rsc files using rcomp.exe 


The resource compiler is a tool rcomp.exe that operates on a so-called resource script, which is a text 
file, to produce a resource file as output. 


The process is akin to ordinary compilation: 
*.c + compiler -> *.obj 
*.rss + resource compiler -> *.rsc 


with .7ss being the usual extension for a resource script. 


23 


ADDITIONAL SYSTEM INFORMATION 


As an example, suppose a file eg.7ss has the following contents: 
STRUCT STRING 


> 


RESOURCE STRING res_start_cale {str="Starting calculation":) 
RESOURCE STRING res_scanning {str="Scanning":} 


{ 
TEXT str; /* zero terminated text string */ 
RESOURCE STRING res_items_found {str=""%d items found!':} 


Then invoking the command line | 
rcomp eg 
produces as output a file eg.rsc whose contents are exactly as described in the earlier section on the 
format of .rsc files. 
Note: some earlier versions of rcomp. exe do not accept the syntax 

RESOURCE <struct-name> <identifier> <definition> . 
instead requiring the addition of the keyword GLOBAL: 


GLOBAL RESOURCE <struct-name> <identifier> <definition> 


Generated .rsg files 


| 
As well as producing a .rsc resource file, running rcomp. exe also has | effect of creating a generated 
header file, with extension .rsg. : 


Thus the output of typing rcomp eg is not only the file eg.rsc but also the file eg.rsg, having the 
following contents: 


#idefine RES_START_CALC 1 
#define RES SCANNING 2 
#define RES_ITEMS FOUND 3 


In turn, C source files that need to specify resource indices ought to #include these generated .rsg files, 
so that they can include code such as 


InfoMsg(RES_ SCANNING); 


The present value of RES_SCANNING is 2. Suppose however that a new resource is added at the beginning 
of eg.rss. This means that the resource "Scanning" is of course no longer the second in the resultant .rsc 
file, but the third. Accordingly, any calls such as 


InfoMsg(2)>; | 
have to change into calls such as 
InfoMsg(3); 
in order that they have the same effect as before. Note that having th e lines of code instead as 
InfoMsg(RES_SCANNING); 
and recompiling the C source files after changing the resource script automatically ensures that the 
desired outcome transpires. 


The syntax of the rcomp command 
The syntax for invoking rcomp. exe includes: 


rcomp [-s]<name> [-o<oname> -h<hname>] 


where 

<name> is the name of the resource script 
<oname> is the name of the resource file output 
<hname> is the name of the generated header file. 


One possible use of the fuller syntax is to redirect the generated header . to an .. \include\ directory. 


24 


2 RESOURCE FILES 


Include files within a resource script 


A resource file can contain lines such as 
#include "archive.dh" 

or 
#include <archive.rh> 


(no particular significance should be attached to the extensions used in these examples). As would be 
expected, files specified using the quote form of #include are expected to be found in the local directory. 
However, files specified using the angle bracket form of #include are expected to be found in the 
directory (if any) specified by the value of the DOS environment variable INCLUDE. 


If required, a batch file such as follows could be used to invoke rcomp. exe: 


set OINCLUDE=%INCLUDE% 
set INCLUDE=..\include 
\sibosdk\sys\rcomp 41 
set INCLUDE=ZOINCLUDE% 
set OINCLUDE= 


preserving any previous value of INCLUDE for other purposes that may apply on a PC. 


Conditional compilation in resource files 
Note that the resource compiler supports conditional compilation such as 


#ifdef BUILD_ONE 

#endif 
and 

#ifndef BUILD_ONE 

fendi f 
Names (such as BUILD_ONE) may be defined when invoking the resource compiler using a -d flag as 
follows: 

rcomp resfile -dBUILD_ONE 
This has the same effect as including the corresponding #define in the resource file, for example: 
#define BUILD_ONE 


i a ee | 
Contents of .rss files 
Resource scripts (together with other files they #include) are made up of three types of statement: 
= comments (identified by C-style /* and */ delimiters) 
= declarations of STRUCTs and constants 
= declarations of RESOURCES, which are instances of the sTruCTs defined. 
All the declarations of structs have to precede the first definition of a RESOURCE. 


White space is ignored (after the first white space character), except within quoted strings. Thus the 
definitions 
RESOURCE STRING res_start_cale {str="Starting calculation";} 


and 


RESOURCE STRING res_start_calc 
{ 
str="Starting calculation": 


} 


25 


ADDITIONAL SYSTEM INFORMATION 


are equivalent. Any indentation of source lines in resource scripts is purely for convenience. 


Declaring STRUCTs 


STRUCTS are formed of a name and a series of member definitions. STRUCT names must always be given in 
upper case, whereas member names are given in lower case. For example, 


STRUCT STRING 

{ , 
TEXT str; | 
> 


defines a STRUCT with name STRING and just one member, which has type TEXT and member name str. 


Again, the definition 


STRUCT MENU_BAR_ITEM 
{ 
LINK menu_id; 
TEXT mb_item; 
> 


defines a STRUCT with name MENU_BAR_ITEM and with two members, the 
with type TEXT. 


t with type LINK and the second 


As is discussed below, member definitions can also include default initialisations. 


Possible member types in STRUCTs 
The set of allowed struct member types is as follows: 


cluding the terminating zero 


BYTE stores a numerical value in one byte 

WORD stores a numerical value in two bytes 

LONG stores a numerical value in four bytes 

DOUBLE stores a floating point numerical value in eight bytes 
TEXT stores a zero-terminated sequence of bytes, i 

LINK stores a two-byte reference to another RESOURCE 
STRUCT stores a sub-STRUCT in-line. 


Of these types, only TEXT and struct have variable length (see below fo 
WORDS are stored low byte first then high byte. Similarly, LONGs are sto 


more on variable length items). 


low word first, then high word. 


The resource compiler accepts any value from -128 to +255 for a BYTE,|so that C programs are free to 


interpret the contents as either signed or unsigned. WORD and LONG can si 
signed or unsigned. 


ilarly be interpreted either as 


The resource compiler can undertake some limited arithmetical evaluation of data supplied in numeric 


fields (eg val=4*3.18). 


TEXT data can be entered as a combination of quoted strings, binary = 
str="This is a string.": 

or 
Str=<84><104>"is a str"<0x69>"'ng""<46>; } 

or even | 


#tdef ine DOUBLE_QUOTE <34> 


str="Missing "DOUBLE_QUOTE; 


Standard C-style processing of backslashes applies within quoted strings. Thus to enter a single 
backslash in a string, the backslash character has to be repeated in the input, and so on. Thus the final 


example above could also be given as 


str="Missing \": 


26 


2 RESOURCE FILES 


Allowed values of LINK items are constants, symbolic constants, or (lower-case) identifiers of other 
resources. In referring to another resource, both forward and backward references are possible. 
Declaring RESOURCEs 
A RESOURCE is declared by specifying: 

= the name of the struct being instanced 

= the identifier of the RESOURCE 

8  initialisers: values of all the members of the STRUCT. 


The name of the STRUCT must always be given in upper case, whereas the identifier of the RESOURCE must 
always be given in lower case. 


For example: 
RESOURCE MENU_BAR_ITEM file_mbar_item 
menu_id=file_menu; 


mb_item="File't; 
> 


During resource compilation, the various identifiers encountered are assigned the values 1, 2, 3, .... 


There is no requirement to list the members of the STRUCT in the same order as their definition. Nor is it 
always necessary to give values for every member: 


= any member omitted will be given the default value supplied for that member, in the declaration 
of the struct, if any 


= failing this, a “default default" value of zero will be supplied 
= however, it is an error to omit altogether to give a value for a LINK member. 
For example, it is possible to declare an instance of 


STRUCT NCEDIT 
{ 
WORD current; 
WORD low; 
WORD high=65535; 
> 


just by the line 
RESOURCE NCEDIT nc_edit { } 


in a resource script, in which case a 6-byte long resource will be created, with the three consecutive 
words containing the values 0, 0, and 65535. 


Again, the result of resource compiling the following: 


STRUCT TEST 
{ 
TEXT str; 
BYTE byt; 
STRUCT more; 
> 


RESOURCE STRUCT TEST empty ¢€ } 
is a 2-byte long resource, with each byte being set to zero. (Note that "zero" sub-STRUCTs are omitted in 
their entirety, ie taking up zero length in the resource file.) 


Declaring the values of sub-STRUCTs 
Whereas the way to define the value of most members of RESOuRCEs is by a statement in the form 


<member-name> = <constant>; 


27 


ADDITIONAL SYSTEM INFORMATION 


the way to define the value of a sub-strucT member is 


<member-name> = <struct-name> {<initialisations>); 


| 
with the form of <initialisations>, if present, matching that of the definition of a RESOURCE itself. For 


example: 


STRUCT NCEDIT 
{ 
WORD current; 
WORD low; 
WORD high=65535; 
> 


STRUCT TEST 
{ 
TEXT str; 
BYTE byt; 
STRUCT more; 
> 


RESOURCE TEST values 
{ 
str="This is a string": 
byt=42; 
more=NCEDIT {(current=100;}; 


> 
Sometimes when there is a sub-STRUCT member in a STRUCT, there will only be one intended struct to fill 
this slot, but in other cases, there may be more than one possible type of sub-sTRUCT. 


Leading byte and word length values . 


In cases when STRUCTs contain sub-STRUCTs, it is frequently helpful to have the instance of the sub-STRUCT 
preceded by a byte or word giving the length of the instance. This is achieved by amending the 
definition of the sub-sTRUCT: the keyword BYTE or woRD should be included before the opening curly 
bracket prior to the definitions of the members of the STRUCT. 


For example, resource compiling | 


STRUCT FIRST BYTE 
r 
BYTE one; 
> 


STRUCT SECOND WORD 
 €£ 

BYTE two; 

> 


STRUCT THIRD 
{ 
BYTE three: | 
. 


STRUCT FOURTH BYTE 
r 
_ STRUCT a; 
STRUCT b; 
STRUCT c: 

) 


RESOURCE FOURTH test 
{ 
a=FIRST {one=1;); | 
b=SECOND {two=2;); | 
=THIRD {three=3;}; 
> 


—$ $$ $e 


2 RESOURCE FILES 
SSeS 


results in the following 6-byte long resource: 
<01><01><01><00><02><03> 


in which the first byte gives the length of the following sub-resource, the third and fourth bytes together 
constitute a word giving the length of the second sub-resource, and the final sub-resource has no 
preceding byte- or word- length value. 


Note that the resource as a whole lacks a leading byte- or word- length value, despite the presence of the 
BYTE qualifier in the definition of FourRTH. These leading length values are emitted only when the instance 
of the STRUCT is as a sub-resource. 


Incidentally, it is common for definitions such as 


STRUCT FIRST BYTE 
{ 
BYTE one; 
> 


to be given instead in the equivalent form 


STRUCT FIRST 
BYTE ¢ 
BYTE one; 
> 
Arrays within resource files 


The resource compiler is at perhaps its most powerful in dealing with arrays of resources - strictly 
speaking, arrays of sub-resources. 


In order to declare an array of sub-resources, a member definition in a STRUCT definition such as 
<type> <member-name>; 
has to be changed into one of the forms 
<type> <member-name> [<array-size>]; 
<type> <member-name>[ }; 
LEN <type> <member-name>[ ]; 
or 
LEN BYTE <type> <member-name> [ J; 
For example, 


STRUCT HELP_ARRAY 
{ 
LINK topic_id=0; 
TEXT topic; | 
LEN BYTE STRUCT strist{]; 
> 


in which the initial LINK and TEXT sub-resources are followed by a variable number of sub-sTrUCTs (the 
number varying between different instances of HELP_ARRAY). 


In all cases with arrays, the corresponding initialiser statement in a RESOURCE definition 
<member-name> = <constant>; 

changes into the form 
<member-name> = { <constant>, <constant>, ..., <constant> ); 


with <constant> being replaced by <struct-name> {<initial isations>} in the case of an array of sub- 
STRUCTS. 
For a variable sized array, the array of sub-resources may be preceded in the resource file by a byte or 


word giving the number of elements actually in the array. This count is recorded in a word if the prefix 
LEN is used, and in a byte if the prefix LEN BYTE is used. 


29 


ADDITIONAL SYSTEM INFORMATION 


| 
Evidently, the number of sub-resources that actually occur in any given instance of the STRUCT is 
determined by the syntax of the intialiser, with all but the last element being preceded by a comma. 


For example, resource compiling 


STRUCT STRING 

{ 

TEXT str; : 
STRUCT HELP_ARRAY 

{ 

LINK topic_id=0; 

TEXT topic; 

LEN BYTE STRUCT strlist{f]; 

> 


RESOURCE HELP_ARRAY sys help print 

{ 

topic="How to print": 

strist= 
{ 
STRING {str="Set Printer Model with ‘Print setup'":), 
STRING {str="in Word/Agenda/Data, then use 'Print'";} | 
); 


> 
produces a single resource in which: | 
s the first word is zero (the supplied default value for the topic id member) 
s then there follows the sub-resource "How to print" 
= next comes a byte containing the value 2, being the count of the items in the following array 


= finally the strings “Set Printer ..." and "...Print'™ are — 


Creating SYSTEM resource files i 


For completeness, it should be mentioned that the resource compiler hie a special mode if the first line 


of a resource script is found to consist of precisely the single word | 

SYSTEM 
In this mode, all LINK references are automatically resolved with the naganve of the correct value. 
Thus whereas the resource script | 


STRUCT STRING {TEXT str;} 
STRUCT TEST {LINK lLnk;> 


RESOURCE STRING alpha {str="Xyz";) | 
RESOURCE TEST beta (lnk=alpha;} 
lin i 


results in the second resource consisting of the word 1, inserting a 
SYSTEM 


at the beginning of the resource script changes the value of this reso | to -1. 


The rationale of this behaviour is connected with the facility offered to object-oriented programmers by 
the appman class in olib.dyl, to load in resources from the so-called system resource file instead of from an 
application-specific resource file, if the resource identifiers passed are negative. See the documentation 
On appman for more details. P 


CHAPTER 3 


WDR PRINTING 


i ee ne Se ee ee 
Introduction 


SIBO computers which contain form.dyl in their ROM (or on an SSD) support a wide range of services 
connected with so-called WDR printing. These services include the interpretation of printer driver files 
in the Psion-proprietary .wdr format, and the generation of suitable printer command sequences to effect 
printing operations requested by applications. One key idea is that applications do not need to know 
which particular printer driver has been selected by the user; system software takes care of converting 
requests made by applications into command sequences suited to the current printer. 


Another service which code in form.dyl can provide is opening the correct printer device - whether that 
be the parallel port, the serial port, or a file. Once again the idea is that users can specify the printer 
device, and have their choice picked up by system software, without any conscious intervention to this 
effect by individual applications. 


All versions of the Series3 have form.dyl in their ROM, as do suitably reprogrammed versions of the 
HC. 


Whilst the full power of the WDR printing system can be utilised only by object-oriented programmers, 
applications that are not themselves object-oriented may still be able to make considerable use of these 
services: 
= picking up the choices made by the user as regards the printer device (these choices are stored in 
environment variables) 
= reading the contents of .wdr files directly (by themselves) 
= reading the contents of .wdr files using services of the wdr class in form. dyl. 


In addition, the Hwif library contains routines hPrintSetupDialog, hPrinterSetupDialog, hPrint, 
hPrintSetS!I, hPrintSensePageWidth, and hPrintSenseBufWidth, which layer over WDR printing services to 
achieve impressive results adequate for many purposes - without requiring any explicit use of object- 
oriented techniques (nor any explicit reference to the contents of .wdr files). See the Hwif Manual for 
more details. 


Creating .wdr files 


The creation of .wdr files is a quite separate process from their use, once created. Psion can supply a set 
of .wdr files covering some common printers, and other .wdr files may be available from third parties. 
However, it may prove desirable to produce a .wdr file for another printer not presently supported - or to 
enhance the .wdr file for a new version of a given printer. 


Note that whatever the origin of the .wdr file, the file name must not begin with fax. Such filenames are 
reserved for fax driver files and are automatically interpreted as such. 


One way to create .wdr files is by using the Sibo printer driver translator, wdtran. exe, which creates .wdr 
files from plain text input known as printer scripts typically having extension .wd. 


The operation of wdtran. exe is described later in this chapter. 


31 


ADDITIONAL SYSTEM INFORMATION 


The WDR printing environment variables 


WDR printing software may at various times attempt to read or write the four environment variables ps0, 
PSS, PSF, and PSM: 


PSD is one byte long, having the value '0' to denote that the has chosen to print using the 


parallel port, '1' to denote the choice of the serial port, | d '2' to denote printing to file 


P$s is twelve bytes long, being a copy of the P_SRCHAR struct matching the choices last made by 
the user in any serial port and handshaking dialog(s) 


PSF can be up to P_FNAMESIZE (128) bytes long, being a copy of the filename last chosen by the 
user as the recipient of any data printed to file 


: 
PSM can be up to P_FNAMESIZE+1 (129) bytes long, the first byte recording the printer model 
number (see below), and the remainder giving the full path name of the last .wdr file chosen 
by the user. 


Any software that attempts to read these environment variables should in mind that these variables 
do not always exist. Ordinarily, they are created only when the user makes an explicit choice via a 
- dialog box. In the absence of one of the environment variables, the following defaults are assumed to 
apply: 

PSD effectively has the value '0', meaning that printing should be via the parallel port 


PSS see below : 
PSF any printing to file is to the file p. lis ) 


PSM the printer model number is 0 and the printer driver file rom::bj.wdr should be used. 
The default values of the P_SRCHAR struct are as follows: 


P_SRCHAR ser; 


ser. tbaud=P_BAUD_9600; 
ser .rbaud=P_BAUD_ 9600; 
ser. frame=P_DATA_8; 
ser .parity=0; 
ser.hand=P_OBEY_XOFF|P_OBEY_DSR|P_IGN_CTS; 
ser .xoff=0x13; 
ser .xon=0x11; 
ser. flags=0; 
ser. tmask=0; 
For more details on the P_SRCHAR struct, see the Serial Port chapter in the I/O Devices Reference manual. 


The essential point is that the contents of the P_SRCHAR struct should be|used to P_FSET the serial port after 
opening it. 

For convenience, the printer model number is stored in printable form, with the value of '0' being added 
to its numerical value. Thus to use the second model in a . wdr file - > that the printer model number 
would be 1 - the first byte in PSM should be 1+'0', ie '1'. | 

A note on reading environment variables LL 

See the discussion on p_getenviron and p_getenv in the Plib Reference ual 


Note that it is also possible to read and modify environment variables (eg for experimental purposes) by 
using the SIBO Debugger. | 


Overview of the contents of a .wdr file 


This section provides an overview of the contents of a . wdr file. More details are provided in later 
sections. 


32 


3 WDR PRINTING 


ee 


Just about the simplest possible . wdr file would have the following contents, when dumped: 


0: 
10: 
20: 
30: 
40: 


89 00 Oc 00 57 44 52 30 

47 65 6e 65 72 61 6c 00 

00 00 00 00 00 00 00 00 
0 


35 00 00 00 01 00 05 00 
00 00 00 00 00 00 00 00 
17 00 00 00 00 00 00 00 
Oc 01 Od 02 2a Oa 00 02 
01 00 02 05 23 4d 6f 6e 
00 00 00 CO CO 00 00 00 


50: 

H 03 00 01 
70: 00 00 01 00 01 00 01 00 
80: 00 00 00 00 00 01 00 04 
90: 00 7b 00 89 00 


This conforms to the pattern 


<header><resources><index table> 
of Sibo standard .rsc resource files, as discussed in the Resource Files chapter in this manual. 


Indeed, . war files are but examples of .rsc files, with the extension changed to denote the particular 
purpose of being a wdr printer driver file. 


In fact, .wdr files come in two types - compressed and uncompressed (standard), corresponding to the 
-'zc and .rsc forms of resource file. Uncompressed files can be read by a variety of methods, as 
discussed in the Resource Files chapter. However, in order to read compressed .wdr files, it is more or 
less necessary to use some of the functionality of object-oriented classes in the ROM, using either: 


# the rscfile class in olib.dyl 
ws the wdr class in form.dyl 


with the preference being for the latter, since it contains more explicit knowledge of the particular 
contents of . wdr files. 


Various services provided by the wdr class are described later in this chapter. 


Deciphering general.wdr 


The above dump is in fact that produced from an (uncompressed) version of the file general. wdr that is 
part of the Series3 ROM. This file describes the most basic kind of printer possible, possessing only one 
font, which is monospaced, and assumed to be 12 point (ie six lines per inch - one point corresponding to 
1/72 of an inch) and 10 cpi (characters per inch). For this printer, the only way to position the print 
head horizontally is by emitting space characters or carriage returns, and the only way to position the 
print head vertically is by emitting line feeds or form feeds. 

The index table for the file starts at file offset 0x89 (as contained in the first word in the file). Reading 
successive words from this index indicates that the individual resources in the file are to be found at file 
offsets 0x04, 0x28, 0x48, Ox4d, and 0x7b. 


The header resource 

The first resource in any .wdr file is always the header resource, having the following structure: 
= the first six bytes give a signature, which must always be "wor05" for a valid .wdr file 
= the next word gives the so-called wdr-flags for the file - evidently 0 in this case 


= the word after that gives the number of different printer models in the file - in this case, there is 
only one in the file 


= finally there is an array of WOR_MODEL_INDEX structs, one struct for each printer model in the file 


= each WOR_MODEL_INDEX starts with a word giving the resource identifier for the model resource 
(see later) giving more information about the printer model - this identifier has value 5 in this 
case 


= the WOR_MODEL_INDEX struct concludes with up to 24 bytes giving the public name of the model, in 
a zero-terminated string - "General" in this case. 


For general. wdr, the total size of the first resource is evidently 6+2+2+1*(2+24), ie 0x24. For other .war 
files which contain more than one printer model, the first resource will be larger. 


33 


| re 
(77) 06x0 xutul 


‘SMOT]OJ SB APUOPLAS oJe SoNEA SNOLBA OU} JO SonfeA oN} ‘“upm ‘yv19Ua8 10,q 


"saomMOsal sovjodA3 Jo slayHuep! Jo Joqumnu poyrtoods om jo Lee ue Aq pemo]fo] SIs a 


SJoyUSpr wy arnfediy SULMOT[OJ JO JoquInu oy) SUIAIZ PIOM B SOUIOD jxoUsg 


Jopou seyunid om 
Joy ssppf-japou pue ‘Kdrys ‘xdrys “kuru ‘curs poyyed-Os 9t} JO SanTea oq} AIS SpIOM SAY SI OT on 
| 


SSMO[[OJ SB SI SOMOSEI [POUL B JO SIN|ONIs OY] 

"(L 38 JIBS SIO_HUSp! soNOsar yey) [TEdOI) A/xO Jos]JO ofYy ye SyES SoINOseI sTy 

Je} SOPBOIPUT OT Ot JO; oIqQu) Xopur o~ SuUNMsUCD “s JoLyHUEpr sey “pM -yo4auas UI soMoser Jspour ATO 
oY) “SAO PeUOHUSM sy ‘soIMOSal JopEoy OY} Ul poysl] oe SoomMOsel JOPOUT [[e JO SJoyHUSp! soMosal ou], 
soounosei japo-= 


! “MO[Oq Pessnosip 
‘saoinosat arnfadds Kq pocualejal ase pue ‘s}UOJ SNOLIVA 32S 0} Pasn oq WED SSULYS PUEWIMIOS [BUOHIPpy 


wadVOISGNYVIa O02 
aXId4dNS LHDIY 3AOW 61 
nlHSIY 3AOWu St 
wX1d3ud LHOIY 3AOWKH ZL 


nuNMOG 3AOQNn SL 
wNUNL3Y SOWIAVIn SL 
a39Vd MAIN = YL 


| uddO IdI¥ISENSH EL 
uNO LdIBISENSn 21 
nddO LdIYOSHSdNSH LL 
wNO LdIddSkadNSe OL 
uddO DIWIIn 66 
wNO OJITVLIn 
u4JO O108n = Z 
wWO O108n 9 
0440 SNITEZONNG 86S 
wNO ANITYSQNNn 9 
na IGWVLSOds ¢ 
old ISHVSUdn yA 
nHIONAT WUOdn = 
wLl3S3ue 0 


:(Ja;8] Woes sazif pm: 
JO SIUITUOZ BES) S]If pm’ Ul Sp 0S Seq} TIM poyeroosse 3x9} SANdLIOSep oy) SUTAIS Aq SUIS} o[dunts 
UI poqiiosep 1Soq ‘SSUTUBOU PSAJOSOI SALT YOO]G PUBUIWIOS 94} UI SSULNS PUBITMIOD OY) JO [Z ISIN CULL 


O2X0 1: ONTBA Og} Seq YOM SI Suis 

G0XO i: ONTBA 9} SB YOM Q[ suis 

POxO SNyBA O47 Set] YOrM GT SuLys 

20X0 ON{VA oq} Seq WOM pI suLys 
:(O19Z 


ye SuUNOS SuTjIE3s) Joy Jdaoxa ‘OJOZ OB SSUTS PUBUTTIOS €7 Oy} [TB “ApH ‘WDiauas Joy ‘USES 0q TED SY 


*(solez pappaquia uteyn00 [eloued UI UBD SSULIS PUBTMIOD 94} 3eU} UOAIS ‘oyetdodde st se) 
olez Sueur; Aue ynogM pup ‘UNOS o74q SuIpEo & WIM WAIT SI SMOTIO} JeE) Sus puwUUOS Youy 


| "€2 OI ‘ZLX0 SI 934q JUNO 94} JO ONTBA OG} ‘BAOGB AM “7D19uas UT 
“uoIsuedxo omny JO} poAsosel St Suruveul csoym pJom Surrey} w Aq pemoyfoy = 
(aomMosel oY} Ul 334q ISIIY 94) 334q yUNOD & Aq popecold =n 
s8u1ags pupunuoo JO kee wen 
:JO S}SISUOO sca ‘Q24NOSAL Spuduiuios sm) SXemye St 4pm’ AUB UI GOINOSAI PUOSES OU], 
9D1NOS9! SPUBWIWIOS ou 


! 
| 
NOLLVWHOANI WA.LSAS TVNOLLIGGY 


3 WDR PRINTING 
a 


miny Oxf0 (240) 
skipx and skipy both zero 
model-flags zero 


and there is just one reference to a typeface resource, this having resource identifier 4 (whence it can be 
found at file offset 0x4d). 
Typeface resources 
The structure of a typeface resource is as follows: 
= the first 20 bytes give the public name of the typeface, as a zero-terminated string 
= the next word gives the typeface number of the typeface 
= the word following contains typeface-flags 


= next comes a word which, if non-zero, contains the identifier of a translates resource to be used 
by the typeface 


= the word following that gives a count of the number of different sizes (or fonts) that the typeface 
comes in 


. asi a iS an array of WOR_FONT structs, one struct for each font size supported by the 
type 


= the WOR_FONT struct consists of nine words: height, height_max, height_delta, width_scale, 
width_normal, width_italic, width_bold, width_italic, width_bold_italic, and concluding with 
the number of the command string, in the commands resource, of the associated printer 
instruction to set this particular font. 


The difference between a “typeface” and a "font" is discussed in more detail below. 


In general.wdr, the public name of the only typeface in the file is "Mono", the typeface number and the 
typeface flags are both zero, the translates resource with identifier 3 is to be used, and there 1s only 1 
WOR_FONT struct following in-line. 


In a WOR_FONT struct: 
s The fields height_max and height_delta are only relevant for so-called scalable typefaces 
= The field width_scale is only relevant for proportional typefaces 


= For monospaced typefaces, the values of the four fields width_normal through width_bold_italic 
are to be interpreted as real numbers; for proportional typefaces, in which the widths of the 
characters vary from character to character, these values are identifiers of font width table 
resources. 


There are no font width table resources in general.wdr. Incidentally, font width tables are stored in 
difference form in .wdr files - see later for more details. 


Translates resources | 
The first word in a translate resource gives the number of translates that follow in-line. 


Each translate starts off with a byte giving the length of the remainder of the translate. The next byte is 
the Ascii value of the character to be translated, and that is followed by a sequence of bytes into which 
the character is to be translated. 


In general. wdr, there is only one translates resource, which in turn only contains one translate, whose 
effect is to convert every character with Ascii value 0x05 into one with value 0x23. This results in 
telephone symbols (recorded internally on the Series3 as 0x05's) being printed as hash signs. 


Summary of resource types in a .wdr file 


The above survey contains one example of every possible type of resource in a .wdr file, except for font 
width table resources. 


In summary, the possible resource types are: 


header (always the first resource in the .wdr file) containing an index of all the printer 
models supported by the file, as well as some important wdr-flags 


i 


35 


ADDITIONAL SYSTEM INFORMATION 


commands (always the second resource in the .wdr file) patting the character command 
sequences for resetting the printer, controlling the text format, moving the 
print head position, selecting specified ont and so on 


translates used to map the printer's character set onto that used by the SIBO computer 
(which is based on IBM code page 850) 


font width tables defining the widths of all the characters in p eoleuaan typefaces 


models giving essential data governing the capabilities of a printer, and listing the 
typefaces supported by the printer 
typefaces describing the typefaces supported by a printer model, including the various 


"font sizes” available for that typeface. 


More details on the contents of .wdr files 


Possible wdr-fiags 


The only wdr-flag of any general significance is WR_DYL_LOAD, with a 0x01. If set (in the header 
resource), this means that the contents of the .wdr file are insufficient, [by themselves, to describe the 
behaviour of the printer fully, and that the wdr printing system software should load a suitable external 
dyl to additionally customise the print behaviour. | 


Examples of . wdr files with the woR_DYL_LOAD flag set are the printer % files for postscript printers. 
Further discussion of loading additional printer dyls is beyond the scope of this document. 
Other bits set in the wdr-flags may have special significance for code : the extra print dyls. 


The notion of "printer models" 
The notion of a printer model is essentially a device to cover more one printer using the same data. 


Different printer models can be described in the same .war file, even if they support different sets of 
typefaces or have other differing characteristics, so long as they have the same basic set of printer 
command strings (and the same wdr-flags). | 

The public name of a printer model is what is presented to the user in y dialog offering a list of 
“printer models” for selection. i 


Overview of the different command strings 


As well as the command strings to select various fonts, a .wdr file con commands to have the printer 
perform other functions. These commands are by and large clearly in the listing given earlier, eg 
"ITALIC_ON" and "ITALIC_OFF", "BOLD_ON" and “BOLD_OFF", and “SUPERSC IPT_ON" and “SUPERSCRIPT_OFF". 


If a printer cannot support a given feature, the corresponding comman string would generally be left 
null (“"). One possible exception is italic which, if not supported, co Id be implemented as an underline. 
(Note incidentally that it is possible for a printer which supports italic in one font not to support it in 
another a and so on. Again, a printer may support both italic and superscript, but not both at the 
same time. : 


The "LANDSCAPE" command, if non-null, is the command to cause the pie to enter landscape mode (as 
opposed to portrait mode). 


The string of commands sent to the printer when printing starts are ambng the most important, as regards 
influencing the printed outcome. The very first command the software sends the printer is the "RESET" 
command. Then it sends a “FORM_LENGTH" command, and then the "PREAMBLE" command, before starting to 
print the document proper (together with headers and footers, etc). At/the very end, a "POSTAMBLE" 
command is sent. 


The "POSTAMBLE" command may be needed to flush the printer buffer, and to restore the printer to its 
default settings. | 


The "PREAMBLE" Command may have such drastic consequences as choosing the basic configuration of the 
printer (possibly overriding defaults set via dip switches). In any case of doubt, the documentation for a 
particular printer should be consulted carefully. 


a | 
36 : 


) 


+ 


3 WDR PRINTING 


Special characters in command strings 


The commands "MOVE_RIGHT", “MOVE_DOWN", and "FORM_LENGTH" are each used in conjunction with a value 
passed by the printer subsystem software. For example, the commands are to set the form length to a 
given value, or to move the printer position right by a given amount. This value may either end up in the 
command string by a process of substitution, or it may result in the command being repeated as required: 


= if any of these commands is defined as starting off with an asterisk character ('*'), what is 
actually sent to the printer is the remainder of the command string (ie minus the initial asterisk) 
repeated the specified number of times 


e if the string "%d" is contained within the command string, the specified value is converted into 
decimal representation and is substituted for the "%d" (like printf in C) 


s likewise the string “%c" means to substitute the specified value as a single byte (character), and 
"Xw" means to substitute it as a pair of bytes (low byte first). 


For example, in some printer drivers "MOVE_DOWN" is defined as "*<10>", so that "MOVE_DOWN n* will be sent 
to the printer as n line feed characters (line feed is Ascii 10). 


Again, in the HP Laserjet III printer driver, "“ovE_DOwN" is defined as "<27>&a+%dv", so that "MOVE_DOWN 6" 
(say) will be sent to the printer as "<27>&a+6v". 


This kind of substitution can also take place in the command strings to select a specific size of a so-called 
scalable font - see below. 


The MOVE_RIGHT commands 
For some printers, the command to move right by a certain amount is of the general form 
<prefix><repeated body><suffix> 


with the central part being repeated as many times as required, depending on the amount by which the 
print position is to be adjusted. 


It is to cope with this case (as well as ones even more complicated) that the commands 
"MOVE_RIGHT_PREFIX" and "MOVE_RIGHT_SUFFIX" are provided. These will be left null for most printers. 


Printer units 


The units for the "FORM_LENGTH" command are always 1/6 of an inch. Thus if the print software wishes, 
as part of initialising a printer, to set the form length to 12 inches, the command 


“FORM_LENGTH 72" 
should always be sent. 


However, the units used in many other features of printer driver files varies from printer to printer. The 
key quantities are the values of minx and miny, as specified in the model resource for a printer. 


Minx and miny are themselves standardly given in so-called twips, where twenty twips make a point (so 
that 1440 twips make an inch). For example, in the file general. wdr discussed above, minx has the value 
144 twips, ie 1/10 of an inch, and miny has the value 240 twips, ie 1/6 of an inch. This matches the 
basic assumptions made in general.wdr that the font printed is 12 point and 10 cpi (see earlier). 


The fundamental significance of minx is that this is the smallest amount by which the print position can 
be adjusted horizontally. Similarly, miny is the smallest amount by which the print position can be 
adjusted vertically. Clearly, the smaller minx and miny are, the higher the resolution of the printer. 


The above values make sense for general. wdr since the only way the print position can be adjusted 
horizontally is by emitting a space character (or by emitting a carriage return, which resets the horizontal 
position), and the only way the print position can be adjusted vertically is by emitting a linefeed character 
(or by emitting a formfeed character, which effectively resets the vertical position). 


A command such as "MOVE_RIGHT n" actually means to move the print position right by n times minx, and 
similarly a command such as "MOVE_DOWN m" means to move the print position down by m times miny. 


The value of skipx for a printer model is subtracted from the first "MOVE_RIGHT" command in each line of 
text, to compensate for the fact that many printers cannot print at the left edge of the paper. The value of 
skipy is likewise subtracted from the first "MovE_DowN" command in each page, to compensate for the fact 
that many printers cannot print at the very top of the paper. 


37 


ADDITIONAL SYSTEM INFORMATION 
! 


The values of skipx and skipy are themselves expressed in terms of mae and miny, respectively. Thus if 
skipy is given as 36 whereas miny is given as 20, this translates to an tual height of some 20*36 twips, 
ie half an inch, at the top of the paper which is inaccessible to the printer. 


Possible model-flags 
There are two bits that can be set in the model-flags in a model resource: 
@ WOR_MODEL_LANDSCAPE_AVAILABLE (0x01) has to be set if the model supports being put into 


landscape mode 


™ WOR_MODEL_MINX_IS_DOTS_PER_INCH (0x04) should be set if the value of minx is expressed, not in 
twips (as standard), but in reciprocal inches (so that a minx of|300 would correspond to 1/300 of 
an inch - which is not expressible as an exact number of twips). 


Note that even if WR_MODEL_MINX_IS_DOTS_PER_INCH is set, the value of miny is always expressed in twips. 


Typefaces and fonts 


A typeface is considered to be a set of characters in a particular style, whereas a font is a particular size 
of a typeface. 


The public name of a typeface is what is presented to the user in any dialog offering a list of "fonts" 
(actually typefaces) for selection. The various different fonts within a chosen typeface will be selected 
via a secondary choice list, keyed by the notional height of the fonts. | 


There can be considerable scope for authors of .wdr files in deciding how to represent the different fonts 
supported by a printer (especially dot matrix printers). For example, many dot matrix printers support a 
condensed font: this may be represented as a typeface called "Pica condensed" (say) or as a smaller font 
of the "Pica" typeface. It is generally more useful for the user to have a number of size variants (fonts) 
of one typeface rather than a number of typefaces each having only one size. For this reason the second 
of the above approaches is the recommended one. It also has the advantage that the typeface names will 
then (generally) be language independent, whereas the addition of a phrase such as “double width" or 
"condensed" immediately makes the .wdr file language dependent. | 


A dot matrix printer may support a number of variants of a font including: condensed, double height, 
double width, condensed double width etc. For a twelve point base font it is recommended to map these 
to the following heights: | 


condensed 7 point (140 twips) 
normal 12 point (240 twips) | 
condensed double width 13 point (260 twips) ! 
double width 16 point (320 twips) 
double height 22 point (440 twips) 
double height double width 24 point (480 twips) 


Note that a taller font must have a larger size than a shorter font, in particular the point sizes of all the 
double height fonts must be larger than all the single height fonts. 


If a dot matrix printer supports a large number of variations on a base font, it may turn out that two 
different variations would be mapped onto the same point size. In this|case it would be perfectly 
acceptable to just omit one of the fonts: if there are already 12,13,14,15 and 16 point fonts available then 
omitting (say) a second 14 point is not really a hardship to the user. Alternatively, the font could be 
incorporated in another typeface. In case it is decided to omit a font, in mind that double height 
fonts generally look much better than double width fonts, so given a choice it 1s better to omit the latter. 


Typeface numbers 


The main significance of the typeface number of a typeface is when a | set up for one printer is 
subsequently printed on another printer. Font “substitutions” have to be made - and these are done 
according to the values set for the typeface number. 


Thus if a document is prepared for one printer model, and some text is|to be printed in a typeface having 
typeface number 2, say, and then the user changes the printer model setting for the document to another 
printer, that text, when printed, will be printed in the first typeface found in the new printer model, 
having the same typeface number. 


\) 


3 WDR PRINTING 
eee 


In case no exact match in typeface number is possible, the first typeface defined in the new printer model 
is used instead. 

There are a large number of allowed typeface numbers, listed later in this chapter. Note that typeface 
numbers are completely independent of the public names of typefaces. 


Typeface numbers may also be used in some forms of RTF file conversion. 


Possible typeface-flags 
There are three bits that can be set in the typeface-flags in a typeface resource: 


= WOR_TYPF_PROPROTIONAL (0x01) set if the widths of the characters in a font in this typeface can vary 
among themselves (the alternative is that the fonts are monospaced) 


= WOR_TYPF_SCALED (0x02) set if the fonts supported by the typeface are all generated by the printer 
as being different scaled versions of one common pattern 


= WOR_TYPF_SERIF (0x04) set if the typeface is serif. 
The WOR_TYPE_SERIF flag has significance only in certain types of RTF file transfer. 


Note that scalable monospaced typefaces are not supported, so that scalable fonts always have to be 
regarded as proportional, even if the widths of their characters do not vary in fact. 


For scalable typefaces, there is only one woR_FONT struct per typeface, with all required information for 
differently sized fonts being generated from this by arithmetical scaling. 


Heights of fonts 


The command string of a scalable typeface must include some kind of parameter (eg "%d") for the 
particular size required to be specified when setting the font. This parameter will be filled in by system 
software giving the height of the required font in point units. 


However, heights of fonts in .wdr files are always given in twips (thus 240 for a 12 point font). 


For non-scalable fonts, the height_max and height delta fields in a woR_FONT struct are meaningless. For 
scalable fonts, the set of supported font sizes is obtained by repeatedly incrementing by height-delta, 
from the value of height to the value of height _max (so that the "height" field actually plays the role of a 
“height _min" field). 


In general, 4 points (80 twips) is a sensible minimum height for a font, whereas the maximum allowed 
height is determined by the fact that the widths of characters must at all times remain less than 255. 
Widths of characters in fonts 

Widths of characters in fonts in .wdr files are expressed - as are all horizontal measurements in .wdr files 
- in units of minx. 


The wdr system allows for widths of characters altering as they are italicised or bolded, and again when 
they are simultaneously italicised and bolded. In case there is no such variation, the values of the fields 
width_normal, width_bold, width_italic, and width_bold_italic, will merely duplicate each other. 


For proportional fonts, these four fields each refer to font width tables. These are stored in difference 
form in .wdr files. Thus if the array of stored widths is stored[: 


= width of character 0 = stored([0] 

® width of character 1 = width of character 0 + stored[1] 
= width of character 2 = width of character 1 + stored{[2] 
= width of character 3 = width of character 2 + stored{[3] 


and so on. The rationale for this is that the differences are frequently zero, so that the font width table is 
stored as an array, many of whose values are zero. In turn, this compresses much more markedly (for 
compressed versions of . wdr files) than tables containing many different values - with the result that 
smaller .wdr files get produced (bear in mind that font width tables potentially make up large parts of 
these files). 


The values obtained from a font width table should all be multiplied by the width_scale value for the 
font. This mechanism avoids needless duplication of data in which two font width tables would 
otherwise both be present in a .wdr file, even though one is merely a scaled version of the other. 


39 


ADDITIONAL SYSTEM INFORMATION | 


For scalable fonts themselves, the values in the font width table (once multiplied by any width_scale 
value for the font) are what would apply to a fifty point high version of the font. These have to be 
further scaled, in general, to match the chosen height of the font. 


Note that in all cases, widths of characters cannot exceed 255. 


Creating .wdr files using wdtran.exe 


The printer driver translator is a tool wdtran. exe that operates on a so-called printer script, which is a 
text file, to produce a printer driver file as output. 


The process is akin to ordinary compilation: 

*.c + compiler -> *.obj 

*.wd + printer driver translator -> *.wdr 
with .wd being the usual extension for a printer script. 
Some sample .wd files are distributed as part of the optional component of the Sibosdk. 
To produce eg general.wdr from general.wd, simply type 


wdtran general | 


Contents of .wd files | 
The basic contents of .wd files correspond to the different resources in|. wdr files (see earlier in this 


chapter). 


A .wd file consists of a number of resource definitions, of which therejare five types: COMMANDS, 
TRANSLATES, WIDTHS, TYPEFACE, and MODEL. 


There must be one and only one COMMANDS resource in a .wd file. There must be at least one MODEL 
resource and at least one TYPEFACE resource, though there can be more ie each. There can be any number 
(including zero) of WIDTHS and TRANSLATES resources. 


Note that there are no definitions in a .wd file directly corresponding to the header resource in a .wdr 
file. The header resource is specially created by wdtran. exe. 


Each resource definition consists of a header, a number of commands, and then a footer. The header is 
of the form 


<RESOURCE> [identifier] 


with the identifier being required only if the resource is to be referenced by another resource (it may be 
the name of a width table, for example). 


The resource footer is of the form: 


END_<RESOURCE> 
Each intervening command is of the form: 

keyword [parameter] 
For example, the definition of a TYPEFACE resource looks like 


TYPEFACE pica 


| 
END_TYPEFACE 


Iv 


<33Aq> = <3 Aq> 
WO} oy} SAKY PloYs suOHE]sUBI} [ENPLAIPU] 


-gonds oy1GM Aq Jojo Yous Wo poyeredes ZuIeq out] uO Aue UO sUONEISUBI) JBo0e[pE 
WWM ‘suoiyjsuv4t eJOUl JO suo JO dn opeUl oq PfNoYs Yoo[g SILVISNVAL B JO UOHIUYsp of} UII oul] Youy 


UOIIUAP 394N0S94 SJLWISNVEL © UluIM SpueWWOd ajqe}deo0y 


“‘SOUBSIJTUSIS PEOLIO\sty Ayomnd Jo 3TGILVdWOD 19d dH 
SOMOS Jopeoy o4} UT SSeTJ-IPM SY} 03 <s6e}4> UI LO 0} <s68)}> SOV14 
oy _ 
dpm’ 94} JOF SoINOseI Jopesy OY} Ul SseYJ-IJpM OY} UI S¥[J GYOT TAC AGH 9} 30S 0} 7Ad 3sn 


2018 DONTUYSp SoINOsal SGNWRWOD B UTI Ind90 Aud yeq) xe7UAS JoTIO 


*<J2> se polpioods st (17 ONn]BA [BUTIOSp) Opodo [037000 Is3 OW) ofduTExe 

Joq °*(,<, pus ,>,) SjexowIG o[Sue Ur onyeA [eUTISep sy SuIs¥Td Aq porytoeds st epoo joxuOS yW “uONnTUYep 
UOJ B JO PIOMASY ANVHNOD OU} UI JO ‘UONTUSp SoINOSEI SGNYHWOD OY) UI popeou oq AvUI sapod [OWUOD 
‘uOHTUYSp somMosol 

JIVIIdAL JUVADTOI 9Y} UIGIIM USAIS 9G P[NOYS SJUOJ [ENPIAIPUL Jos 0} Posn SSULIYS PUBTATIOS ‘ISAOMOF] 
“IDALS OQ TED SOT] APM’ Ul SAOINOSSI PUBUIUIOD UO UOT}SeS JolpJee ot} Ul Poyst] SpuvUIMOS oy) Jo AUY 


UOIIUIJEaP 99JNOS31 SGNVININOD 2 uluM xe}UAS ajqe}de00Y7 


“ATMO SOUSTUSAOD JO}J SI SOT PM" plepuyYjs Ul SUIS|OS UOTVEJUSpUT YOo]G ol, 


“poJOUsI osye ose Soul] YULT_ *(SuLNs poyonb & UI st j oy} ssofuN) 
OUI] B JO pus oY} pUe j IEW UONME[OXe UB Usemjog SIojoRIEyO Aue SoJOUSI JOje[SUBI} JOAUIp JoyULId oa], 


-(mozeq 
90S) SJa}OeIBYS [01JU0 UTE} ABU SuLIs Oy) ‘(NO A108 30) UOHOUN oIyIOeds 
B WJOJJod 0} JajULId 94} 03 3USS SI 3eq} Soj}OND UT SJo}ONIEYO Jo souNbes B SULIYS Pozong 
eomosel peyroeds 
JoTjoue souasJejos 0} puvuM0S & Aq pesn ‘suLys pozonbun esd Jomo] B JoynuUsp] 
(VOI]TUIJop SoINOSEI JDv4adAL B UT 
adAL Aq ATWO pesn) onyea oLouINU & se poyordJazUI SI YOryM SuLys pojonbun ue jue}suoZ 
(TPM jo; & 3S) ONTBA B SB PoJoICIJOzUI SI YOM JOQUINU [eUIOSp B SLOUNN 
sodA} oy Jo oq APU UONTUYSp somMosel B opIsUI splomASY 0} sJoj}OUTeIEg 
SQNVWNOD GNI 
n<fl>n NUNLIA JOVINYVI 
n<ZL>u 3OVd MN 
us XIddNS LHI 3AOW 
u<ZE>au 1HOIY 3AON 
wa = X143Nd LHOTY SAN 
0<OL>a0 NMOG 3AQW 


ces 440 1d1¥ISYIdNS 
ro8e NO ldlydS¥adNs 
ne 440 LdIYOSENS 
rn NO 1d1¥ISENs 
tae 430 3NI7Y30NN 
nn NO 3NI1Y3qNN 
an 440 DITWALI 
ne NO JIIWLI 
8 440 108 
nts NO Q108 
108 JISWVLSOd 
rote J 1sWV3ed 
ne HLONIT W8Od 
sn6e 13S3u 
SANVWHOD 


*(pM ‘[oLaUas BY OY} OJ GOMNOSEI SONVWHOD OY} SI STO}) O¥1] SYOO] CoINOSEI SGNVWHOD B JO UONTUYSp oy) puB 


ONLINTad YM £ 


ADDITIONAL SYSTEM INFORMATION 


or else 
<byte>:<string> 
For example: 
5:35 
156:"<27>R<3><35><27>R<0>" 
Note that any width table for a font which uses translates must contain the correct width for each 
character after it is translated. The printer driver translator does not check this. 
Acceptable commands within a WIDTHS resource definition 


Each line within the definition of a wiDTHS block should be made up of one or more character widths, 
with adjacent character width definitions on any one line being separated from each other by white space. 


Individual character width definitions should have the form 
<byte>:<width> 


Note that in contrast to .wdr files, which store font width tables in differenced form (see earlier in this 
chapter), . wd files should define the widths of all characters in absolute terms. The differencing is 
performed by wdtran. exe (just as the converse integration is performed by the wdr class in form. dyl 
without the conscious intervention of any application software). 


The printer driver translator will give an error if the widths of the non-breaking hyphen, potential 
hyphen, and standard hyphen (character codes 7, 14, and 45) are not all the same. 


Likewise, the widths given for the non-breaking space, the standard space, and the tab (character codes 
15, 32, and 9) also all have to agree. 


Acceptable commands within a TYPEFACE resource definition 


The following commands may be present within the definition of a TYPEFACE resource: 


PROPORTIONAL to set WOR_TYPF_PROPORTIONAL in the typeface-flags 
SCALED to set WOR_TYPF_SCALED in the typeface-flags 

SERIF to set WOR_TYPF_SERIF in the sal ese, 
MULTIPLE_FONT_WIDTH_TABLES of purely historical interest 

NAME <name> to give the public name of the face 

TYPE <type> to give the typeface number of the typeface 
TRANSLATE <identifier> to specify a TRANSLATES reso to be used 

FONT to commence the definition of a FONT sub-resource. 


| 


The Font keyword must appear at least once in each TYPEFACE definition, and can appear more than once. 
The other keywords should only appear once, at the most. 


Each FONT sub-resource definition follows the same general pattern as the other resources: 


FONT 
<keywords> 


END_FONT | 
Possible keywords in the body of a FONT resource definition are HEIGHT,| HEIGHT _MAX, HEIGHT_DELTA, 
WIDTH_SCALE, WIDTH, WIDTH_BOLD, WIDTH_ITALIC, WIDTH_BOLD_ ITALIC, and C p - each having the 
straightforward meaning of specifying a corresponding field within the|woR_FONT structure for that font 
(see earlier in this chapter). | 
Acceptable commands within a MODEL resource definition 
The following commands may be present within the definition of a MODEL resource: 
LANDSCAPE_AVAILABLE to set WOR_MODEL_LANDSCAPE_AVAIILABLE in the model-flags 


MIN_X_IS DOTS _PER_INCH to set WOR_MODEL_MINX_IS_DOTS_PER_INCH in the model-flags 
| 


42 


3 WDR PRINTING 
eee 
NAME <name> | to give a public name for the printer model 
TYPEFACE <identifier> to specify a TYPEFACE resource supported by the printer model. 


Additionally, the keywords MIN_X, MIN_Y, SKIP_X, and SKIP_Y straightforwardly specify the minx, miny, 
skipx, and skipy values for the printer model. 


In contrast to the case for TYPEFACE resources, which can only have one public name each, MODEL resources 
can have more than one public name each. This avoids needless duplication in a .wd file, if it turns out 
that two MODEL blocks would otherwise be identical. Note that one MODEL resource having two public 
names is not in general the same thing as there being two different MODEL resources in the same .wd file 
(though in each case, there will be two distinct entries in the Printer Model choice list). 


Allowed typeface numbers 
TYPE may take any of the values: 


COURIER OPTIONAL_SB RUSSIAN 

PICA OPTIONAL_SC OPTIONAL_B 
ELITE TIMES_ROMAN OPTIONAL_C 
PRESTIGE CENTURY OPTIONAL_D 
LETTER_GOTHIC PALATINO NARRATOR 
GOTHIC SOUVENIR EMPHASIS 
CUBIC GARAMOND ZAPF_CHANCERY 
LINEPRINTER CALEDONIA OPTIONAL_DA 
HELVETICA BODONI OLD_ENGLISH 
AVANT_GARDE UNIVERSITY OPTIONAL_DB 
SPARTAN SCRIPT OPTIONAL_DC 
METRO SCRIPT_PS COOPER_BLACK 
PRESENTATION OPTIONAL_SCA SYMBOL 

APL OPTIONAL_SCB LINE_DRAW 
OCR_A COMMERCIAL_SCRIPT MATH_7 

OCR_B PARK_AVENUE MATH 8 
STANDARD_ROMAN CORONET DINGBATS 
EMPEROR OPTIONAL_SCC EAN 
MADELEINE GREEK PC_LINE 
ZAPF_HUMANIST KANA OPTIONAL_SYA 
CLASSIC HEBREW 

OPTIONAL_SA OPTIONAL_A 


Suppose, for example, a user has a document written when the Apple Laserwriter printer driver was 
selected, and the document uses two typefaces, Times Roman and Palatino. The user then changes to a 
HP Laserjet II printer driver. Times Roman on the Laserwriter and CGTimes on the HP III both have a 
TYPE Of TIMES_ROMAN and so the Zimes Roman typeface would be mapped to CGTimes. The HP III driver 
has no typeface with a TYPE of PALATINO and so the Palatino font would be mapped to Courier. 


The following rules are useful for guidance: 

One of the printers monospaced typeface should be assigned a TYPE of COURIER: this should be the typeface 
described as Courier or perhaps Pica in the printer's manual. The typeface's NAME should be as in the 
manual (eg "Pica"). 

If a printer supports only one proportional typeface it should be assigned a TYPE of TIMES_ROMAN, although 
it may be given a different NAME (eg "Proportional"). 

If a printer supports more than one proportional font then the one with serifs (if available) should be 


assigned a TYPE of TIMES_ROMAN and the one without serifs should be assigned a TYPE of HELVETICA; their 
NAMES should, however, be those used in the printer's manual, eg CGTimes and Univers for the HP 


Laserjet III. 


43 


. : ' , 
7 + : - a as : 2 
+ ‘ f - Z 5 ‘. 7 A t i" 
? t * + ean ; : 
+ . 
. : 2 a i . 
ve Z : . % . a e 
5 . . depet ae ae 
7 : ne BN 
. ' 
le a 
- _ on . . 
. a . 1 
7 1 
‘ . 
. 
. ” 
Saye, “ite . 2 
ae ; : . 
bag ‘ ah ae 
RTE yi . S 
‘ ¢ . ‘, a 
+ 
‘ : = 
4 a * ¥ ie te . fara 
ha > : - i : * . 31 4 . 
3 s - 
, i s Sy or : ‘ see , ree OS ae ye 
* ’ oF eat teed, 
-- : . nee : , ‘ ae 2 : 
: ' is . * A * ae aS Z , 
' : : Bac FE : 
‘ : ‘ . a . : : ee ‘ ae . . 
. i oot : ‘ 7 f 
A 1 . : > j . ar . : 
. 1 
‘ i : 8 ” ; : 
5 ‘ é i Bee z s a eo . 
a =: . * , 
2 a oe ae s Croan ae at Hv 2 8 4 + = A ot 
: toe ~ Fs se grils erate ane aces ree > : ; ; i 2 
— Pk ‘ 
' 2 
’ 
. 


CHAPTER 4 


DBF FILES 


a Te ee a i ee ee oe, se ee | 
Introduction 


Database files (DBF files) are binary files containing typed, variable length records. Many SIBO 
applications (for example, the MC Diary and the Series 3 Database) store their data in DBF files. The 
data files created and manipulated by Opl are also examples of DBF files. 


Database files are designed to be Flash-friendly, that is, they may be stored and manipulated in Flash 
SSDs (or any other EPROM medium). A DBF file stored on such a medium may be modified by 
appending, deleting, or replacing records without having to make a new copy of the entire file. 


The chapter Database Files in the Plib Reference manual describes DBF files from the point of view of 
reading and writing them using Plib function calls such as DbfOpen, DbfAppend, DbfFindRead, and 
DbfNextRead. The JSAM Manual discusses more advanced techniques for using DBF files, in conjunction 
with independent keyed index files. The present chapter focuses instead upon a description allowing 
access to DBF files independently of these specialised Plib and ISAM functions. 


First, the basic structure of a general DBF file is reviewed, and then particular examples are given of 
how various SIBO applications use DBF files. This information should assist the creation of file format 
conversion programs such as might run on another computer, for example converting between Series 3 
Agenda files and files that can be read directly by PC-based PIMs (Personal Information Managers). 


a a a Ny on ea i fs 
Basic structure of DBF files 


The following discussion is based around a DBF file created by a simple Op! program. It is not necessary 
to be familiar with Opl to follow the discussion, since the contents of the DBF file are described 
independently of the Opl program. It just happens that Opl is a convenient way to create DBF files 
quickly, so that experimentation is easier. 


The Opl program creating the file is as follows: 


PROC writedbf: 
if exist("test.dbf") sdelete "test.dbf" :endif 
create "test.dbf",a,f1$, f2$, f3%, f4 
a. f1$="Hel lo" 
a. f2S="2" 
a. f3%=3 
a.f4=4 
append 
a. f1$="World"™ 
append 
close 
beep 5,300 
ENDP 


The create statement creates a DBF file with the name test.dbf, by default in the lopd\ top-level 
directory on the default drive. This file is assigned the logical handle a inside the program. Each record 
in the file is to have four fields (called f1$, f2$, f3%, and 4 inside the program). Standard Opl naming 
conventions mean that these fields have types string, string, integer, and double, respectively. 


45 


ADDITIONAL SYSTEM INFORMATION 


ee ne eee ee ey ee ee 


The two append statements mean that two records are written to the file, before it is closed. 


Dumping the resulting file yields the following: 


O: 4f 50 4c 44 61 74 61 62 61 73 65 46 69 6c 65 00 OPLDatab aseFile. 
10: Of 11 16 00 Of 11 04 20 03 03 00 02 12 1005 48s... b ete ese H 
20: 65 6c 6c 6f 01 32 03 00 00 00 00 00 00 00 10 40 ello.2! 0 eccncee a 
30: 12 10 05 57 6f 72 6c 64 01 32 03 00 00 00 00 00 oo World .2...00- 
40: 00 00 10 40 000d 


This conforms to the standard DBF format of 


<standard header><extended header><field information ances records> 


where 
<standard header> always has length 22 bytes. 
<extended header> can have variable length and is frequently of zero length (as 
here). 
<field information record> gives the structure of all type J records following. 
<other records> are the main body of the DBF file. 


The standard header 


The first sixteen bytes of all standard DBF files are the zero-termi | string "“OPLDatabasefile". This 
string is used by all SIBO applications. Applications are allowed to use alternative strings although such 
DBF files can not be read by Opl. 


The two bytes at file offset 0x10 will in practice always contain the b 
the bytes at file offset 0x14. 


The two bytes at file offset 0x12 contain the file offset for the start of the field information record. Thus 
in the absence of an extended header they would contain <16><00> and for an extended header of length 
256 bytes they would contain <16><01>. 


2s <0f><11>. The same applies to 


The extended header 

A DBF file has an extended header only if an application calls the Plib|function DbfExtHeaderwrite. At 
the time of writing SIBO applications neither make this call nor make use of the extended header. 

The field information record 

The field information record is a type 2 record. 


The first byte contains the number of fields defined for each type I rd (see below for an explanation 
of type I records). In the above example four fields were defined. The number of fields defined must be 
an integer between 1 and 32 inclusive 


The second byte always contains <20> (see below for an explanation). 


The remaining bytes contains the field types. The first byte contains the type of the first field, the second 
byte contains the type of the second field and so on. The following types are allowed: 


= a type of 0 means that the field is an integer: a numeric value stored in two bytes, low byte first. 
= a type of 1 means that the field is a Jong: a numeric value stored in 4 bytes. 


= a type of 2 means that the field is a double: a floating point value stored in 8 bytes in standard 
IEEE format. 


= a type of 3 means that the field is a string: a sequence of up to 255 bytes preceded by a byte 
giving the length of the sequence. 


The format of all records 


All ae contain a two byte header followed by a sequence of bytes constituting the body of the 
record. : 


The highest nibble of the header word contains the record's type. The lowest three nibbles contain the 
length of the record body (a nibble is four bits, thus each byte consists|of two nibbles). This explains 
why the second byte in the header of the field information record is always <20>. 


| 
. 


4 DBF FILES 
a i 


In the example DBF file (see above) the record immediately following the field informati 
<12><10> as its header and is thus a type 1 record, with a mee of length paobyies eee 


Counting past another 0x12 bytes leads to the header of the following record, which is also <12><10>. 
Counting along yet another 0x12 bytes leads precisely to the end of the file. 


Since each of these records are type J] they must all conform to the internal structure specified in the field 
information record: 


= a leading byte-counted string, for the first string field. 
= asecond leading byte-counted string. 

= two bytes for the integer field. 

= eight bytes for the double field. 


Looking more closely at the above dump, it can now be appreciated how the details of the file contents 
match the earlier Opl program. 


Generally speaking, the only types of record that will be found in any DBF file produced by a SIBO 
application are: 


type 1 standard record. 

type 2 field information record. 
type 3 descriptive record. 

type 0 deleted record. 


Deleted records 
Consider the following Opl program, which differs from the earlier one in only one line: 


PROC writedbf: 
if exist("test.dbf") sdelete "test.dbf" :endif 
create “test.dbf",a, f1$, f2$, f3%, £4 
a. f1$="Hel Lo" 
a. f2$="2" 
a. f3%=3 
a. f4=4 
append 
a. f1$="Wor td" 
update 
close 
beep 5,300 
ENDP 


The change is that the second append instruction has become an update instruction, so that the end result 
is that the file has only one record. 


Dumping the DBF file output by this second program gives (provided the file is created on a Flash SSD): 
O: 4f 50 4c 44 61 74 61 62 61 73 65 46 69 6c 65 00 OPLDatab aseFile. 


10: Of 11 16 00 Of 11 04 20 03 03 00 02 12 00 05 48 — wane ne wa ween H 
20: 65 6c 6c 6f 01 32 03 00 00 00 00 00 00 00 10 40 ello.2.. wcceees a 
30: 12 10 05 57 6f 72 6c 64 01 32 03 00 00 00 00 00 oe World .2...00. 
40: 00 00 10 40 | 


This differs from the earlier dump only with regard to one nibble which gives the record type for the first 
record in the file. The two bytes <12><10> at file offset 0x1c have changed into <12><00>, indicating that 
while the same length of data remains on the file, the first record is no longer type 1 but type 0, i.e. it 
has been deleted. 


Erased records remain in a DBF file until such time as the file is written out again, say in response to a 
"Save As" menu command, or until the file is compressed (say in response to a "Compress" menu 
command). (In fact, Opl programs automatically attempt to compress their DBF files whenever they are 
closed, which explains why the above example gives different results unless the file is created on Flash.) 


Although erased records may remain part of a DBF file long after the application has "deleted" or 
"updated" them, they are inaccessible to normal software (eg to the Plib Dbfxxx calls and the Opl database 
functions such as find and count). 


i S 


47 


ADDITIONAL SYSTEM INFORMATION 


For more discussion about the mechanism of deleting records, see the Database Files chapter in the Plib 
Reference manual. 


The remaining examples of DBF files in this chapter all assume that any deleted records have been 
removed. 


Descriptive records 


From most points of view, records of type 3 and upwards are all potentially "singular" records without 
the usual software support. Operations such as "Find" do not usually find text within such records as 
these record types are not used by standard SIBO applications (with one important exception, discussed 
below). See the Database Files chapter in the Plib Reference manual for more details of these record 


types 


The exception is with a record of type 3, which is a so-called "descriptive" record. See later in this 
chapter for examples of data that may be stored in a descriptive record. 


There is usually at most one record of type 3 in any one DBF file. 


By convention, a descriptive record's data is composed of a number of'typed fields, with the types having 
variable meaning depending on the application. Given that different versions of an application may define 
different types of field within the descriptive record, it is good practice for applications that encounter 
fields in a descriptive record that they do not understand, to preserve these fields and to write them out 


again whenever the descriptive record needs to be changed. 


More on type 1 records 


It is not always necessary for a type 1 record to have entries for each fi ld defined in the field information 
record. Depending on the application, any trailing omitted fields will usually be assumed to be zero or 
null. 


It is also possible for a record to have more than 32 fields. This is allowed in the case where the 
descriptive record explicitly defines 32 fields. In this case, any extra data in a record, beyond the 32nd 
field, is interpreted as a sequence of additional string fields. 


The Series 3 Database 


In this section reference to the Series 3 Database is taken to include the Series 3a Database except where 
explicitly stated otherwise. 


The Series 3 Database stores its files in the DBF file format, as described in general terms at the 

beginning of this chapter. By convention, the Series 3 Database uses file with extension . dbf. 

Field information record 

The field information record of a Series 3 Database file is always as follows: 
<20><20><03><03><03> ... <03><03><03> 

there being 32 <03>'s in all. As mentioned above, this actually means that any type I record in the file 

consists of a variable arbitrary number of string fields (where this number can exceed or fall short of 32). 

Extended header 

There are no extended headers on any Series 3 Database files. 


Descriptive record 


For an example of a descriptive record (type 3) consider the following dump of a default newly-created 
and exited Series 3 Database .dbf file (see below for a Series 3a example): 


2: 4f 50 4c 44 61 74 61 62 


Of 10 16 00 Of 10 20 20 


61 73 65 46 69 6c 65 00 
03 03 03 03 03 03 03 03 


OPLDatab aseFile. 


20: 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03) cena eehe cece eens 
30: 03 03 03 03 03 03 03 03 31 30 02 10 04 000250 __—=........ - 10..... P 
40: 05 00 27 40 05 4e 61 6d 65 3a 07 05 20 48 6f 6d --'@.Nam e:.. Hom 
50: 65 3a 07 05 20 57 6f 72 6b 3a 08 41 64 64 72 65 e:.. Wor k:.Addre 


60: 73 73 3a 00 06 4e 6f 74 65 73 3a sS:..Not es: 
48 


4 DBF FILES 


—— eee 
The header of the first record after the field information record is <31><30>. This indicates that the record 


has type 3 and body length 0x31 bytes and therefore extends to the end of the file. 


Series 3a Database files are longer as the descriptive records contain more fields. Here is a newly-created 


and exited Series 3a Database .dbf file. 


O: 4f 50 4c 44 61 74 61 62 61 73 65 46 69 6c 65 00 OPLDatab aseFile. 

10: Of 10 16 00 OF 10 20 20 03 03 03 03 03 03 03 03) cae ee cece eee 
20: 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 ssa nee wees 
30: 03 03 03 03 03 03 03 03 aa 30 02 10 04 000250 —s.=......... O..-.. P 
40: 14 00 3a 60 82 2e c6 41 08 07 08 07 72 20 bé6 33 ood cesA woe 23 
30: dO 02 dO 02 00 00 00 00 01 00 ff ff 000000 00~—......... 1.2.0... 
60: f0 00 00 00 00 00 00 00 f0 00 02 00 0000 0000... ........ 
70: 00 00 CO 00 00 00 f0 00 00 00 00 00 00 00 0d 70.12... 6. cee eeee 

80: 00 52 4f 4d 3a 3a 42 4a 2e 57 44 52 00 Oc 80 00 eROM::BJ .WOR.... 
90: 00 00 25 50 00 82 2e c6 41 08 07 Oc 90 25 50 00 0eMPecee Ave eeMP. 
a0: 82 2e c6 41 08 07 08 07 72 03 a0 01 00 01 04 bd eoeAhesee Pocccces 
bO: 00 00 ff ff 2e 40 05 4e 61 6d 65 3a 07 05 2048 ~—COti«iw..... @.N ame H 
cO: 6f 6d 65 3a 07 05 20 57 6f 72 6b 3a 06 05 20 46 ome:.. Woork:.. F 
dO: 61 78 3a 08 41 64 72 65 73 73 3a 00 06 4e 6f ax:.Addr ess:..No 


tess 


The header of the first record after the field information record is <aa><30>. This indicates that the record 
has type 3 and body length Oxaa bytes and therefore extends to the end of the file. 


The body of a Series 3 Database descriptive record contains: 
® a field of type 1 and length 2. 
= a field of type 5 and length 2. 
= a field of type 4 and length 0x27. 


The body of a Series 3a Database descriptive record contains the above three fields and adds the 
following additional fields: 


= a field of type 6 and length 58. 
® a field of type 7 and variable length. 
= a field of type 8 and variable length. 
8 aa field of type 9 and variable length. 
® aa field of type 10 and length 3. 
= a field of type 11 and length 4. 

The above field types are as follows: 


type 1 width of a tab in columns. 

type 5 general flags options. 

type 4 template data. 

type 6 printer setup information. 

type 7 printer model: a zero terminated string that starts with the model number and 
continues with the path for the printer driver file. 

type 8 text for header: a zero terminated string. 

type 9 text for footer: a zero terminated string. 

type 10 diamond bar settings: bytes zero, one or two are set to Oxff if 'Find",'Change' 
or 'Add' are included in the diamond bar respectively. 

type 11 current search field: the first two bytes specify the start field with 0x00 


meaning search in all fields, the second two bytes specify the end field with 
Oxff meaning search from start field to last field in record. Thus values of 0x10 
and 0x20 would imply a search from field sixteen to field thirty two inclusive. 


Other types may be used by other versions of the Database application (eg types 2 and 3 are used by the 
_MC Database) and should be preserved intact when encountered. 


49 


ADDITIONAL SYSTEM INFORMATION 


: third 
In the above example it can be seen that the width of the tab is equal to)4 columns as given by the 
and fourth bytes of the type 1 field which starts at offset Ox3b (remember that the first two bytes are the 
record header). The value of the flags options is 0x05, and the contents of the labels can easily be read as 


a sequence of leading byte-counted strings. 


be e e h 
Note that the first character in a template field name can be a telephone symbol (0x05) in which case eac 
part-paragraph in the field matching the template entry can be used for automated dialling. 


Flags options for the Series 3 Database 
The meanings of possible bits in the flags options are as follows: 


0x01 the permanent status window is on 
0x02 entries are word-wrapped 
0x04 a template should be displayed. 


Type 1 records 

' Entries in the Database are stored as single type J records in the corresponding .dbf file. 

The following special (non-text) characters may occur within any string in a type 1 record in a .dbf file, 
with these meanings: 


0x15 forced line feed (with the two part-paragraphs on either ide of the forced line break just 
counting as one paragraph for the purposes of the template, even though each part word- 
wraps separately) 


0x05 prefixes a diallable telephone number (over and above any indication of diallability given in 
the template text) : 


0x14 if this occurs as the first character in a string, it means this field should in fact be joined 
together with the preceding one, as discussed in the following section. 
Continuation sub-fields 


The Series 3 Database uses a special mechanism in order to store fields of text exceeding 255 characters 
in length. Any such fields are broken down into sub-fields with at most 255 characters of text: 


= the first 255 characters form the first sub-field 


= up to the next 254 characters form the second sub-field, with the special character 0x14 being 
placed at the beginning of the string (and included in the p ing byte count) 


= additional continuation sub-fields of up to 254 characters are 
being preceded by the 0x14 character. 


The continuation sub-field prefix character was in fact specially cho 
on the MC, should the .dbf file be read into the MC Database appli 


as required, in each case again 


so as to give a suggestive display 
on. 


The Series 3 Agenda ; 
This section describes only the Series 3 Agenda. The Series 3a Agenda is described in a separate chapter. 


The Series 3 Agenda stores its files in the DBF file format, as described in general terms at the beginning 
of this chapter. By convention, the Series 3 Agenda uses files with extension .agn. 


Field information record 
The field information record of a Series 3 Agenda file is always as follows: 
<05><20><00><00><00><00><03> 


indicating that each type 1 record in a .agn file consists of four integer fields followed by one string 
field. More details of these fields are given below. 


Extended header 
There are no extended headers on any Series 3 Agenda files. 


50 


4 DBF FILES 


Descriptive record 


For an example of a descriptive record, consider the following, which is a d of a default newly- 
created (and exited) Series 3 .agn file: ‘ a aia 


0: 4f 50 4c 44 61 74 61 62 61 73 65 46 69 6c 65 00 OPLDatab aseFile. 
10: Of 10 16 00 Of 10 05 20 00 00 00 00 03 0e 30 0c ........ wee 0. 
20: f0 a4 01 3c 00 01 00 Of O00 1c 02 2e 00 er ee 


The header of the first record after the field information record is <0e><30>. This means that the record 
has type 3 and body length 0x0e bytes. Evidently, this record extends to the end of the file. 


The body of this descriptive record is made up of a single field of type 15 and length 0x0c. The body of 
this single field consists of 6 integers, with the following meanings: 


= the time (in minutes since midnight) for the first appointment slot of the day 

# the default length of an appointment (in minutes) 

® whether or not alarms are on by default 

= the default advance time (in minutes) before a timed appointment for an alarm 

= the default time (in minutes since midnight) for the alarm for an untimed appointment 

« the character (low byte only - the high byte is ignored) to be used as the time separator. 
Evidently, these sub-fields match the various lines in the Settings dialog within the Agenda application. 


Type 1 records 

Entries in an Agenda are stored as single type 1 records in the corresponding .agn file. 
Individual ToDo items and Repeated items are also stored as single type 1 records. 
The five fields in Agenda type 1 records are 


integer: DayNumber 
integer: Duration 
integer: Time 
integer: AlarmTime 
string: Text 


DayNumber is the number of days since 1/1/1900 (which is day zero). As far as the Series 3 Agenda is 
concerned, the first legal day is 1/1/1980, and the last legal day is 31/12/2049. 


Duration, Time, and AlarmTime are all stored in minutes (ignoring for the moment the fact that some 
calculations with these values have to be performed in places - as described below). 


The MSB (most significant bit) of Time is a flag that indicates whether the item is timed or untimed. If 
the MSB is set then the item is untimed. Accordingly, to extract the time from the Time field this value 
must be anded with 0x7fff to remove the MSB 


The LSB (least significant bit) of Duration is a flag that indicates whether the item has an alarm attached. 
If the LSB is set then no alarm is attached. Accordingly, to extract the duration from the Duration field, 
divide this value by 2 (thus removing the LSB and shifting down the duration). 


If the item is untimed then the Time field contains the day note slot number and its MSB must be set (ie 
or in 0x8000). In this case, the Duration field simply equals 0 if an alarm is attached or 0x01 if no alarm 
is attached. 


Note that the end time of a timed item (obtained by adding its start time and its duration) must always be 
less than 1440 (ie midnight). 
Calculating with AlarmTime 


For internal efficiency reasons, the way in which the alarm pre-time (as defined by the user) is stored in 
the .agn file is somewhat counter-intuitive. 


To recover the pre-time of the alarm for a timed appointment, the values of Time and AlarmTime for the 
entry should be added, and then the value (23*60+59) subtracted from this result. 


ae 


51 


ADDITIONAL SYSTEM INFORMATION 


| 


For example, if the value of Time is 0x3fc and the value of AlarmTime iis 0x1b2, the actual alarm pre-time 
is 

Ox3fc + Oxib2 - (235*60 + 59) 
ie 15 minutes (for an appointment actually at 5pm in the afternoon). 


In the case of untimed appointments, the integer value obtained when : larmTime is divided by 24*60 
gives the number of days previous to the appointment when the alarm is due. The time of day when the 
alarm is due is obtained by subtracting the remainder when AlarmTime is divided by 24*60, from 
23*60+59. | 


For example, if the value of Time is 0x8000 and the value of AlarmTime is 0xe87, note that 
Oxe87 = 2*(24+60) + 839 
so that the alarm is due two days in advance of the appointment, at 10am (since 23*60+59-839=600). 


If required, appropriate values of AlarmTime to ensure given alarm pre-times can easily be calculated by 
reversing the above formulae. 


Finally, note that if an appointment does not have an alarm set for it, the value of AlarmTime should be 
set to Oxf fff. | 


The text of an appointment 
The text for an appointment is contained within the Text field of the record. 


In all but the cases of repeated entries, the text is simply the entire content of the field. For repeated 


items, the final six bytes of the Text field have a special meaning, as ss below. 


In all cases, the length of the actual text for an appointment cannot ex 63 characters. 

ToDo items / 

ToDo items have a DayNumber of Oxffff, and must be stored as timed] items (and so the MSB of the 
Time field must be clear). 


The Time field contains the item priority, that is a value from 1 to 9. 
The Duration field contains a secondary integer key, which orders the ToDo items within a given 
priority. 

ToDo items cannot have alarms attached. 


Repeat items 


Timed and untimed repeat items are stored in the same general way as 
except that they have a DayNumber of Oxfffe. 


es specific repeat details are stored in the six bytes at the end of the Text field and have the following 
ormat: 


ormal timed and untimed items, 


52 


Byte: Type 

Byte: Interval 

Integer: StartDayNumber 

Integer: EndDayNumber 
The Type field can take the following values: | 

0 Repeat yearly | 

1 Repeat monthly by date 

2 Repeat monthly by day 

3 Repeat weekly 

4 Repeat daily 

5 Repeat workdays. 


4 DBF FILES 


StartDayNumber and EndDayNumber are stored as the number of days since 1/1/1900 (which is day 0). 
Setting EndDayNumber to zero means the item repeats "forever". 


53 


CHAPTER 5 


SERIES 3A AGENDA FILE FORMAT 


i ae ee ee ee 
Introduction 


Series 3a Agenda files are binary files containing typed variable length records. They use the same basic 
file and record structure as DBF files, but the file signature and internal record structure are NOT the 
same. 


In contrast, Series 3 Agenda files are DBF files and are described separately, in the DBF Files chapter. 


a Ne ee a | 
Basic structure of Agenda files 
The basic file structure for Agenda files is as follows: 


<standard header> Used to identify the file type and the version of the file structure. 
<extended header> For future use, currently omitted. 
<data records> The main body of the file, containing entries and preferences. 


The standard header 
The standard header is present at the start of all Agenda files and is always 32 bytes long. 


AGD_SIG SIZE 16 
AGD_SPARE_SIZE 12 


typedef struct 
{ 
UBYTE sig fAGO_SIG_SIZE}; 
UWORD version; 
UWORD hSize; 
UBYTE spare [AGD_SPARE_SIZE]; 
> AGD_FILE_HEADER; 


The first 16 bytes of the file are always the zero terminated string AgendaF i leType*. This is used to 
identify the file as an Agenda file. 


The two byte parameter version at file offset 0x100f should be interpreted as a hexadecimal word that 
gives the version of the file format. This is currently always Ox100F. The most significant nibble (the 
version number is in the format described in the General System Services chapter of the Plib Reference 
manual) is the major version number and any change in this indicates that the file format may not be 
backwards compatible. 


The two byte parameter hSize gives the combined size of the standard and extended header. This 
effectively gives the file offset of the first data record within the file. Currently this is always 0x0020. 


The array spare should not be used and is reserved for future use. 


ADDITIONAL SYSTEM INFORMATION 


The extended header 
At present this is never used and is reserved for future expansion. 


The data records 


As in DBF files all data is stored as variable length, typed records, a the type and length combined 
into a single word (two bytes). The most significant nibble of the word) gives the record type. The type 
determines how the contents of the record are to be interpreted. The remainder of the word gives the 
length of the data that follows. This file structure is designed to be flash friendly in that deleted records 
are not normally removed from the file but are marked with record type 0 which can be done in place. 


This structure allows 16 record types 0x0 to Oxf, each of which are allowed to be up to Oxffe (4094) bytes 
long. Although a record length of Oxfff is not explicitly illegal it is ” used. 


| 
a Nh Ait ee ee 
Record Types 


There are sixteen record types as follows. 


Type Record 
0 Deleted 
1 Appointments (timed day entries) 

2 Day notes (un-timed day entries) 

3 Anniversaries 

4 To-do entries 

5 Repeat records | 
6 Anonymous data 
7 Reserved | 
8 Reserved 
9 To-do list information : 
10 Descriptive records 1 
11 Descriptive records 2 | 
12 Descriptive records 3 
13 Descriptive records 4 

14 Descriptive records 5 
15 Illegal (used to mark write failure) | 


Currently record types 6, 7 & 8 are never generated by the Series 3a Agenda. 


A number of the records contain day numbers and times. Unless stated] otherwise all dates are given as a 
daynum. A daynum is the number of days from 1 Jan. 1970. For technical reasons dates before 1 Jan. 
1980 (daynum 3652) or after 31 Dec. 2049 (daynum 29219) are ignored by the Agenda and where 
appropriate will be 'clipped' to one or other of these dates (for example a repeating entry that starts on 10 
June 1970 will have its start date ‘clipped’ to 1 Jan. 1980). 


a ea OR Ae A A TT EE TE 
Type O - deleted record | 


As for DBF files, deleted records are not normally removed from the file but have their record type 
changed to type 0. As any of the above record types may be converted to a type O record, there is nothing 
that can usefully be said about the contents of such a record (indeed the record may not even have been a 
valid Agenda record before it was deleted). Records of this type should be ignored except to calculate the 
amount of space that would be freed by compressing the file. 


56 
| 


5 SERIES 3A AGENDA FILE FORMAT 


There may be any number of such records in the file. 


Sa a Mes aa a I eT ae 
Types 1 to 4 - entry records 


Records of type 1 to 4 contain details of individual Agenda entries. Each has the same conceptual 
structure as follows: 


<Entry details field This is dependent on the entry type. 

<Title field> Obligatory, variable length field containing the text of the entry. 
<Alarm field> Optional, fixed length field containing alarm time and sound. 
<Memo field> Optional variable length field containing any memo for the entry. 


The record type is used to determine the length and meaning of the first field. Although these have some 
similarities all four are individually described in details below. 


Type 1 (timed day entry/appointment) 


A type 1 record stores details of entries that occur at a specific time on a specific day. In the Series 3a 
Agenda these are called timed day entries. 


The details field for a timed day entry consists of eight bytes structured as follows: 


UWORD day; 
UWORD time; 
UBYTE attr; 
UBYTE code; 
UWORD dur; 
day is the daynum of the day on which the entry appears. 
time is the time of the start of the appointment in minutes from midnight. 
attr is a byte containing flags for attributes the entry may or may not have (see 
below). 
code is the ASCII character code for the symbol that is to be associated with the 
entry when it is visible in the Year view. Values less than 32 are ignored and 
treated as if the entry should not appear in the Year view. 
dur is the duration of the appointment measured in minutes. It is constrained such 


that the appointment cannot end after 11:59 PM. i.e. this field is between 0 
and 1439 - time (inclusive). 
Type 2 (untimed day entry/note) 


A type 2 record stores details of entries that appear on a specific day but do not have a time associated 
with them. In the Series 3a Agenda these are called untimed day entries. 


The details field for an untimed day entry consists of six bytes structured as follows: 


UWORD day; 
UWORD slot; 
UBYTE attr; 
UBYTE code; 
day is the daynum of the day on which the entry appears. 
slot is the time slot (in minutes from midnight) in which the entry will appear in 


the Day and Week views. For example a slot value of 780 would show the 
entry at the start of the 1pm slot. If this is Oxffff then the entry will appear in 
the default slot. 


57 


ADDITIONAL SYSTEM INFORMATION 


attr is the attributes byte (see below). 


ode is the ASCII character code for the symbol \. is to be associated with the 
° entry when it is visible in the Year view. Values less than 32 are ignored and 


treated as if the entry should not appear in the Year view. 


Type 3 details (anniversaries) 


A type 3 record stores details of anniversaries (entries which appear in| the Anniversary view). Although 
these are usually repeated there are cases where a single anniversary entry will exist. For details of 
repeated entries see type 5 records below. 


The details field for an anniversary record consists of nine bytes struc as follows: 


UWORD day; 
UWORD slot; 
UBYTE attr; 
UBYTE code; 
UWORD baseYear; 
UBYTE displayAs; 


day is the daynum for the day the anniversary entry will appear on. 


slot is the time slot (in minutes from midnight) in which the entry will appear in 
the Day and Week views. For example a slot value of 780 would show the 
entry at the start of the lpm slot. If this is Oxff#f then the anniversary will 


appear in the default slot. 
attr is the attributes byte (see below). 
code is the ASCII code for the character to display when the entry is visible in the 


Year view. Values less than 32 are illegal and cause the entry not to appear in 


the Year view. 


baseYear is the year of the event that the anniversary commemorates. Positive values 
indicate AD years e.g. 55 means 55 AD i negative values indicate BC e.g. 
-5 means 5 BC. A value of zero indicates that there is no baseYear. The 
allowed range is from 30000 BC to 2049 


displayAs contains flags detailing how the entry is to be displayed. The flags are as 
follows: 0x01 for baseYear displayed, 0x02 for elapsed years displayed, 0x03 
for both of the preceding options and 0x00 for none of them. 


Type 4 details (To-do) 
A type 4 record holds details of to-do entries. 


These are entries which usually have an associated due date and a display from date. They appear in the 
corresponding to-do list, and depending on the preference settings will appear in the Day view from the 
displayFrom date until they are crossed out or deleted. 


The details field for a to-do entry consists of 14 bytes structured as follows: 


UWORD displayFrom; 

UWORD slot; 

UBYTE attr; 

UBYTE code; 

UWORD dueDate; 

UBYTE ListNo; 

UBYTE priDisp; 

ULONG order; 


displayFrom is the daynum of the day on which the entry first appears in the Day/Week 
views of the Agenda. This must normally be the same or less than the dueDate 
value. 


If the entry is crossed out (see the description of the attr byte below) this is 
the daynum of the day on which the entry was crossed out. In this case, and 
only in this case, the displayfrom can be later than the dueDate. 

If the displayFrom daynum is Oxffff, then this is an un-dated to-do i.e. one that 
always appears on today. In this case the dugDate will also be Oxffff. 


58 


5 SERIES 3A AGENDA FILE FORMAT 


slot is the time slot (in minutes from midnight) in which the entry will a in 
the Day and Week views. If this is oxfff¢ then the entry will appear inthe 
default slot of the appropriate to-do list. 


attr is the attributes byte (see below). 


code is the ASCII code for the character to display when the entry is visible in the 
Year view. Values less than 32 are illegal and cause the entry not to appear in 
the Year view. 


dueDate is the daynum of the day the to-do should be done by. If this value is oxffff 
the record is an undated to-do (i.e. one which always appears on today when it 
appears in the Day/Week views). 

ListNo is the internal number (0-255) of the to-do list on which the entry will appear. 


Note that a value of zero does not necessarily mean that the entry appears on 
the first to-do list in the To-do view. See type 9 records for further details of 
the meaning of this byte. 


priDisp this byte consists of two nibbles that give the priority and the method of 
displaying the to-do. 
The least significant nibble (bottom four bits) has a value one less than the 
priority of the to-do. Thus a priority one to-do has value zero, priority two has 
value one etc. This will currently always be in the range zero to eight inclusive 
and all other values are illegal. 
The most significant nibble (top four bits), determines how the due date should 
be displayed there are currently four legal values: 
O - automatic, shown as date until within a week then shown as e.g. Next wed. 
1 - Always shown as date. 
2 - Shown as number of days until due date. 
3 - Due date never shown. 


order this determines the position of the entry in its to-do list when the list is 
displayed in manual order. This field is not assigned consecutively. Thus a 
value of 3 for example in this field does not necessarily mean that the entry 
appears third (or fourth) on the to-do list. 


The attributes byte ‘aétr'. 


The above record types (1 to 4) contain an attributes byte as the fifth byte within the record data. This 
byte contains flags which indicate which of the two optional fields are present in the record, whether or 
not the entry is repeated etc. The following flags are currently defined for the attributes byte (all other 
bits should be 0). 


Bit Meaning 
00000001 Once only: if this bit is set the entry appears only once in the Agenda. If it is 


clear the entry is repeating and there will be an associated type 5 repeat record 
elsewhere in the file. 


00000010 Pending: this bit is set if the entry has not been crossed out. If it is clear the 
entry has been crossed out. In the case of to-do entries this alters the meaning 
of the displayFrom field of the details. 


00000100 Display code: if this bit is set the entry should be displayed in the Year view 
(providing it has a legal code field): if it is clear the entry should not appear in 
the Year view, regardless of the value of the code field. 


00001000 No alarm: this bit is set if the entry does not have an associated alarm in which 
case there will be no alarm field at the end of the record. If it is clear there is 
an alarm field immediately after the title field. 


00010000 No memo: this bit is set if there is no memo associated with the entry, in 
which case there will be no memo field at the end of the record. 


The title field must be present for entry records of all four types. This field follows immediately after th 
details field and contains the text for the entry as well as flag for how that text should be displayed e.g. 
bold, italic etc. 


59 


ADDITIONAL SYSTEM INFORMATION 


The format of the title field is: C) 
UBYTE style; 
UBYTE len; 
title text. 
style contains flags indicating how the text should] appear. The flags are as follows: 
0x01 for bold, 0x02 for underline, 0x20 for italic. 
len is the length of the text comprising the title, and the number of bytes 
following. This may take any value from 0 -|254. 
title text is Len bytes of the title. Note that this text is/mot zero terminated. 
This fixed length field is only present if the attributes byte does not ave bit 3 (0x08) set, i.e. there is an 
alarm set for the entry. | 
When present this entry immediately follows the title field and has the following format: 
UWORD preTime; 
UBYTE Len; | 
UBYTE sound[8] ; - 
preTime is the time at which the alarm should occur given in minutes before 11.59 on 
the day the entry appears on. (In the case ofa type-4 to-do record this is the 
due date). This field can be between 0 and 46079 (midnight before, 31 days 
before the entry). 
len this gives the length of the text in the sound element. 
sound is always eight bytes long the first len of which contain the name of the WVE 
file for the alarm. A number of WVE files having names of the form 
SYS$ALnn are built-in to the ROM. In addition name can be set to an ASCII 
character with value between 1 and 16 inclusive: currently only “\0x01", 
"\0x02" and "\0x10" are used corresponding to the rings, chimes and silent 
alarms. If the name of the file is less than eight bytes long, all remaining bytes 
should be zero. 
When present this field comes at the end of the record immediately after the alarm field if there is one, ~~) 


and after the title field if there is not. The field has the following format: 


UWORD dataLength; 
UBYTE data[]; 


dataLength is the length (in bytes) of the data in the memo field. This can be between 0 
and 3600 (inclusive). 
data is a block of data consisting of dataLength bytes containing the memo - details 


of the memo are beyond the scope of this manual. 


Type 5 - repeats 


When an entry is set to repeat in the Agenda, a second record is written to the file in addition to the type 
1 - 4 entry record. This record contains the date to repeat until, the days to repeat on and a list of those 
dates for which the repeat should be suppressed. 


Repeat records are always paired with an entry record which has bit 0 (0x01) of the attributes byte clear. 
Because of the way the Series3a Agenda writes the file a type 5 repeat fecord will always occur after the 
associated entry record, but this is not necessary and there is no reason! why it should not occur earlier in a 
the file. If a repeat record is missing its associated entry record or if a repeated entry record exists for 
which there is no associated repeat record, then the record in the file will be ignored. 


60 


5 SERIES 3A AGENDA FILE FORMAT 


eee 


The repeat record is structured as follows: 


alg 


ival 


endDate 


type 


tags 


filePos 


exceptions [] ; 


is the repeat algorithm and various flags. The bottom three bits of this byte 
may take one of the following values: 0 - repeat daily, 1 - repeat weekly, 2 - 
monthly by date, 3 - monthly by days, 4 - repeat annually. 

If bit 3 (0x08), of this byte is set, the repeat should only appear once in the 
dated views on the first occurrence after today. Otherwise all valid occurrences 
are shown. All other bits in this byte should be 0. 


is the daily repeat interval. This is zero if the entry repeats daily, 1 if the entry 
repeats every other day etc. A value of 255 is not valid. 


this is the daynum of the last day on which the entry can repeat. This is not 
necessarily the last day on which it will appear. The start date is taken from 
the day value at the start of the details field in the entry record. In the case of a 
repeating to-do this is the displayFrom field that is normally used to give the 
date from which to display the entry. Here it is used to determine the start date 
of the repeat algorithm and hence determine which due dates will be associated 
with the todos. To work out the display from dates for each instance of the 
repeated to-do use the dueDate-displayFrom in the entry record to determine the 
number of days warning for each instance of the repeat. 


is the type (1-4) of the associated entry record. This information is actually 
redundant since it can be determined by reading it directly once the associated 
record has been found but is a useful optimisation internally to the Agenda. 


is n bytes that determine which days occur in the repeat sequence. The number 
of bytes n and their meaning is determined by the repeat algorithm. For repeat 
daily/annually there are no tag bytes since the start date and ival determine 
which dates to repeat over. 

For weekly repeats there are two tag bytes. The first has a bit set for each day 
of the week on which the repeat occurs. Bit 0 for Monday, bit 1 for Tuesday 
etc. Bit 8 is not used and should always be 0. The second byte determines 
which is the first day of the week, 0 for Monday, 1 for Tuesday etc. This is 
significant when the repeat does not occur every week. A repeat which occurs 
on say, Tuesday and Thursday of every other week, occurs on different dates if 
the week starts on Monday than it does if the week starts on Wednesday. 

For monthly by date repeats there are four tag bytes. Each bit in these bytes 
represents a different day of the month. Bit 0 in the first byte is the ist of the 
month, bit 1 the second and bit 7 the eighth of the month. Bit 0 of the second 
tag byte is set if the repeat occurs on the 9th and so on. Bit 7 of the fourth byte 
is not used and should be 0. 

Monthly by days repeats have five tag bytes. Bytes 0 to 3 correspond to the 
first, second, third and fourth occurrences of each day, for example bit 1 of 
byte 2 is set if the algorithm repeats on the 3rd Tuesday of each month. The 
last tag byte contains bits set if the repeat should occur on the last Monday, 
say, of the month. 


is the offset from the start of the file at which the corresponding entry record 
can be found. This is given in bytes from the start of the file (not the start of 
the data records), and gives the position of the type length word at the start of 
the record. Note that this mechanism of associating repeat records with the 
underlying entry relies on the deleted entries not being removed from the file: 
they are just marked with the deleted record type. Removing such records 
would require all FilePos fields to be recalculated. 


61 


ADDITIONAL SYSTEM INFORMATION 


exceptions The remainder of the record consists of words, each of which is the daynum of 
a day on which the repeat should be suppressed. The number of exceptions 1s 
determined by the length of the record. pepsi the Series 3a Agenda 
currently always writes these exceptions in strictly increasing order, there is no 
guarantee that this will always be the case. Any illegal values (either outside 
the valid range for the Agenda or on a day which is not normally a repeat 
instance) should be ignored but preserved. 


Type 6 - anonymous data 


This record type is currently not used and is set aside for storing aclu text carried with the 
Agenda. It is intended that this information will be used by, say, conversion programs that convert other 
Agenda file formats to that of the Series 3a. This allows the file to be converted back without losing 
information from the original file. These records are ignored by the series 3a engine except when a 
merging files. In this case incoming anonymous data records are ito the file into which data is being 
merged. 


Types 7 and 8 - reserved 


These record types are reserved for future expansion and should not 


Type 9 - to-do list information 


There is one record of this type for each to-do list in the Agenda. Each contains the setting for the to-do 
list and the to-do list number (as in type 4 to-do records) that corresponds to the list. 


The format for these records is as follows: 


UBYTE sig; 
UBYTE data[] 
sig a signature byte which determines the format of the rest of the record. 
Currently the only legal value is Oxff. 
data is data for the to-do list: the details of the data are beyond the scope of this 
manual. 


a hg i Eg ee 
Types 10 to 14 - descriptive records 


Type 10 to 14 records contain the preferences settings for the Agenda (these may be set via the 
preferences dialog). Only one record of each type is allowed per Agenda file. If there is more than one 
record of any type, only the last record is significant. 


A descriptive record consists of the usual header word followed by the/record body. The record body 
contains either simple data or a set of type/length/value (TLV) fields. A TLV field consists of a one word 
header followed by the field body. The top four bits of the field heade ' contain the field type. The 
bottom 12 bits contain the length of the field body. No more than one of each of the specified fields can 
be present in a given record. 


The structure of these records should not be extended (extra 7LV fields should not added even though 
these would be ignored). 


Type 10 to 14 records are described in greater detail below. 


62 


5 SERIES 3A AGENDA FILE FORMAT 
ee ee 
a a a gee OS ee eee] 
Type 10 - styles descriptive record 


The styles record contains the Memo editor preferences and its styles and emphases. 


The styles record gets written after a memo has been created for the first ti d 
ateiconten fins changed. e first time, and thereafter whenever 


The details of this record are beyond the scope of this manual. 


I eT Eg ee ge ee 
Type 11 - to-do manager descriptive record 


This record is written on creation of a new Agenda and so is always present. It gets rewritten whenever 
changes have been made. 


This record contains the information that the Agenda needs to determine which position each to-do list 
ag the To-do view. The record consists of a header word followed by a body of three bytes structured 
as follows: 


UBYTE sig; 
UBYTE ncats; 
UBYTE catid[ncats] 


sig is the signature and is always 0xéc. 
ncats is the number of categories. 
catid{ncats] contains ids for each category (i.e. to-do list) in the display order. Thus 


catid(0) holds the id of the first displayed category, catid{1] the id of the 
second, and so on up to a maximum of catid(98]. These are used to identify 
each record as coming from a given category in a record. 


Ea a ae a aw a Ug ea ee ON Te 
Type 12 - frequently changing data descriptive record 


This record is written on creation of a new Agenda and so is always present. However, as it contains data 
that changes frequently, it is only rewritten when the file is closed. 


This record contains zoom, wrap and status window settings for each view. It consists of a header word 
followed by six VIEW_SCREEN_CFG structures for the Day, Week, Year, To-do, Anniversary and List views 
respectively. A VIEW_SCREEN_CFG structure consists of three bytes and is structured as follows: 


UBYTE statmode; 
UBYTE wrapmode; 


UBYTE zoom; 
statmode this field is a flag for the status window. It is 0 if a status window is not 
visible, 1 if the small status window is visible and 2 if the large status window 
is visible. This flag applies to all views. 
wrapmode in all views except the Year view the wrapmode field is 1 if wrap is on, and is 


otherwise 0. In the Year view (which does not use wrapping) the wrapmode field 
contains the index of the month that is displayed in the first row of the planner 
(O = January, 11 = December). 


zoom this field takes the value 0 to 3 corresponding to Roman fonts of height 8, 11, 
13 and 16 respectively. It is relevant for the Day, Week, To-do, Anniversary 
and List views. The zoom field is unused in the Year view entry and is set to 0. 


aa aa rr a et rT 
Type 13 - general descriptive record 


This record is written on creation of a new Agenda and so is always present. It stores data shown in the 
dialogs under the Preferences menu. It gets written whenever the values shown in one of these dialogs are 
changed. 


an a 
63 


ADDITIONAL SYSTEM INFORMATION 


is record contains entry defaults and all individual view preferences (to-do entry defaults are stored in 
en list records). heck record has the normal Agenda type/length header followed by one or more 7LV 
fields. There are sixteen possible type fields only some of which are currently used: the rest are reserved 
for future use. If a field is not found the Agenda will use the corresponding default values. The fields can 
be in any order. 


Type Field 
4 Diamond list setup | 
5 Day entry defaults 
6 Anniversary defaults 

7 General defaults 
9 Day view settings 

10 Week view settings 

11 Year view settings 

12 To-do view settings 

13 Anniversary view settings 

14 List view settings 


six bytes structured as follows: 


UBYTE fnbar [6]; 


fnbar contains six bytes corresponding to the Day, Week, Year, To-do, List and 
Anniversary views respectively. Each byte is either TRUE or FALSE depending on 
whether or not the view is to be included in|the diamond list. 


bytes structured as follows: 


UWORD DefUnt imedEntViewT ime; 

UWORD DefT imedEntT ime; 

UWORD DefTimedentDuration; 

UBYTE DefTimedByDefault; 
UBYTE DefYearSym; 

AGPREF_ALARM UntimedAlarmefs; 

AGPREF_ALARM TimedAlarmDefs; 

UBYTE style; 

UBYTE spare; 


DefUntimedEntViewTime is the default display time for untimed entries in minutes since 00:00. 


DefT imedEntT ime is the default display time for timed entries in minutes since 00:00. 

DefT imedEntDuration is the default duration for a timed entry in minutes. 

DefT imedByDefault is 1 if entries are timed by default, ae it is O. 

DefYearSym is the character code for the default year sy bol. 

Unt imedA LarmDefs contains details of the default alarm for unti entries (see below for a 
description of the AGPREF_ALARM structure). 

TimedA Larmefs contains details of the default alarm for timed entries (see below for a 
description of the AGPREF_ALARM structure). 

style is the style of the font used for the entry. It should be a suitable ored 


combination of the Wserv G_STY_Xxx flags: 0x00 for normal, 0x01 for bold, 0x02 
for underline and 0x20 for italics. | 


. 


5 SERIES 3A AGENDA FILE FORMAT 
—_—_—_—_—_—_—_—nknre eg» 


spare is reserved and is set to 0. 


An AGPREF_ALARM structure contains default alarm details. It consists of 14 bytes structured as follows: 


UBYTE on; 
UBYTE ndays; 
UWORD minutes; 


SE_SND snd; 

on is 1 if an entry has an alarm by default and 0 otherwise. 

minutes for timed entries minutes is the time interval in minutes between the alarm 
going off and the start of the entry. For untimed entries minutes is the default 
alarm time in minutes from midnight. 

ndays for timed entries ndays is unused but should be set to 0. For untimed entries 
ndays is the default number of days between the alarm going off and the start 
of the entry. 

snd contains details of the default alarm sound (see below for a description of the 


SE_SND structure). 


hes SE_SND structure contains details of the default alarm sound. It consists of ten bytes structured as 
ollows: 


UBYTE Len; 
TEXT name [8] ; 
UBYTE zero_term; 


Len is the length of the name of the alarm. 


name contains the name of the alarm stored as a sequence of ten characters. When 
Len is less than eight the first unused byte contains a NULL character. Any 
remaining unused bytes can take any value. 


zero_term contains the NULL character. 


aaa 


0,2 0,0,0,0,9,0,0,6,0,9, FMM eM sMaMaMeMeMeMaMareeMeMetaotetatateeMetabetaelaMatetetetetetetaMeteletatetatatetatel, CRD 
O OHO) PI I IK PO I RD eta ORD 
s tasatetatotetatatat acetareteratetetatonst et atatanetaratnatotetasecateranstsrorerere srg srs ROR RR RD oneege, 
be ee Od 
6 

o ' 4 5 ee 
LR aac wth xn ain ot ae aH eS 

wogecesorototececestses cece se, NH, 


An anniversary entry defaults field contains the defaults for entries in the Anniversary view. It consists o 
20 bytes structured as follows: 


UWORD DefEntViewT ime; 
UBYTE AutoApplyYearSym; 
UBYTE DefYearSym; 
AGPREF_ALARM AlarnmDefs; 
UBYTE style; 

UBYTE spare; 


DefEntViewT ime is the default display time for anniversaries in minutes since midnight. 

AutoApplyYearSym is 1 if the year symbol is on by default, otherwise it is 0. 

DefYearSym is the character code of the default year symbol. 

Alarnefs contains the default alarm details for timed and untimed entries (see the Day 
entry defaults field for details of the AGPREF_ALARM structure). 

style is the style of the font used for the entry. It should be a suitable cored 


combination of the Wserv G_STY_Xxx flags: 0x00 for normal, 0x01 for bold 0x02 
for underline and 0x20 for italics. 


spare is reserved and is set to 0. 


UBYTE p_psion_enter; 
UBYTE timesep; 


p_psion_enter is set to TRUE if PSION+-ENTER is used to complete an entry without going into 
the Entry details dialog. Otherwise p_psion_enter is FALSE. 
timesep is the character code for the Agenda time separator character. 


65 


ADDITIONAL SYSTEM INFORMATION 


O88 0,90 00,8 Mah eM Ms 0 050,00 ,8 8,8, F Mahe ramaaMseMstatamerareMeMeMetetaMetaretsr sea teteterersteratetanerenatann ests gan etate enare tans’ 
aren ogh senha eat aces eileterarcassecenorenenceccereresonesotetsteapl ces 


UWORD agnv_flags; 
ADENTVU_PREF left; 
ADENTVU_PREF right; 


agnv_flags this field contains both general view flags and Day view flags (all bits not used 
are reserved). The general view flags are as follows: 
0x01 for show appointment duration (Day, List, Week and Year views), 
0x02 for show appointment end time (Day; List, Week and Year views only), 
0x100 for show untimed day notes (Day, List and Week views only), 
0x200 for show anniversaries (Day, List and Week views only), 
0x400 for show to-dos (Day, List and Week views only) and 
0x800 for show timed day notes (Day, List and Week views only). 
The Day view flags are as follows: 
0x04 for title to go on right hand side, 
0x08 for slot compression off, 
0x10 for duration arrows off and 
0x20 for show overlap bars off. 


left contains the preferences for the left hand side of the Day view (see below for a 
description of the ADENTVU_PREF structure). 


right contains the preferences for the right hand side of the Day view (see below for 
a description of the ADENTVU_PREF structure). 


An ADENTVU_PREF structure consists of 12 bytes structured as follows: 


UWORD flags; 
UWORD begint ime; 
UWORD beginvis; 


flags contains a combination of the slot lines on |. (0x01) and the slot times on flag 


UWORD endvis; 

UWORD endtime; 

UWORD slotdur; 

(0x02). | 

begintime is O for the left hand side and beginvis for the right hand side. 
beginvis is the start time of the first slot in minutes from midnight. 
endvis is the start time of the last slot in minutes from midnight. 
endt ime is right.beginvis for the left hand side and 1440 for the right hand side. 
slotdur is the slot duration in minutes. 


UWORD pref_flags; 


pref_flags contains both general view flags (see above under the Day view settings field), 
and Week view flags. Currently there is only one Week view flag: 0x4 for 
show title on right hand side. 


Wetetatstatetetetetetntatea*ete e%ete'ee%ee" 


> AS 
eter’ Ce te ee 


s field consists of two bytes as follows: 


UWORD pref_flags; 


pref_flags contains a combination of the general flags (see under the Day view settings 
field above) for showing appointment duration and/or end time or neither. 


ws 0+ 01,0,050,000 
nessrcesesececece me cateresetatotaSotote aie etetatenatetetetaraetatetstatetetetesatenatatePatatsesPatetatateteReSatatetalits ata atate tits tate teMatats tat 
ee ceeears 


field consists of two bytes structured as follows: 


5 SERIES 3A AGENDA FILE FORMAT 


UWORD ncols; 


ncols contains the number of columns to be shown in the To-do view. The value of 
ncols should not be more than the number of existing categories. 


Wa%ePe%e"ateeMeMeeMe%e tote sZatatnteMa%a%e"a"s"ohoatat 
I CO 
ESO RIK RR oni etn Ke ie 
=e an... re. ese 
S enero, io 
. oon 8 jones 
onene % 
e' Seen bet ot 
eee, Oyama at » one, 
OO) ostetotetate”s OOO 


settings field consists of two bytes structured as follows: 


UWORD ncols; 


ncols contains the number of columns to be shown in the Anniversary view (1 to 4). 


wsostacatatotateretstatetetefotatePata'etstatetatetetetetatetete’stutetet . 
Re SRN ST ONY RUNNER RAKE REST USOR 
Be SRD EF atte oe 
RS SR at a Ee 

5S 
seeatataratanerateetetatSeetatetaSeoeioatetatteneenesenstenetetenescueconmronsiiearetate 


The List view settings field consists of two bytes structured as follows: 
UWORD pref_flags; 


pref_flags contains a combination of general view and Day view flags (see under the Day 
view settings field above) and the show-repeats-once flag (0x04). 


eee et 
Type 14 - print setup descriptive record 


This record does not initially exist. It is created/rewritten to contain a new copy of the data for the 
Agenda print setup after using the Agenda Print setup dialog. It is also created/rewritten after a memo 
has been created or edited and Print setup data has been changed. Hence it is possible that the record will 
only contain Agenda Print setup data or Memo Print setup data. 


The record consists of a one word header followed by a series of 7LV fields. 

Field types 0 to 3 and 6 to 9 are allowed. Field types 0 to 3 are used for the main Agenda print setup. 
Field types 6 to 9 are identical to field types 0 to 3 and are used for the memo print setup. 

Field type O and 6 

Contains printer parameters in a PRINTER_PARAMS structure as returned by the PR_GET_PARAMS method of the 
printer active object of the FORM dyl. 

Field types 1 and 7 

Contain printer model data from the PR_SENSE_MODEL method of the printer active object. The first byte is 
the model number as returned by PR_SENSE_MODEL, followed by the name, up to and including the NULL. 
Field types 2 and 8 

Contain printer header text from the PR_GET_HD method of the printer active object including the 
terminating NULL. 

Field types 3 and 9 


Contain printer footer text from the PR_GET_HD method of the printer active object including the 
terminating NULL. 


RR a er mr ee pe ea 
Type 15 - illegal 


This record type is illegal and is used to protect the Agenda against write failures on a flash SSD. 
Writing to a flash SSD can fail at any time due to, say, a low battery. To protect as much as possible 
against this the Agenda will write the whole of the rest of the record before ‘blowing down’ the byte 
containing the record type to its correct value. This means that any file which contains a record with type 
15 (Oxf) has suffered a write failure and data beyond this point cannot be trusted. 


67 


ADDITIONAL SYSTEM INFORMATION 


This record type is probably best thought of as an End Of File record, a any program finding a file 


with a type 15 record should start by setting the end of the file to the start 


record. 


(the type length word) of the 


CHAPTER 6 


WORD PROCESSOR FILE FORMAT 


This document describes the structure of a Psion word processor document to a degree which allows 
external software to read and write non-password-protected documents. 


Psion word processor document files contain a file header, followed by a number of type-length-value 
records, from the following list: 


= options data 
= printer-related data 
® printer model data 


= page header 

= page footer 

= style data 

=" emphasis data 


= document text 
= document index 


eee files created by the word processor will contain records in the order listed above. Each record 
consists of: 


= atwo-byte record type 
s atwo-byte record length, ten 
# len bytes of data 
Unless stated otherwise, all dimensions are stored in twips (1/1440 inch). 


Reserved locations 
All locations reserved for future use contain a value of zero. 


aa a ag at ee ee ee ae 
The document header 


The document header is 40 bytes long. It starts with the 16-byte zero terminated file signature 
"PSIONWPDATAFILE" followed by a two byte file version number. 


Following this is a 20-byte struct, containing password data. For a non-password-protected document 
there are two bytes of zero followed by eighteen bytes, each containing OxEA. 


The remaining two bytes of the header are reserved for future use. 


69 


ADDITIONAL SYSTEM INFORMATION 


Record types 


UWORD cpos 
UBYTE symbols 


UBYTE backup 


UBYTE statzoom 


UBYTE style 
UBYTE mono 
UBYTE outlevel 
UBYTE spare 


UWORD spare2 


saved cursor position 


show screen symbols 


TRUE to keep backups (this item is used on the MC only: it is not used on 
Series3 machines) 


top four bits indicate the current zoom state (0x22 by default), lowest four bits 
indicate the status window size: 0, 1 or 2 forjoff, small or big respectively 
(this item is used by the Series3a only) 


TRUE to show style bar 

TRUE to load text by line, else by paragraph 
lowest outline level to display 
reserved for future use 


reserved for future use 


Displayed screen symbols are determined by any combination of the following bit fields in symbols: 


0x01 
0x02 


show tabs 

show spaces 

show paragraph end markers 
show hyphens 

show forced line breaks 


printing process. It includes, amongst other items, descriptions of the page size and margins, the page 
numbering style, header and footer position and alignment. 


This record consists of a structure that is used to control the display and WDR printing of formatted text 
in all applications that require such services. It therefore contains some fields that are not relevant to the 


word processor. 


The following description is in terms of the P_EXTENT, SCRLAY_FONT and 


typedef struct 
{ 


> P_POINT; 
typedef struct 
{ 


P_POINT tl; 
WORD width; 
WORD height; 
) P_EXTENT; 


typedef struct 
{ 


UWORD fid; 
UWORD style; 
UWORD height; 
> SCRLAY_FONT; 


PAGES_HEADER structs, defined as: 


/* typeface number */ (1) 
/* font style */ (2) 
/* height of font in twips */ 


70 


typedef struct 
{ 
SCRLAY_FONT f; 
UBYTE align; 


UBYTE first_page; 


> PAGES _HEADER; 


/* font data */ 
/* header alignment */ (3) 


In these terms, the content of the printer-related record is: 


PAGE DATA 


WORD width 
WORD height 
P_EXTENT body 
WORD hdtop 
WORD hdbot 
WORD pdrflags 
WORD docflags 


UWORD pgbeg 
UWORD pgend 


RUNNING PAGE HEADERS 


PAGES HEADER top 
PAGES HEADER bot 


PAGE NUMBERING 


WORD offset 
WORD last 
WORD style 


MISCELLANEOUS 


SCRLAY_FONT f 
UBYTE size_choice 
UBYTE wo_control 
UWORD spare 
UWORD spare2 


Notes 


page width 
page height 


/* TRUE to emit on first page */ 


6 WORD PROCESSOR FILE FORMAT 


body print region, with respect to top left of page (4) 


page header position (5) 

page footer position (6) 

O for portrait, 1 for landscape 
always 3 for word processor 


page number to start printing (first page is 1) 


last page number to print (7) 


page header 
page footer 


page numbering offset 


page count, for %m (always reset by pagination) 


page number style (8) 


base font for body print region (9) 
paper size index (10) 


TRUE to disable widow and orphan control 


reserved for future use 
reserved for future use 


(1) Typeface numbers are defined in the following list: 


0 COURIER 22 OPTIONAL_SB 
1 PICA 23 OPTIONAL_SC 
2 ELITE 24 TIMES ROMAN 
3 PRESTIGE 25 CENTURY 

4 LETTER_GOTHIC 26 PALATINO 

5 GOTHIC 27 SOUVENIR 

6 CUBIC 28 GARAMOND 

7 LINEPRINTER 29 CALEDONIA 

8 HELVETICA 30 BODONI 

9 AVANT_GARDE 31 UNIVERSITY 
10 SPARTAN 32 SCRIPT 

11 METRO 33 SCRIPT_PS 

12 PRESENTATION 34 OPTIONAL_SCA 
13 APL 35 OPTIONAL_SCB 
14 OCR_A 36 COMMERCIAL_SCRIPT 
15 OCR_B 37 PARK_AVENUE 
16 STANDARD_ROMAN 38 CORONET 

17 EMPEROR 39 OPTIONAL_SCC 
18 MADELEINE 40 GREEK 

19 ZAPF_HUMANIST 41 KANA 

20 CLASSIC 42 HEBREW 

21 OPTIONAL_SA 43 OPTIONAL_A 


44 RUSSIAN 

45 OPTIONAL_B 
46 OPTIONAL_C 
47 OPTIONAL_D 
48 NARRATOR 

49 EMPHASIS 

50 ZAPF_CHANCERY 
51 OPTIONAL_DA 
52 OLD_ENGLISH 
53 OPTIONAL_DB 
54 OPTIONAL_DC 
55 COOPER_BLACK 
56 SYMBOL 

57 LINE_DRAW 
58 MATH 7 

59 MATH_8 

60 DINGBATS 

61 EAN 

62 PC_LINE 

63 OPTIONAL_SYA 


A typeface that is not supported by the current printer will be mapped to a supported typeface. 
(2) The font style may be zero, or any sensible combination of the following attributes: 


71 


ADDITIONAL SYSTEM INFORMATION 


0x01 underline 
0x02 bold 

0x04 italic 

0x08 superscript 
0x10 subscript 


(3) The running page header alignment may be any one of: 
left aligned 


Styles or style combinations that are not supported by the current pri “y are ignored. 


0 

1 right aligned 
2 centred 

4 2-column 

5 


3-column i 
(4) In terms of the body struct and the page width and height, the page margins are: 


left body. tl.x 

top body.tl.y 

right width-body.tl.x-body.width 
bottom height-body.tl.y-body. height 


(5) The page header position measures the vertical distance between th the bottom of the header text and the 
top edge of the page body print region. 


(6) The page footer position measures the vertical distance between the, bottom of the footer text and the 
bottom edge of the page body print region. 


(7) To print all pages, the last page number should be set to Oxffff. 
(8) The page number style is one of: 


0 Arabic 
1 Roman, upper case 
2 Roman, lower case. 


(9) The body area base font data is not used by word processor documents. It should always specify the 
default font, with font number 0 (Courier) a style of 0 (normal) and a size of 240 (12 points). 


(10) The page size choice should correspond with the earlier page width and height. The following 
(English) page sizes are recognised: 


Choice fed type Width Height 


0 11906 16838 
1 Esai 

2 Executive 10440 15 120 
3 Legal 12240 20160 
4 Letter 12240 15840 
5 Monarch 5580 10800 
6 DL 6236 12472 


Note that items 2 to 6 may be different in non-English versions of the software. 


The record consists of a zero terminated string, containing the full path name of the current printer driver 
file, preceded by a one byte index to the printer model within the file. 


The default value is: 


i) 
MROM: :\BJ .WOR" 


The record contains a5 page ieadnen text as a zero ae ae oie string may not exceed 80 bytes. 


ocese 
eeeceseeeateee 


Then ey contains the page ne text as a zero a tepitndied ring: e. The string may not seed 80 0 bytes. 


72 


| 


6 WORD PROCESSOR FILE FORMAT 


Style data record (type 6. length 80 
The file may contain up 


The following description is in terms of the SCRLAY_FONT struct (described above) and the SCRLAY_ MARGINS, 
SCRLAY_SPACING and SCRLAY_TABSTOP structs, defined as: 7 


typedef struct 
{ 
UWORD left; /* left margin */ (1) 
UWORD right; /* right margin */ 
UWORD indent; /* left margin for first line of a paragraph */ 
UWORD align; /* alignment */ (2) 
} SCRLAY_MARGINS; 
typedef struct 
{ 
UWORD Line; /* space between lines in a paragraph */ 
UWORD above; /* space above paragraph */ 
UWORD below; /* space below paragraph */ 
UWORD flags; /* keep together/next and new page */ (3) 
} SCRLAY_SPACING; 
typedef struct 
{ 
UWORD x; /* tab position */ 
UWORD type; /* tab type */ (4) 


} SCRLAY_TABSTOP; 


In these terms, the content of the style data record is: 


TEXT sc[2] two-letter short code 
TEXT tag(16] style tag name 

UWORD sflags style control flags (5) 
SCRLAY_FONT f paragraph base font (6) 
UWORD inherit inherited attributes (7) 


SCRLAY_MARGINS marg margin positions 

SCRLAY_SPACING spc paragraph vertical spacing 

UWORD olevel outliner level 

UWORD ntabs number of tabstops in following table 
SCRLAY_TABSTOP tab[8] up to 8 tabstops, in ascending position order 


Notes 
(1) Paragraph margins are relative to the page margins (the left and right edges of the body print region). 


(2) The paragraph alignment may be one of: 


0 left aligned 

1 right aligned 

2 centred 

3 justified 

(3) The spacing flags may be any combination of: 

0x01 keep on same page as following paragraph 
0x02 keep whole paragraph on one page 
0x04 paragraph starts a new page 

(4) The tab type may be any one of the following: 

0 left tab 

1 right tab 

2 centred tab 

(5) The style control flags may contain any combination of: 
0x02 undeletable 

0x04 default 


There must be one default style and at least one undeletable style in every document (in all Psion 
documents they are the same - style BT). It does not make sense for the default style to be deletable. 


ee ae ee Se ee 
73 


ADDITIONAL SYSTEM INFORMATION 


(6) In addition to the typeface numbers listed earlier, a typeface canted of -1 is used to signify that the 


typeface and font size are to be inherited from the default style. In such|a case the font size is 
conventionally set to zero. 


(7) The inherited attributes field may contain any combination of: 


0x01 underline 
0x02 bold 
0x04 italic 


For each bit that is set, the corresponding bit in the style field of the SCRLAY_FONT struct must be clear. 
Inherited attributes are taken from the default style. 


The file may contain 


gle emphasis. 


The following description is in terms of the SCRLAY_FONT struct (described above). In these terms, the 
content of the emphasis data record is: 


TEXT sc[2] two-letter short code 

TEXT tag({16} emphasis tag name 

UWORD sflags emphasis control flags (1) 

SCRLAY_FONT f emphasis font (2) 

UWORD inherit inherited attributes (3) 

Notes 

(1) The emphasis control flags must contain the value 0x01, together with any combination of: 
0x02 undeletable 

0x04 default 


There must be one default emphasis and at least one undeletable emphasis in every document (in all Psion 
documents they are the same - emphasis NN). It does not make sense for the default emphasis to be 
deletable. 


(2) In addition to the typeface numbers listed earlier, a typeface n of -1 is used to signify that the 
typeface and font size are to be inherited from the enclosing paragraph|style (which may itself inherit 
from the default style). In such a case the font size is conventionally set to zero. i 


(3) The inherited attributes field may contain any sensible combination of: 


0x01 underline 
0x02 bold 

0x04 italic 

0x08 superscript 
0x10 subscript 


For each bit that is set, the corresponding bit in the style field of the s RLAY_FONT struct must be clear. 


Inherited attributes are taken from the enclosing paragraph style (which may itself inherit from the 
default style). 


sdawa noeeces a aes cocschoscoceaiuid einige nea. V8.6 8m. nineaa hoe N RA gas Leads aie Chae ebigs Lh bape eat beese case sneusnmneesalsacaeaes 
natstorsretatotecetatonenswoteteteegtotete stotetocerer gus tetecotereceretetetatetetatetetstntatststate Bl totcte Mm cosets tstscatesrerensnsceets scentte, JRO RRR, OOO FOS SR COSTE Ske ecto 
Seca tatatiican ee Ee RR ee % OE BO cB dad Salen SO aS Sxeere 
settetescecersrebotce mac mes Pe%e"e’a'e' cx "e’e er erares re PN NN I A IK, 


ere ete a earn e ene" e poe a ase" earn es 


This record contains the entire text of the document. Each paragraph, ee for the final one, is 
terminated by a zero. 1 


The content conforms with the IBM Code Page 850 symbol set, togetiee with the following additional 
symbols: 


HARD_HYPHEN 7 unbreakable hyphen, not a word delimiter 
SOFT_HYPHEN 14 optional, or potential, hyphen 


—__—_—eeeeeeeeeee 


HARD_SPACE 15 unbreakable space, not a word delimiter 
74 | 


6 WORD PROCESSOR FILE FORMAT 


® a length (word) 

= = the two character short code of a style 

= the two character short code of an emphasis 
The entries conform to the following rules: 


= the sum of their lengths is one more than the length of the document text record (i.e. the 
document size, including the final paragraph terminator). 


= there is at least one entry per paragraph 
= the final entry for each paragraph includes the zero that terminates the paragraph 


= the short codes must correspond with styles and emphases contained in the earlier style data and 
emphasis data records 


75 


CHAPTER 7 


WRITING DEVICE DRIVERS 


SN a ee, de ae ee 
Introduction 


This chapter is aimed at the programmer who wishes to write an installable device driver and anyone who 
wishes to improve their general device driver background. The details of communicating with device 
drivers can be found in the J/O System chapter of the PLIB Reference manual. Details of the resident 
device drivers can be found in the appropriate chapters of the I/O Devices manual and the PLIB Reference 
manual. The Borland Turbo assembler was used throughout. See also the following Example Device 
Drivers chapter. 


Psion SIBO machines are supplied with a set of resident device drivers built in to the ROM each of which 
can be replaced with an installable device driver having the same name. Installable device drivers can 
also be added to increase the number of available device drivers. Installing a device driver is carried out 
dynamically without resetting the machine (this is not the case with many operating systems). 


The device driver performs the logical processing required to translate low level hardware instructions 
into high level services suitable for an application. Conventionally, device drivers are divided into a 
logical layer riding astride a physical layer. The physical device driver (PDD) contains the code required 
for talking directly with the hardware device and provides a set of low level hardware specific services. 
The logical device driver (LDD) performs the logical processing that transforms these low level services 
into the high level services used by an application. 


The following example illustrates the two layer nature of device drivers. An application using the serial 
driver decides that it requires RTS/CTS handshaking. It calls an LDD which decides whether or not a 
line should be driven. If the answer is yes the LDD calls the appropriate PDD and asks for a specific line 
to be driven to a specific state. The PDD duly carries out the requested service. 


In the above example the LDD could have talked directly with the hardware. However Psion SIBO 
machines will often use the same LDD with a PDD written specifically for each version of the hardware 
device. Splitting the device driver is thus highly desirable. 


An LDD must provide eight functions for use by the operating system. The functions are passed to the 
operating system via a table of function offsets (sometimes called the vector function table). These 
functions are mandatory. Similarly a PDD must provide two functions for use by the operating system 
and may provide a further two if required. 


An LDD will usually provide further services/functions for use by an application. The form that these 
take is dependent on the LDD requirements and the functions supplied by the associated PDD(s). It is 
advisable to adopt the predefined system defines for these services as this allows the LDD to receive I/O 
requests via the usual route (p_read, p_write etc). 


A PDD will usually define further services specifically for use by LDDs or (less frequently) 
applications. ~ 


The operating system will send device drivers system events not sent to other applications. Examples are 
events generated by the machine being switched on or off, memory segments being moved about and the 
owning application being panicked. 


Any device driver configuration that has associated hardware interrupts must contain at least an LDD. 


The EPOC operating system can handle a maximum of 32 device drivers on a Series3 machine and 48 on 
other machines. 


77 


ADDITIONAL SYSTEM INFORMATION 


The location of device drivers 


Resident device drivers are built into the operating system, with the code residing in the ROM. 


Installable device drivers are loaded into a device memory segment from the file in which they exist. The 
device memory segments are created, owned and managed by the SYS$FSRV process. 


Under no circumstances should any application or device driver attempt to create, delete or change the 
size of a device memory segment. 


Device Driver Names 
Device drivers are known to the EPOC operating system by their names. 


A logical device driver name always has three characters followed by a}colon. For example: 
= Try: is the serial LDD 
= TIM: is the timer LDD 
= SND: is the sound LDD 


A physical device driver name always has three characters followed by|a period, a further three 
characters and a colon. For example: 


@ TTY.UAR: is the 16450 UART driver 
= TTY.AS5: is the ASICS driver 


The first three characters of a PDD name are the name of the LDD to which the PDD belongs. The 
second set of three characters uniquely identify the PDD. In the above examples both PDDs belong to the 
Try: LDD. 


The name of the device driver is the mechanism by which an application can obtain a ‘channel’ to the 
device driver. 
Device Driver Channels 


To obtain a channel to an LDD, an application should call the 100pen operating system service. A channel 
can be opened by calling the PLIB library function p_open. For example: 


»  p_open(&chan,"SND:", -1) 
»  p_open(&chan, "TIM:",-1) | 
To obtain a channel to a PDD, an application should call the DevOpenPDD operating system service. 
Ll pe LDDs open PDDs. The p_open library function can be used to open a PDD indirectly as 
escri ow. | 


For a device driver configuration consisting of an LDD and a PDD the application will usually open a 
channel to the LDD only: the LDD as part of its initialisation would open a channel to the required 
PDD. A channel can be opened by calling the PLIB library function p open. For example: 


=  p_open(&chan, "TTY .UAR:", -1) 


2 p _open(&chan, "TTY.AS5:", -1) 


If the LDD requires a PDD and none is specified, it is up to the LDD to either fail the open request or 
hunt for a loaded PDD that it can use. The tty: device hunts for an ee PDD. 


A device driver may be capable of supporting more than one open channel at a time. In order to 
distinguish the channels, a qualifier can be added to the open request as part of the device name. It is up 
to the device driver to specify the format of the qualifier. By convention channels are allocated a single 
character sequentially from the character 'A'. For example, the parallel driver can support two open 
eae 'A' and 'B'. The LDD requires one of these qualifiers in order to open a parallel driver 
channel. 


*® p_open(&chan,"PAR:A", -1) 
=  p_open(&chan, "PAR:B", -1) 


LDDs have been designed to be accessed via the I/O system. I/O requests on the opened channel will 
reach the ‘strategy vector’ of the device driver. 


78 


7 WRITING DEVICE DRIVERS 
eee 


ase have been designed to be accessed by an LDD either via far calls or the Dewector operating system 
on. 


Searching for PDDs 


In the case that an LDD requires a PDD to provide some hardware specific functionality and the open 
LDD request does not specify a PDD, the LDD should search for a PDD to use. In this case either there 
is only one PDD for that machine (but is different across machines) or the PDDs are capable of 
determining whether it can drive the specified channel. 


For example the serial LDD requires a PDD. However there is currently only one serial PDD on each 
machine (each machine has a different PDD though). By searching for the appropriate serial PDD, the 
serial LDD can be the same on all machines. 


On the other hand there are several filing system PDDs each of which is capable of reading an ID byte 
from a SIBO pack. The PDD can then determine if it is the correct PDD for that hardware or not. 


To search for a PDD, an LDD should use the DevF ind service. For example the Fsy: LDD would search 
for all Fsy.* PDDs. As each PDD is found, it can be requested to open the appropriate channel by using 
the DevOpenPpD operating system service. 


Device Driver Hierarchies And Attached Drivers 
LDDs are classified as either root or attached drivers. 


Device drivers exist in a hierarchy the first of which is termed the root driver. The other drivers in the 
hierarchy are termed attached drivers. In the language of object oriented programming, an attached driver 
subclasses the root driver. In this document, the driver to which another driver is attached is referred to 
as the underlying driver. 


An attached device driver requires the underlying driver to provide a specified set of functions. How 
these are implemented is of no concern to an attached driver. For example, the Xmodem device driver is 
an attached driver which can, for example, attach to the serial driver which happens to be a root device 
driver. The Xmodem driver requires the underlying driver to support the serial sense, serial set, read, 
write and close functions. The power of attached drivers comes from the fact that the Xmodem driver 
does not need to know anything about the physical transmission medium, and can run on either serial 
port quite happily. In fact the Xmodem driver could run over any physical medium e.g. telephone, 
parallel, radio, infra-red etc as long as the underlying driver supported the small set of functions 
required. 


Additional power comes from the fact that a driver does not have to be attached to the root driver 
directly: other attached drivers may exist in the hierarchy. For example an Xmodem driver can be 
attached to a modem driver that provides modem configuration and dialling functions. This can in turn be 
attached to the resident serial driver. 


Notice that the Xmodem driver neither knows nor cares about the driver hierarchy. 
There is no limit to the number of drivers that exist in a device driver hierarchy. 


When the operating system routes an I/O request to a device driver, it follows this hierarchy and calls the 
strategy vector of the device driver at the top of the hierarchy. The device driver at the top of the 
hierarchy is the last opened device driver on that I/O channel. 


The routing mechanism is best explained by an example of an application that wishes to use the parallel 
driver with a timeout facility. In its raw form, the parallel driver does not allow for timeouts. Although 
the application could handle this, a neater solution (in terms of application code) is to use an attached 
driver. The application opens the parallel driver in the normal way and then opens the attached driver 
(written as part of the application) passing the currently opened parallel device channel handle to the open 
vector. The attached driver will open a timer channel for itself and use the IoFuncAttach I/O service on 
the passed opened channel. This request will go to the parallel driver since it is the next down the _ 
hierarchy. The parallel driver, not supporting this function, passes it on to the operating system (using 
the IoRoot service) to perform the attach service. The parallel drivers open channel handle is returned by 
the attached driver to the caller of the 100pen service. From this point on all I/O requests made on the 
parallel drivers I/O channel handle will be directed to the strategy vector of the attached driver first 
which can then process it and pass on any requests it feels necessary. For example, the loFuncWrite 
request would go to the attached drivers strategy vector. It would queue a timer for an appropriate length 
of time and then pass on the !ofuncWrite request to the parallel driver. If the timer expired before the 
write completed, the attached driver would cancel the outstanding write request on the parallel driver and 
inform the application that the timer expired. | 


79 


ADDITIONAL SYSTEM INFORMATION 


In the above example the same attached driver could in fact attach itself to any device driver that requires 
a timeout on the IoFuncWrite request. | 


An attached driver is written in exactly the same way as any other driv r. However, if the driver does not 
support a requested function, the strategy vector of an attached driver calls the 1oSuper operating system 
service rather than the 1oRoot system service. 


Sa ee eC 
Interrupts and Interrupt Service Routines 


Device drivers that talk to hardware tend to have interrupt service routines associated with them, 
especially if they are receiving data from an external source. 

The EPOC operating system provides a framework within which an interrupt service routine can be 
written relatively easily. 


The SIBO architecture allows for eight independent hardware interrupt sources, some of which are pre- 
allocated to system components (see the ASIC1 section of the Hardware Reference manual for details). 


The operating system provides the GenSetRevector service to allow a device driver to install an interrupt 
service routine for any of the eight hardware interrupt sources. 


A device driver should use this system service and not poke directly into the 8086 interrupt vector table. 
The address passed to the GenSetRevector service is not written into the interrupt vector table but to an 
internal table. 


When an interrupt occurs, the operating system builds the mandatory operating system call frame, 
preserving all registers on route. The interrupt service routine is then called as a FAR routine. Since the 
operating system preserves all registers the interrupt service routine is free to use any register. 


To remove the interrupt service routine address, the operating system service GenResetRevector should be 
used. This will reset the internal table entry to the default held in the ROM. 


As with all interrupt service routines various rules apply: 


= Interrupt service routines should execute as fast as possible. Operating system interrupt service 
routines are tuned to last no longer than one millisecond. | 


= Typically, interrupt service routines do not enable interrupts unless the routine can handle 
reentrancy. 


= Interrupt service routines run in the context of whatever pr 3 is running at the time of the 
interrupt. An interrupt service routine should not attempt to obtain admissibility to the process 
that opened the channel but access the internal driver space only which in general is its own code 
space. 


® An interrupt service routine must not directly cause a reschedule as this would significantly 
delay its completion. It must use the IoSignalByP idNoReSched system service in order to indicate 
that an event has occurred to the owning process. The handler|function of the device driver must 
pick up the event and inform the owning process. 


= An interrupt service routine should return with the carry flag clear if it requires a reschedule to 
occur (it has called 1oSignalBy? idNoReSched) otherwise return with the carry flag set. This will 
cause the operating system to reschedule if the internal state allows such an action otherwise the 
reschedule request is effectively queued until such time that the operating system can reschedule. 


Device Driver I/O Semaphore Waithandlers 


An LDD may nominate one of its functions to be called by the operating system every time the I/O 
semaphore of the process that opened the channel is signalled. The nominated function will only be called 
if the application is waiting for an outstanding I/O request to complete, For well written applications this 
is practically all the time. ac 


By convention the vector table entry after the mandatory vectors contains the handler vector. 


A handler routine is similar to an interrupt service routine in that it appears to run ‘from nowhere’. 
Comparing handlers and interrupt services routines shows that: 


80 | 


7 WRITING DEVICE DRIVERS 
eee 


* A handler will always run in the context of the process that has opened a channel. An interrupt 
ceca routine will run in the context of whatever process happens to be running at the time of 
é interrupt. 


2 A handler can access the data space of the process that opened the channel. The interrupt service 
routine must not. An interrupt service routine should only access the data space in the driver 
which is usually its own CS space. 


= A handler can cause a reschedule. An interrupt service routine must not cause a reschedule. If it 
did, the interrupt would not be fully serviced (the rest of the interrupt service routine would not 
be executed until a reschedule back to the process running at the time of the interrupt, which 
may not happen for a significant length of time). The interrupt service routine must only use the 
loSignalByPidNoReSched to signal the channel owner. 


The handler is the mechanism by which hardware interrupt events can be filtered through to the process 
using the I/O channel. 


ee 
Loadable Logical Device Driver Structure 
A loadable LDD must obey the following rules: 

= The must be a single code segment and no data segments. 

s The code segment must start with a Libent structure. 

= There must be at least eight supported functions. 


Single Code Segment 


An LDD must be written to contain any internal variables within its own code segment. In general these 
variables are only concerned with unit allocation and the hardware state. 


Data space for a particular open channel can be allocated in the heap space of the process that opens the 
device. This data space will however disappear if the process terminates. Therefore any variables 
required for 'freeing' the hardware after a process terminates must exist in the code space of the device 
driver. 
The LibEnt Structure 
A Lib€nt structure has the following format: 

= two byte signature 

8 eight byte name 

s two byte vector count 

» A vector table 
The two byte signature should contain the 'LoDSignature’ define. 


The eight byte name contains the name of the device driver stored as a zero terminated string. Note that 
the trailing colon is omitted. 


The two byte vector count contains the number of vectors that follow immediately after the count. This 
should be equal to at least eight. 


For example: 


$1 


ADDITIONAL SYSTEM INFORMATION 


dw LDDSignature s Its an LOD 

db ‘pvr! ,0,0,0,0,0 s Name of the driiver 

dw (VectorEnd-Vector )/2 : Number of vectors 
Vector: 

dw Dvrinstall : Install vector 

dw DvrRemove s Remove vector 

dw DvrHold 3; Hold vector 

dw DvrResume s Resume vector 

dw DvrReset 3; Reset Vector 

dw DvrUnits > Units Vector 

dw DvrOpen 3 Open Vector 

dw DvrStrategy : Strategy vecto 
VectorEnd: 


The vector table contains the offsets within the device drivers code se: t for the functions required by 


the EPOC operating system. Throughout this document the terms vector and function are used 
interchangeably. The vector table must have the entries in the order shown in the example. 


Mandatory LDD Functions 
All LDDs must support the following eight functions: 
= DevFuncinstall called on device installation. 
S DevFuncRemove called on device removal. 
= DevFuncHold called to temporarily disable the driver. 
= DevFuncResume called to enable the driver after it has been temporarily disabled. 
= DevFuncReset called when an application terminates without closing the channel. 
® DevFuncUnits called to query the number of supported units (i.e. channels). 
= DevFuncOpen _callled to open a channel to an LDD. | 
® DevFuncStrategy called to access the device drivers functio ny from the I/O system. 


All of the routines pointed at by the function vector table will be called FAR by the operating system and 
should consequently use a FAR return machine code instruction to we back to the operating system. 


Since the FAR return address is to the operating system it does not matter if the operating system moves 
memory whilst code in the LDD is being executed: the operating system cannot move its own code. 


PoPateaMeteretareMete Pete PeMetetetsetate tet tet Meh ee9, 
*.] Prete rate one” Fat, eesese 
7 voters: 
6 o 6 jegeeee 
ke < ogeeee 
5 e Dc aso 
ERS 


internal variables. It can not be called directly by an application p : 


The Devinstall operating system service will cause this function to be ais Applications should not call 
this service directly and should call instead the DevLoadLDD service. 


An installable device driver may have the same name as a resident device driver and when loaded is 
placed at the end of the device driver table. When the operating system wishes to establish a channel with 
a device driver, it searches for the device driver starting at the end of the table. It will thus find the most 
recently loaded device driver having the required name. By this mechanism an installable device driver 
can replace a resident device driver of the same name. 


An installable device driver may have the same name as a resident device driver. When the operating 
system loads a device driver, it places it at the end of the device driver table. The operating system will 
search this table for the appropriate device driver when it wishes to establish a channel. The search starts 
at the end and thus will locate the most recently installed device driver (if any) or if not, the resident 
driver. By this mechanism an installable driver can replace any resident driver. 


When called, the DS and ES segment registers are in an unknown state| The device driver should take 
whatever steps necessary to obtain direct addressability to its data. For|loadable device drivers this 
involves setting the DS and ES registers to the CS register. 


The operating system will not move memory whilst in this function, thus the normal rules governing DS 
and ES may be ignored. 


All operating system services may be called, except those concerning file or device access. 


—=—_—_ 


| 


called by the operating system when the device driver i loaded in order to initialise any 


7 WRITING DEVICE DRIVERS 
a 


PASSED 
No values are passed to the install vector. 


RETURN 
If the installation was successful, return with the carry flag clear. 
If the installation failed, return with the carry flag set and the error number in the AL register. 


PANIC 
The install vector must not panic: it will cause an operating system kernel fault if it does. 


PRESERVE 
The SS, SP and BP registers must be preserved by the install function. 


It can not be called directly by an application process. 


The DevRemove operating system service will cause this function to be called. Applications should not call 
this directly, they should use the DewDelete service. 


Before the remove function is requested, the device driver will have received a hold request. Thus 
devices will only ever be removed when in a held state. 


If the device driver is currently busy serving a client, the remove request should return an error. 


All resident device drivers will return an error since there is no mechanism by which they can be re- 
installed. 


When called, the DS and ES segment registers are in an unknown state; the device driver should take 
whatever steps necessary to obtain direct addressability to its data. For loadable device drivers this 
involves setting the DS and ES registers to the CS register. 


The operating system will not move memory whilst in this function, thus the normal rules governing DS 
and ES may be ignored. 


All operating system services may be called, except those concerning file or device access. 


PASSED 
No values are passed to the remove vector. 


RETURN 
If the remove was successful, return with the carry flag clear. 
If the remove failed, return with the carry flag set and the error number in the AL register. 


PANIC 


The remove vector must not panic: it will cause an operating system kernel fault if it does. 


PRESERVE 
The SS, SP and BP registers must be preserved by the remove vector. 


. 
atetstetatatenenatotateter 


2,2 ,0.0,8,8, 


; NOSOS ase 

OVE 
5 a OR Sate 

Saretetetetoconeneteterenoresetetesesesey 


This vector will be called by the operating system when the device driver is requested to be held. The 
hold vector is called in the context of the operating system. 


The Deviold operating system service will cause this vector to be called. Applications should not call this 
service. 


The operating system will call the hold vector under three conditions: 
=» Device memory segments are about to be moved. 


83 


ADDITIONAL SYSTEM INFORMATION 


s The machine is about to switch off due to the auto switch off timeout or user request, it enters 
the standby state. 


s The machine is about to switch off due to the power source being removed. 


In all cases the device driver must respond to the request as quickly as possible. It must also ensure that 
ALL interrupts from the hardware device that it is driving are disabled! 


Device memory segments can only be moved if an installable device iver is being installed or removed. 
If the LDD uses an attached PDD and uses the faster FAR call mechanism to call the PDD strategy 
vector, the PDD strategy vector address will potentially move, thus the FAR address will be wrong. This 
address can be resolved in the resume vector. The LDD must not call the PDD between a hold and 
resume. Typically, the device driver only needs to disable its interrupts. When a resume occurs, the 
device driver should continue as though nothing had happened. 


If the machine is about to switch off due to the auto switch off or user request mechanisms (enter the 
standby state), the device driver should make an orderly shut down of the device such that the state 
before the shut down can be recovered when the system powers up again. The device driver should also 
attempt to ensure that no data is lost. For example, in the serial driver the current state of the hardware 
handshaking lines should be noted so that each state can be restored on power up. For this type of power 
down the hold vector is allowed to take a significant length of time to shut down a device. For example 
in a serial driver the hold vector should wait until the remote end stops transmitting data after any 
hardware handshaking has been applied. Of course, the time taken should be kept to a minimum: in the 
case of the serial driver above the time is roughly equivalent to 3 character transmission times. When a 
resume occurs the device driver should continue as though nothing had happened. 


If the machine is about to switch off due to the power source being removed, the device driver should 
reset the device in the minimum possible time: no attempt should be made to perform an orderly shut- 
down. The device driver is not expected to be able to recover the hardware state. When a resume occurs, 
the device driver would typically fail any outstanding application requests. If the hold vector takes too 
long the voltage will fall below the threshold to hold the state of the internal RAM. If this occurs the 
machine will perform a warm re-boot when powering up, all data in the internal memory of the machine 
bebe be lost including the device driver code! On power fail there is about 2ms available to power down 
devices. 


On a power failure hold, the operating system will already have sent a |reset' to all the SIBO serial 
channels. Any device drivers using these channels need only record the hold reason for the resume 
vector. Any other peripherals should be designed to allow a power faill mechanism with the minimum 
amount of code. 


It must be noted that the power fail type hold can occur whilst the device driver is in the memory move 
hold state. In this case, the device driver will receive two hold requests before seeing a resume request. A 
device driver must be capable of handling this. In this case, the device |driver will also receive two 
resume requests. A device driver will not get a power fail hold whilst in power down hold. 


A call to the hold vector will always be followed by a call to the e vector (except when a device is 
requested to be removed). 


When called, the DS and ES segment registers are in an unknown state: the device driver should take 
whatever steps necessary to obtain direct addressability to its data. For|loadable device drivers this 
involves setting the DS and ES registers to the CS register. 


The device driver should not call any operating system services due to the time taken, especially on 
power failure. 


PASSED 
The AH register takes one of the following 
= DevioldNormal Device memory is about to be moved 
= DevioldPowerDown The system is about to enter the eas State. 
= DevHoldPowerFail The system has lost its power supply. 
RETURN 
None. 
PANIC 


The hold vector must not panic: it will cause an operating system it fault if it does. 


84 


7 WRITING DEVICE DRIVERS 


PRESERVE 
The SS, SP and BP registers must be preserved by the hold vector. 


The DevResune operating system service will cause this vector to be called. Applications should not call 
this service. 


The resume vector will be called either when memory has finished being moved or when the machine 
powers back up. In both cases the hold vector will have been called before this vector is called. 


The device driver is expected to recover from the previous hold request (except power fail) and resume 
any I/O that was suspended. 


If the device driver has an interrupt service routine, it should reset the interrupt service routine's address 
since the device driver may have moved in memory; its absolute segment address will be different. 


If the hold was a device memory segment move type hold, interrupts should be re-enabled. If the LDD 
uses an attached PDD and uses the FAR call mechanism to access the PDD strategy vector, the address of 
the PDD should be reset by using the DevGetPDDAddress operating system service before enabling 
interrupts. Typically, the PDD will have a call back to the LDD and it needs to be informed of the 
change of address of the LDD call back function; the LDD-PDD interface definition should allow such a 
function request. 


If the hold was a power down type hold, the resume vector needs to power up the peripheral and set it to 
the state that it was in before the power down occurred. If this is not possible or data has been lost, the 
device driver should inform any outstanding requests of this fact. 


It is also possible that the hardware device that the driver is associated with has been removed. The 
driver should be able to handle this properly. 


If the device driver is expected to generate events due to an external state change, the driver should check 
the external state and generate appropriate events. For example, the serial driver may be requested to 
inform an application when the DTR line changes state. The remote end may have changed the state of 
DTR whilst the driver is held. 


If the hold was a power failure type hold, the resume vector should power up the peripheral and put it 
into a known state, preferably the state that the application software thinks that the device is in and fail 
any outstanding requests as data is quite likely to have been lost. 


When called, the DS and ES segment registers are in an unknown state. The device driver should take 
whatever steps necessary to obtain direct addressability to its data. For loadable device drivers this 
involves setting the DS and ES registers to the CS register. 


All operating system services may be called, except those concerning file or device access. 


PASSED 


None 


RETURN 


None. 


PANIC 
The resume vector must not panic, it will cause an operating system kernel fault if it does. 


PRESERVE 
The SS, SP and BP registers must be preserved by the resume vector. 


channel. The reset function is called in the context of the operating system. 


85 


ADDITIONAL SYSTEM INFORMATION 


1 
I 


The device driver must request that the operating system call the reset function. This is achieved by C) 
calling the IoRequestReset system service, usually in the open vector. To cancel this request, the device | 
driver should call the 1oRequestResetCancel system service. The cancel |service is usually called as part of 

the close functionality in the strategy vector. 


The reset vector will be called when the operating system is tidying up) resources owned by a process that 
has terminated. If a process terminated before it closed the device driver channel and no reset service is 
requested, that channel would remain allocated; no process will ever close the channel. The reset vector 
allows a device driver to reset itself and allow the channel to be opened again. 


| 


Any data required to perform the reset must be stored in the device driver. The data space belonging to 
the process that originally opened the channel has been returned to the joperating system memory pool 
and is no longer valid. 


If a device driver can handle multiple channels then the data passed to the IoRequestReset system service 
should identify the channel. This data will be passed in the CX register to the reset vector. 


The device driver should only have a reset request outstanding with the operating system while a process 
has a channel open. 


When called, the DS and ES segment registers are in an unknown state; the device driver should take 
whatever steps necessary to obtain direct addressability to its data. For loadable device drivers this 
involves setting the DS and ES registers to the CS register. 


All operating system services may be called, except those concerning file or device access. 


PASSED 
This function is passed data in the CX register that the device driver requested it be sent to determine 
which channel should be reset. 


RETURN 


None. 


PANIC 


The reset vector must not panic; it will cause an operating system kernel fault if it does. 


PRESERVE 
The SS, SP and BP registers must be preserved by the reset vector. 


The operating system places no significance on the number of channels a device driver can support. It is 
primarily used for informational purposes. 


fa application may use the number of units to attempt to open any re channel on that device 
ver. 


When called, the DS and ES segment registers are in an unknown state; the device driver should take 
whatever steps necessary to obtain direct addressability to its data. For loadable device drivers this 
involves setting the DS and ES registers to the CS register. 


All operating system services may be called, except those concerning file or device access. 


PASSED 


None. 


RETURN 


The AX register should contain the number of channels supported. If a device driver can support multiple 

channels (limited only by memory constraints) then the driver may return -1. A serial device driver, for a 
example, might only support two channels (TTY:A and TTY:8) whereas the file device driver can open an 
unlimited number of files. 


86 


7 WRITING DEVICE DRIVERS 
—— eee 


PANIC 


The channels units vector must not panic; it will cause an operating system kernel fault if it does. 


PRESERVE 
The SS, SP and BP registers must be preserved by the units vector. 


The device driver is passed two parameters, its device handle and a pointer to an Open€nt structure. 


The device handle is the entry in the system device table of this device driver. The device driver is 
required to place this handle in the Chant ibandle field of the Chan€nt structure which must be allocated in 
the user's data space. The operating system uses the device handle to route any I/O requests on the 
opened channel to the correct device driver. 


The OpenEnt structure contains three fields, OpenNamePtr, OpenMode and Openchan. 


The OpenNamePtr field contains a pointer to the character that exists after the device name as passed to the 
IoOpen system service. For example, if the 1o0pen service was passed a name of PAR:A, the OpenNamePtr 
field would point to the colon. If the 1o0pen service was passed a name of TTY.AS5:8 the OpenNameptr field 
would point to the full stop. The device driver should process the name appropriately, opening the 
correct PDD as required. 


The OpenMode field contains the mode for opening the device driver. The available modes are specified by 
the device driver writers. For example, a combined Xmodem and Ymodem device driver could use the 
mode to specify whether the Xmodem or the Ymodem protocol is to be used. 


The Openchan field contains the I/O channel handle of the device that this driver is required to ‘attach’ to. 
Attached device drivers are dealt with later in the chapter. 


The code in a device driver open vector tends to follow a very similar pattern. This is demonstrated by 
the following code fragments and associated comments. 


The first stage is to allocate some data space in the calling process’ heap space. This will contain the I/O 
channel control block: 


mov cx, (size DeviceEnt) 

HeapAl LocateCel | 

jc noMemory 

mov bx, ax 3; cell handle 


If the device driver requires a WaitHandler (described later): 


mov al, (VectorHandler-Vector)/2 
IoAddHandler 

jc endFreeMemory 

mov [bx] .DriverHandler, ax 


If the device driver's DevFuncReset vector is required to be called: 


push bx 

mov cx, Channel Indicator 3 unique per channel 
mov bx, dx s the device handle 
ToRequestReset 

pop bx ; restore alloc cell 


The ChanEnt field of the DriverEnt structure must be initialised: 


mov [bx] .Driverlo.ChanNext, bx 
mov [bx] .Driverlo.ChanSignature, IoChanSignature 
mov [bx] .Driverlo.ChanLibHandle, dx 


The ChanNext field is used by attached drivers and will usually be set to be the allocated cell handle of the 
device driver being opened. The IoFuncAttach and loFuncDetach functions manipulate these fields. The 
I/O system uses this field to direct the I/O request to the correct driver. 


87 


ADDITIONAL SYSTEM INFORMATION | 


The ChanSignature field is checked by the operating system during any ” requests for the value 
IoChanSignature. If it does not contain that value, the process calling the I/O service will be panicked for 
having passed an invalid I/O channel handle. 


The ChanLibHandle field is used by the operating system to route an application's I/O request to this 
device. The I/O request will call the DevFuncStrategy vector of the device driver. 


If the driver is an attached driver the following is required: 


mov cx, bx : allocated channel 
mov bx, [si] .OpenChan * channel attaching to 
mov al, lIoFuncAttach s return in BX the 
ToWwithwWait s channel attached to 


Finally, if the channel has been successfully opened: 


cle ; Opened Ok 
ret s return BX and DX 


The error recover code typically follows the following pattern: 


endF reeReset: 
push ax 
push bx 
mov cx, Channel Indicator 
mov bx, dx 
ToRequestResetCancel 
pop bx 
pop ax 
endF reeHandlter: 
push ax 
push bx 
mov bx, [bx] .DriverHandler 
ToRemovelandler 
pop bx 
pop ax 
endF reeMemory: 
push ax 
HeapFreeCel l 
pop ax 
stc 
noMemory: 
ret 


If a device driver supports a fixed number of channels, it typically contains static control blocks. In order 
to determine if a requested channel is currently open, a field should be interrogated. The device driver 
should ensure that interrupts are disabled during this sort of check since a context switch could occur and 
another process request the opening of the same channel. This is the classic 'test and set' problem 
encountered in multi-tasking environments. 


When called, the DS and ES segment registers point to the data segment of the application process 
attempting to open a device channel. The application should ensure the DS and ES segment registers 
do in fact point to its data segment. The device driver must obey the normal rules concerning segment 
register manipulation. The DS and ES segment registers can be reloaded if required from the Intent 
structure pointed at by the BP register. 


All operating system services may be called. | 
PASSED 

DX contains the device handle of the device driver. 

SI is a pointer to the OpenEnt structure 

BP is a pointer to the IntEnt structure. 


RETURN 


If the channel open was successful, return with the carry flag clear and the BX register containing the 
open channel. 


If the open failed, return with the carry flag set and the error number in the AL register. 


88 


7 WRITING DEVICE DRIVERS 


PANIC 


The open vector can panic; it will cause the process requesting the device open to terminate. It is 
however more usual to return an error to the calling process. 


PRESERVE 
The DS, ES, SS, SP, BP and DX registers must be preserved by the open vector. 


not have to support any particular function, as it is a matter of design between a device driver writer and 
application writer as to what functions and associated parameters are provided. 


To obtain the power of attached device drivers, it is recommended that the device driver use the system 
defines with their appropriate functionality, for example, the loFuncWrite function number should always 
be associated with writing data. 

The strategy function is passed the channel handle as allocated in the open vector in the BX register. This 
typically contains control information concerning the current state of the I/O channel. 


The SI register contains a pointer to a RqEnt structure. This structure contains four fields, RqFunction, 
RqgStatusPtr, RoA1Ptr and RaA2Ptr. 


The RqFunction field contains the function number as passed to the IoWithWait (or loAsynchronous) I/O 
request by the application. If a device driver does not support the specified function, it should pass the 
request on to its ‘parent’ device driver. 


The RqStatus pointer contains a pointer to a memory location in the application process's data space that 
receives the I/O requests completion status. The device driver must set this memory location to the value 
PendingErr whilst the I/O request is outstanding and a completion code when the I/O request completes. 
An I/O request may complete within the strategy vector or it may complete some time in the future, 
presumably from some interrupt. 


The RqA1Ptr and RqA2Ptr fields contain the argument 1 and 2 parameters as passed to the IoWithwait (or 
IoAsynchronous) system services. The device driver is free to specify what these parameters are (if any). 


The operating system defines a set of common function numbers used by device drivers referred to as the 
loFuncxxx set of defines. By convention, a device driver should select from this list, particularly if some 
of the more advanced features of the I/O system are to be used, such as attached device drivers. The more 
common defines are: 


= loFuncRead ; read from the device. 

® IlofuncWrite ; write to the device. 

@ toFuncClose ; Close device channel. 

® oFuncCancel ; cancel an I/O request. 

® loFuncSet ; set driver characteristics 

=  loFuncSense ; sense driver characteristics. 
® oFuncF lush ; flush any buffers. 


The PLIB library functions p_read, p_ write and p_close will call the device driver with the 1oFuncRead, 
loFuncWrite and IoFuncClose function numbers. Thus, if the device driver choses an alternative function 
number set, an application will not be able to use the supplied library functions. 


All resident device drivers obey the following conventions: 
= Acancel request will cancel any outstanding requests. A cancel request will not return any error. 


=» Aclose request will ensure that any outstanding requests are completed before closing the 
channel. A close request will not return any error. 


= Only one request of a particular type can be outstanding at any one time. If a second request is 
made the device driver will panic the calling application. 


89 


ADDITIONAL SYSTEM INFORMATION | 


Any functions that the strategy function does not support should be sasbed on to the next driver down the 
driver hierarchy. If the driver is a root driver (attached driver), this is achieved using the 1oRoot 
(I1oSuper)system service. If the requested function is not supported by any driver, the operating system 
will return a NotSupported error. 

When called, the DS and ES segment registers point to the data segment of the application process 
making the I/O function request. The application should ensure that the DS and ES segment registers do 
in fact point to its data segment. The device driver must obey the normal rules concerning segment 
register manipulation. The DS and ES segment registers can be reloaded if required from the Intent 
structure pointed at by the BP register. 


All operating system services may be called. 


PASSED 

BX contains the allocated channel control block. 
DX contains the device handle of the device driver. 
SI is a pointer to the RgEnt structure. 

BP is a pointer to the IntEnt structure. 


RETURN 


If the function request is successful, the strategy vector should return with carry clear. A request 
typically causes some I/O. If the I/O is completed by the strategy vector (eg the close function), the 
completion status should be written back to the RqStatusPtr location and the I/O semaphore signalled 
(using the IoSignal system service). If the request has not yet completed, the RqStatusPtr location should 
contain the value PendingErr and the I/O semaphore should not be signalled. 


If the function request failed the strategy vector should return with set and the error code in AL. 
Typically no I/O requests will be completed. 


PANIC 


The strategy vector can panic; it will cause the process making the I/O request to terminate. In most cases 
it is usual to return an error to the calling process. A major exception to this is if the calling process 
makes an I/O request of the same type as one that is currently outstanding and the device driver only 
supports one I/O request of a particular type at a time; by convention the device driver should panic the 
calling process with the PanicloPending panic code. | 


PRESERVE 
The DS, ES, SS, SP and BP registers must be preserved by the strategy vector. 


Loadable Physical Device Driver Structure 
A loadable PDD must obey the following rules: 
= There must be a single code segment and no data segments. 
« The code segment must start with a LibEnt structure. 
= There must be at least two supported functions, with typically|a further two defined. 


Single Code Segment 


A PDD must be written to contain any internal variables within its own code segment. Typically, these 
variables are only concerned with unit (i.e. channel) allocation and hardware state. 


Data space for a particular open channel can be allocated in the heap ig of the process that opens the 
device. This data space will however disappear if the process terminates, thus any variables required for 
‘freeing’ the hardware after a process terminates must exist in the code/space of the device driver. 


The LibEnt Structure 
A LibEnt structure has the following format: 


90 


7 WRITING DEVICE DRIVERS 


—— eee 
2 A two byte signature 
= An eight byte name 
= A two byte vector count 
# A vector table 
The two byte signature should contain the "PDDSignature' define. 


The eight byte name contains a zero terminated name, being that of the device driver. Note that there is 
no trailing colon. 


The two byte vector count contains the number of vectors that follow immediately after the count. There 
should be at least two. 


For example: 
dw PDDSignature ; Its an PDD driver 
db "DVR .HW1' 0 ; Name of the driver 
dw (VectorEnd-Vector )/2 ; Number of vectors 
Vector: 
dw Dvrinstalt ; Install vector 
dw DvrRemove ; Remove vector 
VectorEnd: 
Most PDDs also define a further two vectors: 
dw DvrOpen : Open Vector 
dw DvrStrategy : Strategy vector 


The table of vectors is a table of offsets within the device drivers code segment of the routines that 
implement the required functionality. The vector table must have the entries in the order shown in the 


example. 


Mandatory PDD functions 
All PDDs must support the following two functions: 


® DevFuncinstal LPDD called on device installation. 
S DevFuncRemovePDD called on device removal. 
Most PDDs will support the following two additional functions: 
® DevFuncOpenPDD called to open a PDD 
= DevFuncStrategyPDD called to provide PDD functionality 


All of the routines pointed at by the function vector table will be called FAR by the operating system and 
should consequently use a FAR return machine code instruction to return back to the operating system. 


Since the FAR return address is to the operating system, it does not matter if the operating system moves 
memory whilst code in the LDD is being executed; the operating system cannot move. 


by the operating system when the device driver is loaded to initialise any of its 
internal variables. The install vector is called in the context of the operating system and not the process 
that is loading the device driver. 


The Devinstall operating system service will cause this vector to be called. Applications should not call 
this directly, they should use the DevLoadPpD service. 


An installable device driver may have the same name as a currently installed device driver. When 
installed, the driver is added to the end of the device driver table. When a channel to a device driver is 
being established by the operating system, it searches the device table from the end first, thus the latest 
installed device driver with the required name will be asked first for a channel. By this mechanism, 
installable device drivers can replace any of the resident drivers. 


When called, the DS and ES segment registers are in an unknown state. The device driver should take 
whatever steps necessary to obtain direct addressability to its data. For loadable device drivers this 
involves setting the DS and ES registers to the CS register. 


91 


ADDITIONAL SYSTEM INFORMATION 


| 
The operating system will not move memory whilst in this function, as the normal rules governing DS 
and ES may be ignored. 


All operating system services may be called except those concerning file or device access. 


PASSED 
No values are passed to the install vector. 


RETURN 
If the installation was successful, return with the carry flag clear. 


If the installation failed, return with the carry flag set and the error —" in the AL register. 


el fault if it does. 


PANIC | 
The install vector must not panic; it will cause an operating system | 


PRESERVE 
The SS, SP and BP registers must be preserved by the install vector. | 
| 


driver is requested to be unloaded. 
The remove vector is called in the context of the operating system and not the process that requests the 
unload. 


The DevRemove operating system service will cause this vector to be called. Applications should not call 
this service directly; instead, they should call the DevwDelete service. 


Before the remove function is requested, the operating system will send a DevFuncHold request to all 
LDDs. The LDD is responsible for ensuring that no activity will occur during the remove. Note that any 
device driver that handles hardware interrupts must contain an LDD since only LDDs receive a hold 
request. 


If the device driver is currently busy serving a client, the remove request should return an error. 


All resident device drivers will return an error since there is no mechanism by which they can be re- 
installed. 


When called, the DS and ES segment registers are in an unknown state; the device driver should take 
whatever steps necessary to obtain direct addressability to its data. For loadable device drivers this 
involves setting the DS and ES registers to the CS register. 


The operating system will not move memory whilst in this function, thus the normal rules governing DS | 
and ES may be ignored. 


All operating system services may be called except those concerning file or device access. 


PASSED 
No values are passed to the remove vector. 


RETURN 
If the remove was successful, return with the carry flag clear. 
If the remove failed, return with the carry flag set and the error number in the AL register. 


| 
PANIC 


The remove vector must not panic; it will cause an operating system ~~ fault if it does. 


PRESERVE 
The SS, SP and BP registers must be preserved by the remove vector. 


92 


7 WRITING DEVICE DRIVERS 


When an application opens a channel to an LDD, it normally uses the 1o0pen system service. If the name 
specifies, or the LDD requires, a PDD then it needs to open a channel to a PDD. The Devopenppp system 
service will call this PDD vector to establish a channel. The LDD now has a choice of calling a PDD 
vector using the Dewector system service or calling the fourth vector in the vector table directly. The 
fourth vector is assumed to be a strategy vector to which any parameters as required by the LDD-PDD 
interface can be passed. The FAR address of the strategy vector is returned by the DevGetPpDAddress. 
When an LDD receives a DevFuncResume it should call DevGetPDDAddress again to ensure that if the PDD 
has moved the LDD still has its correct address. 


As a design, a PDD could provide many vectors, one for each required function. The LDD would then 
use the Dewector system service to access each of these functions. The DevGetPpDAddress will only return 
the FAR address of the fourth vector. 


When called, the DS and ES segment registers point to the data segment of the application process 
making the open function request. The application should ensure that this is indeed the case. The device 
driver must obey the normal rules concerning segment register manipulation. 


All operating system services may be called. 


PASSED 


The BX register contains a pointer to the PDD unit name. The pointer passed to the DevOpenPpD service is 
used to find the PDD device to open. The BX register is loaded with a pointer to the trailing colon (if 
any) in the PDD unit name. For example if the name TTY.AS5:A was passed to the DevOpenpDD service, BX 
would contain a pointer to :A upon calling the open vector. 

RETURN 

If the open was successful, return with the carry flag clear. 


If the open failed, return with the carry flag set and the error number in the AL register. 


PANIC 
The open vector can panic; it will cause the process requesting the device open to terminate. It is 
however more usual to return an error to the calling process. 


PRESERVE 
The SS, SP and BP registers must be preserved by the open vector. 


Typically, all application function requests are routed through the strategy vector. To speed the calling 
interface, the DevGetPDDAddress operating system function will return a FAR address of this vector. 


The device driver writer defines all the functions and return values as required. 


When called, the DS and ES segment registers point to the data segment of the application process 
making the function request. The application should ensure that the DS and ES segment registers do in 
fact point to its data segment. The device driver must obey the normal rules concerning segment register 
manipulation. 


All operating system services may be called. 


PASSED 
The parameters passed are defined by the device driver write. 


RETURN 
All returns are defined by the device driver writer. 


93 


ADDITIONAL SYSTEM INFORMATION 


PANIC 


The strategy vector can panic; it will cause the process requesting the function to terminate. It is however 
more usual to return an error to the calling process. 
{ 


PRESERVE 
Which registers are preserved is defined by the device driver writer. 


94 


CHAPTER 8 


EXAMPLE DEVICE DRIVERS 


This chapter contains explanatory notes for the example device drivers supplied with the Psion C SDK. 
aad ae code for these examples can be found in \sibosdk\ldd. The Borland Turbo assembler is used 
ugnout. 


See also the preceding Writing Device Drivers chapter and the appropriate chapters in the I/O Devices 
Reference manual. 


ee ee 
An Attached Device Driver Example 


The code in atimdvr.asm contains an example of an attached device driver. Attached drivers add 
functionality to, or replace, a service provided by an underlying device driver. The example is a generic 
timeout device driver that adds a timeout facility to the underlying device driver's P_FREAD requests. The 
example driver may be attached to either the serial or the parallel drivers. 


The example code in ¢_atim.c shows how the device driver is loaded and attached to a serial driver. It 
also ponte tl the additional functionality becomes transparent to the application once the driver has 
been attached. 


The device table 


The start of the file consists of the device driver header. The name of the driver is specified to be ATM. 
The driver is an LDD type driver consisting of nine callable functions, the first eight of which are 
mandatory. The ninth function (a wait handler) is required by the device driver to function correctly. 


Note that the following notes apply specifically to the functions as used in the example driver. 


The Install Function 


The install function does not have to perform any actions apart from report that it has completed 
successfully. 


The Remove Function 


The remove function does not have to perform any actions apart from reporting that it has completed 
successfully. This makes the reasonable assumption that the user of the device driver will not attempt to 
remove it if it is associated with any open channels. 


The Hold Function 
The hold function is not required to do anything since it does not access or use hardware directly. 


The Resume Function 


Since the hold function does not do anything that needs to be undone, the resume function is not required 
to do anything (otherwise it might have performed tasks such as stopping interrupts, shutting down 
hardware etc). 


The Reset Function 


The reset function is not required to do anything: it can never be called since the driver does not ask the 
operating system to call this function if its client terminates without closing an open channel. The timer 


95 


ADDITIONAL SYSTEM INFORMATION | 


! 


device driver and the driver attached to are responsible for releasing system resources if a client 
terminates. Thus this driver can leave it up to those drivers to tidy up. | 


The Units Function 


The driver can support an unlimited number of open requests subject ; system memory and timer 
channel availability. | 


The Open Function 


The open function is called by the operating system when an applicatioy uses the IoOpen system service to 
open the ATM: device. This is usually done via the PLIB library function p_open. 


The open function runs in the context of the process that makes the open request. Thus resource 
allocation (e.g. memory allocation requests) will be associated with process. 


The open function allocates enough memory to hold all of the required |internal variables and if itialises 
the memory to zero. It then makes function nine in the device table a wait handler function by jusing the 
loAddHandler system service. This installs the function in the linked list of wait handler functions. The 
wait handler by default is not callable, and should, for performance reasons, only be made callable when 
it has some processing to do. 7 


A channel to a timer device is opened, the name TIM: is generated on T. run time stack. 


The I/O system channel header is set up, the I/O system requires that 
structure as the first item in the allocated cell. 


Finally, if all has gone well, our driver attaches itself to the underlying driver whose already open handle 
was passed to the open function. 

If any errors occur, the device driver is responsible for tidying up all of the currently allocated resources. 
It may be noted that any I/O requests made by the device driver on its own channel (as allocated) after 
the attach request has been made will be routed to the underlying driver rather than starting from the top 


of the driver chain. Thus for example in the CancelRead procedure the loFuncCancel request ill be routed 
to the strategy function of the ‘attached to' driver and not to the strategy function of our attached driver. 


device driver has a ChanEnt 


The Strategy Function 


Once opened, the strategy function will be called when an application makes an I/O request. All I/O 
requests on the open channel will be routed to our example driver which must decide how they are to be 
handled. Some I/O requests are not recognised by the example driver and should be passed to the 
underlying driver. This may be done using the 1oSuper system service (note that a root device driver 
would make an IoRoot system service request to pass on any meaningless I/O requests). 


Some requests may be redefined; the example driver redefines the meaning of the lofuncSet and 
loFuncSense (P_FSET and P_FSENSE) services to allow an application to set and sense the timeout| values to 
use. The application that attaches the example driver to the serial driver must be careful when ing these 
services, since they produce different results depending on whether the time out driver has been attached 
or sash ns one case they set and sense the serial characteristics and in T other they set and sense a time 
out value). 


Some requests may be modified to enhance them; this driver enhances the IoFuncRead (P_FREAD) service 
and, as a side effect, the loFuncCancel (P_FCANCEL) service causing the read request to time out./ This type 
of modification is transparent to an application. It may use the IoFuncRead service identically regardless of 
whether this time out driver has been attached (the IoFuncRead service will of course not time dut if this 
driver has not been attached). 


“Because the 1oFunckead service effectively runs two I/O requests, that i the lower driver's loFUncRead and 
a timer channel's loFuncRead, both requests must be cancelled by the example driver if the application 
wishes to cancel the original request. Thus the example driver is required to add functionality to the 


loFuncCancel service. 


It should be noted that an loFuncClose (P_FCLOSE) request should only detach itself from the lower driver 
and release any resources allocated by this drivers open function. It should not attempt to pass| on the 
IoFuncClose request to the lower level driver (after a detach the I/O system will no longer be able to route 
any I/O requests to a lower driver). 


The Wait Handler Function 


When an application makes an 1oFuncRead request, the example driver makes two asynchronous I/O 
requests, one on the timer and one on the lower driver. In order for the device driver to gain some 


| 
96 


8 EXAMPLE DEVICE DRIVERS 


processing time, so as to find out what happened to these requests, it needs to enable the already installed 
wait handler routine. When the I/O semaphore is signalled, the wait handler function will be called by 
the operating system (only if the application is currently waiting for an I/O request to complete) so it can 
check to see if either of the two asynchronous requests that it made have completed. 


It is possible that neither of the outstanding requests has completed in which case the wait handler 
function should return with the carry flag clear. 


If either of the outstanding requests has completed, this driver cancels the other request using up the 
signal generated by cancelling. The wait handler should return with the carry flag set and the AL register 
set to zero since there is no more processing to do at this time. 


Although synchronous I/O requests are used within the wait handler (in cancelling and using up signals) 
the wait handler will not be called, i.e. it is not called re-entrantly by the operating system. 


Non Interrupt Based Sound Driver | 


The code in snddvr.asm contains an example of a root device driver that does not require interrupt 
service routines. 


The driver accesses the sound chip within the Series3 and can play notes passed to it from an application. 


The sound system within a Series3 can only be accessed by a single process at a time. The operating © - 
system has some state variables that can be used (via system services) as mutual exclusion semaphores. 


When the channel to the sound driver is opened, it requests exclusive use of the sound system. When the 
channel is closed it releases this resource. The hardware sound device is switched on only when sound i is 
to be played. 7 cs 


The example device driver times the duration of the notes using a system timer. This limits the device : 
driver to ten notes per second as the system timer can not go beyond a resolution of one of. a 
second. This is not a particularly high resolution for the note duration. pe a 


As well as the system timer, the device driver makes use of a wait handler function in order aie the “: 
notes. as 


The example code in t_mus.c shows how the device driver is loaded and the functions provide a are used 
to generate sound. ; 

The device table s 

The start of the file contains the device driver header. The name of the driver is specified to be mus:. The 
driver is an LDD type driver consisting of nine callable functions, the first eight of which are mandatory. 
The ninth function (nominated to be a wait handler function) is required by the device driver to function 

correctly. 


Note that the following notes apply specifically to the functions as used in the example driver. 
WANE! 


The Install Function 


The install function should indicate that the device driver has no channel open on it yet. This variable. (in 
the device driver space) is required to know how to handle the remove, hold and resume Pare 7 


The Remove Function 


If the device driver currently owns the sound channel, the remove function will stop the playing of — 
and release to the operating system the sound channel resource. ee 


In the normal course of events, the remove function would not be called when an eppiicaiiba has an open 
channel to the device driver. It is however quite possible for this to occur and a device driver should — 
accommodate such a possibility. The StopSound routine and HwFreeCombo operating system service should 
only be called if the driver owns the sound channel otherwise any sound and ownership from other device 
drivers (e.g. alarms) will be ecversey affected when this driver is removed. _ oe 


ae ie 


The Hold Function 


The hold function will stop any sound that is currently being made if this driver currently owns the 
systems sound resource. This device driver does not attempt to determine how far through the current _ 
note (duration) it has got. When the resume function is called, the following note (if any) will be played. 


97 


_ ADDITIONAL SYSTEM INFORMATION | 


The Resume Function 


The resume function will, if the driver currently owns the systems sound resource, simply switch back on 
the hardware sound device. No note is played at this point. Because the driver uses the services of the 
timer device driver, any outstanding timeout will eventually complete causing the device driver's wait 
handler routine to be run. This in turn determines whether or not more notes are to be played. 


The Reset Function | | 
Since the reset function can only be called when there is an open channel, the device driver does not have 


. to check that it owns the systems sound resource. The reset function simply stops any current sound, 


~~ 


“nt 


powers down the sound system and marks the channel as closed. 


The Units Function 


The sound system can support no more than one user; thus the device driver supports no more] than one 
open channel at any given time. Note that the device driver will report|that it supports one sound channel 
whether or not that one channel is available. 


The Open Function 


The open function is called by the operating system when an application wishes to obtain a channel to a 
device called mus: (the example device driver's name). The open function attempts to obtain exclusive use 
‘of the sound resource by calling the HwGetCombo operating system service. It returns with the carry flag 
clear if the driver has successfully obtained the sound resource. 


The open function then allocates the I/O control block, adds function i e as a wait handler function and 
obtains.a channel to a timer device. If any of these requests fail, the driver tidies up after itself. 


It finally requests that the operating system call the reset function if the client terminates without closing 


<4 the’I/O channel. Once successfully opened, the internal variable is set to indicate this. 


Yk 


4 


Sie. 
ee 


. 98 | 


completion status. 
ay cre on eee? 


- 


The Strategy Function | 


The example device driver supports three functions: playing sound, cancelling the playing and closing the 
channel. This implementation uses the 1oFuncWrite (P_FWRITE) service to play sound, the !oFun¢Cancel 
(P_FCANCEL) service to cancel playing and the-IoFuncClose (P_FCLOSE) service to close the channel. 


| 


The playing of a sound is achieved by writing the user specified note at the required volume to the sound 
generation chip. The specified timeout is used to queue a timeout request on the timer channelj opened by 
this device driver. When the timeout occurs, the timer device driver will write the completion|status 
word and signal the I/O semaphore. Providing the application is waiting for an I/O request to complete, 
the device driver's wait handler will be called. The wait handler writes the next note into the sound chip 
thus playing the required tune. 

Here lies a fundamental difference between wait handlers and interrupt service routines. Not on y does an 
application have to be waiting for an I/O request to complete but it must also be able to obtair processing 
‘time in which to run the wait handler code. If a higher priority process is using all of the CPU (even if 
only for a short period of time), the sound application will not get a chance to run the wait handler 
function. Thus applications using this device driver will find that notes sometimes play for a lot longer 
than originally intended. 


This effect can be observed by running the example program and switching to the system task |(by 
pressing the System button on the Series3 machine for example ) forcing the system to update the lists. 


The lofuncCancel service simply cancels any outstanding write request |by cancelling the outstanding 
‘timer request, waiting for its completion and then completing the write request with the E_FILE_CANCEL 
completion status. The wait handler is also disabled, primarily for system performance reasons. 


The lofuncClose request will cancel any outstanding write close the ‘a channel, cancel the reset 
‘Tequest and release the sound resource back to the operating system. | 3 
The Wait Handler Function -_ | 


This function should check whether the outstanding timer request has completed and, if so, start playing 
‘the next note. If there are no more notes to play, the original write request is completed with zero 


* N 

+ rs ~ 

" ae . + - 
ae a a 


.8 EXAMPLE DEVICE DRIVERS 


Exercising the vectors 


The hold and resume vectors can be exercised simply by switching the machine off and then back on 
again. The sound should stop when switched off and resume when switched back on. 


The reset function can be exercised by running the example program, switching to the system task and 
terminating the example program. If the example program can be re-run and generate sound and/or the 
alarms still work then the driver has tidied up any system resources it needed to. 


oy 


Interrupt Driven Sound Driver we 


The code in sndfrc.asm contains an example of a root device driver that uses the FRC as annang: 
counter) as an interrupt source to drive a sound system. _ 


eve 
ref 


The driver accesses the sound chip within the Series3 and has the ability to play the notes pied to it’ 
from an application. 


The sound system within a Series3 should only be accessed by a single process at a time. The operating 
system has some state variables that can be used (via system aking, as mutual exclusion semaphores, 


Similarly the FRC should only be accessed by a single-process at a time. Ifa: second process grabs. the; 
FRC without the first knowing then the first will a never receive. e another FRC eas and hence 


appear to hang. a ay de 


When the channel to the sound driver is opened, iceauceie: exclusive use of the:sound system and the; 
FRC; when the channel is closed it releases these resources. It is only when some.sound is tq be: made, 
that the hardware is switched on and the notes played. 


Ta 


This device driver uses the FRC as a timer to time the duration. of cote. The FRGo can be programmed to 
run at either 32Hz or 512kHz, thus allowing a much greater resolution than the system timer device 
driver that can only provide 1/ 10th of a second resolution. This version allows for a minimum duration 
of 10ms, allowing notes of shorter duration and hence increasing the frequency with which the interrupt 
service routine is called causing avery high percentage of the cae bandwidth: ‘to: Pe used:i.s3 S07 


For this driver an eight bit number is used to specify. the, duration of a note and hence) the ‘nexinon a 
duration is 2.56 seconds. 


Since the notes are ‘changed i in the interrupt service youtine which i is independent off ‘most other F system, 
activity, a high level of accuracy of note duration can be obtained. . ea eee a 7 


The example code 1 in t  musfre.c Shows how thé device driver i is 5 loaded and the fuictiong pov are, 
used to generate sound: ore saree 


The device table ~--..:: Gp Re ae ye Att Fe Oy ck BAP: te Loe tee ae 


The start of the. file contains the device driver header. The name of the driver is specified | to Bé MUS:? : The 
driver is an LDD consisting of nine callable functions, the first eight of which are mandatory. The ninth 
function (nominated to be a wait handler, function) is required by the device driver i in. order to * ieee 


correctly. gon Ree pe pas 


Note that the sie ta as notes apply ores to the functions as used in the cxample driver.. sue 


“ . ; yo ty ty gs 
“ape eee PRE the Q ’ pone a sath elk Se agen ax 


The instal Function _ 


The install function should set the fact that the device driver has.n no o channel open. on ‘it yet. This ‘Variable 
(in the device driver space) is required to know how, to handle the remove, hold and resume Tequests. - 


The Remove Function = _ “> ea ae oh 3 a a 


The remove function will, if the driver currently owns s the systems sound resource, stop any sound being 
made, stop the FRC from generating interrupts, remove the FRC interrupt service routine address and. 
free the sound channel. 


In the normal course of events, the remove function: would not be called when an application ‘has’ an open 
channel to the device driver. It is however quite possible for this to occur and a device driver. should. 
accommodate such a possibility. The stopSound routine and HwFreeCombo operating system service should 
only be called if the driver owns the sound channel, otherwise any sound and ownership from other 
device drivers (eg alarms) will be adversely affected when this driver is removed. 


‘ ADDITIONAL SYSTEM INFORMATION 


The.Hold Function ._. 


The hold function will, if the driver currently owns the systems sound meat stop any sound that is 
currently being made and stop the FRC from generating interrupts. , | 


The device driver does not attempt to determine how far through the c 


t note (duration) it has got; 
when the resume function is called the following note (if any) will be p : 


layed. 


‘The ‘Resume Function. «© :. -: 


The resume function will, if the driver currently owns the systems sound resource, reset the FRC 
interrupt service routine address held by the operating system to point to the drivers interrupt service 
routine code. The device driver may have moved in memory and thus the absolute CS. address will be 

wrong. If a write request is currently queued (i.e. a hold request was made while the driver was playing 
some sounds), the sound hardware and FRC interrupts are re-enabled. eee 3 


After a power down type hold:the FRC is reset and hence needs to be re-programmed to generate 
interrupts at the required frequency. With a memory move type hold the FRC will continue its 
countdown and, if the count reaches zero, generate the next interrupt. This will be ignored by this device 
driver since the FRC is re-programmed in the reset function. 2) | 


The Reset Function: §° °°: © 0iu"’ 


Since the reset function can only be called when there is an open channel the device driver does not have 
to check that it owns the systems sound resource. The reset function s PS any current sound, powers 
down the sound system, disables FRC interrupts, resets the FRC interrupt address back to the default 
address and marks the channel as closed. 


The Units Function 


The sound system will support no more than one user and hence the device driver supports only one open 
channel at any given time. Note that the device driver does not guarantee that a channel is avai able by 
reporting that it supports one channel; another system component may own the sound resource|when the 
open request is made. | 


The Open Function 


The open function is called by the operating system when an application wishes to obtain a channel to a 
device called mus: (our device driver name). The open function attempts to obtain exclusive use of the 
sound resource by calling the HwGetCombo operating system service. If this returns with the carry flag clear 
then the driver has successfully obtained the sound resource. 


The open function then attempts to obtain exclusive use of the FRC resource by calling HwGetChannel with 
the interrupt channel number as the hardware resource required. If this returns with the carry flag clear 
then the driver has successfully obtained the FRC resource. 


The open function then allocates the I/O control block, adds function nine as a wait handler function, and 
requests that the operating system call the reset function if the client terminates without closing the I/O 
channel. | 

| 


Once successfully opened, the SoundChan.Pid internal variable is set to the process id of the client process 
(required by the interrupt service routine) and the SoundChan.OpenfreChan is set to indicate the channel has 
been opened (as required by the hold, resume and remove vectors). 


The Strategy Function | 


This device driver supports three functions: playing sound, cancelling he playing and closing the 
channel. This implementation chose to use the IoFuncWrite (P_FWRITE) service to mean play sound, the 


IoFunecCancel (P_FCANCEL) service to cancel playing and the loFuncClose (P_FCLOSE) service to clase the 
channel. 


The playing of a sound is achieved by writing the user specified note at the required volume to| the sound 
generation chip. The FRC interrupt service routine is the routine that actually writes the data to the sound 
chip. As it is an interrupt service routine, it cannot gain addressability to its client data space. Thus the 
sound data to be played must be copied into the device driver space. This has a side effect that|the 
maximum number of notes that can be played (by this driver) is limited by the size of the internal buffer 
as defined by the driver. The buffer can be made any size although in the majority of cases a larger buffer 
will most probably waste space. | 


The device driver could be written to handle arbitrarily long sequences of notes. When the interrupt 
service routine reaches a ‘low water mark' of notes to play, it can signal the wait handler routine which 


we yee gs eee a | 


100 | 


& 


wis." "8" EXAMPLE DEVICE DRIVERS 


will eventually run to copy more data from the client process space into the internal buffer. This is;.‘>~ 
however, a fairly complex task. niece Le et Ge: f ne 


When all the notes in the device driver's antecnal buffer iiave een played; the: interrupt service routine: 
will call the JoSignalByPidNoReSched system service to signal t the. client Process that the playing of sound 


1: ¥ i: rs Per ee 
has completed: er a oe 
om vi Jf oe ad hoes . mes : St eet ‘ i a cee : vty - oe ag f: ety 
3 be Nee Bl Poe ges hoa. ho eM 


The wait handler function will pick up the fact that the interrupt service routin has finished (from the 
SoundChan.WriteStat variable) and report the completion status to the client; the:wait handler runs,in the 
context of the client process and can thus write back the completion status word. oe 


ag See ap ve the Lome, oy semen of 
AY “a s nek ae dass Meese 7 waa : ak, wre Aree ey pate Se i Oreee Ber) 2 dat 


The loFuncCancel service. simply petee any ‘outstanding write request by: mopoing any.1 more FRC:: :.«: 
interrupts, stopping the’ sound generation, switching off the hardware.and‘then:completing. the cae es 
request with:the €_FILE_CANCEL bases eines status. Sst wait: handler is: also eirpiceay anda seta? hecaam 
performance reasons. Se a, tT ae Sa, UME Oa 


The loFuncClose' request will cancel any outstanding write, cancel. the. eniion vars and ewaas the sound 
and FRC resources back to the opoaims system. OT SR ERT Oath EME Sal ed te cthts 


¥ 
Y ' aa as ens Oe Std ne. ta x oem “ose iS Se 2) Fad ay 1 Oe ed 
: ae . Cr) 7 eed ii hee. ~ oj ! Lira cD | are a 2° ty in oe be ORE Ke ae ee eee ’ 4 ON, rm a Wier a 
s *4 e re hie oe ~ 
a ae a me axa ey , i aN the gay ot, er wee : v Peomras 3 + ah atone ae 2 Ae \ Wee ve 
fe! RE eae teat ves tan zr Ts Pes, 8 ; oo ae . a i ae dees vhs ad 


The Wait Handler Function 


This function should check whether all the notes have been played in which case it has completed the ~- 
users request. | 


’ 4 “ ® et . s vies * i” ae : a. 8 a 

tos & art ’ 8 . ‘oN Lite Rane rad ee _o™ Ls Cons bs Oe po § iw, 
ee ¥ ‘ 

' - . + tiome 8 oy! pom 

‘ fa ; = As fjom a ni mare % rit 2 Le Dts org ite q 2 D ethene he Note tet 

a t . : toy — : : Set YE L Beating J vhoot Seeds ies Riots Sa ea eit 

yay oo: ty vet Dag Op og! : ooo te che aleg wpe ite ars oki Lae hye a : : » *y ‘ a : ren ty 

ae ee me . SONG ee BO cee im ce Gad ee TR nara a] 6 a Pk 

Ror eee a8 3 as y aect go wigs ty ope vay s. ro oe GE 3 

a. Sa i es eae 5 ed . : Boe hore a . THel abet dee? F 


: ‘ Aves nee Ne AAR Gr Lat a . api vor: a + ary ae 4 rake) 
Oo, sic ot soivedeue. Bui lp te ae OO ted A at rept dine as jee Dyes at 
‘ . ie 


pee a er a Po Sah TR OV ire ate auwan cid eg: aaah los Gey og 8 $id nSEATS 


bi as 
. ay : a a4 p oon « cr’ . py os es eo #4 ‘ ona owe Saget a be at og rs Z oe 4 
, oe te Tey . go | A came a elie + r : * a ate _ 2 “t wa i€9 i er oes EN hw aa : Lis “y rit AGH foot. a } eRe ste ie ae 


SEP va GELS OSH 


‘ eR: yo we here pan b spa: i ne 3 ee at < 
. ee : ans an wee an , 25 43 - % a 
s : ured a ae eee A oe tees aes as) ea é thks e ek Bu 3 tt ay ers ad 3 BRAY hae rt | alt i) ae orey 7 LE wate 
wa d 
- : x 
' . wa ; mo peck Aaya aay ae gt ee gee 
ae. gage ai . i" a, ee ! at . . in ae fom ay Cr led a ey oe ‘ ay ‘ TER 
ne Was ae See Se ee wats Boe ee EE Ge te ee a ar ia as WO s 3 toe ue sad igs | eer ass: 
: age : : - ; | ee 
: 3 od Beg | 1 eed eae : Lf ng ri Roni SP, Sa Ge RE ENE eS are wee aaa a heros Ws 
te 2 Ee ee Ee Ge Ee Oy, Ps hg i ed ase eae ene ee 
: : : : 
Fs 5 eed . o , esti a toca jest 
et ars ae mR) Ok ae a ‘ cer 0 yey ° ef we yh me ae ean sia S4 
sean ron . “ “i ra) Ms ee « epee : hits re ” a , o oe lB aye 3 “ a4 ee ay 
: . me 
oe ie : 2 SRD oS gee : oe Ta eee a can acetate ar oe. tLe a. mi 
o. : ee $ , ead | a . ee tee! ape y S34 ee ea es she » oat ft CRS ae ae ay ix war zg rAd. caahe oe ade hay a 6 
"oe & eae awe ‘* hee é ée ‘ 
: 5 : : f : ; sex 
aa . : Eyre capes ac ar * sont Oey ee ee De OM Mees 233 Be me oY oeey 
* : : 2 o fee Oe tos, aot BS ton fae : t gue I. Cae ; 
; Dog tele AU USI « aE OS Bee RSE OM ee as tO ROO EE UES PU ad- 
' . . 
a ae €. nee 2 * » o.8 see ae re wh tote x f t gt 
5 ra : a4 meas oe oa % a ase 3 rit a fe 
Oy et oa a a as 2th oe me Le dio ay. ve ahs jute dt . ae fo fy 7% = mh ts ai 
: : “ 14 
. “ : Does : Se te a oa sy ‘ Ri ey TES a vl Medal: fhe 
PPE as Sahat se 1 te We I wo ees oe St eee “ to oe ee Seer | seat dda ok i 
Py q 
. es. : : ~~ op Wa ene A a8 arts . ges sh 
a tate Buby, ’ Aeon ey 4 a . ee . 1 8. we: : ‘ “3 ; £ a sabe Sate pL se a: ; ! WSS tf: & 4 
. Cae ws og - : fe 


Bats bee ae 


; ; : » ne | ‘ Sa y 

* . a . Bes? ae # Oar) . Ne re Z 4 Ad ton We v, agtey rate eg a] Pr a a ’ : 
} : Cs y af ‘ " r a} ‘ahs ‘ 7 = : : t, : : we * of Pa Terodbe §. 4@e ee ia oe” Ast ra Ey ae ™ if r Lae ra Bangle, ve ad 

Ul ee aoe ae foe en a gi aa et ’ 0 e 


r : é : “ : sg A wees rr ‘ Sat Ce 4 a PRIM af 50 Ot oa 5 
aw ‘ « eae Be eget “oe ‘ bate ot ar 4ge. ee yea Yat ea at mo Weed a x1 akeee. ; “os 2) } 
oe rae eo | =e woo gee at, 3" ees Bg OE ee re Li fe Bees tits ate TALE os < aA baad res 
, t foo ‘ 2 ‘ , 

7 : a See . o s ~ on — ao Cate 

ogi eg Shred tee . ae -. 8 a fh . . yt 4 ote: vy nk te. : : ae 4 ace 

a} Ia ee. eee ae hee wR tA GF ; z a Lee see to et cttes s 
4. Set debe) —_ 

sem a ar 4 2 

ers 4 . ca t a hes Pid i tw she 7 Y au 

. . « + qeaye 
: . ' 5 ‘ ; 
<4 : ' ett igs ignites eg ate! ee 2 nm i my tee ne” ae 7 ‘ eyrtiay a 2 e 
mee ey ap? See : ‘ re mre ca ene fs eM a Dee en Ms ee eee ilar) Bee hee 
wee Oe : eo o : “a ie 
6 ope ere ba 
: : ag cugy teas ts ey te yor resets oS rep errs, ae § aa ag Nee eae 
tem 7 Se oe ’ Ee ee ee Ve ‘ ‘i J Sy. sh. oy aah 5 ay att ' ae e shea ee . n% On Ped q ° iC. esa: * 
zs RVD ee Re ~ rod 
z s on te - 
tees : seed ns yee. és seh iis se tee ; be SE Es Tf - Be “gga Vee tsi 
sete a Sev at we 8 Sa BG Me Boss Mo hs i ree ay 
~ set 58 ae sot we ‘ 


SOOPER. 


eee, 
°} . we t . Bfe . . ” + rat Ls ontay'g 4 
ei Pes ec tym . Pee eR MES See CN DE ? Cc y aa 61% Saeed e 
eee Re Se OF See ee a ae Neat cme Ca ela Pe wee BER orgy FAB ; = 
te er) af ie . ‘© ‘5 
: je ; : oa rr aa cr rr vite je FTC, 73 
* xt phe toy oagk tyre Sg tet oe er aa "hee : Sige ee Soe 
. gos ‘, eee TF og tase oP ey SR Ba Pha See iat Pk wedi. wee, a so a 
: ba z B ? 
° : . . ahh: Sh . “4 f - an 
; i ae oe aes Roe Nan VTE AY Ey PM Se : are kd pe Gly eon oe oe, ace an in A. 
. eS Stee ea Vee ae ee . SOM Ale eT Nei aT Sa puter ies je hos ve i be Dan 
4 i . ; " 5 4 : Se ree wi bees ‘ i : Pee. oy 
7 “¢ ea oe opagr ele eh ovree th, om tyra ee ig Poe be ee 
age Pe oe f we geate had LRT cage She er Re ed i : 4 % Petal 
Ae ; . 
ce aye ~ \o™ are 
ws H te - vy ey . x Ves. art 3? « : hat; : at aN lee 
- Noa + dle. es = 


. hae fool 
a bn FL a 
: , rey : rye ers Va ae ey i gat wail vt rapa “nk £ 
va Pee 
ihe ~. ‘ CE Md vise as ees a ie 
pee} : mat i seky ag h Ls) ey ee 
« 


¢ 201 


- base 
a is ii RSS ~~ we te ba 
BE OR eS 


“. && DS, Bo. Sala aoe: 
» 
593 cae “yee Tigi} . ars 
oe L wrt ar Lek 


Ru 
oe #fT : Ji: Y oe aes ee ar he a ° : . 
ne) 4 - a ct ATES f J see y t 4 feed? fale. Bs 5 vw hoy 
Me i 2 ae ae Bs Bite 
Be aay oe seers ae aery : ate 
rou a : . ott ie 
cs ‘i eomatetehs ok. at? 
‘ 
aie Ryser oe ices 
a Nas? ye, rae Pees wh ® epee 


a 
obweBe CS 


» 
ty. syne 


RY ve 
. nf 


at: 


got tag 
ay. cm caine: 
~ " é. 74 . 
1 fe vr - 22,2 wet * G a €eo4 
hee we i? ates wets bade we, . $a 
. S's 
we moe yetie. 
Valk wa Je a 
' . ” 
° gis } ‘ te ae ir bar » - 
or Stam Alt ite ve 5s i wat, ne.) Eat 3 
"tr : } 2 ar eee 7 > . wh ‘ ‘ ce 
3 Pan Py Se ? ao oe. ae 4, ey 
a Rise 8 ges Ba. ahd i. y a€ +a “ 
* @ 
Lome go 2 - bd 
: i «age aye ren * os ge ean Teo 
ar ay os. te NE ete z 7 at, ‘ 
aal 4 eth Deg 5 toe f ue" Po mr aN ae 4 SEPP LES 
7 pe ae a oe a 
wae ee ® a we owen f ¥é 
Par rae cae oe a oe 
BREAN 4 mPa, 
. ite 3 
© 4 wet Lawl” eo Na oat 
Pr a ces . . oe fay 300 on is fe t; i 
' ae wee . ay PERN oF a ce 4g.” ’ "es oae Ft es, 2 et ee 
: wd, re , kt. roa ce vy bea Aa vee OM TAD COAL aoe + hd ne Po a aa 3 Bd we “ wa hte 7 + Bali aes 
? 
, aR he 
. Corey ee Y Lak ve 
1 cet s A . eee Qe ‘ 
rah i! z : 2 My * ‘ , Os eg : LFS tye Set meee oe 
a Niele yes er 4 . ; Ee ae ee Oe: Pe 
7 ‘ ton te i, 
me fe ~ % Z a “ . ‘i *: be o 
‘. ; : tes pte pee — Wee hatte air sae eb 
abel Sate: . Pi eee age, oe Pr a 3 “4 a Sa * Sati rf ree Spire ee 
are AS? vaey: Pe ro ofee ee ee st a ee eee ee ; 
j . a . ‘ . : yok vee : “f * a . che 
Syr8 0 So ads ee Bf, ale eee at dea ye ees rer ¢ ceca fe wifte th St 
rit verhe ger "een > a oa ei, ge . 4 o oe . 
. . 2 i : Pow 4% oF : weit N, é “art 
a . 7 
Cat pee ag " : i f : 
: \ nae a @ -Pyer sew or es Lm re . é . 
Oy 5 Adie weitad £ ie 3 MOB. ly TTES ree VAS by : wet ae re 
aaa . 5 
Sabre Feb 4 ws footie , t wos Pa : : 
», i ee 27 Cb bn Y ek ¢ Yam hota ee oe wa ct ‘ ‘ae er 
G te we bs. Ses : Hy : ee “soe 7 OG BMS ¢. . “ Pa aaee, tar ee, a8 ay pea ied i we 7 & vege 
£ ae ae ee ‘ thom lepdtt We RN tks wa iB 3 wet oe) ale vedas daARd a OG! ag a eae tele the Bacnies LA. t we 
+e Sip © wey 4 a ee x Ns Ee ’ : ‘ eof. ' : es : 
30) SRLS Ketek. eg a a SO Shes oe Aime meh se. ee Be. es eC, Ae | 
. oe se tee F. aa ad 4 res YS | saeod wee Roe, A is : re “y Ativite ge 3, ee ee 
. sf 
¥ erage yo. *, td 
4 Bo Mee Oe A 
' 48% mm. . tee, i rere : as 
bog ; "p tie 4 SS ‘ . 
ar eae SR te Pa reer bo a rT a ry 
‘ . . 
+ Lay ue a: i wen aS ' ’ , cfGa. 4% ' os 
oe are Vanes ne ALOR PURO FR oo : 
ae ; ; ot 
: SEA ET Ee 2 £FF7- ; 
x A Ee be ode a a3 ro 
-¢ aaa 7 > 7 . ‘ + 
honey Syee fo of amt ay ? 
A eos oo. Stdad oc: 7 APE gs ' , ee ae 
my . 7 ei ‘ ’ 1 ee ~& 
cag hs ’ soe 
4 a 2 er ae a ee : . a ‘ . 
rae we ns at a fey 7 os ae: r ee Bite ? 2 be b eerie yng . + om shat 4: 
oy ri . . fate tw 04 heh 
. 
te 
weak oe . 
oF wos t 
tl en me = wee 
0 el Sl SET LE aie, ag eerie + . Fates nPrmene tC OOS 8 SoA ms "58? amar 8 Aw br! epee ies aw NOW de ele th Prd Sherk EU Om terete sen ou a oe oe eo 


TENE RED Reape, JOT HEUER Be Mee 6 - 


CHAPTER 9 


PCMCIA CARDS AND SSDs 


Certain manufacturers of hand-held computers have recently been vigorously promoting the so-called 
PCMCIA standard for plug-in cards for portable computers. The idea is that PCMCIA cards that can 
plug into one hand-held computer ought to be able to plug just as easily into another. 


However, the SSDs used in SIBO computers do not conform to this standard. This fact may be seen as a 
potential problem - possibly as a disincentive against taking the time to learn how to program within the 
Sibosdk system. More precisely, it may be seen as a reason why the SIBO range of computers might 
enjoy but a limited lifetime in the marketplace, before being eclipsed by other, PCMCIA-based portable 
computers - in which case, studying the Sibosdk system in any detail would be a poor investment. 


This chapter aims to answer these worries by dispelling the hype around PCMCIA, through documenting 
some of the considerable benefits of SSDs as compared to PCMCIA cards. 


Mobility and robustness 


Serious doubts can be raised over the suitedness of PCMCIA cards to genuinely mobile computing. The 
simple fact is that SSDs are much more robust and portable than PCMCIA cards. 


In the first place, these doubts revolve around the fact that PCMCIA cards require no fewer than 68 
independent connections to the main body of the computer. This is an enormously large number of 
connections for hardware to protect, and contrasts vividly with the 6 connections of SSDs. 


There are two aspects to this: mechanical and electrostatic. At the mechanical level, the 68 pin edge 
connector of PCMCIA cards is inevitably vulnerable to pin failure with constant removal and insertion. 
At the electrostatic level, the fact that there are only two data lines in the SSD Serial Protocol means that 
each data line can be amply electrostatically protected in a way impossible for PCMCIA cards. The 
PCMCIA parallel interface has many more data lines, increasing the potential for data corruption. 


The very name "PCMCIA" betrays the origin of this proposed standard as an accessory to the basic "PC" 
architecture. PCMCIA was fundamentally designed as a plug-in extension of the memory map of PCs; in 
contrast, SSDs were designed with secure data storage, ruggedness, and high mobility as the foremost 
priorities. (SSDs actually developed out of Psion's long experience with DataPacks on the Organiser 
range, in which it became clear how vital it is to keep data transmission lines to a minimum.) 


Size considerations 


Another important point is the sheer physical size of the PCMCIA cards. Although slightly thinner than 
SSDs, they have a much larger body area - famously, the same profile as that of a credit card. 


For example, were HCs to be converted, hypothetically, to the PCMCIA standard, it would mean only 
having one drive, instead of two as at present. There would be no room in a standard-sized HC for two 
PCMCIA card slots. Yet practical experience demonstrates how crucial having two SSD drives is - one 
SSD (possibly a one-time-programmable one) containing a program, and another containing data files. 


In general, the greater body area of the PCMCIA card means that SSDs are suited to a wider range of 
different application devices. 


Different standards for different purposes 


In proposing their standard, the originators of PCMCIA had various different goals in mind for what 
PCMCIA cards could do. In retrospect, the standard seems appropriate only to some of these goals. 


PCMCIA is at its most impressive as a standard for detachable plug-in extensions to PC RAM memory; 
it is significantly less impressive as a standard for secure off-line data storage. This is where the SSD 
format (in particular, the Psion Serial Protocol) wins out. 


103 


ADDITIONAL SYSTEM INFORMATION 


It seems more than likely that the Psion Serial Protocol will also become a de-facto industry standard, 

alongside the PCMCIA standard. Just as various different computers, from a variety of manufacturers, 
currently contain PCMCIA card slots, so too will SSDs become incorporated 1 in an ever wider range of 
computers and computer peripherals. (But it should be bome in mind that there are already not one but 
three different PCMCIA standards, whereas there is only one Psion Serial Protocol standard.) 


To this end, Psion is actively supporting interested third parties, supplying relevant ASICs, more detailed 
documentation (see the Hardware Reference manual in the first instance), and other practical assistance. 
Contact Psion for more information about the SSD Hardware Development Kit. 


| 
Hot insertion : | 


Compared to PCMCIA cards, SSDs offer another significant advantage | in “hot insertion". What this 
means is that SSDs can in general be inserted or removed from a computer without that computer first 
having to be powered down. (After all, PCMCIA cards plug directly into the bus of a PC or PC-clone.) 


Now whilst this is not directly relevant to the case of the HC (which automatically switches off whenever 
its rear cover is opened), it is highly relevant for other computers in the SIBO range - such as the laptop 
MC and the ubiquitous Series3. It is also relevant for PCs with attached SSD drives. 


More generally, support for hot insertion makes SSDs behave like ssaaiesl and logical extensions of the 
floppy disks of a PC. An SSD can be removed from one computer and plugged into another just as 


easily as a floppy disk can; there is no need to power the computer down first. 


| : 
In order to achieve a similar result, PCMCIA cards need the addition of extra memory buffers, both in 


the card and in the reading device - adding to the cost and design complexity of both. 


Flash filing systems | 


On the particular subject of Flash PCMCIA cards, whilst it may be eas for applications to read data 
from such cards, it is much harder for them to write data back. This requires a sophisticated filing 

system which is very different from the FAT (File Allocation Table) filing systems that work so well 
with RAM memory. 


At the time of writing, no full-featured Flash filing system exists for any PCMCIA card, and there seems 
little prospect of one being produced in the near future. This absence contrasts sharply with the mature 
SSD Flash filing system that is contained within Epoc. 


Flash SSDs have been shipping since 1989, and Psion is now widely gnised as the world's leading 
authority in the use of Flash memory. 


Cost considerations 


In view of these problems facing PCMCIA cards, it is hardly surprising that more SSDs are being 
produced than cards conforming to PCMCIA. As a result, SSDs are well on the way (at the time of 
writing) to being significantly cheaper. | 


Another factor favouring SSDs being cheaper than PCMCIA cards is the simpler nature of their basic 


construction. Inevitably, it is mechanically harder to manufacture a 68 | pin connector. Note that this 
consideration is just as pertinent for the socket the memory card plugs into, as for the memory card itself. 
Architectural openness 


Possibly the most significant point of all still remains to be made. Namely, the SSD interface makes no 
presumption on the architecture of the system that is driving it - unlike PCMCIA which is designed for 
PC-hardware compatible systems. This gives the ee of the system considerably greater freedom: 
SSDs are truly independent of the host system. 


To re-emphasise: SSDs do not presuppose the Epoc or Sibosdk architectures in any way. The interface to 
SSDs is actually extremely flexible, and can be addressed: 


= via hardware, using an ASIC-2 card, or 
=" via software, using just two microprocessor i/o lines. 
Finally, two further points, each emphasising the greater flexibility ein by SSDs to system designers: 


= at the level of engineering layout, SSDs can be located significantly further away from the main 
processor than PCMCIA cards (by virtue of the different interfaces) 


= there is no intrinsic design constraint to the address limit of . providing potentially 


unlimited capacity. 


7 7 _ 


