Legacy SIBO/EPOC16 Documentation

This is a collection of publicly available documentation created way-back-when, collected here for both convenience and posterity. The Psionics Files by Clive DW Feather The Psion FAQ by David Pfund

The Psionics Files

The Psionics Files was Clive Feather's name for his project for collating information about programming the Psion Series 3 and 3a which is not in the manuals provided with the machines. The intended audience of the files was the Series 3/3a OPL programmer. Thus, for example, material that can only be used by assembler programmers is usually (though not always) omitted, and constants are expressed as numbers rather than symbolic names. Except where explicitly stated, material applies to both systems and MS-DOS emulations of both; differences are always indicated. In addition, most material also applies to the HC and MC, but differences are not always indicated. The term "Series 3t" is used to refer to the original Series 3 and the Series 3s (which is basically the original with the spreadsheet application built-in), while the term "Series 3" applies to both these and the 3a. [Note: Clive previously used "3s" for this. He did not alter the "last changed" date on files changed only for this purpose.] Where Series 3c or Siena material has become available to me, Clive edited the files accordingly. But in general it can be assumed that Series 3a covers the 3c and Siena.

The Psionics Files

Introduction

The Psionics Files

Clive D.W. Feather

The Psionics Files has been reproduced here with kind permission of Clive D. W. Feather.

Last updated 2009-03-27

The Psionics Files is my name for my project for collating information about programming the Psion Series 3 and 3a which is not in the manuals provided with the machines.

The intended audience of the files was the Series 3/3a OPL programmer. Thus, for example, material that can only be used by assembler programmers is usually (though not always) omitted, and constants are expressed as numbers rather than symbolic names. Except where explicitly stated, material applies to both systems and MS-DOS emulations of both; differences are always indicated. In addition, most material also applies to the HC and MC, but differences are not always indicated. The term "Series 3t" is used to refer to the original Series 3 and the Series 3s (which is basically the original with the spreadsheet application built-in), while the term "Series 3" applies to both these and the 3a. [Note: I previously used "3s" for this. I have not altered the "last changed" date on files changed only for this purpose.]

Where Series 3c or Siena material has become available to me, I've edited the files accordingly. But in general it can be assumed that Series 3a covers the 3c and Siena.

Legalisms

The first version of the files was built up from information freely available, such as the standard manuals, the source code of various games, and Usenet postings. After I first posted them, the response of Psion was surprising: David Wood arranged for me to receive a complete set of SDK manuals!

According to David: the purpose of the copyright messages in the SDK is to allow Psion to express its proprietorial ownership over the material. It may be copied and distributed so long as the original derivation from the SDK is acknowledged. What might cause Psion to seek legal redress is someone claiming complete credit for something that is actually derived from the SDK, and did not point readers to the SDK as the source of more information. Psion has no interest in trying to make any profit directly from sales of the SDK. Psion simply wishes the information to reach as many people as possible, trusting that, as a result, many good third party products will be written.

In addition, and subject to the above, I retain copyright in my intellectual property in these files; that is to say, the effort in editing and arranging them, and any text I have written. These files may be distributed through normal Usenet mechanisms, may be archived at sites offering free access to contents, and may be converted to other formats (such as HTML). However, all public copying and distribution is to be of the entire set of files, and not any subset, and any versions that are not a direct copy (this includes format conversions unless done completely automatically) are to carry a prominent note indicating that they have been edited and by whom, and that errors may have resulted.

While these files have been generated in good faith, there may be errors in them, and/or they may not reflect current releases of the EPOC operating system. No warranty, express or implied, is offered by myself or Psion in these matters.

This the preceding three paragraphs are not to be removed or materially altered by any changes.

[Phew ! If you want to do something that the above doesn't cover, please contact me at clive@davros.org. I'm quite reasonable.]

Files

The following files exist at present:

AGENDA.FMT Format of Series 3t Agenda (.AGN) files
AGENDA3A.FMT Format of Series 3a Agenda (.AGN) files [incomplete]
BITMAP.FMT Format of Bitmap (.PIC) files
COUNTRY.FMT Format of Country information files
DBF.FMT Format and use of Data (.DBF) files [incomplete]
DEVICES Device driver interfaces
ENVVARS Environment variables
ERRCODES Standard Psion error codes [incomplete]
FILEIO Filing system IO interfaces
FLASH Format of Flash SSD cards and ROMs
FONT.FMT Format of Font (.FON) files
IMG.FMT Format of executable Image (.IMG/.APP) files
INTRO This file
LINK Description of the 3-Link protocol [not yet available]
KERNEL Kernel memory organisation
KEYWORDS More information about OPL keywords [incomplete]
LOCALES Locale codes
MENUPROB Series 3t menu problem workaround
MISC Various miscellaneous notes
OPLSOCK OPL interface to PsiMail TCP/IP [withdrawn]
OPO.FMT Format of OPL object (.OPO/.OPA) files
PROCESS Processes and their properties
RESOURCE.FMT Format of resource files
SOUND.FMT Format of sound (.WVE) files
SPR.FMT Format of SH3 Spreadsheet (.SPR) files
SYSCALLS.n System calls
SYSCALLS.IDX Alphabetic index to system calls
TCPIP PsiMail TCP/IP programming interface
WORD.FMT Format of Word (.WRD) files
WSERVER Window Server calls [several missing things]

[Note that DATA.FMT has been replaced by DBF.FMT.]

Other notes

The following terms have specific meanings:

byte one byte integer
word two byte integer
trip three byte integer
long four byte integer
real 8 byte floating point number
cstr a string, as found in C programs, ending with the first zero byte; the contents are all non-zero bytes, the string may have zero length (excluding the terminating byte), and there is no limit on the length unless stated otherwise.
qstr a string, as found in translated OPL programs, consisting of a count byte followed by that many bytes; the contents may include zero bytes, and the length is in the range 0 to 255 (excluding the count byte).
text a string, whose length is expressed externally (for example, by occupying a fixed size buffer); it may contain zero bytes, and does not have an initial count byte. [This definition does not apply when the "text" is explicitly described as a cstr or qstr.]
address a word (two bytes), containing the address of a variable in the same or a different address space (all address spaces are limited to 64k). It may be obtained with the ADDR keyword.
day number a number of days since 1900-01-01.
abstime a number of seconds since 0000 GMT on 1970-01-01 (the format used by the DATETOSECS keyword).
interval a number of seconds since 0000 on the relevant day.

All integers are little-endian. Whether a value is signed or unsigned can normally be deduced from context.

A real number uses IEEE 64 bit format, using a little-endian layout

Bits 0 to 51: mantissa, with binary point at left and implicit leading 1
Bits 52 to 62: biased exponent (1023 = value in range 1 <= V < 2)
Bit 63: sign (0 = positive, 1 = negative)

Data structures are always shown with each field described as a byte offset from the start of the structure. Each field is given as either a start and end offset (the field including both), or as a start offset and type. Bytes not included in any listed field have an unknown meaning. Unused bytes are shown, and should be set to zero.

Hexadecimal numbers are indicated by a $ or & prefix. These are used interchangeably; they do not imply the type or number of bits of the value.

Bits within bytes are always numbered from 0 (least significant) to 7 (most). Unused bits are not described, and should be set to zero.

Many operations use cstr values. These can be converted to and from qstr (OPL string) values as follows:

An at sign (@) is used to indicate incomplete or missing information, or text that I planned to rewrite.

The Psionics Files

AGENDA.FMT

PSIONICS FILE - AGENDA.FMT
==========================
Format of Series 3t Agenda files
Last modified 1994-09-14
================================

Series 3t Agenda files are normal database files (see Psionics file DBF.FMT).

Each record holds five fields: four words followed by one qstr.

The descriptive record contains one subrecord of type 15. This subrecord
always contains exactly 12 bytes:
  Offset  0 (word): time of first appointment slot shown on a day, in minutes
                    past midnight
  Offset  2 (word): default length of an appointment, in minutes
  Offset  4 (word): 0 = alarms off by default, else alarms on by default
  Offset  6 (word): default advance time for alarms, in minutes
  Offset  8 (word): default alarm time for untimed appointments, in minutes
                    past midnight
  Offset 10 (byte): time separator character
  Offset 11 (byte): unused

Each data record holds one calendar event (possibly repeating), one day-note
event (possibly repeating), or one to-do item. The record contents for each
of these are described here.

Calendar events have the format:
  Field 1 (word): day number of the event
  Field 2 (word): duration of the event in minutes, times 2, plus 1 if there
                  is not an alarm attached
  Field 3 (word): time of the event, in minutes past midnight
  Field 4 (word): time of the alarm in minutes before 23:59 of the day the
                  event occurs on, or $FFFF if there is no alarm
  Field 5 (qstr): item text

Repeating calendar events have the format:
  Field 1 (word): $FFFE
  Field 2 (word): duration of the event in minutes, times 2, plus 1 if there
                  is not an alarm attached
  Field 3 (word): time of the event, in minutes past midnight
  Field 4 (word): time of the alarm in minutes before 23:59 of the day the
                  event occurs on, or $FFFF if there is no alarm
  Field 5 (qstr): item text followed by repeat information

Day note events have the format:
  Field 1 (word): day number of the event
  Field 2 (word): 0 if an alarm is attached, or 1 if not
  Field 3 (word): position of item in list:
    $8000 = first day item on that date
    $8001 = second day item on that date
    etc.
  Field 4 (word): time of the alarm in minutes before 23:59 of the day the
                  event occurs on, or $FFFF if there is no alarm
  Field 5 (qstr): item text

Repeating day note events have the format:
  Field 1 (word): $FFFE
  Field 2 (word): 0 if an alarm is attached, or 1 if not
  Field 3 (word): position of item in list:
    $8000 = first day item on that date
    $8001 = second day item on that date
    etc.
  Field 4 (word): time of the alarm in minutes before 23:59 of the day
  Field 5 (qstr): item text followed by repeat information

To-do items have the format:
  Field 1 (word): $FFFF
  Field 2 (word): position of item among those with this priority:
    0 = first item
    2 = second item
    4 = third item
    6 = fourth item
    etc.
  Field 3 (word): item priority (1 to 9 inclusive)
  Field 4 (word): unused
  Field 5 (qstr): item text


For repeating items, the item text is always followed by a 6 byte block giving
the repeat information (this block is included in the qstr as far as the
database format is concerned). This block has the form:
  Offset  0 (byte): repeat type:
    0 = yearly
    1 = monthly by date
    2 = monthly by day
    3 = weekly
    4 = daily
    5 = workdays
  Offset  1 (byte): repeat interval
  Offset  2 (word): day number of the first occurence
  Offset  4 (word): day number of the last occurence, or 0 if repeats forever


Day numbers must lie between 29219 and 54786 (years 1980 and 2049) inclusive.
The end of a calendar event must lie in the same day as its start.
The Psionics Files

AGENDA3A.FMT

PSIONICS FILE - AGENDA3A.FMT
============================
Format of Series 3a, 3c, and Siena Agenda files
Last modified 1999-10-05
===============================================

Series 3a Agenda files are a form of Database file (see the Psionics file
DBF.FMT). However, there are some differences:
* The file signature is the cstr "AgendaFileType*".
* The version number is that of the Agenda software.
* The value at offset 20 is not a version number (it is unused).
* The record types (other than types 0 and 15) are specific to Agenda; in
  particular, types 2 and 3 are not treated specially.

Series 3c and Siena Agenda files are mostly compatible with 3a files, but
contain some changes and extensions.

The record types are as follows:
  0 = deleted record
  1 = timed day entry
  2 = untimed day entry
  3 = anniversary
  4 = to-do entry
  5 = repeat information
  6 = anonymous data
  7 = reserved
  8 = entry code descriptive record (Series 3c and Siena only)
  9 = to-do list definition
Types 10 to 14 are descriptive records, and type 15 is an incomplete record.
There is exactly one record of each type 10 to 13, and at most one of type 14.
There is at most one record of type 8 on the Series 3c and Siena.

Note that all undescribed bits and bytes must be zero.

For convenience in formatting, the views of the agenda are abbreviated as
follows:
    DV = day view
    WV = week view
    YV = year view (Series 3a and Series 3c only)
    TV = to-do view
    LV = list view
    AV = anniversary view
    BV = busy view (Series 3c and Siena only)

The "entry code" is used on the Series 3a as the symbol to appear in the
year view (codes 0 to 31 mean that the entry should not be shown). On the
Series 3c and Siena they are used to select a subrecord from the type 8
record.


Types 1 to 4: entries
---------------------

Each record consists of a required part, described below, and optional alarm
and memo parts, in that order. The required part will indicate whether the
other two parts are present.

The required part has the following format.

Type 1 (timed day entry):
  Offset  0 (word): day number of the entry
  Offset  2 (word): time of entry, in minutes past midnight
  Offset  4 (byte): attributes (see below)
  Offset  5 (byte): entry code
  Offset  6 (word): length in minutes
  Offset  8 (byte): text style (see below)
  Offset  9 (qstr): text

Type 2 (untimed day entry):
  Offset  0 (word): day number of the entry
  Offset  2 (word): time where entry shown, in minutes past midnight, or $FFFF
                    for the default location
  Offset  4 (byte): attributes (see below)
  Offset  5 (byte): entry code
  Offset  6 (byte): text style (see below)
  Offset  7 (qstr): text

Type 3 (anniversary):
  Offset  0 (word): day number of the entry
  Offset  2 (word): time where entry shown, in minutes past midnight, or $FFFF
                    for the default location
  Offset  4 (byte): attributes (see below)
  Offset  5 (byte): entry code
  Offset  6 (word): start year (-30000 to 2049, 0 means none)
  Offset  8 (byte): bit 0: show base year, bit 1: show elapsed years
  Offset  9 (byte): text style (see below)
  Offset 10 (qstr): text

Type 4 (to-do entry):
  Offset  0 (word): day number to display from, or day number when crossed out,
                    or $FFFF if undated
  Offset  2 (word): time of entry, in minutes past midnight
  Offset  4 (byte): attributes (see below)
  Offset  5 (byte): entry code
  Offset  6 (word): day number to be done by, or $FFFF if undated
  Offset  8 (byte): internal code for to-do list holding the entry
  Offset  9 (byte):
    Bits 0 to 3: priority minus 1
    Bits 4 to 7: 0 = automatic, 1 = show date, 2 = show days to go,
                 3 = due date not shown
  Offset 10 (long): position in manual order
  Offset 14 (byte): text style (see below)
  Offset 15 (qstr): text

Note that positions in manual order (offset 10) are not necessarily
consecutive, and may have gaps in any individual list.

The attributes byte is used as follows:
    Bit 0: set for single entry, clear for repeating entry
    Bit 1: set if pending, clear if crossed out
    Bit 2: set if shown in year view, clear if not shown
    Bit 3: set if no alarm part, clear if alarm part follows
    Bit 4: set if no memo part, clear if memo part follows

If bit 3 is clear, the text is immediately followed by an alarm part:
  Offset  0 (word): alarm time in minutes before 23:59 of the day the event
                    occurs on (0 to 46079, meaning 00:00 31 days earlier)
  Offset  2 to  10: name of alarm sound (qstr, padded with zero bytes)
The sound name may be one of the following:
- the name of a sound file; this is searched for in each of:
    A:\WVE\name.WVE
    B:\WVE\name.WVE
    M:\WVE\name.WVE
    ROM::name.WVE
  [This appears to be the search order, but it is not documented.]
  The Series 3a ROM contains the sounds:
    SYS$AL01   Fanfare
    SYS$AL02   Soft bells
    SYS$AL03   Church bell
- a single byte (thus offset 2 is set to 1) with the value 1 (for rings),
  2 (for chimes), or 16 (for silence).

The text style byte is used as follows:
    Bit 0: set for bold entry
    Bit 1: set for underlined entry
    Bit 5: set for italic entry

If bit 4 of the attributes byte is clear, the text or alarm part is followed
by a memo part. This has the format:
  Offset  0 (word): length of memo information (L, from 0 to 3600)
  Offset  2 (word):
    Bits  0 to 11: total size of components A to C
    Bits 12 to 15:  4 = unencrypted memo
                   12 = encrypted memo
  Offset  4 (word): size of component D
  Offset  6 to L+1: components A to D, in that order
The memo information then consists of four components, each of which is the
data portion of a Word record (see WORD.FMT), excluding Word's type and
length header.

Component A is a Word type 1 record, except that the cursor position is
always stored as zero, and the status window setting as 2 (wide). It is
always 10 bytes and always occupies offsets 6 to 15 of the memo information.

Component B is empty if the memo has not been encrypted with a password,
and is 18 bytes if it has:
  Offset 16 to 24: encryption key check value
  Offset 25 to 31: copy of offset 16 to 22
  Offset 32 (word): unused

Component C is a Word type 8 record. It starts at offset 16 of the memo
information if not encrypted, and offset 34 if encrypted. Component D is a
Word type 9 record.


Type 5: repeat information
--------------------------

When an entry of type 1 to 4 repeats, a separate type 5 record will exist
elsewhere in the file. This has the format:
  Offset  0 (byte):
    Bits 0 to 2: 0 = daily, 1 = weekly, 2 = monthly by date,
                 3 = monthly by days, 4 = annually
    Bit 3:       set to show next occurrence only, clear to show all
  Offset  1 (byte): repeat interval minus 1 (0 to 254)
  Offset  2 (word): ending day number, or $FFFF if none
  Offset  4 (byte): type of associated entry
  Daily and annual repeats:
    Offset  5 (long): position of associated entry
  Weekly repeats:
    Offset  5 (byte): days to repeat (bit 0 = Monday, ... bit 6 = Sunday)
    Offset  6 (byte): first day of the week (0 = Monday, ... 6 = Sunday)
    Offset  7 (long): position of associated entry
  Monthly by date repeats:
    Offset  5 (long): dates to repeat (bit 0 = 1st, ... bit 30 = 31st)
    Offset  9 (long): position of associated entry
  Monthly by day repeats:
    Offset  5 (byte): "1st"  days to repeat (bit 0 = 1st Monday, etc)
    Offset  6 (byte): "2nd"  days to repeat (bit 0 = 2nd Monday, etc)
    Offset  7 (byte): "3rd"  days to repeat (bit 0 = 3rd Monday, etc)
    Offset  8 (byte): "4th"  days to repeat (bit 0 = 4th Monday, etc)
    Offset  9 (byte): "last" days to repeat (bit 0 = last Monday, etc)
    Offset 10 (long): position of associated entry

In each case the position of the associated entry is the offset in the file
of the type/length word at the start of that record. Thus compressing the file
can require all type 5 records to be altered.

The remainder of the record is a sequence of words, each of which is the
number of a day on which the entry should be suppressed. These entries are
unordered; illegal values should be ignored but preserved.


Type 6: anonymous data
----------------------

These records are ignored by Agenda (except to include them when merging
agendas). The intent is that applications converting between this and other
formats can use these records to hold information not used by Agenda.


Type 8: entry code descriptive record
-------------------------------------

This record is ignored by the Series 3a. It is used to describe entry codes
on the Series 3c and Siena. Offset 0 (byte) is a version number, and must
be zero. The remainder of the record is a sequence of subrecords. Each
subrecord has the format:

  Offset 0 (byte): entry code
  Offset 1 (byte):
    Bits 0 to 3: length of description (L)
    Bits 4 to 7: class of entry code
                 (0=default, 1=open, 2=restricted, 3=private)
  Offset 2 to L+1: (text) description of entry code


Type 9: to-do list definition
-----------------------------

There is one record of this type for each to-do list, always 42 bytes long:
  Offset  0 (byte): must be $FF
  Offset  1 (byte): internal code for to-do list
  Offset  2 (cstr): list name
  Offset 19 (byte): same as offset 1
  Offset 20 (byte):
    Bits 0 to 3: maximum priority shown in other views
    Bits 4 to 5: sort order (0=date first, 1=priority first, 2=manual)
    Bit 6:       display crossed out entries in TV
    Bit 7:       display crossed out entries in other views
  Offset 21 (byte):
    Bit 0: set to bullet with numbers, clear to bullet with priorities
    Bit 1: set to display entries in other views
    Bit 2: set if entries dated by default
    Bit 3: @always set so far
  Offset 22 (word): default position in DV, in minutes past midnight
  Offset 24 (byte): default days warning
  Offset 25 (byte): default entry code
  Offset 26 (byte): 0=alarm off by default, 1=alarm on by default
  Offset 27 (byte): default alarm days ahead
  Offset 28 (word): default alarm time, in minutes past midnight
  Offset 30 to  39: default alarm sound name (qstr, padded with zero bytes)
  Offset 40 (byte): default text style
  Offset 41 (byte): unused, must be zero

On the Series 3c and Siena, offset @@ is the default class for entry codes
on to-do entries (@=open, @=restricted, @=private)

See above for the details of alarm sound names.


Type 10: descriptive record (memos)
-----------------------------------

@The format is not yet available.


Type 11: descriptive record (to-dos)
------------------------------------

This has the format:
  Offset  0 (byte): must be $6C
  Offset  1 (byte): number of to-do lists (L, from 1 to 99)
  Offset  2 to L+1: internal codes of the to-do lists, in display order


Type 12: descriptive record (views)
-----------------------------------

This record is divided into one or more subrecords. Each subrecord consists
of a type/length word followed by data, just as for the main records of the
file. The following subrecord type exists:

* Subrecord type 0 - view settings

This has the format:
  Offset  0 (byte): DV: status window
  Offset  1 (byte): DV: wrap mode
  Offset  2 (byte): DV: font size
  Offset  3 (byte): WV: status window
  Offset  4 (byte): WV: wrap mode
  Offset  5 (byte): WV: font size
  Offset  6 (byte): YV: status window
  Offset  7 (byte): YV: month shown at top (0 = Jan, ... 11 = Dec)
  Offset  8 (byte): unused, must be zero
  Offset  9 (byte): TV: status window
  Offset 10 (byte): TV: wrap mode
  Offset 11 (byte): TV: font size
  Offset 12 (byte): AV: status window
  Offset 13 (byte): AV: wrap mode
  Offset 14 (byte): AV: font size
  Offset 15 (byte): LV: status window
  Offset 16 (byte): LV: wrap mode
  Offset 17 (byte): LV: font size
  Offset 18 (byte): BV: status window
  Offset 19 (byte): BV: @=show work hour marker lines, @=hide lines
  Offset 20 (byte): @@@ unknown
  Offset 21 (byte):
    bits 0 to 3: view to use on opening ) 0=DV, 1=WV, 2=YV, 3=TV,
    bits 4 to 7: previous view          ) 4=AV, 5=LV, 6=BV

Offsets 18 to 21 do not apply to the Series 3a.

Valid status window settings are 0 (none), 1 (small), and 2 (full). The wrap
mode is 0 if wrapping is off and 1 if it is on. The font size ranges from 0
(the smallest) to 3 (the largest).


Type 13: descriptive record (preferences)
-----------------------------------------

This record is divided into one or more subrecords. Each subrecord consists
of a type/length word followed by data, just as for the main records of the
file. The following subrecord types exist:

* Subrecord type 4 - diamond list
  Offset  0 (byte): 1 = include DV in diamond list, 0 = don't
  Offset  1 (byte): 1 = include WV in diamond list, 0 = don't
  Offset  2 (byte): 1 = include YV in diamond list, 0 = don't
  Offset  3 (byte): 1 = include TV in diamond list, 0 = don't
  Offset  4 (byte): 1 = include AV in diamond list, 0 = don't
  Offset  5 (byte): 1 = include LV in diamond list, 0 = don't
  Offset  6 (byte): 1 = include BV in diamond list, 0 = don't

Offset 6 does not apply to the Series 3a.

* Subrecord type 5 - day entry defaults
  Offset  0 (word): display time for untimed events (minutes past midnight)
  Offset  2 (word): display time for timed   events (minutes past midnight)
  Offset  4 (word): length of timed events in minutes
  Offset  6 (byte): 0 = new events are untimed, 1 = new events are timed
  Offset  7 (byte): entry code
  Offset  8 (byte): 1 = untimed events have an alarm, 0 = no alarm
  Offset  9 (byte): number of days between alarm and untimed events
  Offset 10 (word): untimed event alarm time in minutes past midnight
  Offset 12 to  21: untimed event alarm sound name
                    (qstr, padded with zero bytes)
  Offset 22 (byte): 1 = timed events have an alarm, 0 = no alarm
  Offset 23 (byte): unused, must be zero
  Offset 24 (word): timed event alarm advance time in minutes
  Offset 26 to  35: timed event alarm sound name (qstr, padded with zero bytes)
  Offset 36 (byte): text style
  Offset 37 (byte): unused, must be zero

On the Series 3c and Siena, offset @@ is the default class for entry codes
on day entries (@=open, @=restricted, @=private)

See above for the details of alarm sound names.

* Subrecord type 6 - anniversary entry defaults
  Offset  0 (word): display time for anniversaries (minutes past midnight)
  Offset  2 (byte): 0 = entry code disabled, 1 = entry code enabled
  Offset  3 (byte): entry code
  Offset  4 (byte): 1 = anniversaries have an alarm, 0 = no alarm
  Offset  5 (byte): number of days between alarm and anniversary
  Offset  6 (word): anniversary alarm time in minutes past midnight
  Offset  8 (qstr): anniversary alarm sound name (qstr, padded with zero bytes)
  Offset 18 (byte): text style
  Offset 19 (byte): unused, must be zero

On the Series 3c and Siena, offset @@ is the default class for entry codes
on anniversary entries (@=open, @=restricted, @=private)

See above for the details of alarm sound names.

* Subrecord type 7 - general defaults
  Offset  0 (byte): 0 = PSION+ENTER disabled, 1 = PSION+ENTER enabled
  Offset  1 (byte): time separator character
  Offset  2 (byte): starting view (0=DV, 1=WV, 2=YV, 3=TV, 4=AV, 5=LV,
                    6=BV, 7=last view used)
  Offset  3 (byte): 0=hide entry codes, 1=show entry codes

Offsets 2 to 3 do not apply to the Series 3a.

* Subrecord type  8 - Siena day view
* Subrecord type  9 - Series 3a and Series 3c day view
* Subrecord type 10 - week view
* Subrecord type 11 - year view
* Subrecord type 14 - list view
Offsets 2 to 13 apply only to subrecords type 8 and 9. Offsets 14 to 25
apply only to subrecord type 9.
  Offset  0 (word):
    bit  0: set to show timed event durations
    bit  1: set to show timed event end times
    bit  2: title position: clear=left, set=right (DV and WV only);
            show repeats: clear=all, set=next only (LV only)
    bit  3: slot compression: clear=on, set=off (DV only)
    bit  4: clear to show duration arrows (DV only)
    bit  5: clear to show overlap bars (DV only)
    bit  8: set to show untimed events (DV, WV, and LV only)
    bit  9: set to show anniversaries  (DV, WV, and LV only)
    bit 10: set to show to-do entries  (DV, WV, and LV only)
    bit 11: set to show timed events   (DV, WV, and LV only)
  Offset  2 (word): left  side shows: 0=neither, 1=lines, 2=times, 3=both
  Offset  4 (word): must be 0
  Offset  6 (word): left  side "from" time in minutes past midnight
  Offset  8 (word): left  side "to"   time in minutes past midnight
  Offset 10 (word): right side "from" time in minutes past midnight
  Offset 12 (word): left  side slot duration in minutes
  Offset 14 (word): right side shows: 0=neither, 1=lines, 2=times, 3=both
  Offset 16 (word): must equal offset 10
  Offset 18 (word): must equal offset 10
  Offset 20 (word): right side "to"   time in minutes past midnight
  Offset 22 (word): must be 1440 ($05A0)
  Offset 24 (word): right side slot duration in minutes

* Subrecord type 12 - to-do view
* Subrecord type 13 - anniversary view
  Offset  0 (word): number of columns shown (limit 4 in AV)

* Subrecord type 15 - busy view (does not apply on the Series 3a)
  Offset  0 (word): view start time in minutes past midnight
  Offset  2 (word): view end time   in minutes past midnight
  Offset  4 (word):
    bit 0: set to show appointment duration
    bit 1: set to show appointment end time
    bit 2: unused, must be zero
    bit 3: set for "show in Series 3c"
    bit 4: set to show vertical grid
    bit 5: set to show horizontal grid
    bit 6: set to show overlap bars
    bit 7: set to show crossed out entries
  Offset  6 (word): work hours start time in minutes past midnight
  Offset  8 (word): work hours end time   in minutes past midnight


Type 14: descriptive record (printing)
--------------------------------------

This record is divided into one or more subrecords. Each subrecord consists
of a type/length word followed by data, just as for the main records of the
file. Subrecord types 0 to 3 apply to printing the agenda, and correspond to
record types 2 to 5 respectively of Word format (see Psionics file WORD.FMT).
Subrecord types 6 to 9 apply to printing memos, and correspond to the same
Word record types.
The Psionics Files

BITMAP.FMT

PSIONICS FILE - BITMAP.FMT
==========================
Format of Bitmap files
Last modified 1996-01-26
========================

A bitmap file (also called a .PIC file) begins with an 8 byte header of the
following form:
  Offset  0 to   2: "PIC"
  Offset  3 (byte): $DC
  Offset  4 (byte): format version number
  Offset  5 (byte): OPL runtime version number
  Offset  6 (word): number of bitmaps in the file

The format and OPL runtime version number are always $30.

This header is then followed by the appropriate number of bitmap descriptor
records. These are each 12 bytes:
  Offset  0 (word): CRC of bitmap data (but not descriptor)
  Offset  2 (word): width of bitmap
  Offset  4 (word): height of bitmap
  Offset  6 (word): size of bitmap data in bytes
  Offset  8 (long): distance from the end of this record to the start of
                    the data, in bytes.

Note that offset 8 is relative to the current record, not to the end of all
the descriptor records. For example, if the file contains 3 bitmaps of 48,
52, and 30 bytes respectively, the three offsets are 24 (2 * 12), 60 (1 * 12
+ 48), and 100 (48 + 52). If a fourth bitmap is added at the end, these three
will be increased by 12, and the fourth offset will be 130 (48 + 52 + 30).

The data is stored from top to bottom. Each row is rounded up to an even
number of bytes, and is stored from left to right, with bit 0 of each byte
being the leftmost pixel of the 8 represented.
The Psionics Files

COUNTRY.FMT

PSIONICS FILE - COUNTRY.FMT
===========================
Format of Country information files
Last modified 1997-04-02
===================================

The ROM:: filing system contains files which hold localization data.
These files have names like SYS$CTRY.~01, where the number is the locale code
(the built-in language file, English on my machine, is SYS$CTRY.CFO).

These files appear to have the following format (note that the first 40
bytes have the same format as used by system call Fn $8B Sub $05):
  Offset   0 (word): country code (e.g. UK is 44) of locale
  Offset   2 (word): current offset from GMT in minutes (+ is ahead)
  Offset   4 (byte): date format (0 = MDY, 1 = DMY, 2 = YMD)
  Offset   5 (byte): time format (0 = am-pm, 1 = 24 hour)
  Offset   6 (byte): currency symbol position (0 = before, 1 = after)
  Offset   7 (byte): currency symbol separated with space (0 = yes, 1 = no)
  Offset   8 (byte): currency decimal places
  Offset   9 (byte): currency negative format (0 = minus, 1 = brackets)
  Offset  10 (byte): currency separate thousands
                     (0 = no, 1 = yes, 4 = 10000 and over)
  Offset  11 (byte): thousands separator
  Offset  12 (byte): decimal separator
  Offset  13 (byte): date separator
  Offset  14 (byte): time separator
  Offset  15 (cstr): currency symbol
  Offset  24 (byte): start of week (0 = Mon, 1 = Tue, ... 6 = Sun)
  Offset  25 (byte): summer times: 2 = European, 4 = Northern, 8 = Southern
  Offset  26 (byte): clock type (0 = analogue, 1 = digital)
  Offset  27 (byte): number of letters in day abbreviation (0 to 6)
  Offset  28 (byte): number of letters in month abbreviation (0 to 255)
  Offset  29 (byte): workdays (the set bits indicate the workdays)
    Bit 0: Monday
    Bit 1: Tuesday
    Bit 2: Wednesday
    Bit 3: Thursday
    Bit 4: Friday
    Bit 5: Saturday
    Bit 6: Sunday
    Bit 7: unused, always zero
  Offset  30 (byte): units (0 = inches, 1 = centimetres)
  Offset  31 to  39: unknown, always zero
  Offset  40 (word): locale code
  Offset  42 (cstr): suffix for ordinal 1 ("st" in English)
  Offset  45 (cstr): suffix for ordinal 2 ("nd" in English)
  ...
  Offset 132 (cstr): suffix for ordinal 31 ("st" in English)
  Offset 135 (cstr): suffix for 12-hour clock times before midday
  Offset 138 (cstr): suffix for 12-hour clock times after midday
  Offset 141 to 396: character type table - entry i describes character i:
    Bit 0: set if an uppercase letter
    Bit 1: set if a lowercase letter
    Bit 2: set if a decimal digit
    Bit 3: set if a cursor movement code
    Bit 4: set if an other graphic character
    Bit 5: set if a control code
    Bit 6: set if a hexadecimal digit
    Bit 7: space
  Offset  397 to  652: table to convert to uppercase
  Offset  653 to  908: table to convert to lowercase
  Offset  909 to 1164: table to fold character (see below)
  Offset 1165 to 1996: unknown [looks like a table of words]

Starting at offset 1997 are 5 message tables:
  Application errors
  OPL errors
  I/O errors
  OS errors
  System messages
Each table has the format:
  Offset  0 (word): number of first message in the table (F)
  Offset  1 (byte): number of last message in the table (L)
  Offset  2 (word): offset in the file of the next table
  Offset 4 onwards consists of (L - F + 1) qstrs.

Folding characters (offset 909) converts the character to a form which omits
accents and case; by convention (but not required) folded characters are always
uppercase.
The Psionics Files

DBF.FMT

PSIONICS FILE - DBF.FMT
=======================
Format and use of Data files
Last modified 1998-08-03
========================

File format
-----------

A data file (also called a DBF file) begins with a 22 byte header of the
following form:
  Offset  0 to  15: file signature
  Offset 16 (word): DBF software version number used to create the file
  Offset 18 (word): size of header in bytes (N)
  Offset 20 (word): earliest DBF software version number that can use the file
  Offset 22 to N-1: extended header

The signature is used to verify that the file is applicable to the application
using it. The version numbers are used to verify that the format is compatible;
only the top 4 bits are tested.

Files created using the Data or Agenda (Series 3t) applications or the CREATE
keyword have a signature which is the cstr "OPLDatabaseFile". Series 3c Jotter
files are also DBF files.

The rest of the file consists of records. All records have the form:
  Offset  0 (word):
    Bits  0 to 11: size of data portion (L)
    Bits 12 to 15: record type
       0 = deleted record (should be ignored)
       1 = mergable data record
       2 = field information record
       3 = descriptive record
       4 = private data record
       5 = private data record
       6 = private data record
       7 = private data record
       8 = mergable data record
       9 = mergable data record
      10 = mergable data record
      11 = mergable data record
      12 = mergable data record
      13 = mergable data record
      14 = mergable voice data record
      15 = reserved for system use
  Offset  2 to L+1: data portion

There may be at most 65534 records, and the data portion of each is limited
to 4094 bytes (so the total record length is limited to 4096 bytes).

When a file is merged into another one, mergable data records will be copied,
but not private data records, the field information record, or the descriptive
record.

Data files are based around fields. fields may be words, longs, reals, or
qstrs (limited to 254 characters). Fields after the first 32 are less usable;
for example, they must be qstrs, and cannot be accessed through OPL data file
keywords.

The first record in the file must be a field information record, and all other
field information records in the file will be ignored. Each byte of the record
specifies the type of the corresponding field:
    0 = word
    1 = long
    2 = real
    3 = qstr
The field information record must define between 1 and 32 fields; if it defines
exactly 32, then fields 33 onwards are all qstrs, as noted above.

Data records are broken into fields by the DBF software according to the field
information record; there are no separators between the fields of a record.
Trailing fields that are empty qstrs or zero numbers may be omitted from a
record.

The Data application uses the following special character codes within qstr
fields:
   5 = diallable telephone number follows
  20 = (if first character of field) treat this field as joined on to the
       previous one, which must also be a qstr
  21 = forced line feed

There should only be one descriptive record in a file, but it can occur
anywhere in the file. The descriptive record consists of one or more subrecords
with the same format (length, type, data) as normal records. In general,
unknown types of subrecord should be copied unchanged, as other applications
may be using them.

The Data application uses the following types of subrecord. Types 2 and 3 are
used on the MC and are not described. Types 6 to 11 are not used on the
Series 3t version of Data, and types 12 to 14 are only used on the Series 3c
and Siena.

* Subrecord type 1
This contains 2 bytes:
  Offset  0 (word): tab size

* Subrecord type 4
This contains the field labels as qstrs, in order. Trailing blank labels may,
but need not, be omitted.

* Subrecord type 5
This contains 2 bytes:
  Offset  0 (byte):
    Bit 0:        status window visible (Series 3t)
    Bit 1:        wrap on
    Bit 2:        labels visible
    Bits 3 and 4: status window (Series 3a): 0=none, 1=narrow, 2=full
    Bits 4 and 5: zoom level (3, 0, 1, 2 from smallest to largest, 0 default)
  Offset  1 (byte): unused

* Subrecord type 6
This holds information about printer set-up and is identical to record type 2
in Word files (see WORD.FMT).

* Subrecord type 7
This is used to store the printer driver. It is identical to record type 3 in
Word files:
  Offset  0 (byte): printer driver model number
  Offset  1 (cstr): printer driver library
A printer driver library can support several similar printers; the model number
specifies which is selected.

* Subrecord type 8
This holds the header text as a cstr.

* Subrecord type 9
This holds the footer text as a cstr.

* Subrecord type 10
This contains 3 bytes and holds diamond settings:
  Offset  0 (byte): 0=omit Find,   255=include Find
  Offset  1 (byte): 0=omit Change, 255=include Change
  Offset  2 (byte): 0=omit Add,    255=include Add

* Subrecord type 11
This contains 4 bytes and holds the current search status:
  Offset  0 (word): start field (0 means all fields, 1 means first field, etc.)
  Offset  2 (word): end field (255 means all from start field)

* Subrecord type 12
This contains information concerning List view. The first 6 bytes are:
  Offset  0 (word): number of locked columns
  Offset  2 (byte): zoom level
  Offset  3 (byte): status window size
  Offset  4 (word): 0=no grid lines, 2=grid lines
This is followed by words giving the width in pixels of the columns in order.

* Subrecord type 13
This contains 4 bytes and holds diamond settings (overriding those in any
subrecord type 10):
  Offset  0 (byte): 0=omit Find,   255=include Find
  Offset  1 (byte): 0=omit Change, 255=include Change
  Offset  2 (byte): 0=omit Add,    255=include Add
  Offset  3 (byte): 0=omit List,   255=include List

* Subrecord type 14
This contains 16 bytes and holds the sort settings:
  Offset  0 (word): number of sort keys (1 to 3)
  Offset  2 (word): field number of sort key 1
  Offset  4 (word): field number of sort key 2
  Offset  6 (word): field number of sort key 3
  Offset  8 (word):
    Bit @: set if sort is case sensitive, clear if case insensitive
    Bit @: set if sort key 1 is descending, clear if ascending
  Offset 10 (word): 0 = sort key 2 is ascending, @ = descending
  Offset 12 (word): 0 = sort key 3 is ascending, @ = descending
  Offset 14 (byte): size of sort key to be stored (@@@?)
  Offset 15 (byte): sort file on opening (0 = no, 1 = ask, 2 = yes)

* Subrecord type 15
This is used by the Series 3t Agenda. See AGENDA.FMT for more details.


Kernel services
---------------

See the file SYSCALLS.1 for the general notation used. In every case, the
Fn value is $D8.

Most calls require use of a working buffer. This buffer can be between 512 and
16384 bytes long, but must be at least as long as the longest record in the
relevant file (including the header), so a buffer of 4096 bytes is always
sufficient. In general, file access will be faster with a larger buffer.
Except where stated, the contents of the buffer may changed by any call on that
DBF, and must not be altered by the application.

A file may be opened in indexed or unindexed mode. Unindexed mode is faster to
open, but certain calls (those marked "indexed") can only be made if the file
was opened in indexed mode. It is not possible to change the mode once the
file has been opened. It is only possible to access one type of record via a
given file handle (though, if a read-only-sharing mode is used, more than one
handle can be open to the same file); to change the type, it is necessary to
close and reopen the file.

Record numbers are those of the selected record type (starting at 0), ignoring
all other types. If a file holds more than 65534 records of a given type, those
beyond that number are ignored unless stated otherwise.

Calls that read a record always read it into the working buffer. The call will
always return two values: the record length and the record "offset". The
length is that of the data portion. The offset is the offset, in the working
buffer, where a copy of the record can be found. This copy includes the size
and type word, so the data starts two bytes later. This mechanism allows data
to be read into the buffer ahead of time, improving efficiency.


Sub $00
DbfOpen fails
    BX: address of control block
    CX: record type to access (1, or 4 to 14)
    DX: size of the working buffer
    SI: address of the working buffer
    DI: open flag -> new flag
Opens a DBF file. The open flag may be one of the following:
  -2 = open in unindexed mode; when the call returns, the file is open
  -1 = open in indexed mode; when the call returns, the file is open
   0 = open in indexed mode; when the call returns, the file is not yet open.
       The call should then be repeated until 0 is returned in DI.
       Alternatively, the file may be closed before it is completely open.
       The total number of calls required to open the file is approximately
       the file size divided by the working buffer size.
When the file is completely open, the current record is set to record 0.

The control block has the following format:
  Offset  0 (word): address of a word into which the DBF handle will be written
  Offset  2 (word): (cstr) file name
  Offset  4 (word): file open mode
  Offset  6 (word): address of header block
The meaning of the file open mode is as for IOOPEN (see Psionics file FILEIO),
except that the format component is ignored. The header block consists of a 56
byte block as follows:
  Offset  0 to  15: file signature
  Offset 16 (word): DBF software version number used to create the file
  Offset 18 (word): size of file header in bytes
  Offset 20 (word): earliest DBF software version number that can use the file
  Offset 22 (word): header of the field information record ($2000 plus the
                    number of fields, or $2020 if more than 32 fields)
  Offset 24 to  55: body of the field information record

If the file is being created or replaced, the entire block will be written to
the file (with a gap before the field information record if offset 18 is
greater than 22, and truncated to the length of the field information record).
The top 4 bits of offset 20 must be consistent with the current DBF software
version number (see DbfVersion).

If an existing file is being opened, the file signature (all 16 bytes) must be
identical to that in the file, and the top 4 bits of the software version
number at offset 20 of the file must be consistent with the current DBF
software. If both are true, the file header and field information record are
copied into the header block. Otherwise the open fails.


Sub $01
DbfClose fails
    BX: DBF handle
The DBF file is closed.


Sub $02
DbfFlush fails
    BX: DBF handle
All buffers associated with the DBF file are flushed.


Sub $03
DbfTrash
    BX: DBF handle
Instructs the kernel that the working buffer contents are about to be altered,
and so will not be valid at the point of the next call on this DBF. The
application can then use the buffer for other purposes (e.g. to construct the
record to be written by DbfAppend).


Sub $04
DbfCopyDown
    AX: -> length of record
    BX: DBF handle
    SI: record offset returned by another DBF call
The record at the given offset is copied to the start of the working buffer,
and instructs the kernel that the working buffer must not be used.


Sub $05
DbfCompress fails indexed
    BX: DBF handle
    DI: compress flag -> new flag
Compresses the DBF file if on a compressible device. The flag may be:
  -1 = when the call returns, the file is compressed
   0 = when the call returns, the file is not yet compressed. The call should
       then be repeated until 0 is returned in DI. The total number of calls
       required is approximately the file size divided by the working buffer
       size.
When the file is compressed, the current record will be the end of file.


Sub $06
DbfCopyFile fails
    BX: DBF handle
    CX: record type to copy (15=all types), plus 256 if copying in, not out
    DX: open mode for target file (see DbfOpen for details)
    SI: (cstr) target file name
    DI: copy flag -> new flag
Copies all records of the indicated type from the DBF file indicated by the
handle to the target file (if 256 was added to CX, then copies from the target
file to the open file).

If the target file is created or replaced, the original file's header and field
information record are copied to the target file. If an existing file is
opened (including when copying in), the signatures must be the same and the
field information records must be compatible. Opening for append only is the
same as opening for update.

If type 15 is selected, then:
* if copying to an existing file or copying in, only mergable data records
  (record types 1 and 8 to 14) are copied;
* if copying to a new or replaced file, all records (types 1 to 14) are copied.

The copy flag may be:
  -1 = when the call returns, the copy is complete.
   0 = when the call returns, the copy is not yet complete. The call should
       then be repeated until 0 is returned in DI. Alternatively, DI may be
       set to -2, which will abandon the copy. The total number of calls
       required is approximately the file size divided by the working buffer
       size.


Sub $07
DbfFileSize fails
    BX: DBF handle
    DX: low half of file size
    DI: high half of file size
Returns the size of the file, in bytes.


Sub $08
DbfExtHeaderRead fails
    AX: 0=start at beginning, 1=continue -> number of bytes read
    BX: DBF handle
    CX: number of bytes to read
    SI: address of buffer
The indicated number of bytes are read from the extended header of the file
into the buffer; the call fails when the header is exhausted. If AX is 0, the
first byte read is from offset 22. If AX is 1, it is that following the last
byte read by the previous call.


Sub $09
DbfExtHeaderWrite fails
    AX: 0=start at beginning, 1=continue -> number of bytes written
    BX: DBF handle
    CX: number of bytes in buffer
    SI: address of buffer
The indicated number of bytes are written from the buffer to the extended
header of the file. If AX is 0, the first byte is written to offset 22. If AX
is 1, it is written immediately following the last byte written by the previous
call. The call fails if offset 18 of the file is 22, or if the previous call
(when AX is 1) filled the space indicated by offset 18.


Sub $0A
DbfVersion
    AX: -> version number
Returns the version of the DBF software. The top 4 bits indicate the major
version number, which is used to determine compatibility of files.


Sub $0B
DbfAbsReadSense fails
Sub $0C
DbfAbsRead fails
    AX: -> record length
    BX: DBF handle
    CX: record number
    DX: -> low  half of record position within file
    SI: -> record offset
    DI: -> high half of record position within file
Reads the specified record into the working buffer. If the record number is
too large, the call fails and the current record is set to the end of file.
Otherwise the current record is set to the record read. DX and DI are only set
by DbfAbsReadSense, and are unaltered by DbfAbsRead.


Sub $0D
DbfNextRead fails
Sub $0E
DbfBackRead fails
Sub $0F
DbfFirstRead fails
Sub $10
DbfLastRead fails indexed
    AX: -> record length
    BX: DBF handle
    SI: -> record offset
Reads the next, previous, first, or last record. If the record does not exist,
the call fails and the current record is set to end of file; if DbfBackRead is
called when the current record is record 0, the call fails and the current
record remains record 0. Otherwise the current record is set to the record
just read.


Sub $11
DbfAppend fails indexed
    BX: DBF handle
    CX: record length
A record built from the data starting at offset 2 of the working buffer is
appended to the file.


Sub $12
DbfEraseRead fails indexed
    AX: -> record length
    BX: DBF handle
    SI: -> record offset
    DI: erase flag -> new flag
The current record is deleted, and the following record is read. The call will
fail if either the record deleted was the last one (though the record will have
been deleted) or if the current record was end of file (in which case nothing
is deleted). The erase flag may be:
  -1 = when the call returns, the operation is complete.
   0 = when the call returns, the operation is not yet complete. The call
       should then be repeated until 0 is returned in DI.


Sub $13
DbfUpdate fails indexed
    BX: DBF handle
    CX: record length
    DI: update flag -> new flag
A record built from the data starting at offset 2 of the working buffer is
appended to the file, after which the current record is deleted. When this has
been done, the current record is set to the newly written record. If there is
no record to delete, the call will fail without writing anything. If the record
deleted is the last one in the file, the write and delete will work, but the
call will still appear to fail.

The update flag may be:
  -1 = when the call returns, the operation is complete.
   0 = when the call returns, the operation is not yet complete. The call
       should then be repeated until 0 is returned in DI.


Sub $14
DbfFindRead fails indexed in some cases
    AX: number of fields to search -> record length
    BX: DBF handle
    CX: length of pattern
    DX: control flags
    SI: address of the pattern -> record offset
    DI: match flag -> new flag
Searches the file for a record containing a field matching the pattern (which
can contain wildcards). If a match is found, the corresponding record is read;
otherwise the call fails. Only the number of string fields indicated are
examined (non-string fields are ignored), or all string fields if AX is -1.
The control flags are as follows:
    Bits  0 to  7: maximum number of characters in the field to examine (255
                   means the entire field)
    Bits  8 to 11:
        0 = backwards starting at current record [not indexed]
        1 = forwards  starting at current record [not indexed]
        2 = backwards starting at end of file    [indexed]
        3 = forwards  starting at record 0       [not indexed]
    Bits 12 to 15:
        0 = case independent
        1 = case dependent
The match flag may be:
  -1 = when the call returns, the search is complete.
   0 = when the call returns, the search is not yet complete. The call should
       then be repeated until 0 is returned in DI. The total number of calls
       required is approximately the file size divided by the working buffer
       size.


Sub $15
DbfSense
    AX: -> record number
    BX: DBF handle
Returns the current record number (the number if records if the current record
is the end of file).


Sub $16
DbfCount indexed
    AX: -> number of records
    BX: DBF handle
Returns the number of records (of the appropriate type) in the file. The
current record is unaltered.


Sub $17
DbfDescRecordRead fails indexed
    AX: -> length of the descriptive record data
    BX: DBF handle
Reads the descriptive record into the start of the working buffer.


Sub $18
DbfDescRecordWrite fails indexed
    BX: DBF handle
    CX: length of descriptive record data (0 = delete descriptive record)
Replaces the descriptive record with that in the working buffer. The record
data should start at offset 2 (the word at offset 0 will be altered).


Sub $19
DbfFindReadField v3 fails indexed in some cases
    AX: number of fields to search -> record length
    BX: DBF handle
    CX: length of pattern
    DX: control flags
    SI: address of the pattern -> record offset
    DI: match flag -> new flag
This call is identical to DbfFindRead, except that it skips N string fields in
each record before examining the next AX string fields. The value of N is taken
from offset 14 of the data segment of the current process. For example, to
examine only the fourth and fifth string fields, set N to 3 and AX to 2.

Warning: this location is used by many OPL keywords (particularly those for
dialogs and menus). It should be saved and restored around the call to this
function.
The Psionics Files

DEVICES

PSIONICS FILE - DEVICES
=======================
Device driver interfaces
Last modified 1998-11-06
========================

This document describes all known functions for all known device drivers. It
does not include file IO, even when done through the same interfaces.

The device drivers documented are:
  SND: Sound device
  TIM: Timer device
  ALM: Alarm device
  WLD: World device
  TTY: Serial port device (including IR)
  PAR: Parallel port device
  FRC: Free running counter
  XMD: XModem driver
  YMD: YModem driver
  WLS: Workabout laser scanner
  AIR: AccessIr driver
  Console device


Types of device driver
----------------------
On the Series 3, much functionality, including the filing system, is provided
via device drivers. There are three kinds of device drivers:
* physical device drivers: these drive the hardware directly
* base logical device drivers: these provide a basic abstraction for working
  with logical device drivers
* stacked logical device drivers: these provide higher levels of abstraction
Only logical device drivers need to know about physical device drivers; all
user applications operate through logical device drivers.

For example, the 3-Link pod and cable might be accessed through a physical
device driver called TTY.LNK: (all physical device drivers have a two part
name). This is automatically loaded the first time that the logical device
driver TTY: is opened, and TTY: will use it to actually communicate with the
pod.

When TTY: is opened, the kernel will return a handle. Read and write operations
on that handle will send data directly to and from the port. Alternatively,
the XMD: device driver could be stacked on top of TTY: on that handle. Once
this has been done, read and write on that handle will now be done via the XMD:
driver, which wraps the data in the XModem protocol and calls the TTY: driver
to do the actual output. There is no limit to how many device drivers can be
stacked upon one another.


Opening a handle
----------------
A base logical device driver is opened with the IOOPEN keyword or the IoOpen
system call; a stacked logical device driver is opened with IoOpen. The name is
examined to see whether it has a colon as the fourth character but not the
fifth; if so, it is split into a device name and a channel name. The kernel
then checks that the logical device exists; if not, or if the name does not
have the correct form, it prefixes "FIL:" to the name and tries again (FIL
is the filing system logical device driver). For example:
    "SND:"        device "SND"  channel name ""
    "TTY:A"       device "TTY"  channel name "A"
    "FIL:A:XXX"   device "FIL"  channel name "A:XXX"
    "HELLO.TXT"   device "FIL"  channel name "HELLO.TXT"
    "ROM::XXX"    device "FIL"  channel name "ROM::XXX"
    "FIL:TTY:"    device "FIL"  channel name "TTY:"
    "QXV:"        device "FIL"  channel name "QXV:"
[the last example assumes there is no QXV device driver].

The filing system and the FIL: driver are described in the Psionics file
FILEIO. All other known drivers are described here.

IOOPEN and IoOpen are passed a mode to open the device or file. Drivers other
than the filing system and those specifically mentioning it ignore the mode.
It is recommended that a mode of -1 be used, as this is always rejected by the
filing system; thus an error in the device name or a missing driver will be
detected. Note that the IOOPEN keyword uses a qstr, while the IoOpen system
call uses a cstr.

A driver may refuse to open a given channel name, or all channels, more than
a certain number of times without closing some first. For example, a TTY
driver might only allow one open handle at a time for each port.

In OPL there are two special handles that do not need to be opened:
    -1: the device opened by LOPEN
    -2: the console device (see below)


Using the device driver
-----------------------
Once a device driver has been opened, it is accessed with the keywords IOW,
IOA, and IOC (Series 3a only). These keywords offer the same services, and
differ only in the way completion is indicated.

IOW waits until the operation completes, and then returns. No signal is
    generated.
IOA has an extra status variable argument. The variable is set to -46 at the
    start of the operation, and then to the final result when it completes; a
    signal is generated at this moment (it can be collected with IOWAIT or
    IOWAITSTAT). Note that some operations complete immediately, and so the
    status of -46 is never seen.
IOC is like IOA, but if the operation completes immediately, it places the
    result into the status variable and generates a signal. Thus the code
    making the call can check the result in one place (after collecting the
    signal) rather than two (after the call and after the signal).

Each call is passed a function number and two parameters for passing other
information. The latter identify blocks of memory; the actual argument can be
either the name of an OPL variable (typically the first element of an array),
in which case that variable marks the start of the block, or it can be the #
operator applied to the address of the block. The former is equivalent to
#ADDR(variable).

If the parameter is shown as "unused", then any variable or value can be used,
as it will be ignored; it is often convenient to use #0 as such an argument.

Unless stated otherwise, a successful call returns zero, and an unsuccessful
call some non-zero error code.


Standard functions
------------------

These functions apply to all drivers.

Function:   1 (read)
Function:   2 (write)
Argument 1: buffer
Argument 2: count (word)

These functions are equivalent to the IOREAD and IOWRITE keywords. They read
or write up to the specified number of bytes from or to the device; in the
case of function 1, the count is changed to the actual amount read.

These functions can be used with any handle that is using a driver labelled
as a data device (such as the serial port device or the XModem driver).


Function:   3
Argument 1: unused
Argument 2: unused

This will close the handle; it is equivalent to the IOCLOSE keyword.


Function:   4
Argument 1: unused
Argument 2: unused

This will cancel any uncompleted function on the handle; the function will
complete immediately, with the status variable set to -48 ("I/O cancelled").
A signal will still be generated, and must be collected with IOWAITSTAT or
IOWAIT.


Sound device
------------

The sound device has the name "SND:". There are no channel names. Only one
handle can be open at a time, and so the device should be closed as soon as
possible.


Function:   1 (sound channel 1)
Function:   2 (sound channel 2)
Argument 1: note information
Argument 2: word holding number of notes
This function is supported by the HC, MC, and Series 3a only.

This plays a sequence of notes on the specified sound channel. The note
information is an array of words, two per note; the first is the frequency of
the note (in Hz), and the second the duration in beats (see function 7).
The sound will not start until both these functions have been called (thus
ensuring the sound is synchronized on both channels). The function completes
when the specified channel finishes playing, even if the other has not.


Function:   7
Argument 1: 2 byte information block
Argument 2: unused

The characteristics of the sound system are set according to the block:
  Offset  0 (byte): beats per minute (2 to 240, default 120)
  Offset  1 (byte): volume (0 max to 5 min)
The beats per minute is only supported by the HC, MC, and Series 3a. On the
Series 3a, volumes 1 and 2 are identical, as are 4 and 5. On the Series 3t,
volumes 0 and 5 are unavailable.


Function:   8
Argument 1: 2 byte information block
Argument 2: unused

The block is filled in with information about the sound channel, using the
same format as function 7.


Function:   9
Argument 1: alarm type (0 = rings, 1 = chimes)
Argument 2: unused

The specified alarm is played; this function completes when the sound has
completely played.


Function:   10
Argument 1: phone number (cstr)
Argument 2: parameter block

This generates DTMF dialling sounds. The number contains the digits to be
dialled (0 to 9, *, #, and A to F can be used; E is the same as *, and F the
same as #). The parameter block has the format:
  Offset 0 (byte): tone length   )
  Offset 1 (byte): delay length  ) all in 1/32 seconds
  Offset 2 (word): pause length  )



Timer device
------------

The timer device has the name "TIM:". There are no channel names.

Several channels may be opened at the same time by the same process.

Function:   1
Argument 1: delay in 1/10 seconds (long)
Argument 2: unused

This will complete after the specified delay. Time when the machine is switched
off is not counted as part of the delay. Changing the system clock will not
affect the completion of this function.


Function:   2
Argument 1: abstime (long)
Argument 2: unused

This will complete at the specified time. If the machine is switched off at
that time, it will switch back on. Changing the system clock will affect the
completion of this function.


Alarm device
------------

The alarm device has the name "ALM:". There are no channel names.

Function:   1 (display date only)
Function:   2 (display date and time)
Argument 1: time specification block
Argument 2: message (cstr)

This schedules an alarm, which causes a message box to be shown at some later
time. The time specification block has the format:
  Offset  0 (long): abstime when the alarm should sound
  Offset  4 (long): abstime to be displayed in the message box
The message (maximum 64 characters) is shown in the message box.

The function completes when the alarm goes off. If the machine is switched off
at that time, it will switch back on. Changing the system clock will affect the
completion of this function.


Function:   10 (display date only)
Function:   11 (display date and time)
Argument 1: time specification block
Argument 2: message (cstr)
These functions are supported by the Series 3a only.

This schedules an alarm, which causes a message box to be shown at some later
time. The time specification block has the format:
  Offset  0 (long): abstime when the alarm should sound
  Offset  4 (long): abstime to be displayed in the message box
  Offset  8 (qstr): name of alarm sound

These functions are identical to functions 1 and 2, except that the alarm sound
is specified by the call. The sound name may be one of the following:
- the name of a sound file; this is searched for in each of:
    A:\WVE\name.WVE
    B:\WVE\name.WVE
    M:\WVE\name.WVE
    ROM::name.WVE
  [This appears to be the search order, but it is not documented.]
  The Series 3a ROM contains the sounds:
    SYS$AL01   Fanfare
    SYS$AL02   Soft bells
    SYS$AL03   Church bell
- a single byte (thus offset 8 is set to 1) with the value 1 (for rings),
  2 (for chimes), or 16 (for silence).


World device
------------

The world device has the name "WLD:". There are no channel names.

This device gives access to the World database. This includes the built-in
database and any one world file. If the World application is running, this is
the file it currently has open. Otherwise it is the last world file to be open,
or the world file opened with function 21.

World files have a format which varies from version to version of the operating
system, and are limited to 32 entries. This is because the file is mapped into
kernel address space and accessed directly, rather than being loaded in the
usual manner.

Several functions use a "city name block". This is a 42 byte block with the
format:
  Offset  0 to 20: name of a city (cstr)
  Offset 21 to 41: name of a country (cstr)
Unless stated otherwise, the country is that in which the city lies.

Many functions establish or use a searching order. This can be set to:
- all cities, in alphabetical order ("city order")
- capital cities, in alphabetical order of country ("country order")
Search order is cyclic: the last city or country is followed by the first.


Function:   10
Argument 1: clue (cstr)
Argument 2: city name block

This locates a city whose name begins with the clue (the search is done with
folded strings, so "lon" will find London, but "ond" will not). If successful,
the city block is filled in with the city, and city order is set.


Function:   11
Argument 1: clue (cstr)
Argument 2: city name block

This locates a country whose name begins with the clue (the search is done with
folded strings, so "lon" will find London, but "ond" will not). If successful,
the city block is filled in with the capital city of the country, and country
order is set.


Function:   12
Argument 1: city name block
Argument 2: unused

This locates either the city whose name is in the city part of the block, or,
if the city part is an empty string, the capital city of the country whose name
is in the country part of the block (in either case, the string must be exact
after folding). If successful, the block is filled in, and city or country
order (according to what was searched for) is set.


Function:   13 (next city)
Function:   14 (previous city)
Argument 1: city name block
Argument 2: unused

These functions fill the block with the next (or previous) city in the current
search order.


Function:   15
Argument 1: city name block
Argument 2: unused

This function fills the block with the home city; city order is set.


Function:   16
Argument 1: unused
Argument 2: unused

This function sets the home city to the last city returned.


Function:   17
Argument 1: city name block
Argument 2: unused

This function fills the block with the capital city of the default country;
city order is set.


Function:   18
Argument 1: unused
Argument 2: unused

This function sets the default country to that of the last city returned.


Function:   19
Argument 1: original number (cstr)
Argument 2: diallable number (cstr)

This function generates a diallable number (up to 24 characters) from the
original number (up to 128 characters), using the following rules:
- all characters before the first digit are stripped from the number;
- the number then ends at the first character other than a digit, space, or the
  special characters * # , and - (star, hash, comma, and dash);
- if there are any spaces or dashes in the number, they are removed and the
  diallable number is modified as follows:
  * if the first digit was a zero, it is removed;
  * if the home city is not in the default country, the sequence is prefixed
    with the international sequence to dial from the home city to the default
    country;
- if not, the number is precisely those characters left.

For example, "abc,123,456xx789" generates "123,456". Assuming that the default
country is the UK and the default city is in the USA, "abc00-34 56x78"
generates "01144003456".

@David said that this just generates the dial string@
@David implied this also does [country]@


Function:   20
Argument 1: (word) the value 0 (to add) or 1 (to update)
Argument 2: 80 byte information block

Adds or updates the city described by the information block (in the format of
function 22) to the open world file.


Function:   20
Argument 1: (word) the value 2
Argument 2: unused

The current item is deleted from the open world file if it is in it, not the
current home city, and not a capital city of an added country. The function
returns 1 if the entry was hiding an entry in the ROM database, and 0
otherwise.


Function:   20
Argument 1: (word) the value 3
Argument 2: 66 byte information block

Adds or updates the country described by the information block (in the format
of function 23) to the open world file. All cities in the country will have
their GMT offset and DST rule updated to match the data.


Function:   21
Argument 1: (word) mode (0 = open, 1 = create, 2 = replace)
Argument 2: (cstr) filename

This function opens, creates, or replaces a world file for use. The modes have
the meanings described in the Psionics file FILEIO. If the last returned city
is in the database, it is no longer valid (but functions 13, 14, and 25 still
work). The default extension is ".WLD".


Function:   22
Argument 1: 80 byte buffer
Argument 2: unused

This function fills the buffer with information about the last city returned:
  Offset  0 to  20: (cstr) city name
  Offset 21 to  41: (cstr) country name
  Offset 43 (byte): DST rule: 0 = none, 2 = European, 4 = North, 8 = South
  Offset 44 (word): minutes ahead of GMT for city
  Offset 46 (word): city latitude in minutes north (negative means south)
  Offset 48 (word): city longtitude in minutes west (negative means east)
  Offset 50 to  66: (cstr) dial code from home city
  Offset 67 to  75: (cstr) area code of city
  Offset 76 (word): X coordinate of city on map (in pixels)
  Offset 78 (word): Y coordinate of city on map (in pixels)


Function:   23
Argument 1: 66 byte buffer
Argument 2: unused

This function fills the buffer with information about the country of the last
city returned:
  Offset  0 to  20: (cstr) city name
  Offset 21 to  41: (cstr) country name
  Offset 43 (byte): DST rule: 0 = none, 2 = European, 4 = North, 8 = South
  Offset 44 (word): minutes ahead of GMT for capital city
  Offset 46 to  50: (cstr) national dialling code
  Offset 51 to  55: (cstr) international dialling code
  Offset 56 to  64: (cstr) country code


Function:   24
Argument 1: (word) status
Argument 2: 66 byte information block

This function does a calculation on the contents of the information block. The
function should be called with the status set to 1. If it returns successfully,
then, as long as the status is non-zero, it should be called again. When the
status is zero, the calculation has completed. Intermediate stages may use
extra internal memory, so if you wish to abandon the calculation partway, use
function 4 to cancel (this can be done at any time) rather than just stopping.

The initial value of the information block should be:
  Offset 42 (byte): units (0 = miles, 1 = km, 2 = nautical miles)
  Offset 43 (byte): DST rule: 0 = none, 2 = European, 4 = North, 8 = South
  Offset 44 (word): minutes ahead of GMT for city
  Offset 46 (word): point latitude in minutes north (negative means south)
  Offset 48 (word): point longtitude in minutes west (negative means east)

The final value of the information block is:
  Offset  0 (word): distance in stated units from home city to point
  Offset  2 (word): sunrise time at point in minutes past midnight
  Offset  4 (word): sunset  time at point in minutes past midnight
  Offset  6 (word): 0 = times valid, 1 = light all day, -1 = dark all day


Function:   25
Argument 1: city name block
Argument 2: unused

This function returns the next city in the same country as the last city
returned (using city order).


Serial port device (data device)
--------------------------------

The serial port device has the name "TTY:". The channel name is a single
letter from A to Z, identifying the particular port to use. Which ports are
actually provided depends on the specific system.

On the Series 3t and 3a, the two RS-232 ports are channels A and B. On
those machines with an infra-red port, it is channel I.

An open serial port can be read and written with IOREAD and IOWRITE, or with
IOW functions 1 and 2.


Function:   7
Argument 1: 12 byte control block
Argument 2: unused

This function sets various characteristics of the serial port. The control
block has the format:
  Offset  0 (byte): transmit baud rate
  Offset  1 (byte): receive baud rate
    Baud rates are encoded as:
     1 =    50      7 =   600     13 =  4800     19 = 115200
     2 =    75      8 =  1200     14 =  7200
     3 =   110      9 =  1800     15 =  9600
     4 =   134     10 =  2000     16 = 19200
     5 =   150     11 =  2400     17 = 38400
     6 =   300     12 =  3600     18 = 57600
  Offset  2 (byte): framing
    Bits 0 to 3: number of data bits minus 5 (e.g. 3 means 8 bits)
    Bit 4:       clear for 1 stop bit, set for 2 stop bits
    Bit 5:       parity bit enabled if set
  Offset  3 (byte): 0 = no parity, 1 = even parity, 2 = odd parity
  Offset  4 (byte): handshaking
    Bits 0 to 1: 3 = XON handshaking, 0 = no XON handshaking
    Bit 2:       0 = RTS handshaking, 1 = no RTS handshaking
    Bit 3:       1 = DSR handshaking, 0 = no DSR handshaking
    (Any combination of XON, RTS, and DSR can be set at once.)
  Offset  5 (byte): XON character (usually 17)
  Offset  6 (byte): XOFF character (usually 19)
  Offset  7 (byte): flags
    Bit 0: ignore parity errors
  Offset  8 (long): terminating mask
The terminating mask specifies which of the characters with codes 0 to 31
terminate a read. For example, if bits 10 and 13 are set, then a read on the
port will terminate after reading a byte with value 10 or 13.


Function:   8
Argument 1: 12 byte control block
Argument 2: unused

This function fills the control block with the current settings (see function
7).


Function:   9
Argument 1: unused
Argument 2: unused

This function discards any buffered input and any error state. Any handshaking
is set to restart reception.


Function:   10
Argument 1: count (word)
Argument 2: unused

The count is set to the number of bytes buffered and waiting to be read.


Function:   11
Argument 1: 2 byte control block
Argument 2: unused

The first byte of the control block is set to indicate the state of the modem
control lines:
    Bit 0: set if CTS active
    Bit 1: set if DSR active
    Bit 2: set if DCD active

The second byte specifies the new setting for the DTR line:
    0 = leave unchanged
    1 = set DTR active
    2 = set DTR inactive


Function:   12
Argument 1: 6 byte information block
Argument 2: unused

The information block is filled in to indicate which facilites are supported
by the port.
  Offset  0 (long):
    Bit  0: set if supports 50 baud
    Bit  1: set if supports 75 baud
    Bit  2: set if supports 110 baud
    Bit  3: set if supports 134 baud
    Bit  4: set if supports 150 baud
    Bit  5: set if supports 300 baud
    Bit  6: set if supports 600 baud
    Bit  7: set if supports 1200 baud
    Bit  8: set if supports 1800 baud
    Bit  9: set if supports 2000 baud
    Bit 10: set if supports 2400 baud
    Bit 11: set if supports 3600 baud
    Bit 12: set if supports 4800 baud
    Bit 13: set if supports 7200 baud
    Bit 14: set if supports 9600 baud
    Bit 15: set if supports 19200 baud
    Bit 16: set if supports 38400 baud
    Bit 17: set if supports 57600 baud
    Bit 18: set if supports 115200 baud
  Offset  4 (word):
    Bit  0: set if supports 5 bits
    Bit  1: set if supports 6 bits
    Bit  2: set if supports 7 bits
    Bit  3: set if supports 8 bits
    Bit  4: set if supports 2 stop bits
    Bit  5: set if supports even parity
    Bit  6: set if supports odd parity
    Bit  7: set if supports mark parity
    Bit  8: set if supports space parity
    Bit  9: set if supports setting DTR
    Bit 10: set if supports different transmit and receive baud rates
    Bit 11: set if supports soft xon/xoff characters


Parallel port device (data device)
----------------------------------

The parallel port device has the name "PAR:". The channel name is a single
letter from A to Z, identifying the particular port to use. Which ports are
actually provided depends on the specific system. A port will consume power
while open.

An open parallel port can be written with IOWRITE, or with IOW function 2.

No other functions are available on the Series 3.


Free running counter
--------------------

The Free running counter has the name "FRC:". There are no channel names. It
is only available on the Series 3a. Only one process may have the FRC open
at a time, and so it should be closed as soon as possible.

In the following description, an "FRC-tick" is 1/1024 seconds.


Function:   1
Argument 1: (word) set to current count
Argument 2: unused

The current setting of the counter is placed in the word. If the counter is
in mode 1, the count is then reset to zero (the counter continues counting).
This call will not complete while the counter is zero.


Function:   15
Argument 1: (word) operating mode (0 or 1)
Argument 2: (word) step time (10 to 65535)

Starts the counter from zero. Mode 0 means that the counter will increment
every FRC-tick. Mode 1 means that the counter will increment at every N
FRC-ticks, where N is the step time. Any uncompleted function on the counter
will be completed.


XModem and YModem drivers (data device)
---------------------------------------

The XModem driver has the name "XMD:", and the YModem driver the name "YMD:".
There are no channel names. Both are stacked on to another data device.

Once stacked, the driver will use the underlying device to transfer data
using the XModem (single transfer) or YModem (multiple transfer) protocol.
These protocols have a number of variants:
- XModem may use checksums or CRCs on each frame. CRCs are more reliable.
- YModem may use the error correcting or G mode. The G mode does not allow
  errors to be corrected, only detected.
- The transfer may use short frames (128 data bytes) only, or both short and
  long frames (1024 data bytes).

Function 1 is used to receive data. The initial value of the length argument
will be ignored, and a whole frame (128 or 1024) bytes will be placed in the
buffer, which must therefore be large enough. When an end-of-file message is
received, the function will fail with error -36.

Function 2 is used to send data. The length is used as follows:
       0 : an end-of-file message is sent
     128: a short frame is sent
    1024: a long frame is sent
If the length is any other value, the specified amount of data is transferred,
followed by enough $1A bytes to fill a frame (a short frame if the length is
less than 128, and a long frame otherwise).

With YModem, the first frame must be a short frame with the following contents,
in order:
  - (cstr) file name
  - file length in bytes (decimal digits)
  - a single space, then the abstime file last modified (octal digits)
  - a single space, then the file mode, using Unix conventions (octal digits)
  - a single space, then the sending software version number (octal digits)
The last field or fields may be omitted, provided that the name is present.
The rest of the frame must contain only zero bytes. A frame consisting only of
128 zero bytes indicates that there are no more files.


Function:   10
Argument 1: (word) direction: 0 = transmit, 1 = receive
Argument 2: (word) mode

This establishes a connection with the other end of the link. The direction
indicates which way the file transfer will take place. The mode is one of
the following values:
  If long frames are to be rejected while receiving:
    XModem:
      0 = CRC mode if supported by far end, otherwise checksum mode
      1 = CRC mode
      2 = Checksum mode
    YModem:
      3 = Error correcting mode
      4 = G mode
  If long frames are to be accepted while receiving:
    XModem:
      $8001 = CRC mode
    YModem:
      $8003 = Error correcting mode
      $8004 = G mode

With YModem, this function must be called for each file.


Function:   11
Argument 1: unused
Argument 2: unused

This disconnects an existing connection while leaving the driver attached.
With YModem, this function should not be called between files.


Workabout laser scanner
-----------------------

The laser scanner has the device name "WLS:" and channel name "D" (that is,
it is opened as "WLS:D"). Only one handle can be open at a time.
Furthermore, opening the device activates the scanner for 5 seconds, after
which it will no longer read and should be closed; it should also be closed
after a successful read.

Reading from the device returns a string which is not terminated (the
amount of data read gives the length). There are no other IO functions
known.



AccessIR device (data device)
-----------------------------

The AccessIR device has the name "AIR:". There are no channel names. Only
one handle can be open at a time, and so the device should be closed as
soon as possible.

On the Series 3c, the device is built-in to the kernel and is always
available. On the Siena it is provided as a separate file called
ACCESSIR.LDD, and is only available once it has been loaded with system
call DevLoadLDD.

There is a separate IR protocol stack process. This must be started by
executing the program SYS$IRDA.IMG (from ROM:: on the 3c) in the normal
way (system calls FilExecute and ProcResume).

Function 4 has the side effect of disconnecting from the remote machine
if a connection is established.


Function:   5
Argument 1: application name (cstr)
Argument 2: buffer

Waits for a connection from another machine, completing when another
machine connects successfully. If the call is successful, the buffer
is filled with a cstr containing information from the other machine
(up to 56 characters excluding the terminating zero) and the call returns
the maximum amount of data that may be sent in a single write.


Function:   6
Argument 1: information block
Argument 2: maximum number of machines to find

Searches the physical neighbourhood for machines willing to accept an
IrDA connection. The second argument is overwritten with the actual number
of machines found, and 36 bytes are placed in the buffer for each machine:
  Offset  0 (long): @@@@
  Offset  4 (long): machine address
  Offset  8 (long): @@@@
  Offset 12 (cstr): machine nickname (up to 23 characters)


Function:   7
Argument 1: machine address
Argument 2: unused

The device is initialized ready to connect to the specified machine.


Function:   8
Argument 1: application name (cstr)
Argument 2: buffer

Connects to the specified application on the selected machine. If the
connection is successful, the buffer is filled with the information passed
from the other machine (up to 60 bytes). The application name is limited
to 25 characters excluding the terminating zero. If this call is successful,
it returns the maximum amount of data that can be sent in a single write.


Console device
--------------

This is a special device that does not need to be opened; it has the
handle -2.


The console device outputs text in the text area (as set by the SCREEN
keyword), and many of its functions duplicate OPL keywords. Up to 255
characters may be written to the device, and the corresponding text will be
output. Certain characters have the following meaning:
    7 = beep
    9 = go to next tab stop (multiple of 8 characters)
    8 = backspace
   13 = go to start of the line
   10 = go down one line
   11 = ditto
   12 = go down one screen
If the text will not all fit in the current line, what happens depends on the
autowrap and scroll lock flags (defined below). If auto wrap is on, moving
past the end of the line moves to the beginning of the next line. Otherwise
further characters overwrite the last character on the line. If scroll lock is
off, moving down from the bottom line (including because of an auto wrap) will
scroll the screen up one line. Otherwise moving down from the bottom line has
no effect. Writing cannot fail.

Reading from the device ignores the length and always reads exactly 4 bytes,
representing a single keystroke:
  Offset  0 (word): keycode
  Offset  2 (byte): modifiers
    Bit 1: set if SHIFT pressed
    Bit 2: set if CONTROL pressed
    Bit 3: set if PSION pressed
    Bit 4: set if CAPS LOCK in effect
    Bit 5: set if NUM LOCK in effect
  Offset  3 (byte): autorepeat count
The autorepeat count indicates how many keystrokes have been combined into one
return; it will only be greater than 1 if processing of the keystrokes is not
keeping up with the autorepeat.


Function:   7
Argument 1: (word) the value 0
Argument 2: (word) style

This alters the text style as specified:
    Bit 0: bold
    Bit 1: reverse
    Bit 2: underline
    Bit 3: flashing
    Bit 4: italic
Unsupported styles and those requiring a different character width will be
silently ignored. This function cannot fail.


Function:   7
Argument 1: (word) the value 1
Argument 2: control block

This scrolls a rectangle (ignoring the scroll lock flag) by any amount
according to the control block:
  Offset  0 (word): left   edge of rectangle (inclusive)
  Offset  2 (word): top    edge of rectangle (inclusive)
  Offset  4 (word): right  edge of rectangle (exclusive)
  Offset  6 (word): bottom edge of rectangle (exclusive)
  Offset  8 (word): horizontal scroll distance (positive=right, negative=left)
  Offset 10 (word): vertical   scroll distance (positive=down,  negative=up)
The rectangle will be clipped to the text area. This function cannot fail.


Function:   7
Argument 1: (word) the value 2
Argument 2: control block

This clears a rectangular area described by the control block:
  Offset  0 (word): left   edge of rectangle (inclusive)
  Offset  2 (word): top    edge of rectangle (inclusive)
  Offset  4 (word): right  edge of rectangle (exclusive)
  Offset  6 (word): bottom edge of rectangle (exclusive)
The rectangle will be clipped to the text area. This function cannot fail.


Function:   7
Argument 1: (word) the value 3
Argument 2: control block

The cursor moves to the specified location; if that is outside the text area,
it moves to the closest point within. The control block has the format:
  Offset  0 (word): x coordinate
  Offset  2 (word): y coordinate
This function cannot fail.


Function:   7
Argument 1: (word) the value 4
Argument 2: control block

The cursor moves the specified amount, or to the edge of the text area if that
is closer. The control block has the format:
  Offset  0 (word): horizontal distance to move (positive=right, negative=left)
  Offset  2 (word): vertical   distance to move (positive=down,  negative=up)
This function cannot fail.


Function:   7
Argument 1: (word) the value 5
Argument 2: control block

Sets the size of the text area according to the control block:
  Offset  0 (long): must be zero
  Offset  4 (word): new width
  Offset  6 (word): new height


Function:   7
Argument 1: (word) the value 6 (for scroll lock) or 7 (for auto wrap)
Argument 2: (word) 0 for off or 1 for on

Sets the scroll lock or auto wrap flag. This function cannot fail. The initial
state is auto wrap on and scroll lock off.


Function:   7
Argument 1: (word) the value 8
Argument 2: unused

Moves the cursor to the start of the next line, obeying the scroll lock flag.
This function cannot fail.


Function:   7
Argument 1: (word) the value 9
Argument 2: (word) 0 to turn cursor off, 1 to turn it on

Turns the cursor on or off; this has no effect other than altering the
appearance of the cursor on the screen. This function cannot fail.


Function:   7
Argument 1: (word) the value 10
Argument 2: (word) 0 to disable, 1 to enable (default)

Enables or disables exiting via the PSION-ESC key sequence. This function
cannot fail.


Function:   7
Argument 1: (word) the value 11
Argument 2: (word) 0 for buffering, 1 for immediate execution (default)

Enables or disables buffering of commands. When buffering is in effect, calls
to the console are buffered up, and executed only when the buffer is full, a
result is required, or on an explicit flush of the buffer. As a side effect,
errors will be reported to the function causing the buffer contents to be
executed, not the one making the call. This function cannot fail.


Function:   7
Argument 1: (word) the value 12
Argument 2: control block

Sets the text area according to the control block:
  Offset  0 (word): left   edge (inclusive) of the text area
  Offset  2 (word): top    edge (inclusive) of the text area
  Offset  4 (word): right  edge (exclusive) of the text area
  Offset  6 (word): bottom edge (exclusive) of the text area


Function:   7
Argument 1: (word) the value 13 (set up) or 14 (cancel)
Argument 2: control block

Sets up or cancels capturing of a key or combination of keys by this process,
whether or not it is in the foreground. The cancel must specify an identical
control block to the set up. The control block has the format:
  Offset  0 (word): keycode
  Offset  2 (byte): modifiers that must be pressed (if tested)
  Offset  3 (byte): modifiers that are tested
Both modifier values use the bits:
    Bit 1: set if SHIFT pressed
    Bit 2: set if CONTROL pressed
    Bit 3: set if PSION pressed
    Bit 4: set if CAPS LOCK in effect
    Bit 5: set if NUM LOCK in effect
Unused bits must be zero, and a bit must not be set in offset 2 while clear in
offset 3.


Function:   7
Argument 1: (word) the value 15
Argument 2: (word) process id

Moves the indicated process to the foreground. This call cannot fail.


Function:   7
Argument 1: (word) the value 16
Argument 2: (word) 0 for off or 1 for on

Sets the last line wrap flag. This function cannot fail. The initial state of
the flag is off. When off, printing to the bottom right corner of the text area
causes an immediate wrap and scroll. @???@ @Obeys other flags@


Function:   7
Argument 1: (word) the value 17
Argument 2: control block

This sets the font type for the text area, resizing the latter as necessary to
handle the new font, and clears the text area. The control word has the format:
  Offset  0 (word): window server font id
  Offset  2 (word): style
    Bit 0: bold (by double printing)
    Bit 1: underlined
    Bit 2: inverse
    Bit 3: double height
    Bit 4: must be set for proportional fonts, ignored for monospaced fonts
    Bit 5: italic (by printing the top half one pixel to the right)
Note that the console device uses a fixed character grid; if a proportional
font is chosen, bit 4 of the style must be selected, and the characters will be
printed on that grid, and not proportionally.

Window server font ids are $3FFF greater than the OPL font id @CHECK@. The
current system font has id $4099 (widget server) or $9A (OPL).


Function:   7
Argument 1: (word) the value 18
Argument 2: (word) 0 for disabled, 1 for enabled (default)

Enables or disables reads from the console. The console may only be read (via
functions 1, 14, or the equivalent OPL keywords) when enabled. This function
cannot fail.


@@Subs: 19 SET_PRIORITY_CONTROL, 20 COMPATIBILITY, 21 GREY, 22 FONT_EXT ??


Function:   8
Argument 1: 12 byte buffer
Argument 2: must be the same as argument 1

The position of the text area and the current cursor position (as set by the
AT keyword) are written into the buffer.
  Offset  0 (word): set to left   edge (inclusive) of the text area
  Offset  2 (word): set to top    edge (inclusive) of the text area
  Offset  4 (word): set to right  edge (exclusive) of the text area
  Offset  6 (word): set to bottom edge (exclusive) of the text area
  Offset  8 (word): set to cursor x coordinate relative to offset 0
  Offset 10 (word): set to cursor y coordinate relative to offset 2
All coordinates are in character positions. 0,0 is the top left corner of
the screen; note that the bottom and right edges are outside the text area.
This function cannot fail.


Function:   9
Argument 1: unused
Argument 2: unused

This function discards any waiting keypresses. It cannot fail.


Function:   10
Argument 1: word set to 1 if keypresses waiting, and 0 otherwise
Argument 2: unused

This function tests whether there are any keypresses waiting. It cannot fail.


Function:   11
Argument 1: 258 byte control block
Argument 2: word holding maximum length

This function allows the user to edit a string on the screen. The control block
has the following format:
  Offset  0 (byte): unused
  Offset  1 (byte): non-zero allows escape from editing
  Offset  2 to 257: string buffer
The initial value of the string must be placed in the buffer; the resulting
string will also be placed there (in both cases it is a cstr). The length of
the string, excluding the terminating zero, is limited to the specified
maximum. If ESC is pressed with the string currently non-empty, it is cleared.
If ESC is pressed with the string empty and escaping is allowed, the function
will fail; otherwise ESC will be ignored in this circumstance.


Function:   12
Argument 1: 8 byte buffer
Argument 2: unused

The buffer is filled with information about the text area:
  Offset  0 (word): window server id of the console window
  Offset  2 (word): window server id of the console font
  Offset  4 (word): height of a text line in pixels
  Offset  6 (word): width of a text character in pixels
This function cannot fail.


Function:   13
Argument 1: unused
Argument 2: unused

If console buffering is in effect, any buffered commands are executed.
Otherwise this function has no effect. It cannot fail.


Function:   14
Argument 1: 4 byte buffer
Argument 2: unused

This function is equivalent to the GETEVENT keyword. It behaves the same as
reading from the device, except that events other than keypresses can be
returned; for example, foreground, background, and change file events. Unlike
GETEVENT, this function can be called from OPL programs whether or not they
are OPA applications.


Function:   15
Argument 1: word set to 1 if any events waiting, and 0 otherwise
Argument 2: unused

This function is equivalent to the TESTEVENT keyword. It behaves the same as
function 10 except that events other than keypresses are also detected. It
cannot fail.
The Psionics Files

ENVVARS

PSIONICS FILE - ENVVARS
=======================
Environment variables
Last modified 1998-11-06
========================

Psion system software always places a dollar sign ($) in the names of the
environment variable it uses. Other applications should use names without a
dollar sign in them.

Psion issues environment variable name prefixes to registered developers;
these prefixes will contain dollar signs, but names based on them should
have no further dollar signs.


The following environment variables are known:

"$WS_FL": initial value of the window server settings (changeable using
the wSystem call). Only applies to window server version 4.
  Offset  0 (word): initial settings

"$WS_FNTS": fonts used by the window server (version 4):
  Offset  0 (word): general system purposes
  Offset  2 (word): notifer and alerts
  Offset  4 (word): status window
  Offset  6 (word): special font holding the diamond symbol
  Offset  8 (word): medium digital clock
  Offset 10 (word): medium date
  Offset 12 (word): notifier/alert buttons
  Offset 14 (word): small status window clock

"$WS_PW": owner information: up to 218 bytes:
  Offset  3 (byte): length of first line
  Offset  4 (byte): offset of start of first line (always 18)
  Offset  7 (byte): length of second line
  Offset  8 (byte): offset of start of second line
  Offset 11 (byte): length of third line
  Offset 12 (byte): offset of start of third line
  Offset 15 (byte): length of fourth line
  Offset 16 (byte): offset of start of fourth line
  Offset 18 onward: text of the information
@The remaining bytes appear to be zero, except 2,6,10,14, which are $6. Why ?

"C$P#": parameters used by Link. [Workabout only]

"C$P$": current keyboard setting. [Workabout only]
  Offset  0 (byte): setting (0 = standard, 1 = special)

"C$P@": current drive last time the command processor was exited.
[Workabout only]
  Offset  0 (byte): drive letter (e.g. $4D or %M for the internal drive)

"C$PA": current path on drive A last time the command processor was exited.
[Workabout only]
  Offset  0 (cstr): current path
If the variable is unset, then the path is the root directory. Variables
"C$PB" to "C$PZ" can also exist.

"D$X": @@@ alleged to be something to do with dialling settings

"EM$": full pathname of the 8087 emulator software.
  Offset  0 (cstr): pathname

"P$D": printer device: 1 byte:
  Offset  0 (byte):
    48 = print device is a parallel port
    49 = print device is a serial port
    50 = print device is a file

"P$F": print to file name: up to 128 bytes:
  Offset  0 (cstr): last file used for printing to file

"P$M": printer driver: up to 129 bytes:
  Offset  0 (byte): printer driver model number
  Offset  1 (cstr): printer driver library
A printer driver library can support several similar printers; the model
number specifies which is selected.

"P$S": serial port setup: 12 bytes:
  @Unknown, but includes fields called tbaud, rbaud, frame, parity, hand,
  xoff, xon, flags, tmask@@something called P_SRCHAR format@

"S$SVER": system screen version number. [Workabout only]
  Offset  0 (cstr): version number as text

"WP$SPEL": used by the word processor @in some way when constructing its
menus, probably to indicate that the spell checker is available.

"WP$THES": used by the word processor @in some way when constructing its
menus, probably to indicate that the thesaurus is available.
The Psionics Files

ERRCODES

PSIONICS FILE - ERRCODES
========================
Standard Psion error codes
Last modified 1994-10-19
==========================

This file lists the standard Psion error and panic codes. An error code is
returned by a device driver (through IOA, IOC, and IOW) or a system call
(through CALL and OS). A panic code is used when a process is terminated by
the kernel, a server, or itself because of an unrecoverable error (panics
should never happen just because of errors in user input).

@To be completed; see PLIB Reference page 50 et seq@

Error codes
-----------

NoErr                   0    No error
FailErr                -1    Failure 
ArgumentErr            -2    Invalid arguments 
OsErr                  -3    Operating system error 
NotSupportedErr        -4    Not supported function 
UnderflowErr           -5    Underflow 
OverflowErr            -6    Overflow 
RangeErr               -7    Argument range 
DivideByZeroErr        -8    Divide by zero 
InUseErr               -9    Resource in use 
NoMemoryErr           -10    No memory left OR IoAllocErr@
NoSegmentsErr         -11    No segments left 
NoSemaphoreErr        -12    No semaphores left 
NoProcessErr          -13    No processes left 
AlreadyOpenErr        -14    Resource already open 
NotOpenErr            -15    Resource not open 
ImageErr              -16    Invalid image file 
NoReceiverErr         -17    No message receiver 
NoDevicesErr          -18    No devices left 
NoFileSystemErr       -19    No file system left 
FailedToStartErr      -20    Failed to start application 
FontNotLoadedErr      -21    Font not loaded
TooWideErr            -22    Too wide
TooManyItemsErr       -23    Too many items
BatLowSoundErr        -24    Battery too low for sound
BatLowFlashErr        -25    Battery too low for flash OR invalid world file
WLD:DelHome           -26    Attempt to delete current home city
WLD:DelCapital        -27    Attempt to delete a capital city
WLD:Duplicate         -28    Duplicate entry in world file
ExistsErr             -32    Object already exists
NotExistsErr          -33    Object does not exist
WriteErr              -34    Unable to write
ReadErr               -35    Unable to read
EofErr                -36    End of file reached
FullErr               -37    Device full
NameErr               -38    Bad name
AccessErr             -39    Access not permitted
LockedErr             -40    File or device locked
DeviceErr             -41    
DirErr                -42
RecordErr             -43
ReadOnlyErr           -44
IoInvalidErr          -45
PendingErr            -46
VolumeErr             -47
CancelErr             -48
ReservedErr           -49
DisconnectErr         -50
ConnectErr            -51
ReTransmitErr         -52
LineErr               -53
InActivityErr         -54
ParityErr             -55
FrameErr              -56
OverrunErr            -57
ModemConnectErr       -58
ModemBusyErr          -59
ModemNoAnswerErr      -60
ModemBlacklistErr     -61
NotReadyErr           -62
UnknownErr            -63
DirFullErr            -64
WriteProtectErr       -65
CorruptMediaErr       -66
AbortErr              -67
EraseErr              -68
InvalidFileErr        -69
ERR_IPC_QUEUE_LEN    -150    Bad queue length for IPC messages
ERR_IPC_MESS_SIZE    -151    Bad IPC message size
ERR_MENU_NO_WINDOW   -170    No more windows left
ERR_MENU_BAD_STRUCT  -171    Bad menu structure
ERR_MENU_DUP_FASTKEY -172    Attempt to add fastkeys with duplicate letter
ERR_INVALID_PATH     -200    Pathname is invalid
ERR_COMM_PORT        -220    Invalid port name
ERR_COMM_BAUD        -221    Invalid baud rate
ERR_COMM_PARITY      -222    Invalid parity setting
ERR_COMM_FRAME       -223    Invalid data frame
ERR_COMM_HAND        -224    Invalid handshaking
ERR_COMM_TIMEOUT     -225    Timeout occurred
The Psionics Files

FILEIO

Filing System IO Interfaces

By Clive Feather. Last modified 1998-06-23. Original location: https://www.davros.org/psion/psionics/fileio

 

PSIONICS FILE - FILEIO
======================
Filing system IO interfaces
Last modified 1998-06-23
===========================

This document describes the use of the IO interface for accessing the filing
system. For general discussion on IO, see the Psionics file DEVICES.

The filing system is a special device driver, called "FIL:". Whenever an open
fails to locate a device, or if the name opened is not that of a device driver,
the driver name "FIL:" is prefixed, and the open is retried. Thus the original
name becomes the channel name. For file IO, the channel name is, or controls,
the file name.

An addition filing system called "TXT:" also exists. This is identical to
"FIL:", and accesses the same files, except that all files are assumed to
be text files (see below). There is no normal need to use "TXT:"; instead,
use "FIL:" and open files with a format component of 2 (see below).


Filing system organisation
--------------------------

The filing system is divided into one or more nodes. A node has a name ending
with a double colon. The nodes most commonly met are:
  "LOC::"  files in the internal ram and on attached SSDs and 3-Link pods
  "REM::"  files accessed via the 3-Link (not the 3-Link pod itself)
  "ROM::"  files in the internal rom

A node may be monolithic, or may be divided into devices. The devices available
and the format of their names depends on the node. For example:
  LOC::  devices are usually "M:", "A:", "B:", and possibly "C:".
  REM::  device names depend on the remote system
  ROM::  monolithic
Unless explicitly stated otherwise, the term device includes monolithic nodes.

A node may be flat or hierarchical. In the former case, each device is a single
directory which contains files. In the latter, each device has a directory
hierarchy starting with a root directory; each directory can hold files and
other directories.

The format of file and directory names depends on the node. Various system
calls (such as FilChangeDirectory) can be used to manipulate file names. The
LOC:: node uses \ as a directory name terminator (the root directory is just
called "\"), and allows both file and directory names to consist of up to 8
characters, a dot, and then up to 3 characters. The ROM:: node is flat, and
uses the same rules for file names.

The full pathname of a file consists of the node, the device (if any), the path
of directories (if any), and the filename, all joined with no intervening
spaces. It is limited to 128 characters.

The system has the concept of a current path. When any filename does not
include a node, device, or directory, that of the current path is used. For
example, if the current path is "LOC::A:\APP\", then the names "XXX\YYY" and
"M:ZZZ" actually refer to "LOC::A:\APP\XXX\YYY" and "LOC::M:\APP\ZZZ". However,
the default path will only be used for names which are on the same node (either
explicitly or because no node is specified).


Opening files
-------------

There are two kinds of open: open for scanning, and open for access. These
are both done with the IOOPEN keyword, but once the file is open, it is used
in totally different ways.


Opening for scanning
--------------------

A file is opened for scanning by specifying one of the following modes to
IOOPEN:
    $0030 = scan a directory
    $0050 = scan a node
    $0060 = scan all nodes
    $0040 = format a device
    $8040 = format a device in low density

In each case, once the file is opened, it is scanned or formatted by making
several calls to function 1 until one fails with error -36 (end of file).
[Note: the IOREAD keyword should be equivalent to function 1. However, there
have been reports of problems with using it.] Once a call fails, the handle
should be closed. All these calls will ignore the length variable (argument 2).

Scanning generates a list of names. There are three different scans that can
be done:
* Scan all nodes; the name opened is ignored (and so would normally be "FIL:"),
  and a list of all the available nodes is returned.
* Scan a node; the node is extracted from the name opened, and a list of all
  devices on that node is returned.
* Scan a directory; the name opened should either identify a directory (on
  the LOC:: node, this is done by having it end with a backslash), or should
  contain wildcards in the filename part. [If neither of these is true, only
  the original name will normally be returned; "A:" counts as a directory for
  these purposes.] A list of all names in the directory, or all matching names,
  is returned.

One member of the list is returned, as a cstr, by each call to function 1. The
buffer (argument 1) should be at least 128 bytes long.


Formatting is used to prepare a device to contain files and to erase any
previous contents. If a device supports multiple densities, it can be formatted
at normal or low density. The node and device part of the name identifies the
device to format; the remainder, if any, specifies a new volume name for the
device (otherwise the previous one is reused).

The first call to function 1 will write a count into the first word of the
buffer (argument 1); subsequent calls will ignore the buffer. This first call
will not alter the device, and if the handle is closed immediately afterwards,
nothing will happen. Otherwise, the count indicates the number of subsequent
calls required to format the device. If the handle is closed before that number
of calls has been made, the device will be left in an unusable state; it can
be recovered by reformatting, but any information normally transferred to a
reformatted device, such as the previous volume name or the unique serial
number, will be lost.

As an example, when formatting a 2Mb flash SSD, the format count was 513. This
consisted of:
* 256 calls which each wrote all zeroes to 8192 bytes of the card, starting
  at address 0.
* 8 blocks of 32 calls; the first call in each block restored 256 kbytes to
  all $FF, and the other 31 did nothing.
* A final call which restored the initial area of the card (serial number,
  volume name, empty root directory, etc.).


Opening for access
------------------

A file is opened for access in order to read or write the file. To open a file
for access, the mode parameter to IOOPEN has the following value:
    Bits 0 to 3: (service component)
      0 = open an existing file
      1 = create a new file
      2 = replace an existing file
      3 = open a file for appending only
      4 = open a new file with a new, arbitrary, name
    Bits 4 to 7: (format component)
      0 = open a binary file for binary access
      1 = open a text file for binary access
      2 = open a text file for text access
    Bit  8: allow writing
    Bit  9: allow random access
    Bit 10: allow shared access
These individual components are now described.


Service component
-----------------

The service component indicates what to do with the existing contents of the
file. There are five possibilities:
* 0 and 3 open an existing file, leaving the content unchanged. They differ
  only in the setting of the current position (0 = start, 3 = end). If the
  file does not exist, the open fails.
* 1 and 2 will create the file if it does not exist; 1 will fail if the file
  does already exist, while 2 will succeed. After opening, the file will
  be empty (length 0), and so the current position will be at both the start
  and end of the file.
* 4 is equivalent to 1, but with a new file name. The file name passed is
  examined to determine the directory, and a new file is created in that
  directory; the resulting name overwrites the passed name. If the IOOPEN
  keyword is used, the name parameter is replaced by ADDR(qstr), as explained
  in the OPL manual. If the IoOpen system call is used, the name (a cstr) is
  passed in the same way as for other modes, and will be overwritten; there
  should thus be room for 128 bytes.


Format component
----------------

There are two kinds of file: text and binary. A text file consists of a
sequence of records, each ending with a newline character, while a binary
file consists of arbitrary data, which is not broken into records.

Each node has its own way of storing text and binary files. On some nodes,
the two types are completely distinct. On others, text files are merely a way
of interpreting binary files. This is the case for the LOC:: and ROM:: nodes.
In either case, a record in a text file is limited to 256 bytes, and may not
contain $0A, $0D, or $1A.

In the LOC:: and ROM:: nodes, a text file obeys the following rules:
* Each of the following sequences marks the end of a record:
    $0A $0D $1A
    $0A $1A
    $0A
    $0D $0A $1A
    $0D $1A
    $0D
    $1A
  In each case, the longest applicable sequence is used. These bytes are not
  part of the record.
* Anything after a $1A byte (including one in a record terminator) is ignored.

The three access modes are used to determine the way the file is processed.
* Mode 0 opens a binary file for binary access.
* Mode 1 opens a text file for binary access.
* Mode 2 opens a text file for text access.
The meaning of each of these is discussed below, under reading and writing.
If a node does not distinguish binary and text files, the contents of the file
are treated in the way described above. If it does distinguish them, the open
will fail if the file has the wrong type.


Other opening flags
-------------------

If the "writing" flag is not set on opening, all attempts to alter the file
will fail. This includes files created by the open function.

If the "random access" flag is not set on opening, all attempts to set the
current position (as opposed to altering it by reading and writing) will fail.

If the "shared" flag is not set on opening, the file is locked, and no other
process may open it until this one closes it. If the flag is set, the file
is open for sharing; other processes may also open it for sharing, but none
of the processes may alter to the file.


Reading and writing
-------------------

When reading or writing a binary file, the requested data is transferred
directly without change. Up to 16k can be read or written with one call. On
a read, the length argument is changed to the actual number of bytes read. The
data is read from or written at the current position, which is moved to the
end of that data.

When reading a text file as binary, the file is treated exactly as if each
record were followed by $0D $0A; partial records can be read into the buffer,
and the remaining portion will be retained until the next read.

When writing a text file as binary, the following sequences of bytes are taken
to mark the end of a record:
    $0A $0D
    $0A
    $0D $0A
    $0D
Again, in each case the longest applicable sequence is used, and these bytes
are not written as part of the record.

In all other respects access to a text file as binary behaves the same as
access to a binary file.

When reading a text file as text, exactly one record is read from the file into
the buffer; no explicit end-of-record marker is added. If the record is larger
than the buffer, the trailing data is ignored and error -43 is returned. The
length argument is changed to the number of bytes placed in the buffer. The
record is read from the current position, which is moved to the start of the
next record. Since text records are limited to 256 bytes, no more than that
can ever be read.

When writing a text file as text, the contents of the buffer are written as a
single record at the end of the file, no matter what the current position. The
current position is moved to the end of the file. Records are limited to 256
bytes, and must not contain $0A, $0D, or $1A.

When writing to a flash SSD, there is one special case: if the write is a
single byte, and if every bit of that byte is left unchanged or changes from
1 to 0 [equivalently, if (old AND new) = new], then the byte will be modified
in situ. In all other cases, the old data will remain in place, but the file
structure will be modified to skip it and point to the new data instead.


Seek
----

Seeking in a file is done using IOSEEK. It is reported that mode 4 returns
the position of the current record (which is the record just read) within
a text file (*not* the pointer after the read), and mode 5 allows you to
seek to that position. I have not verified this. @@@@@


Other IO functions
------------------

Function:   9
Argument 1: unused
Argument 2: unused

Any buffered data is written to the file, and the file's modification date is
updated if necessary. On the LOC:: node, the only buffering done for binary
files is of the modification date of files on flash. Text files are buffered.


Function:   11
Argument 1: (long) new filesize
Argument 2: unused

If the file is shorter than the specified length, random data is appended to
bring it to that length; the current position is unaltered. If it is longer,
the file is truncated to that length, and the current position is set to the
new end of file.
The Psionics Files

FLASH

PSIONICS FILE - FLASH
=====================
Format of Flash SSD cards and ROMs
Last modified 1994-09-12
==================================

This file describes information about the structure of existing types of
Flash cards. It does not apply to RAM cards, and might not apply to new types
of SSDs that may become available in the future. It does, however, appear to
apply to the ROM in the 3-Link pod and the SSD ROM used to ship the
Spreadsheet.

The term "erased flash card" is one that was partially formatted, after which
the format was stopped, and then reformatted. This causes the contents of the
start of the flash card, which is normally preserved by the formatting process
(see Psionics file FILEIO) to be lost.

All "trip" values are offsets from the start of the card. The term "NULL"
means the value $FFFFFF.

The flash card always begins with:
  Offset  0 (word): $F1A5 ('Flas')
  Offset  2 (long): unique ID of SSD
  Offset  6 (word): unknown @only ever seen 1@
  Offset  8 (trip): unknown @only ever seen 1@
  Offset 11 (trip): pointer to the root directory entry
  Offset 14 to  21: volume name
  Offset 22 to  24: volume extension
  Offset 25 (long): count of times flash card has been formatted, or
                    $FFFFFFFF for ROMs
It then continues with either:
  Offset 29 (word): size of the card in 256 byte units (i.e. $1000 = 1Mb)
  Offset 31 (word): unknown @only ever seen $FFFF@
  Offset 33 onward: identity string
Or:
  Offset 29 onward: identity string
The first form is seen on flash cards, and the second on ROMs and erased flash
cards.

The unique ID is placed there when the SSD is first created, and is preserved
even when the SSD is formatted. There is no obvious pattern to the ID's.
Note that different 3-Link pods have different unique IDs.

If the first byte of the volume name is 00, the volume name is not in
offsets 14 to 24, but is instead found in a special file record within the
root directory.

The identity string is terminated by a zero byte or a $FF byte. The identity
strings seen to date are:
    "PSION 1.0 01/80"
    "PSION 1.0 06/80"
    "PSION 1.0"
    "Copyright (c) Psion Plc 1991"
The first two were seen on flash cards, the third on an erased flash card,
and the last on both the 3-Link pod ROM and the spreadsheet SSD ROM.


The rest of the flash card is divided into records (unused portions of the
card are full of $FF bytes).

The root directory entry is a filing system record. The directory name is
"ROOT.".

Filing system records represent entries in directories: other directories,
files, and volume names. A filing system record is 31 bytes if it represents
a file, and 26 bytes otherwise:

  Offset  0 (trip): pointer to the next entry in same directory
  Offset  3 to  10: entry name
  Offset 11 to  13: entry extension
  Offset 14 (byte): flags
  Offset 15 (trip): pointer to first entry record
  Offset 18 (trip): pointer to alternate record
  Offset 21 (byte): entry properties
  Offset 22 (word): time code
  Offset 24 (word): date code
  Offset 26 (trip): (file only) pointer to start of first data record
  Offset 29 (word): (file only) length of first data record

The flags are as follows:
  Bit 0: 1 = entry still valid, 0 = entry deleted
  Bit 1: 1 = properties, time, and date valid
  Bit 2: 1 = file or volume name, 0 = directory
  Bit 3: 1 = no entry record (so NULL at offset 15)
  Bit 4: 1 = no alternate record (so NULL at offset 18)
  Bit 5: 1 = no more entries in same directory (so NULL at offset 0)
  Bit 6: all entries seen so far have this bit set to 1
  Bit 7: all entries seen so far have this bit set to 1

The first entry record is:
  for files:        first continuation record of file; if the pointer is NULL,
                    the file only contains one data record
  for directories:  filing system record of first directory entry; if the
                    pointer is NULL, the directory is empty
  for volume names: all entries seen so far have a NULL pointer

If the alternate record exists, then most of the data in the record pointing
to the alternate record should be ignored, and replaced by the corresponding
data in the alternate record. The alternate record is:
  for files:        a continuation record; ignore the first entry record
                    and the data record in the original record
  for directories:  alternate records are not used
  for volume names: alternate records are not used

The entry properties are:
  Bit 0: 1 = read-only file
  Bit 1: 1 = hidden file
  Bit 2: 1 = system file
  Bit 3: 1 = is a volume name
  Bit 4: 1 = directory
  Bit 5: 1 = modified

The time code is: $800 * hour + $20 * minute + second / 2.
The date code is: $200 * (year - 1980) + $20 * month + date.

A file is represented by a linked list of records. The first record is the
filing system record, or its alternate, and the remaining records are all
continuation records. A continuation record is 17 bytes:

  Offset  0 (byte): flags (as above)
  Offset  1 (trip): pointer to next continuation record
  Offset  4 (trip): pointer to alternate continuation record
  Offset  7 (trip): pointer to data record
  Offset 10 (word): length of data record, or $FFFF if it is unknown and the
                    file is still open
  Offset 12 (byte): entry properties
  Offset 13 (word): time code
  Offset 15 (word): date code

Note that bits 5, 2, and 0 of the flags will always be set, and that bits 4
and 3 refer to offsets 1 and 4 respectively. In addition, it is possible for
bit 3 to be clear but for there to be no next continuation record.

To examine all the data in a file, start at the filing system record, and then
proceed as follows for each record in turn:
    If flag bit 4 is set, go to the alternate record and repeat this step.
    Otherwise the next part of the file is given by the data pointer and length
    within this record.
    After using the data: if flag bit 3 is clear and the next continuation
    record pointer is not null, go to that record, starting by examining flag
    bit 4. Otherwise the end of file has been reached.

As files are modified, the records on the flash card become out of date.
For example, data that has been overwritten will remain on the card. In
particular, the properties, time, and date bytes of records will remain even
when they are not valid (as indicated by flag bit 1). Also note that a
change to a file may cause several continuation records to be written at the
same time. In these circumstances, only one of these will have the correct
properties, time, and date, and the others will be written without them, and
with some other record overlapping these 5 bytes.


Reading flash cards
-------------------

On later versions of EPOC, flash cards can be read with FilLocReadPDD (see
Psionics file SYSCALLS). If this is not available, the following code can be
used to read flash cards. The left four columns give individual bytes; the
right column is the bytes reorganized as long words.

  EB  3A  55  E8   E8553AEB
  95  00  83  EC   EC830095
  0E  8B  F4  8D   8DF48B0E
  7E  28  BA  21   21BA287E
  DD  2B  DB  B4   B4DB2BDD
  0A  CD  85  83   8385CD0A
  C4  0E  8B  D8   D88B0EC4
  B4  02  CD  85   85CD02B4
  89  46  00  89   89004689
  5E  02  CD  8F   8FCD025E
  8C  46  32  B4   B432468C
  00  CD  88  80   8088CD00
  E4  0F  89  46   46890FE4
  30  9C  FA  1E   1EFA9C30
  07  9D  5D  CB   CB5D9D07
  83  FB  04  72   7204FB83
  05  B8  FC  FF   FFFCB805
  EB  51  8B  F0   F08B51EB
  55  E8  4F  00   004FE855
  88  5E  20  FF   FF205E88
  36  12  00  8D   8D001236
  46  04  A3  12   12A30446
  00  FF  36  20   2036FF00
  00  80  26  20   20268000
  00  00  E4  14   14E40000
  C4  7E  30  26   26307EC4
  FE  45  0D  1E   1E0D45FE
  07  8B  FA  B0   B0FA8B07
  00  FF  5E  00   005EFF00
  98  8B  D8  C4   C4D88B98
  7E  30  26  FE   FE26307E
  4D  0D  9C  FA   FA9C0D4D
  1E  07  9D  8F   8F9D071E
  06  20  00  80   80002006
  3E  20  00  00   0000203E
  74  02  E6  14   14E60274
  8B  C3  8F  06   068FC38B
  12  00  5D  CB   CB5D0012
  58  FF  E0  E8   E8E0FF58
  FA  FF  05  06   0605FFFA
  00  8B  E8  C3   C3E88B00
  00  00  00  00   00000000
  00  00  00  00   00000000
  00  00  00  00   00000000
  00  00  00  00   00000000
  00  00  00  00   00000000
  00  00  00  00   00000000
  00  00  00  00   00000000
  00  00  00  00   00000000
  00  00  00  00   00000000
  00  00  00  00   00000000
  4C  4F  43  2E   2E434F4C
  54  59  31  00   00315954
  00  00  00  00   00000000

If this code is placed at location bin%, then to initialize the code, call
    USR (bin% + 2, 0, 0, 0, 0)
Then, to copy date from the flash card:
    rc% = USR (bin%, ADDR (loc&), drive%, length%, ADDR (buffer))
copies length% bytes into the buffer, starting from address loc& on card
drive% (0 is A:, 1 is B:, 2 is C:, etc.). A returned value of 0 indicates
success.
The Psionics Files

FONT.FMT

PSIONICS FILE - FONT.FMT
========================
Format of Font files
Last modified 1994-09-13
========================

A font file holds a font for loading with the GLOADFONT keyword. There are two
kinds of font files, standard and fast. The formats are related; the notation
"A // B" means A for normal fonts, and B for fast fonts.

The font file consists of a header, a width table, and a bitmap, with no
intervening space. The header is 62 bytes, and has the format:
  Offset  0 (byte): 'F' (70)
  Offset  1 (byte): 'O' (79) // 'N' (78)
  Offset  2 (byte): 'N' (78) // '1' (49)
  Offset  3 (byte): 227      // 197
  Offset  4 (byte):  48      //  16
  Offset  5 (byte):  48      //  16
  Offset  6 (word): checksum (see below)
  Offset  8 (word): size from offset 10 to end of bitmap data
  Offset 10 (word): lowest character code
  Offset 12 (word): highest character code
  Offset 14 (word): height of font
  Offset 16 (word): descent of font
  Offset 18 (word): ascent of font
  Offset 20 (word): width of numeric characters
  Offset 22 (word): widest character in font
  Offset 24 (word): flag bits:
    Bit 0: the font uses ASCII for codes  32 to 126
    Bit 1: the font uses Code Page 850 for codes 128 to 255
    Bit 2: bold font
    Bit 3: italic font
    Bit 4: serifed font
    Bit 5: monospaced font
  Offset 26 to  41: font name (padded with spaces)
  Offset 42 (word): [appears to be size of the width table in bytes]
  Offset 44 (word): [unknown: 0, 0, 0, 0]
  Offset 46 (word): [unknown: 0, 0, 0, 0]
  Offset 48 (word): [unknown: -9, -7, 72, 46]
  Offset 50 (word): [appears to be height of font again: 8, 8, 6, 9]
  Offset 52 (word): [appears to be width of bitmap in bytes: 256, 256, 10, 6]
  Offset 54 (word): [unknown: 0, 0, 0, 0]
  Offset 56 (word): [appears to be 8 * height of font: 64, 64, 48, 72]
  Offset 58 (word): [unknown: 2, 2, 2, 2]
  Offset 60 (word): [unknown: 0, 0, 0, 0]

The meanings of the fields from offset 42 onwards are not known. @The numbers
shown are their values in the system normal font, the system bold font, the
system digit font, and the Spreadsheet small font (the first two are fast
fonts and the latter two normal fonts).@

The checksum is the X^16+X^12+X^5+1 polynomial, applied to the width table and
the bitmap. See the system call GenCrc.

The header is followed, at offset 62, by the width table. For normal fonts,
the header contains one word for each character in the font, plus an extra
word. Thus if the font contains characters 48 to 52, there will be 6 words in
the table. The first word in the table corresponds to the lowest character
code, up to the last word but one, which corresponds to the highest character
code. For each entry except the last, if the character exists in the font,
then the corresponding word is twice the horizontal position of the start of
the character in the bitmap. If the character does not exist, then the word
is the same as the following word, but with the bottom bit set. The final entry
in the table is twice the width of the bitmap. Thus the bottom bit indicates
whether the character exists or not, and for any character which exists, its
width is given by subtracting the entry from the following entry and dividing
by two (this applies equally to the last character, which is why the extra
entry is there).

For fast fonts, the width table is 256 bytes, from offsets 62 to 317 inclusive.
Each byte holds the width (from 0 to 8) of the corresponding character.

The bitmap immediately follows the width table (thus for normal fonts it starts
at offset (66 + (max_code - min_code) * 2), while for fast fonts it starts at
offset 318). Its size is calculated from the size field in the header, and will
always be a multiple of the height. The data for each row is kept together,
with the rows in order from top to bottom. For each row, the data represents
blocks of 8 pixels per byte; the bytes are in left to right order, and the
least significant bit in the byte represents the leftmost pixel of the block.
For normal fonts, each character occupies a number of columns, with all the
characters that exist in the font being placed side by side in code order.
For a fast font, the character occupies the left side of a block of 8 columns,
again in code order (i.e. character code C occupies byte C of each row, so
its top row is at offset 318+C, its second row at offset 574+C, and so on).
The Psionics Files

IMG.FMT

PSIONICS FILE - IMG.FMT
=======================
Format of executable image files
Last modified 1997-09-20
================================

Executable image files hold programs to be executed; the same format is used
for both IMG and APP files. The file contains control information, an
executable (in DOS format), and up to 4 additional included files (for
example, an icon or a resource file).

The format is:

  Offset  0 (cstr): "ImageFileType**"
  Offset 16 (word): image format version ($200F)
  Offset 18 (word): offset of the start of the executable within the file
  Offset 20 (word): size of the code segment, in units of 16 bytes
  Offset 22 (word): location in the code segment to start execution
  Offset 24 (word): stack size         ) each in units of 16 bytes;
  Offset 26 (word): static data size   ) the initial data segment size is
  Offset 28 (word): initial heap size  ) the sum of these three
  Offset 30 (word): amount of initialized static data, in bytes
  Offset 32 (word): checksum of the code
  Offset 34 (word): checksum of the initialized static data
  Offset 36 (word): version number of the program
  Offset 38 (word): initial priority of the program, usually 128
  Offset 40 (word): offset of the start, within the file, of included file 1
  Offset 42 (word): length of included file 1, in bytes
  Offset 44 (word): offset of the start, within the file, of included file 2
  Offset 46 (word): length of included file 2, in bytes
  Offset 48 (word): offset of the start, within the file, of included file 3
  Offset 50 (word): length of included file 3, in bytes
  Offset 52 (word): offset of the start, within the file, of included file 4
  Offset 54 (word): length of included file 4, in bytes
  Offset 56 (word): the number of DYLs within the file
  Offset 58 (long): offset within the file of the DYL information table
  Offset 62 (word): unused

The stack size includes the reserved statics and space for the floating
point emulator (see Psionics File PROCESS). The first part of the static
data is initialized from the data in the IMG file (stored immediately after
the executable), and the remainder is filled with zeros.

The version number of the program is for internal documentation; it does
not affect the execution of the program. Most development tools set this
to $100F (meaning "1.00 final release").

The resource handling facilities in the system expect the second included
file to be a resource (RSC or RZC) file. The system screen requires the
third included file to be a shell data (SHD) file. Any of the four included
files can be a PIC file holding the icon.

If any of the included files has a zero offset, further entries might be
ignored. Thus if there is no second file but a third file, a zero-length
second file should be provided.

An APP file must include a PIC file holding one of:
- a 24x24 bitmap (Series 3t icon);
- two 48x48 bitmaps (Series 3a icon, black plane then grey plane);
- a 24x24 bitmap followed by two 48x48 bitmaps (both forms).

@@@ SHD files

I have no information about the format of DOS executables. @@@
The Psionics Files

KERNEL

PSIONICS FILE - KERNEL
======================
Kernel memory organisation
Last modified 1997-09-09
==========================

Kernel memory can be examined with the system call GenGetOsData, or in blocks
of assembler with the system call GenDataSegment. Some useful information is
available at known offsets. In addition, a handle is actually the offset, in
kernel memory, of the start of a data structure, which can therefore also be
examined.


Constant offsets
----------------

Offset 1036 (word): number of seconds before auto power-off
Offset 1052 (word): increments every 1/32 second, but is not synchronized
                    to the real time clock (it drifts)
Offset 1056 (word): delay in 1/32 seconds until current time next changes
Offset 1058 (long): current abstime


Data structures
---------------

The bottom 12 bits of a process ID are actually the address of the process's
control block. This has the following format:

  Offset  0 (word): pointer to next process in the same queue
  Offset  2 (word): pointer to previous process in the same queue
  Offset  4 (word): @@ queKey
  Offset  6 (word): @@ queData
  Offset  8 (byte): @@ deltaType
  Offset  9 (byte): @@ addressTrap
  Offset 10 (byte): process status:
      1 = running (there is only one running process)
      2 = ready to run
      3 = waiting for a timer to expire
      4 = suspended
      5 = waiting for a semaphore
    255 = entry not in use
  Offset 11 (byte): non-zero if the process is to be suspended
  Offset 12 (byte): @@ priority
  Offset 13 (byte): @@ priorityH
  Offset 14 (byte): zero if executing ROM code, non-zero if executing RAM code
  Offset 15 (byte): zero for processes, non-zero for sub-tasks
  Offset 16 (cstr): process name
  Offset 29 (byte): zero if non-active, non-zero if active
  Offset 30 (word): handle of the semaphore of the process
  Offset 32 (word): @@ *semHead
  Offset 34 (word): address of the start of the heap
  Offset 36 (word): amount to grow heap by, in 16 byte units
  Offset 38 (word): address of the message control block (0 if none set up)
  Offset 40 (word): minimum heap size, in 16 byte units
  Offset 42 (word): file server's handle for the process (0 if not using files)
  Offset 44 (word): handle of the process's data segment (used for DS and SS)
  Offset 46 (word): handle of the process's code segment (used for CS)
  Offset 48 (word): @@ *saveSP
  Offset 50 (word): @@ *saveBP
  Offset 52 (byte): 0 = unattended, 1 = notify
  Offset 53 (byte): non-zero if waiting for the sound semaphore
  Offset 54 (word): top 4 bits of the process ID @@ in which bits ?
  Offset 56 (word): checksum of code
  Offset 58 (word): ProcOnTerminate message type

One queue (offsets 0 and 2) is maintained for ready processes, in priority
order, one for processes waiting for a timer, in timer order, and one for
each semaphore.

The checksum (offset 56) is used to determine whether two programs of the same
name are running the same code, which can then be shared between them.


The battery status data structure has an address returned by the system call
HwGetBatData. It has the following format: @@@@
    Offset  0 (byte): main battery level
    Offset  1 (byte): main battery status
    Offset  2 (byte): backup battery level
    Offset  3 (byte): mains power status
    Offset  4 (word): warning flags
    Offset  6 (????): insertion date
    Offset  @       : ticks in use battery
    Offset  @       : ticks in use mains power
    Offset  @       : milliamp-ticks
The Psionics Files

KEYWORDS

PSIONICS FILE - KEYWORDS
========================
More information about OPL keywords
Last modified 1998-11-09
===================================

This document consists of two parts. The first is a complete list of keywords,
and the second is a set of notes on various keywords, listing information not
given in the standard manual.

In general, a "standard" keyword is one found on both the 3t and the 3a, while
an "extra" keyword is only on the 3a.


List of keywords
================

There are two kinds of keywords: commands and functions. Within the OPL
translator, each keyword has from 1 to 6 bytes of associated data; this may
differ between the 3t and the 3a.

The tag "changed" after the associated data means that it differs between the
3t and the 3a; the 3a data is shown, and the 3t data is obtainable from it:
  commands:  subtract 3 from the first byte
  functions: change the last byte to 00
In addition, the second byte of the data for all functions (not just the
changed ones) is only present in the 3a (in both the native and compatibility
modes), not the 3t. Apart from this, the compatibility mode on the 3a uses the
same data as the 3t.


ABS             Fn  80 02 21
ACOS            Fn  81 02 21
ADDR            Fn  00 00 51
ADJUSTALLOC     Fn  4D 00 03 00        extra
ALERT           Fn  38 00 3D 33 33
ALLOC           Fn  4B 00 41           extra
APP             Cmd F3
APPEND          Cmd 03 9D
APPENDSPRITE    Cmd 7E 7F 07           extra
ASC             Fn  01 00 31
ASIN            Fn  82 02 21
AT              Cmd 04 1E
ATAN            Fn  83 02 21
BACK            Cmd 05 9F
BEEP            Cmd 06 20
BREAK           Cmd 07 3F
BUSY            Cmd 69 70              changed
CACHE           Cmd 77 FF 0E           extra
CACHEHDR        Cmd 79 7F 15           extra
CACHEREC        Cmd 7A 7F 16           extra
CACHETIDY       Cmd 78 7F 13           extra
CALL            Fn  02 00 0E 00 00 00
CHANGESPRITE    Cmd 80 7F 09           extra
CHR$            Fn  C0 03 01
CLOSE           Cmd 08 A1
CLOSESPRITE     Cmd 82 7F 0B           extra
CLS             Cmd 09 22
CMD$            Fn  D6 03 01
COMPRESS        Cmd 0A A3
CONTINUE        Cmd 0B 3F
COPY            Cmd 0C A4
COS             Fn  84 02 21
COUNT           Fn  03 00 00
CREATE          Cmd 0D A5
CREATESPRITE    Fn  3B 00 00           extra
CURSOR          Cmd 0E 26
DATETOSECS      Fn  45 01 06 00 00 00
DATIM$          Fn  C1 03 00
DAY             Fn  04 00 00
DAYNAME$        Fn  C2 03 01
DAYS            Fn  40 01 03 00
DBUTTONS        Cmd 64 6D              changed
DCHOICE         Cmd 5D 6D              changed
DDATE           Cmd 60 6D              changed
DEDIT           Cmd 61 6D              changed
DEFAULTWIN      Cmd 7C 7F 01           extra
DEG             Fn  85 02 21
DELETE          Cmd 0F A7
DFILE           Cmd 63 6D              changed
DFLOAT          Cmd 65 6D              changed
DIALOG          Fn  37 00 00
DIAMINIT        Cmd 70 7F 02           extra
DIAMPOS         Cmd 71 7F 03           extra
DINIT           Cmd 5B 6C              changed
DIR$            Fn  C3 03 31
DLONG           Cmd 5E 6D              changed
DO              Cmd 00 00
DOW             Fn  05 00 03 00
DPOSITION       Cmd 66 6D              changed
DRAWSPRITE      Cmd 7F 7F 08           extra
DTEXT           Cmd 5C 6D              changed
DTIME           Cmd 5F 6D              changed
DXINPUT         Cmd 62 6D              changed
EDIT            Cmd 2F C2
ELSE            Cmd FB
ELSEIF          Cmd FC
ENDA            Cmd EE
ENDIF           Cmd FA
ENDP            Cmd F7
ENDV            Cmd F4
ENDWH           Cmd FD
ENTERSEND       Fn  49 00 0D A0 AA     extra
ENTERSEND0      Fn  4A 00 0D A0 AA     extra
EOF             Fn  06 00 00
ERASE           Cmd 10 A8
ERR             Fn  07 00 00
ERR$            Fn  C4 03 01
ESCAPE          Cmd 11 29
EVAL            Fn  99 02 31
EXIST           Fn  08 00 31
EXP             Fn  86 02 21
EXT             Cmd F1
FIND            Fn  09 00 31
FINDFIELD       Fn  54 00 34 00 00     extra
FINDLIB         Fn  3E 00 62 03        extra
FIRST           Cmd 12 AA
FIX$            Fn  C5 03 23 00
FLT             Fn  87 02 11
FONT            Cmd 72 7F 04           extra
FREEALLOC       Cmd 74 7F 0C           extra
GAT             Cmd 40 52
GBORDER         Cmd 54 74
GBOX            Cmd 45 5B
GBUTTON         Cmd 56 7F 0F           extra
GCLOCK          Cmd 55 75
GCLOSE          Cmd 34 C6
GCLS            Cmd 3F 51
GCOPY           Cmd 49 E1
GCREATE         Fn  26 00 05 00 50     changed
GCREATEBIT      Fn  27 00 02 00
GDRAWOBJECT     Cmd 58 7F 11           extra
GEN$            Fn  C6 03 22 00
GET             Fn  0A 00 00
GET$            Fn  C7 03 00
GETCMD$         Fn  D5 03 00
GETEVENT        Cmd 4E 64
GETLIBH         Fn  3F 00 01           extra
GFILL           Cmd 47 5F
GFONT           Cmd 38 CA
GGMODE          Cmd 3A 4C
GGREY           Cmd 7B 7F 00           extra
GHEIGHT         Fn  2F 00 00
GIDENTITY       Fn  2B 00 00
GINFO           Cmd 3E 50
GINVERT         Cmd 52 72
GIPRINT         Cmd 6F 7C              changed
GLINEBY         Cmd 44 5A
GLINETO         Cmd 4C 65
GLOADBIT        Fn  28 00 3B 00
GLOADFONT       Fn  29 00 31
GLOBAL          Cmd F8
GMOVE           Cmd 41 53
GORDER          Cmd 3D 4F
GORIGINX        Fn  30 00 00
GORIGINY        Fn  31 00 00
GOTO            Cmd 13 3F
GPATT           Cmd 48 E0
GPEEKLINE       Cmd 4D 66
GPOLY           Cmd 46 5E
GPRINT          Cmd 42 54
GPRINTB         Cmd 43 59
GPRINTCLIP      Fn  33 00 32 00
GRANK           Fn  2A 00 00
GSAVEBIT        Cmd 33 C5
GSCROLL         Cmd 4A 62
GSETWIN         Cmd 36 48
GSTYLE          Cmd 3C 4E
GTMODE          Cmd 3B 4D
GTWIDTH         Fn  32 00 31
GUNLOADFONT     Cmd 39 CB
GUPDATE         Cmd 4B 63
GUSE            Cmd 35 C7
GVISIBLE        Cmd 37 49
GWIDTH          Fn  2E 00 00
GX              Fn  2C 00 00
GXBORDER        Cmd 57 7F 10           extra
GXPRINT         Cmd 53 73
GY              Fn  2D 00 00
HEX$            Fn  C8 03 11
HOUR            Fn  12 00 00
IABS            Fn  41 01 11
ICON            Cmd F0
IF              Cmd 02 00
INPUT           Cmd 14 94
INT             Fn  42 01 21
INTF            Fn  88 02 21
IOA             Fn  0B 00 05 60 AA
IOC             Fn  4F 00 0D A0 AA     extra
IOCANCEL        Fn  52 00 01           extra
IOCLOSE         Fn  10 00 01
IOOPEN          Fn  0D 00 63 05
IOREAD          Fn  0F 00 03 04
IOSEEK          Fn  21 00 03 70
IOSIGNAL        Cmd 32 37
IOW             Fn  0C 00 04 A0 0A
IOWAIT          Fn  11 00 00
IOWAITSTAT      Cmd 50 68
IOWRITE         Fn  0E 00 03 04
IOYIELD         Cmd 51 69
KEY             Fn  13 00 00
KEY$            Fn  C9 03 00
KEYA            Fn  23 00 62 06
KEYC            Fn  24 00 61
KMOD            Fn  22 00 00
LAST            Cmd 15 AC
LCLOSE          Cmd 16 AD
LEFT$           Fn  CA 03 32 00
LEN             Fn  14 00 31
LENALLOC        Fn  4E 00 01           extra
LINKLIB         Cmd 75 7F 0D           extra
LN              Fn  89 02 21
LOADLIB         Fn  3C 00 63 03        extra
LOADM           Cmd 17 AE
LOC             Fn  15 00 32 03
LOCAL           Cmd F9
LOCK            Cmd 6A 71              changed
LOG             Fn  8A 02 21
LOPEN           Cmd 18 AF
LOWER$          Fn  CB 03 31
LPRINT          Cmd 19 0C
MAX             Fn  93 02 08
MCARD           Cmd 5A 6B              changed
MEAN            Fn  94 02 08
MENU            Fn  36 00 59           changed
MID$            Fn  CC 03 33 00
MIN             Fn  95 02 08
MINIT           Cmd 59 6A              changed
MINUTE          Fn  16 00 00
MKDIR           Cmd 6B F8              changed
MONTH           Fn  17 00 00
MONTH$          Fn  CD 03 01
NEWOBJ          Fn  46 00 02 00        extra
NEWOBJH         Fn  47 00 02 00        extra
NEXT            Cmd 1A B0
NUM$            Fn  CE 03 22 00
ODBINFO         Cmd 76 7F 12           extra
OFF             Cmd 1B 32
ON              Cmd F5
ONERR           Cmd 1C 31
OPEN            Cmd 1D B4
OPENR           Cmd 31 C4
OS              Fn  35 00 0B 00
PARSE$          Fn  D7 03 33 63
PATH            Cmd F2
PAUSE           Cmd 1E 35
PEEK$           Fn  CF 03 41
PEEKB           Fn  18 00 41
PEEKF           Fn  8B 02 41
PEEKL           Fn  43 01 41
PEEKW           Fn  19 00 41
PI              Fn  8C 02 00
POKE$           Cmd 23 1B
POKEB           Cmd 1F 1C
POKEF           Cmd 22 1A
POKEL           Cmd 21 19
POKEW           Cmd 20 18
POS             Fn  1A 00 00
POSITION        Cmd 24 B6
POSSPRITE       Cmd 81 7F 0A           extra
PRINT           Cmd 25 08
PROC            Cmd F6
RAD             Fn  8D 02 21
RAISE           Cmd 26 38
RANDOMIZE       Cmd 27 39
REALLOC         Fn  4C 00 02 04        extra
RECSIZE         Fn  1B 00 00
REM             Cmd FF
RENAME          Cmd 28 BA
REPT$           Fn  D0 03 32 00
RETURN          Cmd 29 40
RIGHT$          Fn  D1 03 32 00
RMDIR           Cmd 6C F9              changed
RND             Fn  8E 02 00
SCI$            Fn  D2 03 23 00
SCREEN          Cmd 30 43
SCREENINFO      Cmd 83 7F 14           extra
SECOND          Fn  1C 00 00
SECSTODATE      Cmd 6E 7B              changed
SEND            Fn  48 00 0D A0 AA     extra
SETNAME         Cmd 67 6E              changed
SETPATH         Cmd 6D 7A              changed
SIN             Fn  8F 02 21
SPACE           Fn  44 01 00
SQR             Fn  90 02 21
STATUSWIN       Cmd 68 6F              changed
STATWININFO     Fn  53 00 02 06        extra
STD             Fn  96 02 08
STOP            Cmd 2A 3B
STYLE           Cmd 73 7F 05           extra
SUM             Fn  97 02 08
TAN             Fn  91 02 21
TESTEVENT       Fn  34 00 00
TRAP            Cmd 2B 3C
TYPE            Cmd EF
UADD            Fn  50 00 42 00        extra
UNLOADLIB       Fn  3D 00 01           extra
UNLOADM         Cmd 2E C1
UNTIL           Cmd FE
UPDATE          Cmd 2C BD
UPPER$          Fn  D3 03 31
USE             Cmd 2D BE
USESPRITE       Cmd 7D 7F 06           extra
USR             Fn  1D 00 45 44 44
USR$            Fn  D4 03 45 44 44
USUB            Fn  51 00 42 00        extra
VAL             Fn  92 02 31
VAR             Fn  98 02 08
VECTOR          Cmd 4F 2B
WEEK            Fn  20 00 03 00
WHILE           Cmd 01 00
YEAR            Fn  1E 00 00


Commands
--------
All extra commands have 3 bytes of data, while all standard commands have 1
or 2 bytes.

The first byte of data is unique to each command. Commands with 2 or 3 bytes
have values from $00 to $83 inclusive, while those with 1 byte have values
from $EE to $FF inclusive; in neither case is there a gap. The extra commands
fall into two blocks: three are inserted in the middle of the sequence (and
so all commands with higher first bytes are different between the 3t and 3a),
while the remainder occur after the last standard command.

The commands with only 1 byte are:
    APP             ENDV            ON
    ELSE            ENDWH           PATH
    ELSEIF          EXT             PROC
    ENDA            GLOBAL          REM
    ENDIF           ICON            TYPE
    ENDP            LOCAL           UNTIL
none of which directly correspond to Q-code.

With a few exceptions, the second byte of the data is the Q-code opcode of
that keyword, except that the top bit of the opcode is always set while
that of the data byte may be either clear or set (there is no obvious
meaning to the bit); thus opcode $AB might be represented as $2B or $AB.
If there is a third byte, this is the second byte of the opcode. If the
keyword maps to more than one opcode, the opcode represented is the lowest.

The exceptions are the following:
  $00   DO            IF            WHILE
  $3F   BREAK         CONTINUE      GOTO     ($BF is the opcode for GOTO)

All dialog commands other than DINIT share the second byte $6D; the second
byte of the opcode is not represented here.


Functions
---------
The associated data varies from 3 to 6 bytes (2 to 5 bytes on the 3t).

The first data byte is the second byte of the Q-code opcode. Integral valued
functions have values from $00 to $54, real valued functions from $80 to $99,
and string valued functions values from $C0 to $D7. There are 4 codes that
do not appear ($1F, $25, $39, $3A); these correspond to alternate versions
of the keyword.

The second byte (3a only) gives the type of the function:
  0 = word
  1 = long
  2 = real
  3 = string

The remaining bytes describe the arguments to the function. Each byte is
divided into two nibbles, with the least significant being processed first.
The first nibble (N) indicates the number of arguments:
   0 to  7: exactly N arguments, described by the next N nibbles
   8:       either a list or reals, or a real array followed by an integer
   9:       1 optional argument, described by the next nibble
  10 to 15: between 1 and N-8 arguments, described by the next N-8 nibbles

The remaining nibbles each describe one argument, in order:
   0 = word value (signed)
   1 = long value
   2 = real value
   3 = string value
   4 = word value (unsigned)
   5 = special case (meaning varies)
   6 = word variable
   7 = long variable
  10 = any variable


Notes on keywords
=================

FINDFIELD
---------
The manual description of flags% is wrong; it should be:
    0 = backwards starting at current record
    1 = forwards  starting at current record
    2 = backwards starting at end of file
    3 = forwards  starting at record 0
plus:
    0 = case independent
   16 = case dependent
(in other words, the bold text should be attached to the first bullet item,
not the second).

In all releases up to 3.22F, the keyword will actually do a FIND unless a
certain byte in memory is zero. To ensure this, each use of FINDFIELD should
be immediately preceeded by:
    POKEB PEEKW(28)+7,0

It is reported that the start% and no% parameters only count string fields
in the records; that is, if a record contains other types of field, these
are ignored when doing the searching. This is consistent with the underlying
system call.

If a backwards search fails to find a record, the keyword returns 1 rather
than 0 as it should. The pointer is left at record 1 but the field variables
are all zero or empty strings. If this happens, the instructions:
    CALL($03D8,PEEKW(ODB%))
    BACK
must be done before record 1 can be accessed, where ODB% is the appropriate
element of an array initialized with ODBINFO.

GBORDER
-------
It is reported that the $400 flag of GXBORDER also works with this call.

GFILL
-----
It is reported that this can't cope with negative parameters.

GPATT
-----
It is reported that this can't cope with negative parameters.

LOADM
-----
It is reported that the 3c behaves differently from the 3a when dealing
with calls from one module to another. One specific case mentioned is
that such calls lose track of which data file is current, so that USE must
be used to reselect the correct file.

ON
--
This keyword is not documented. @I don't know what it does.

USE
---
See LOADM.
The Psionics Files

LOCALES

PSIONICS FILE - LOCALES
=======================
Locale codes
Last modified 1994-08-23
========================

Psion allocate a number for each locale. This number is often used as part of
a file name; for example, the ROM:: filing system contains files whose last
two digits are the number of the locale they are for. This document lists the
known codes:

    00  Testing
    01  English - UK
    02  French - France
    03  German - Germany
    04  Spanish
    05  Italian
    06  Swedish
    07  Danish
    08  Norwegian
    09  Finnish
    10  English - USA
    11  French - Switzerland
    12  German - Switzerland
    13  Portuguese
    14  Turkish
    15  Icelandic
    16  Russian
    17  Hungarian
    18  Dutch
    19  Flemish
    20  English - Australia
    21  English - New Zealand
    22  German - Austria
    23  French - Belgium
The Psionics Files

MENUPROB

PSIONICS FILE - MENUPROB
========================
Series 3t menu problem workaround
Last modified 1994-09-12
=================================

There are some circumstances in which OPL programs with menus can gradually
lose small amounts of system memory.

All memory lost in this way is fully recovered by the Series 3t when the OPL
application exits, but if the application runs for a long time without
exiting, it is possible that the cumulative amount of memory lost will in time
adversely affect performance.

This bug is present in all versions of the Series 3t (but has been fixed in
the 3a). It does not affect any programs written in C.

To work around the bug, replace all occurences of the MENU keyword with
calls to a new procedure MENU%: which in turn calls the MENU keyword and
some machine code. The inconvenience of requiring an extra layer around calls
to MENU is slight for commercial OPL programs, since these programs are likely
to have such a layer already (for example to make calls to LOCK on
either side of the call to MENU). This layer can be merged with the MENU%:
procedure shown here. The contents of MENU%: may of course be placed in-line
instead of in a separate procedure.

The machine code called by the USR commands automatically detects the case
when no memory has been lost by the MENU command and does nothing.

    PROC MENU%:
      LOCAL r%
      LOCAL x1&(7),x2&(7),x3&(8)

      x1&(1)=&8BF88BFC
      x1&(2)=&8B00121E
      x1&(3)=&778B205F
      x1&(4)=&E42AAC0C
      x1&(5)=&A5ABC88B
      x1&(6)=&75C084AC
      x1&(7)=&CBF8E2FB
      x2&(1)=&00B4F08B
      x2&(2)=&FC808BCD
      x2&(3)=&AD0D7330
      x2&(4)=&C932D08B
      x2&(5)=&CDD88BAD
      x2&(6)=&F8754ACF
      x2&(7)=&000000CB
      USR(ADDR(x1&(1)),ADDR(x3&(1)),0,0,0)
      r%=MENU
      USR(ADDR(x2&(1)),ADDR(x3&(1)),0,0,0)
      RETURN(r%)
    ENDP
The Psionics Files

MISC

PSIONICS FILE - MISC
====================
Miscellaneous items
Last modified 1998-03-31
========================

This file holds miscellaneous items that can't be otherwise categorised.


World map
---------

The world map used by the World application on the 3a and 3c can be
copied for use in applications. Simply obtain a handle to it by:

    GLOADBIT ("ROM::WORLD.APP", 0, 2)


Dialogs
-------

The dialogs in OPL have a number of facilities not documented in the
manuals. The comments in this section apply from the start of dialog
construction (the DINIT keyword) until the dialog has been evaluated
(the DIALOG keyword returns).

Offset 54 in the process space points to the dialog data structure, which
is @@ bytes long:

  Offset  0 to   9: unknown
  Offset 10 to  51: short item table
  Offset 52 to  60: unknown
  Offset 61 (byte): number of items in dialog

If there are up to 7 items in the dialog (DINIT with a text parameter
generates an item) then information about them is stored in the short item
table. If there are 8 or more items, it is in the long item table; the
address of the long item table is stored in the first word of the short
item table. Each table consists of one or more 6 byte objects:

  Offset 0 (word): unknown
  Offset 2 (word): unknown
  Offset 4 (word): flags (these can be changed)
    bit 0: unknown
    bit 1: unknown
    bit 2: set if the item is underlined
    bit 3: unknown
    bit 4: clear if the item has a prefix, set if it does not
    bit 5: clear if the item can be selected, set if it cannot
    remaining bits unknown
The Psionics Files

OPO.FMT

PSIONICS FILE - OPO.FMT
=======================
Format of OPO and OPA files
Last modified 1998-02-28
===========================
[Much of the information in this file is supplied by Mike Rudin
<mrudin@cix.co.uk>, author of Revtran. My thanks to Mike, who will answer
questions, but asks that if you find things unclear, first try analysing
fragments of real q-code and working it out for yourself.]


File format
-----------
[Because this is somewhat different to normal, a summary is included at
the end.]

An OPO file (OPL translator output) consists of two headers, one or more
procedure bodies, and then the procedure table. An OPA file differs in
that there are one or more embedded files between the two headers.

The first header has a varying length and the following format:

  Offset  0 (cstr): "OPLObjectFile**"
  Offset 16 (word): format version (currently 1)
  Offset 18 (word): offset in file of second header
  Offset 20 (qstr): source filename

The source filename may have a trailing zero (which will be included in
the size of the qstr).

In an OPA file, the embedded files are each preceeded by a word giving
the length of the file. There are normally two embedded files: a PIC file
holding the icon, and an OPA information file (always 36 bytes):

  Offset  0 to  13: name, a dot, and then the extension
  Offset 14 to  33: path
  Offset 34 (word): type

This information is taken from the APP ... ENDA section; the first two
fields are padding out with zero bytes.

The second header is 12 bytes long and has the following format:

  Offset  0 (long): file length
  Offset  4 (word): translator version (S3t: $110F, S3a: $111F)
  Offset  6 (word): required runtime version ($110F, $111F)
  Offset  8 (long): offset of procedure table within the file

The translator and runtime versions seen are $110F for the Series 3t, and
$111F for the Series 3a.

The procedure table consists of one or more entries; the first one is
always the procedure that is executed at the start of the program. Each
entry has the format:

  Offset   0 (qstr): procedure name without trailing colon (length L)
  Offset L+1 (long): offset of procedure within the file
  Offset L+5 (word): line number in the source of the PROC line, minus 1

The table is ended by a zero-length name (always followed by another zero
byte, which will be the last byte in the file).

Each procedure body consists of a declarations block followed by the
"q-code" that is actually executed. The declarations block consists of:
  * Optimisation section (translator version $111F and above only)
  * Space control section
  * Parameter section
  * Global declaration section
  * Called procedures section
  * Global references section
  * String control section
  * Array control section

Various sections refer to a "variable type code". This is a byte describing
the type of a variable:
    bits 0 to 6: 0 = word, 1 = long, 2 = real, 3 = string
    bit 7:       set for an array, clear for a simple variable

The optimisation section consists of a single word, giving the length of
the rest of the declarations block.

The space control section has the format:
  Offset  0 (word): size of data stack frame
  Offset  2 (word): length of q-code
  Offset  4 (word): amount of dynamic stack used

The parameter section consists of a byte giving the number of parameters,
followed by one variable type code per parameter, in reverse order.

The global declaration section describes the global variables defined in
the procedure, and has the format:
  Offset  0 (word): size of rest of section (S):
  Offset  2 to S+1: zero or more per-variable blocks
Each per-variable block has the format:
  Offset   0 (qstr): name including suffix (length L)
  Offset L+1 (byte): variable type code
  Offset L+2 (word): offset within the data stack frame

The called procedure section lists all the procedures called by this one.
It consists of a word giving the length of the rest of the section, followed
by zero or more blocks, each consisting of a qstr (the name, excluding the
trailing colon) followed by a byte (the number of arguments).

The global references section lists all the global variables called but not
declared by this procedure. It consists of a list of blocks, each consisting
of a qstr (the name including the suffix) and a variable type code; the list
is ended by a zero byte (forming an empty qstr).

The string control section consists of a block for each string variable
declared by the procedure. The block has the format:
    Offset  0 (word): location in the data stack frame
    Offset  2 (byte): maximum length of the string
It is terminated by a zero word.

The array control section consists of a block for each array variable
declared by the procedure. The block has the format:
    Offset  0 (word): location in the data stack frame
    Offset  2 (word): number of elements
It is terminated by a zero word.


Summary of file format
----------------------
A file consists of the following items:
- first header (20 bytes + qstr)
- zero (OPO) or more (OPA):
  - (word) length of embedded file
  - embedded file
- second header (12 bytes)
- one or more procedure bodies, each:
  - declarations block:
    - optimisation section (some translator versions only, 2 bytes)
    - space control section (6 bytes)
    - parameter section (length byte, then that number of bytes)
    - global declaration section:
      - (word) size of rest of section
      - zero or more per-variable blocks (qstr then 3 bytes)
    - called procedures section:
      - (word) size of rest of section
      - zero or more per-procedure blocks (qstr then 1 byte)
    - global references section:
      - zero or more per-reference blocks (qstr then 1 byte)
      - (byte) zero
    - string control section:
      - zero or more per-string blocks (3 bytes)
      - (word) zero
    - array control section:
      - zero or more per-array blocks (4 bytes)
      - (word) zero
  - q-code
- one or more procedure table entries (each qstr + 6 bytes)
- (word) zero


Organisation of memory
----------------------
When an OPL procedure is called, the run-time system allocates a block of
memory associated with the call - the "data stack frame" - which will be
freed when the procedure call returns. This block holds the values of all
of the local and global variables defined in the procedure, and also
information required to locate global variables, parameters, and other
procedures referred to by the procedure.

Space is allocated for variables defined in the procedure as follows:

    x%     2 bytes             x%(N)    2N+2 bytes
    x&     4 bytes             x&(N)    4N+2 bytes
    x      8 bytes             x(N)     8N+2 bytes
    x$(L)  L+2 bytes           x$(N,L)  3+N(L+1) bytes

The location of a variable (or, more precisely, of its value) in the stack
frame is the address of some byte within this space:

    x%     offset 0            x%(N)    offset 2
    x&     offset 0            x&(N)    offset 2
    x      offset 0            x(N)     offset 2
    x$(L)  offset 1            x$(N,L)  offset 3

and this is what is used by the q-code. Arrays have the array size N placed
at offset 0 within the space, and it is here that the array control section
points. Strings have the maximum length L placed at offset 0 (or offset 2
for string arrays) within the space, and it is here that the string control
section points. That is, suppose we declare x$(2,4), and set the two elements
to "abc" and "x" respectively, and the variable is placed at location 22
within the data stack frame. Then the memory will contain:

Location: 22  23  24  25  26  27  28  29  30  31  32  33  34
Value:     $0002   4   3  'a' 'b' 'c'  ?   1  'x'  ?   ?   ?

The array control section will contain 22 as the location, the string
control section will contain 24, and the q-code will use 25.


Q-code
------
Q-code is a series of codes of varying length, each of which is an operation.
Most operations involve pushing values on to a stack or popping them. The
first byte of each code is the opcode, with the following bytes being
arguments.

The following conventions are used in this list.

    % (suffix)   a word
    & (suffix)   a long
    $ (suffix)   a qstr
    * (suffix)   a real
    = (suffix)   an address
    ! (suffix)   a single byte
    + (suffix)   see below

    push%    push the word result on to the stack
    pop=     the address at the top of the stack, popped off
             where more than one value is popped off, pop=1 pop=2 etc
             is used to show the order; pop=1 starts at the top of the stack
    addr=&   the long word whose address is that given
    L*       two bytes giving the location of a real in the data stack frame
             the variable is referred to as LL*
    E*       two bytes giving the external reference code for a global
             variable declared elsewhere or for a procedure (in each case
             referred to as EE*); see below for details
    V*       8 bytes forming a real, referred to as VV*
    D        a byte (00 to 03) naming an open data file (A to D)
    N        a byte giving the number of arguments
    N'       a byte giving the number of arguments minus 1
    Na       a byte giving the number of arguments, or 0 meaning 2 special
             arguments: the address of an array and then a word
    Nq       a byte that is 0 or 1 for OFF or ON respectively, or else the
             number of arguments minus 1
    Nx       a byte controlling the number of arguments as described
    Q        a byte that is 0 or 1 for OFF or ON respectively
    Qn       a byte that is 0, 1, or $FF for OFF, ON, and omitted respectively
    Qa       a byte that is 0 or 1 for OFF or ON, or some other value
    J        two bytes giving a location in the Q-code relative to the
             current operation (that is, 0 means this opcode) referred to
             as JJ
    ZZ       other bytes described in the notes

Certain opcodes differ only in the type of some operands. In this case, the
opcode is given as a range (e.g. $00-3 or $4C-E), and the affected operands
are shown by a + suffix. This should be replaced by % & * and $ respectively
for the four opcodes (omitting $ if there are only three).

Unless stated otherwise, keywords take their arguments from the stack in
reverse order. For example, opcode B9 is actually "RANDOMIZE pop&" and
opcode 9E is actually "AT pop%2, pop%1".

For certain keywords and builtin functions, some of the arguments are
required to be variables (for example, the first argument of IOOPEN). In
this case, the appropriate argument is handled by pushing the address of
the variable as a word, not as an address (an address is converted to a
word using the ADDR opcode - 57 00). This is indicated in the following list
by putting [v2] (indicating that the second argument is treated in this way)
after the meaning.


External references
-------------------
Global variables, parameters, and procedures called by a procedure are each
given an external reference code and a code size. The code of the first item
is always 18, and the codes of all other items are found by adding the code
size to the code of the previous item. The codes are allocated in the
following order:
* The global variables defined by the procedure; the code size for a
  variable is 4 more than the length of the name including the type suffix,
  so the code size for "abc&" is 8. These external references do not appear
  in the Q-code.
* The procedures called by this procedure, in the order given in the called
  procedure section; the code size for each procedure is 1 more than the
  length of the name including the colon, so the code size for "xx:" is 4.
  These external references are only used by opcode 53.
* The parameters of the procedure in order; the code size is 2 per parameter.
  These external references are used by opcodes 08 to 0B and 18 to 1B.
* The global variables referenced, but not defined, by the procedure, in the
  order given in the global references section; the code size is 2 per
  variable. These external references are used by opcodes 08 to 0F and 18
  to 1F.


Operation  Meaning
------------------
00-3 L+    push+ the value of LL+
04-7 L+    push= the address of LL+
08-B E+    push+ the value of EE+
0C-F E+    push= the address of EE+ [cannot be a parameter]
10-3 L+    push+ the value of LL+(pop%)
14-7 L+    push= the address of LL+(pop%)
18-B E+    push+ the value of EE+(pop%)
1C-F E+    push= the address of EE+(pop%) [cannot be a parameter]
20-3 D     push+ the value of field pop$+ of data file D
24-7 D     push= the address of field pop$+ of data file D
28-B V+    push+ VV+
2C-F       [[apparently not used]]
30-3       push% pop+2 <  pop+1
34-7       push% pop+2 <= pop+1
38-B       push% pop+2 >  pop+1
3C-F       push% pop+2 >= pop+1
40-3       push% pop+2 =  pop+1 (compare, not assign)
44-7       push% pop+2 <> pop+1
48-B       push+ pop+2 +  pop+1
4C-E       push+ pop+2 -  pop+1
4F V!      push% VV! ($80 to $FF convert to $FF80 to $FFFF)
50-2       push+ pop+2 * pop+1
53 E:      call procedure EE: (see below)
54-6       push+ pop+2 / pop+1
57         see below
58-A       push+ pop+2 ** pop+1
5B J       if pop% is zero, jump to JJ
5C-E       push% pop+2 AND pop+1
5F V!      push& VV! ($80 to $FF convert to &FFFFFF80 to &FFFFFFFF)
60-2       push% pop+2 OR pop+1
63 V%      push& VV% ($8000 to $FFFF convert to &FFFF8000 to &FFFFFFFF)
64-6       push% NOT pop+
67         [[apparently not used]]
68-A       push+ - pop+
6B ZZ      @ operator (see below)
6C         push* pop*2 < pop*1 %  [These are the "x+y%" operators]
6D         push* pop*2 > pop*1 %
6E         push* pop*2 + pop*1 %
6F         push* pop*2 - pop*1 %
70         push* pop*2 * pop*1 %
71         push* pop*2 / pop*1 %
72         [[apparently not used]]
73         [[apparently not used]]
74-7       RETURN no value from type + procedure
78         push% value of pop&
79         push% value of pop*
7A         push& value of pop*
7B         push& value of pop%
7C         push* value of pop%
7D         push* value of pop&
7E         [[apparently not used]]
7F         [[apparently not used]]
80-3       pop+ and discard value
84-7       store pop+1 in location with address pop=2
88-B       PRINT pop+ ;    (i.e. with no following space or newline)
8C-F       LPRINT pop+ ;   (i.e. with no following space or newline)
90         PRINT ,         (i.e. with no following newline)
91         LPRINT ,        (i.e. with no following newline)
92         PRINT           (i.e. newline at end of printing)
93         LPRINT          (i.e. newline at end of printing)
94-7       INPUT+ into location with address pop=
98-B       POKE+ pop+1 in location with address pop=2
9C         POKEB pop%1 in location with address pop=2
9D         APPEND
9E         AT
9F         BACK
A0         BEEP
A1         CLOSE
A2         CLS
A3         COMPRESS
A4         COPY
A5 D ZZ    CREATE pop$ (see below for details)
A6 Qa      CURSOR (Qa is 2, 3, or 4 for 1, 4, or 5 parameters respectively)
A7         DELETE
A8         ERASE
A9 Q       ESCAPE
AA         FIRST
AB V! ZZ   VECTOR pop% (see below for details)
AC         LAST
AD         LCLOSE
AE         LOADM
AF         LOPEN
B0         NEXT
B1 J       ONERR JJ (0 means ONERR OFF)
B2         OFF
B3         OFF pop%
B4 D ZZ    OPEN pop$ (see below for details)
B5         PAUSE
B6         POSITION
B7         IOSIGNAL
B8         RAISE
B9         RANDOMIZE
BA         RENAME
BB         STOP
BC         TRAP action immediately following
BD         UPDATE
BE D       USE
BF J       GOTO JJ
C0         RETURN pop+  (type popped depends on procedure type)
C1         UNLOADM
C2         EDIT
C3         SCREEN pop%2, pop%1
C4 D ZZ    OPENR pop$ (see below for details)
C5 Nx      gSAVEBIT (Nx: 0 = 1 argument, 1 = 3 arguments)
C6         gCLOSE
C7         gUSE
C8 N       gSETWIN
C9 Q       gVISIBLE
CA         gFONT
CB         gUNLOADFONT
CC         gGMODE
CD         gTMODE
CE         gSTYLE
CF         gORDER
D0         gINFO [v1]
D1         gCLS
D2         gAT
D3         gMOVE
D4-7       gPRINT pop+ ;    (i.e. with no following space or newline)
D8         gPRINT ,         (i.e. with no following newline)
D9 N'      gPRINTB
DA         gLINEBY
DB         gBOX
DC         [[apparently not used]]
DD         [[apparently not used]]
DE         gPOLY [v1]
DF         gFILL
E0         gPATT
E1         gCOPY
E2 N       gSCROLL
E3 Qn      gUPDATE
E4         GETEVENT [v1]
E5         gLINETO
E6         gPEEKLINE [v4]
E7         SCREEN pop%4, pop%3, pop%2, pop%1
E8         IOWAITSTAT [v1]
E9         IOYIELD
EA         mINIT
EB Nx      mCARD (there are Nx menu items, and 2Nx+1 arguments)
EC N       dINIT
ED         see below
EE         SETNAME
EF Nq      STATUSWIN
F0 N       BUSY (0 arguments means OFF)
F1 Q       LOCK
F2         gINVERT
F3         gXPRINT
F4 N       gBORDER
F5 Nq      gCLOCK
F6 V!      push* value of calculator memory VV
F7 V!      push= address of calculator memory VV
F8         MKDIR
F9         RMDIR
FA         SETPATH
FB         SECSTODATE [v2, v3, v4, v5, v6, v7, v8]
FC N'      GIPRINT
FD         [[apparently not used]]
FE         [[apparently not used]]
FF         see below


Each of the opcodes 57, ED, and FF are followed by a second opcode byte.
Opcode 57 is used for builtin functions; unless stated otherwise, these
take their arguments from the stack in reverse order and push the result.
For example, opcode 57 33 is actually "push% gPRINTCLIP pop$2, pop%1".


Operation  Meaning
------------------
57 00      push% ADDR pop= (address of a word, long, or real)
57 01      ASC
57 02 N    CALL
57 03      COUNT
57 04      DAY
57 05      DOW
57 06      EOF
57 07      ERR
57 08      EXIST
57 09      FIND
57 0A      GET
57 0B      IOA [v3, v4, v5]
57 0C      IOW [v3, v4]
57 0D      IOOPEN [v1] (second argument is a string)
57 0E      IOWRITE
57 0F      IOREAD
57 10      IOCLOSE
57 11      IOWAIT
57 12      HOUR
57 13      KEY
57 14      LEN
57 15      LOC
57 16      MINUTE
57 17      MONTH
57 18      PEEKB
57 19      PEEKW
57 1A      POS
57 1B      RECSIZE
57 1C      SECOND
57 1D      USR
57 1E      YEAR
57 1F      push% ADDR pop= (address of a string)
57 20      WEEK
57 21      IOSEEK [v3]
57 22      KMOD
57 23      KEYA [v1, v2]
57 24      KEYC [v1]
57 25      IOOPEN [v1] (second argument is a word)
57 26      gCREATE (5 arguments)
57 27      gCREATEBIT
57 28 N    gLOADBIT
57 29      gLOADFONT
57 2A      gRANK
57 2B      gIDENTITY
57 2C      gX
57 2D      gY
57 2E      gWIDTH
57 2F      gHEIGHT
57 30      gORIGINX
57 31      gORIGINY
57 32      gTWIDTH
57 33      gPRINTCLIP
57 34      TESTEVENT
57 35 N    OS
57 36      MENU without argument
57 37      DIALOG
57 38 N    ALERT
57 39      gCREATE (6 arguments)
57 3A      MENU with argument [v1]
57 3B      CREATESPRITE
57 3C      LOADLIB [v1]
57 3D      UNLOADLIB
57 3E      FINDLIB [v1]
57 3F      GETLIBH
57 40      DAYS
57 41      IABS
57 42      INT
57 43      PEEKL
57 44      SPACE
57 45      DATETOSECS
57 46      NEWOBJ
57 47      NEWOBJH
57 48 N    SEND [v3, v4, v5] (arguments 3 to 5 are optional)
57 49 N    ENTERSEND [v3, v4, v5] (arguments 3 to 5 are optional)
57 4A N    ENTERSEND0 [v3, v4, v5] (arguments 3 to 5 are optional)
57 4B      ALLOC
57 4C      REALLOC
57 4D      ADJUSTALLOC
57 4E      LENALLOC
57 4F N    IOC [v3, v4, v5]
57 50      UADD
57 51      USUB
57 52      IOCANCEL
57 53      STATWININFO [v2]
57 54      FINDFIELD
57 58      POPUP @@@@S5@@@@ ?
57 80      ABS
57 81      ACOS
57 82      ASIN
57 83      ATAN
57 84      COS
57 85      DEG
57 86      EXP
57 87      FLT
57 88      INTF
57 89      LN
57 8A      LOG
57 8B      PEEKF
57 8C      PI
57 8D      RAD
57 8E      RND
57 8F      SIN
57 90      SQR
57 91      TAN
57 92      VAL
57 93 Na   MAX
57 94 Na   MEAN
57 95 Na   MIN
57 96 Na   STD
57 97 Na   SUM
57 98 Na   VAR
57 99      EVAL
57 C0      CHR$
57 C1      DATIM$
57 C2      DAYNAME$
57 C3      DIR$
57 C4      ERR$
57 C5      FIX$
57 C6      GEN$
57 C7      GET$
57 C8      HEX$
57 C9      KEY$
57 CA      LEFT$
57 CB      LOWER$
57 CC      MID$
57 CD      MONTH$
57 CE      NUM$
57 CF      PEEK$
57 D0      REPT$
57 D1      RIGHT$
57 D2      SCI$
57 D3      UPPER$
57 D4      USR$
57 D5      GETCMD$
57 D6      CMD$
57 D7      PARSE$ [v3]
57 D8      ERRX$   @@@@S5@@@@

ED 00 Nx   dTEXT (Nx is 2 less than the number of arguments)
ED 01      dCHOICE pop=3, pop$2, pop$1
ED 02      dLONG pop=4, pop$3, pop&2, pop&1
ED 03      dFLOAT pop=4, pop$3, pop*2, pop*1
ED 04      dTIME pop=5, pop$4, pop%3, pop&2, pop&1
ED 05      dDATE pop=4, pop$3, pop&2, pop&1
ED 06      dEDIT pop=2, pop$1
ED 07      dEDIT pop=3, pop$2, pop%1
ED 08      dXINPUT pop=2, pop$1
ED 09      dFILE pop=3, pop$2, pop%1
ED 0A Nx   dBUTTONS (Nx is the number of buttons, there are 2Nx arguments)
ED 0B      dPOSITION pop%2, pop$1

FF 00      gGREY
FF 01      DEFAULTWIN
FF 02 N    DIAMINIT
FF 03      DIAMPOS
FF 04      FONT
FF 05      STYLE
FF 06      USESPRITE
FF 07      APPENDSPRITE (Nx: 0 = 2 arguments, 1 = 4 arguments)
FF 08      DRAWSPRITE
FF 09      CHANGESPRITE (Nx: 0 = 3 arguments, 1 = 5 arguments)
FF 0A      POSSPRITE
FF 0B      CLOSESPRITE
FF 0C      FREEALLOC
FF 0D      LINKLIB
FF 0E Qa   CACHE (Qa is the number of parameters if 2 or more)
FF 0F      gBUTTON
FF 10 N    gXBORDER
FF 11      gDRAWOBJECT
FF 12      ODBINFO [v1]
FF 13      CACHETIDY
FF 14      SCREENINFO [v1]
FF 15      CACHEHDR pop%
FF 16      CACHEREC pop%2, pop%1
FF 17 N    dINITS
FF 18      CALLOPX      @@@@S5@@@@
FF 22      GETEVENT32   @@@@S5@@@@
FF 23      GETEVENTA32  @@@@S5@@@@
FF 24      GCOLOR       @@@@S5@@@@
FF 26      SETDOC       @@@@S5@@@@
FF 29      IOWAITSTAT32 @@@@S5@@@@
FF 30      MCASC        @@@@S5@@@@
FF 33      DCHECK       @@@@S5@@@@


Notes
-----

Procedures expect two values on the stack for each parameter: a value and
a type code. The top of the stack is the variable type code for the last
parameter.

The @ operator expects the procedure name to be below the other values on
the stack. The opcode is followed by two bytes: the first is the number of
arguments to the call, and the second is one of %%, %&, 0, or %$. So
    @$(x$):(y%,z$)
will appear as
    [code to push x$]
    [code to push y%]
    [code to push% 0 (type code for word)]
    [code to push z$]
    [code to push% 3 (type code for string)]
    6B 02 24

The opcodes for CREATE, OPEN, and OPENR are followed by a D byte and then
information describing the field names. For each field in turn there is
a variable type code followed by the name; the list is ended by $FF. So
    OPEN x$,c,AAA$,B%
will appear as
    [code to push x$]
    B4 02 03 04 41 41 41 24 00 02 42 25 FF
       C     <--- AAA$ --->    <- B$ ->

The VECTOR keyword is followed by a byte giving the number of labels, and
then that number of relative addresses J1, J2, etc.
The Psionics Files

PROCESS

PSIONICS FILE - PROCESS
=======================
Processes and their properties
Last modified 1997-09-11
==============================

The Series 3 operating system is a fully multitasking one; at any time it can
be running any number of processes (up to some limit). Much useful information
about processes can be displayed with the SPY program.

Each process has a name, a task number, and a process ID. The task number runs
from 1 upwards (the Series 3 is limited to 24), and a task number can be
reused whenever a process terminates. The process ID consists of the address
of the control block for the process in kernel memory in the bottom 12 bits,
and a simple counter in the top 4 bits; this starts at 0 for the first
process to use this control block, and is incremented whenever the block is
reused.

The name of a process is normally the name of the program (1 to 8 characters),
followed by ".$" (or ".@" for subtasks), and the task number as 2 decimal
digits. The code for a process is placed in a segment called by the name of
the program followed by ".SC". Thus it is not possible to run two programs
with the same name at the same time.

Each process has a priority. Non-operating system processes are limited to
priority 192; the normal priorities are 128 for foreground and 112 for
background. Only the highest priority process(es) able to run will do so; all
lower priority ones will wait.


System processes
----------------

There are two kinds of system processes: fixed ones and optional ones. The
fixed processes are:

    SYS$NULL.$01   handles power off
    SYS$MANG.$02   the process and resource manager
    SYS$FSRV.$03   the file server
    SYS$WSRC.$04   the window server
    SYS$SHLL.$05   the process launcher and system screen
    TIME.$06       the time and alarm server

The optional processes are:

    SYS$NCP.$??    the remote link manager


Registers
---------

Processes may use the data registers (AX, BX, CX, DX, SI, and DI) without
restriction. The kernel may move memory segments about in memory at any time
without warning; when it does so, those of the segment registers (CS, DS, ES,
and SS) that appear to the kernel to be valid will be adjusted automatically.
If it is desired to change these registers at any other time, it should
therefore be done with interrupts disabled.

OPL uses CS, DS, and SS, and these should not be altered by assembler code
invoked from with OPL. ES is not used by the OPL interpreter, and is normally
left the same as DS and SS (which are always the same). Many system calls
use data registers to hold pointers; a segment register is also used with
each such pointer. The Psionics files SYSCALLS.n indicate when an address is
using ES; they do not distinguish DS and SS. Any assembler code called from
OPL should exit with ES equal to DS.

The only other values that can usefully be placed in ES are the kernel data
segment (using system call GenDataSegment), and segments created with the
system call SegCreate. To do the former, just invoke INT $8F; ES will then
point to the kernel data segment, and accesses via ES will behave just as
if done with the system call GenGetOsData (it is not possible to write in
this way). The latter is done as follows:

    ; Assume the segment handle is in BX.
    INT $8F
    MOV ES,ES:[BX]
    ; ES now points to the start of the segment.
    ; If the segment moves, ES will change automatically.
    ; Before returning to OPL:
    CLI      ; with interrupts disabled
    PUSH DS  ; copy DS to ES
    POP ES
    STI      ; and allow interrupts again


Memory
------

Each process has a single segment of memory. From zero upwards, this contains:
    reserved statics
    stack (grows downwards)
    normal statics
    heap (grows upwards)

The heap is divided into allocated and free cells. The SPY program shows the
number and total byte count of each kind of cell. The kernel will remove free
cells from the end of the heap when it needs space.

The stack is initialized to all $FF; it must always hold at least 256 bytes
to allow interrupts to be processed (otherwise panic 69 will occur). A typical
stack size is $A00. The SPY program allows the unused portion of the stack to
be refilled with $FF (to allow the high water mark to be reset).

The heap consists of consecutive cells:
  Offset  0 (word): length of data portion (L)
  Offset  2 to L+1: data portion (whose address is returned by allocators)
@Is that right, or is it 2 to L-1 ?@

Cells are always aligned to even addresses, and for this and other reasons may
be larger than requested.


Specific memory locations
-------------------------

The following table lists some specific use of memory locations.

  Offset  0 (word): initialized to $DEAD; should never change
  Offset  2 to   5: used by the kernel
  Offset  6 (word): handle of the segment holding the fold tables @@
  Offset  8 to  15: used by the object oriented programming system
  Offset 16 (word): used by the kernel
  Offset 18 (word): address of block <P18>
  Offset 20 (word): handle of the application manager object
  Offset 22 to  25: used by the window server
  Offset 26 to  29: used by the OPL runtime system
  Offset 30 (word): used by the debugger
  Offset 32 (byte): zero when address trapping is turned off (do not alter)
  Offset 33 (byte): non-zero when the kernel is modifying the heap
  Offset 34 (word): address of cstr holding the program name; used to determine
                    which list on the system screen a process appears in (@if
                    this word is zero, the process will not be sent X messages)
  Offset 36 (word): address of a heap cell containing a cstr holding the full
                    path name of the program being executed, followed by a
                    qstr holding the program information (see system call
                    FilExecute).
  Offset 38 (word): not used by the kernel or OPL; used by the debugger
  Offset 40 to  53: not used by the kernel or OPL
  Offset 54 (word): address of current dialog structure
  Offset 56 (word): @@ DatGate object handle
  Offset 58 (word): non-zero if locked (by OPL "LOCK ON" or equivalent)
  Offset 60 (word): address of cstr to appear in the status window
  Offset 62 (word): address of cstr holding current file being processed
  Offset 64       : maximum limit of stack (if floating point emulation is
                    in use, the emulator uses offsets 64 to 767).

Certain of these memory locations have names in the system documentation:
  34  DatProcessNamePtr
  36  DatCommandPtr
  40  DatApp1
  42  DatApp2
  44  DatApp3
  46  DatApp4
  48  DatApp5
  50  DatApp6
  52  DatApp7
  58  DatLocked
  60  DatStatusNamePtr
  62  DatUsedPathNamePtr

@Location "winHandle" is the channel number of the console device.


Block <P18> has the following contents:
@this is a "wserv" object@
  Offset 32 (word): address of block <P18P32>

Block <P18P32> has the following contents:
  Offset 12 (word): address of block <P18P32P12>

Block <P18P32P12> is created by the MINIT keyword and destroyed by the MENU
keyword. Outside this range, the block is invalid, and the pointer in the
<P18P32> block is invalid. Each MCARD keyword can move this block, thus
altering that pointer. The block has the following contents:
  Offset  0 (byte): number of MCARD calls so far
  Offset  1 onward: menu information blocks, in order of menu creation

Each menu information block has the following contents:
  Offset  0 (word): address of secondary menu information block
  Offset  2 (cstr): menu title

Each secondary menu information block has the following contents:
  Offset  0 (long): [Only ever seen $7392A1DF]
  Offset  4 (word): number of items in the menu
  Offset  6 (long): [Only ever seen 1 so far]
  Offset 10 (word): address of item table

Each item table has the following contents:
  Offset  0 (byte): number of items in the menu
  Offset  1 onward: item information blocks, in order of item

Each item information block has the following contents:
  Offset  0 (byte): number of bytes in the block, excluding this one
  Offset  1 (byte): Psion+ accelerator code (lowercased)
  Offset  2 (cstr): item text


Time process
------------

The pending alarms can be located in the memory of the Time process. At some
location between offset $0A00 and $0AFF is a block with the form:
  Offset  0 (long): $08040201
  Offset  4 (long): $00402010
  Offset 12 (word): first alarm control block
It is reported that on the Series 3c this has moved to somewhere between
$0C00 and $0CFF. It is also reported that on some versions the control
block is at offset 10 or 15.

The alarm control blocks are in a circular list, with the last pointing to
offset 12 (or 10 or 15) of the above block (which is not an alarm control
block); if that location points to itself, there are no alarms. Each block
has the form:
  Offset  0 (word): next alarm control block
  Offset  2 (word): reported that this is the second next alarm control block
  Offset  6 (word): process ID of process owning alarm
  Offset  8 (byte): 0 = clock alarm, 1 = has time and date, 2 = has date
  Offset 10 (long): abstime alarm expires
  Offset 14 (long): abstime displayed in alarm message
  Offset 18 (qstr): name of alarm sound
  Offset 28 (cstr): text displayed in alarm message
  Offset 93 to 255: [unknown; alleged to be part of the block]

The built-in alarm sounds have names consisting of a single byte (thus
offset 18 is 1 and offset 19 holds the name): 1=rings, 2=chimes, and
16=silence.

@System screen or Window Server (which?) places info about 14 application
buttons at DatApp1.@
The Psionics Files

RESOURCE.FMT

PSIONICS FILE - RESOURCE.FMT
============================
Format of Resource files
Last modified 1994-03-28
========================

Resource files are uses to hold information for a program which does not
need to be held in the program itself. Two reasons for doing this are:
- the contents of the resource file do not take up process memory when
  not being used;
- the resource file can be changed on a per-language basis without changing
  the rest of the program.

A resource file may be standard or compressed. This description only applies
to standard files. The format of a standard file is:

  Offset  0 (word): offset of index table
  Offset  2 (word): length in bytes of index table

The index table is an array of words, giving the offsets of each resource in
order. By convention resources are numbered from 1 upwards. If the table holds
T entries, there are T-1 resources (1 to T-1); entry N is the offset of the
end of resource N-1 as well as the offset of resource N, and entry T is the
offset of resource T-1, and so should equal offset 0 of the file.

For example, if a resource file contains two resources of length A and B
respectively, the file contains:

    Offset 0 (word)    : A+B+4
    Offset 2 (word)    : 6
    Offset 4 to A+3    : value of resource 1
    Offset A+4 to A+B+3: value of resource 2
    Offset A+B+4 (word): 4
    Offset A+B+6 (word): A+4
    Offset A+B+8 (word): A+B+4
The Psionics Files

SOUND.FMT

PSIONICS FILE - SOUND.FMT
=========================
Format of Sound files
Last modified 1995-07-26
========================

Sound files hold recorded sounds, and can only be used by the Series 3a. The
sound is played at 8000 entries per second. The file uses A-Law encoding.

A sound file begins with a 32 byte header of the following form:
  Offset  0 (cstr): "ALawSoundFile**"
  Offset 16 (word): format version number
  Offset 18 (long): number of samples in the file
  Offset 22 (word): length of silence (in 1/32 seconds) to append on playback
  Offset 24 (word): number of times to repeat on playback (0 and 1 both mean
                    play once)

The rest of the file is sound samples. Each byte represents a sound sample
with a value between -4095 and +4095. This value is encoded in two steps:
first the magnitude is reduced from 12 to 7 bits, and then alternate bits
(including the least signficant one) are inverted. The most significant bit
of the byte is set if the value is negative.

Values are thus encoded by:

    S0000000ABCDi -> S000ABCD -> S101APCQ
    S0000001ABCDi -> S001ABCD -> S100APCQ
    S000001ABCDii -> S010ABCD -> S111APCQ
    S00001ABCDiii -> S011ABCD -> S110APCQ
    S0001ABCDiiii -> S100ABCD -> S001APCQ
    S001ABCDiiiii -> S101ABCD -> S000APCQ
    S01ABCDiiiiii -> S110ABCD -> S011APCQ
    S1ABCDiiiiiii -> S111ABCD -> S010APCQ

and decoded by:

    S000ABCD -> S101APCQ -> S001APCQ10000
    S001ABCD -> S100APCQ -> S0001APCQ1000
    S010ABCD -> S111APCQ -> S1APCQ1000000
    S011ABCD -> S110APCQ -> S01APCQ100000
    S100ABCD -> S001APCQ -> S0000001APCQ1
    S101ABCD -> S000APCQ -> S0000000APCQ1
    S110ABCD -> S011APCQ -> S00001APCQ100
    S111ABCD -> S010APCQ -> S000001APCQ10

(a bit shown as i is ignored; a bit shown as P is the inverse of the bit shown
as B, and Q is the inverse of D).

If the values are treated as fractions of full-scale deflection (by dividing
them by 4096), then the following tables give mappings in each direction.

@@ TO BE PROVIDED
The Psionics Files

SPR.FMT

PSIONICS FILE - SPR.FMT
=======================
Format of Spreadsheet files
Last modified 1997-08-14
===========================

This document describes the layout of SPR files for the SH3 spreadsheet.

A data file (also called a database file) begins with a 22 byte header of the
following form:
  Offset  0 (cstr): "SPREADSHEET"
  Offset 16 (word): format version number
  Offset 18 (word): offset value (meaning unknown)
  Offset 20 (word): OPL runtime version number

The version numbers and offset value are all zero.

The rest of the file consists of records. All records have the form:
  Offset  0 (word): type of record
  Offset  2 (word): size of data portion in bytes (L)
  Offset  4 to L+3: data portion

Unless stated otherwise, records may appear in any order. Record types 11 and
12 should not appear in Series 3 spreadsheets - they were used by the MC. Types
13 onwards are new in the Series 3.

Unless stated otherwise, a cell reference is two words - column then row - and
a range reference is four words - left, top, right, bottom, in that order.
Each word is intepreted as follows. If the word is N, then:
      0 <= N <= $1FFF: Nth row or column (so 0 is row 1 or column A)
           N =  $8000: this row or column
  $8000 <  N <  $9FFF: row N-$8000 below or column N-$8000 to right
  $E000 <  N <= $FFFF: row $10000-N above or column $10000-N to left
Values with the top bit set are only permitted in formulae. In some other
circumstances a reference containing all $FFFF values is used for "none".


Record type 1 holds formulae. A formula must come before any cell (record type
2) that accesses it, and the relative order of type 1 records should be
preserved. The record takes the form:
  Offset  0 (word): number of records using this formula
  Offset  2 (byte): length of formula (F)
  Offset  3 to F+2: formula

A formula is stored using a Reverse Polish notation. In other words, to
evaluate a formula, start with an empty stack, and then scan the formula in
order; when finding an operand, push it on the stack, while when finding an
operator, take its arguments off the stack, apply it, and push the answer on
the stack.

Operators are represented by single bytes:
  1 = <      5 = <>     9 = *     13 = -     17 = &
  2 = <=     6 = =     10 = /     14 = NOT
  3 = >      7 = +     11 = **    15 = AND
  4 = >=     8 = -     12 = +     16 = OR
(all take two operands except 12 to 14; 17 is string concatenate).

Delimiters are represented by single bytes:
  18 = (     These are not strictly needed, but allow the original
  19 = )     entered formula to be recreated for editing
  20 = ,
  @The above 3 need testing@
  21 = end of formula

Operands are represented by a byte followed by the value of the operand:
  22 = real (8 bytes)
  23 = word (2 bytes)
  24 = qstr
  25 = cell reference
  26 = range reference

Functions with no arguments or a fixed list of arguments are represented by
single bytes; the operands are treated exactly as for operators. In the
following list, the arguments are shown as "n" for numeric, "s" for string,
and "r" for range.

  27 ERR              55 LOG(n)           83 STRING(n,n)
  28 FALSE            56 LOWER(s)         84 CTERM(n,n)
  29 NA               57 MINUTE(n)        85 DATE(n,n)
  30 PI               58 MONTH(n)         86 DAVG(r,n,r)
  31 RAND             59 N(r)             87 DCOUNT(r,n,r)
  32 NOW              60 PROPER(s)        88 DMAX(r,n,r)
  33 TRUE             61 ROWS(r)          89 DMIN(r,n,r)
  34 ABS(n)           62 S(r)             90 DSTD(r,n,r)
  35 ACOS(n)          63 SECOND(n)        91 DSUM(r,n,r)
  36 ASIN(n)          64 SIN(n)           92 DVAR(r,n,r)
  37 AT(s)            65 SQRT(n)          93 FIND(s,s,n)
  38 ATAN(n)          66 TAN(n)           94 FV(n,n,n)
  39 CELLPOINTER(n)   67 TIMEVALUE(s)     95 HLOOKUP(n,r,n)
  40 CHAR(n)          68 TRIM(s)          96 IF(n,n,n)
  41 CODE(s)          69 UPPER(s)         97 INDEX(r,n,n)
  42 COLS(r)          70 VALUE(s)         98 MID(s,n,n)
  43 COS(n)           71 YEAR(n)          99 PMT(n,n,n)
  44 DATEVALUE(s)     72 ATAN2(n,n)      100 PV(n,n,n)
  45 DAY(n)           73 CELL(n,r)       101 RATE(n,n,n)
  46 EXP(n)           74 EXACT(s,s)      102 SIN(n)
  47 HOUR(n)          75 IRR(n,n)        103 TERM(n,n,n)
  48 INT(n)           76 LEFT(s,n)       104 TIME(n,n,n)
  49 ISERR(r)         77 MOD(n,n)        105 VLOOKUP(r,n,n)
  50 ISNA(r)          78 NPV(n,n)        106 DDB(n,n,n,n)
  51 ISNUM(r)         79 --------        107 REPLACE(s,n,n,s)
  52 ISSTR(r)         80 REPEAT(s,n)     108 SYD(n,n,n,n)
  53 LEN(s)           81 RIGHT(s,n)
  54 LN(n)            82 ROUND(n,n)

Functions with a variable list of arguments are more complex. The call is
built up as follows:
  - a START byte
  - the arguments
  - an END byte
  - the number of arguments (a byte)
The arguments are just placed in order. An argument is either:
  - the value of the argument, followed by an ARG byte
  - a RANGE byte followed by a range reference
Note that all arguments other than ranges, including cell references, work
by evaluating the argument in the normal way; ARG in effect says to pop the
next argument off the stack.

The values of the four special bytes differ for each function:

                START    END     ARG    RANGE
    AVG()        120     112     136     128
    CHOOSE()     121     113     137     129
    COUNT()      122     114     138     130
    MAX()        123     115     139     131
    MIN()        124     116     140     132
    STD()        125     117     141     133
    SUM()        126     118     142     134
    VAR()        127     119     143     135


Record type 2 describes a cell. It has the following format:
  Offset  0 to   3: cell reference
  Offset  4 (byte): flags:
    Bits 0 to 2: cell contents type:
      0 = blank
      1 = real constant
      2 = text constant
      3 = word constant
      5 = real formula
      6 = text formula
    Bits 3 to 4: text alignment: 0 = repeat, 1 = left, 2 = right, 3 = centre
    Bit 5:       set for left aligned numerics, clear for right aligned
    Bit 6:       set if the cell has changed since the last recalculation
    Bit 7:       should not be altered, used by natural order sort
  Offset  5 (byte): format
    Bits 0 to 3: number of digits in display format
      For special formats, this selects the special format:
         0 = bargraph,  1 = general, 5 = show formulae, 6 = hidden, 9 = date,
        11 = time,     15 = default
    Bits 4 to 6: display format: 0 = fixed,      1 = scientific,  2 = currency,
                                 3 = percentage, 4 = triad/comma, 7 = special
    Bit 7:       set if the cell is protected

This is then followed by a value block and then optionally a font byte.
The value block depends on the contents type:
  Type 0 (blank) has no value block
  Type 1 (real constant):
    Offset  6 (real): value
  Type 2 (text constant):
    Offset  6 (qstr): value
  Type 3 (word constant):
    Offset  6 (word): value
  Type 5 (real formula):
    Offset  6 (word): index of formula
    Offset  8 (real): current value
  Type 5 (text formula):
    Offset  6 (word): index of formula
    Offset  8 (qstr): current value
The index of a formula is its position in the set of type 1 records. So 0
means the first type 1 record, 1 the second type 1 record, and so on.

The font byte is simply a number from 0 to 3, giving the font of the cell.


Record type 3 describes column widths, and appears for each column not of the
default width. The record takes the form:
  Offset  0 (byte): column number
  Offset  1 (byte): width


Record type 4 describes the default column width:
  Offset  0 (word): default width


Record type 5 holds general status information:
  Offset  0 (byte): flags
    Bit 0:       set if automatic recalculate is on
    Bit 1:       set if protection override is on
    Bit 2:       set if a cell has been deleted since the last recalculation
    Bit 3:       set if table recalculation is on
    Bits 4 to 7: unused, always zero
  Offset  1 (byte): unused, always zero
  Offset  2 (byte): default numeric display format
  Offset  3 (byte): default alignment for new cells
The default numeric display format uses the same encoding as cells do, with
bit 7 always being zero. The default alignment uses the same encoding as the
flags of a cell, with bits 0 to 2, 6, and 7 always being zero.


Record type 6 holds information about the current state of the display:
  Offset  0 to   7: range reference of titles
  Offset  8 to  11: cell reference of top left displayed cell excluding titles
  Offset 12 to  19: range reference of selected range
  Offset 20 to  23: cell reference of cursor
  Offset 24 (byte): non-zero if grid lines are to be displayed, zero if not
  Offset 25 (byte): zero if zero values are to be displayed, non-zero if not


Record type 7 describes a named cell or range:
  Offset  0 (cstr): name
  Offset 16 to  23: range reference
  Offset 24 (word): type: 25 = cell, 26 = range


Record type 8 describes a range to be offered for selective printing:
  Offset  0 to   7: range reference
There may be any number of such records.


Record type 9 describes the criterion and database ranges for the database
commands. If this record occurs more than once, the last one will be used.
The record takes the form:
  Offset  0 to   7: criterion range reference
  Offset  8 to  15: database range reference


Record type 10 describes information for the table commands. If this record
occurs more than once, the last one will be used. The record takes the form:
  Offset  0 to   7: table range reference
  Offset  8 to  11: input cell 1 reference
  Offset 12 to  15: input cell 2 reference, or $FFFF if only one input cell


Record type 11 describes the print setup. It should not appear in Series 3
spreadsheets - it was used by the MC. The record takes the form:
  Offset  0 (byte): flags
    Bit 0:       set if values are shown, clear if formulae are shown
    Bit 1:       set if hidden cells are shown
    Bit 2:       set if column separators are shown
    Bit 3:       set if headers are shown
    Bits 4 to 7: unused, always zero
  Offset  1 (byte): unused, always zero


Record type 12 describes the printer font. It should not appear in Series 3
spreadsheets - it was used by the MC. The record takes the form:
  Offset  0 (byte): flags
    Bit 0:       set for bold
    Bits 1 to 2: unused, always zero
    Bit 3:       set for double height
    Bits 4 to 7: unused, always zero
  Offset  1 (byte): unused, always zero
  Offset  2 to  17: font name


Record type 13 describes a graph (see Psion-/):
  Offset   0 (cstr): name (see Psion-E)
  Offset  16 to  23: range reference for data range A (see Psion-R)
  Offset  24 to  31: range reference for data range B
  Offset  32 to  39: range reference for data range C
  Offset  40 to  47: range reference for data range D
  Offset  48 to  55: range reference for data range E
  Offset  56 to  63: range reference for data range F
  Offset  64 to  71: range reference for data range X
  Offset  72 to  79: range reference for labels for range A (see Psion-B)
  Offset  80 to  87: range reference for labels for range B
  Offset  88 to  95: range reference for labels for range C
  Offset  96 to 103: range reference for labels for range D
  Offset 104 to 111: range reference for labels for range E
  Offset 112 to 119: range reference for labels for range F
  Offset 120 (byte): format of range A
  Offset 121 (byte): format of range B
  Offset 122 (byte): format of range C
  Offset 123 (byte): format of range D
  Offset 124 (byte): format of range E
  Offset 125 (byte): format of range F
    All the formats (see Psion-L) are encoded in the same way:
    Bit 0:       set if lines are shown
    Bit 1:       set if symbols are shown
    Bits 2 to 7: unused, always zero
  Offset 126 (byte): alignment of label range A
  Offset 127 (byte): alignment of label range B
  Offset 128 (byte): alignment of label range C
  Offset 129 (byte): alignment of label range D
  Offset 130 (byte): alignment of label range E
  Offset 131 (byte): alignment of label range F
    Label range alignments (see Psion-B) are:
    0 = centre, 1 = right, 2 = below, 3 = left, 4 = above
  Offset 132 (byte): x-axis scaling (see Psion-A)
    Bit 0:       set for manual upper range, clear for automatic upper range
    Bit 1:       set for manual upper range, clear for automatic upper range
    Bits 2 to 7: unused, always zero
  Offset 133 (byte): x-axis format (see Psion-A), as for cell format (record
    type 2) but with bit 7 always zero
  Offset 134 (real): x-axis lower limit (see Psion-A)
  Offset 142 (real): x-axis upper limit (see Psion-A)
  Offset 150 (byte): y-axis scaling, as for x-axis
  Offset 151 (byte): y-axis format, as for x-axis
  Offset 152 (real): y-axis lower limit, as for x-axis
  Offset 160 (real): y-axis upper limit, as for x-axis
  Offset 168 (byte): graph type (see Psion-F)
    0 = scatter, 1 = bar, 2 = pie, 4 = line, 5 = stack-bar
  Offset 169 (byte): grid flags (see Psion-F)
    Bit 0:       set if horizontal grid lines visible
    Bit 1:       set if vertical   grid lines visible
    Bits 2 to 7: unused, always zero
  Offset 170 (byte): colour, encoding unknown
  Offset 171 (byte): ranges enabled (see Psion-R)
    Bits 0 to 5: set if ranges A to F respectively are enabled
    Bit 6:       set if range X is enabled
    Bit 7:       unused, always zero
  Offset 172 (byte): range labels enabled (see Psion-B)
    Bits 0 to 5: set if ranges A to F respectively are enabled
    Bits 6 to 7: unused, always zero
  Offset 173 (byte): other flags
    Bits 0 and 1: font size: 0 = auto, 1 = small, 2 = big (see Psion-F)
    Bits 2 and 3: pie labels: 0 = none, 1 = percent, 2 = values (see Psion-F)
    Bit 4:        set for 3D graphs (see Psion-F)
    Bit 5:        set if Y-axis title enabled (see Psion-I)
    Bit 6:        set if X-axis title enabled (see Psion-I)
    Bit 7:        set if titles enabled (see Psion-T)
  Offset 174 (word): unused

At offset 176 onwards are 10 cstrs. These are, in order:
  title first line
  title second line
  x-axis title
  y-axis title
  range A legend
  range B legend
  range C legend
  range D legend
  range E legend
  range F legend
The titles are limited to 40 characters, and the range legends to 20.


Record type 14 indicates which graph is current:
  Offset  0 (word): index of current graph
(the index is the count of type 13 records, so 0 means the first type 13
record in the file, and so on).


Record type 15 describes the fonts used. It consists of 4 font records, which
correspnd to fonts 1 to 4. Each font record has the format:
  Offset  0 to  5: unknown


Record type 16 holds information about printer set-up, and is identical to
record type 2 in Word files (see WORD.FMT).


Record type 17 describes the printer driver. It is identical to record type 2
in Word files:
  Offset  0 (byte): printer driver model number
  Offset  1 (cstr): printer driver library
A printer driver library can support several similar printers; the model number
specifies which is selected.


Record types 18 and 19 hold the header and footer text respectively as a cstr.


Record type 20 holds additional information about the screen. It will be
ignored if it does not directly preceed record type 6. It has the format:
  Offset  0 (byte): flags
    Bit 0:       set if grid labels are shown
    Bit 1:       set if small font is in use
    Bits 2 to 7: unused, always zero
  Offset  1 (byte): ignored (always zero)


Record type 22 indicates that the file is encrypted. It must be the first
record in the file. It has the format:
  Offset  0 to   8: encryption key check value
  Offset  9 to  15: copy of offset 9 to 15
  Offset 16 to  17: the result of encrypting two zero bytes


Encryption
----------

Spreadsheet files can be encrypted with a password on some systems. If so,
this fact is indicated by a type 22 record.

The password is used to generate two 9 byte sequences, called the key value
and the key check value; there is no obvious relationship between the two
sequences. The key check value is written into the type 22 record, while
the key value is used for the actual encryption. The key value is generated
with the system call GenMaskInit; there is no documentation of the algorithm
used to generate the check value, and it is not the same as used by Word.

[Note: different passwords may generate the same key value but different key
check values, or vice versa.]

Encryption is carried out using the system call GenMaskEncrypt: the data
section of each record (other than the type 22 record) is encrypted in the
order they occur in the file, with offset 16 of the encryption control block
being zero before encrypting the first record. The type and length of the
records are not encrypted.
The Psionics Files

SYSCALLS.1

PSIONICS FILE - SYSCALLS.1
==========================
System calls (part 1)
Last modified 1997-09-09
========================

The Psion System 3 operating system offers a large number of system calls.

A system call is identified by either a "function number" or by a "function
number and a "subfunction number". These are abbreviated to "Fn" and "Sub"
in the descriptions of system calls.

Each call can take up to 5 word parameters, called BX, CX, DX, SI, and DI.
In addition, there may be up to two byte parameters (AH and AL) or an
additional word parameter (AX). The values returned from the call have the
same structure; in addition, there is an error flag and three result flags
(the latter are only used by a few system calls). Note that AX is equivalent
to (AH * 256 + AL); the description will use whichever is most convenient.

There are two OPL keywords for making system calls: CALL and OS. They access
the same system calls, and differ only in the way in which the parameters are
passed and the results returned.

The CALL keyword takes from 1 to 6 arguments. If an argument is omitted, the
corresponding parameter is set to an undefined value. The first argument
should be one of:
    Fn
    Fn + 256 * Sub
    Fn + 256 * AH
according to the specific system call. The remaining arguments provide the
word parameters:
    argument 2: BX
    argument 3: CX
    argument 4: DX
    argument 5: SI
    argument 6: DI
The keyword returns a value, which is one of the results:
    AX
    AH * 256 + AL
(which are equivalent). The flags and the other 5 results are not available.

OS takes two or three arguments; if there is no third, it is taken to be
identical to the second. The first argument is Fn, while the second and third
are each the address of a 12 byte buffer, holding the parameters and results
respectively:
  Offset  0 (word): one of:
    Sub * 256 + AL    (parameters only)
    AX                (parameters and results)
    AH * 256 + AL     (parameters and results)
  Offset  2 (word): BX
  Offset  4 (word): CX
  Offset  6 (word): DX
  Offset  8 (word): SI
  Offset 10 (word): DI
The keyword returns a value which represents the error or result flags.
Each flag is held in a specific bit of the value; the remaining bits are
unspecified:
    Bit  0: UL flag or error flag (depending on context)
    Bit  6: EQ flag
    Bit  7: SL flag
Thus, if the call can fail, it has failed if the returned value is odd.

When a parameter or result is described as a cstr, a qstr, a buffer, or any
other construct requiring more than 2 bytes, the actual parameter or result is
the address of the construct.

When a register holds an address (for the above reason or otherwise), it is
relative to some segment register. If programming entirely in OPL, all the
relevant segment registers (DS, SS, and ES) are the same. However, if assembler
is being used, it is sometimes useful to have ES different from the others
(see the Psionics file PROCESS for more details). A prefix of "e" to a register
name (such as "eBX") means that the address is relative to ES. Unprefixed names
are relative to DS or SS (which should be the same). A prefix of "u" means
that the segment register is unknown.


The system calls are described in a standard form. The first line gives the
following information:
* the Fn value
* the Sub value if any
The second line gives the following:
* The name given to the call by the SDK.
* A note such as "v3.1" giving the first version of the operating system
  to support the call; if omitted, all versions support it.
* The word "fails" if the call can fail; if omitted, the call never fails.
  - If a call can fail, then the error flag shows whether or not it did so. If
    it failed, AL holds an error code between 128 and 255; this is normally
    treated as a negative number between -1 and -128, found by evaluating
    the expression (AX OR $FF00). AH, and any of the 5 word results that the
    call would have changed, are unspecified.
  - If a call cannot fail, the error flag may still be set; this should be
    ignored.
  - Even if a call cannot fail, bad parameters can cause a system panic.
* The word "async" if the call is always asynchronous, or the word "vsync" if
  it is sometimes asynchronous; if omitted, the call is synchronous.
  - A synchronous call is "completed" (has carried out all its actions) when
    the system call returns.
  - An asynchronous call returns immediately, even though the call might not
    have completed. A parameter of the call specifies a "status word", which
    the call initially sets to -46 (the error code meaning "not completed).
    When the relevant action has been taken or event occurs, the call
    is completed, the status word is changed to indicate the result of the
    call, and an IOSIGNAL is sent to the process. [This is exactly the same
    behaviour as the IOA keyword.]
  - If a call is "vsync", then it may be made as either a synchronous or
    asynchronous call:
    + to make a synchronous call, set AL to zero (the parameter giving the
      address of the status word will be ignored);
    + to make an asynchronous call, set AL to any other value (the address
      of the status word must be valid);
    + descriptions of such calls will omit AL from the list of parameters.
  - An asynchronous call may complete before returning (for example if the
    relevant event has already happened). In this case the process will never
    see the status word with the value -46, but an IOSIGNAL is still received.
  - Some asynchronous calls have a corresponding "cancel" call. This causes
    the original call to be completed with the status word set to some
    negative value other than -46.

This is then followed by a list of the parameters and results used by the
call; any parameter not listed is ignored. For the 5 main word results, the
result (if the call does not fail) is the same as the corresponding parameter
(including when the former is ignored) unless a different meaning is shown
following an arrow (->). For the results AH, AL, and AX, and also the result
flags, the result is unspecified if no such description is given.


For example, consider the following (non-existent) system call:
Fn $12 Sub $34
GetMagicCookie fails
    AX: -> magic cookie table entry zero
    BX: table entry number
    CX: -> magic cookie entry
    SI: addend -> CX out + SI in
Returns entries from the magic cookie table.

This system call could be used either by:
    entry0% = CALL ($3412, entry%, 0, 0, addend%)
which only returns magic cookie table entry zero, or by:
    LOCAL regs%(6)
    regs%(1)=$3400
    regs%(2)=entryno%
    regs%(5)=addend%
    failed%=1 AND OS ($12, ADDR(regs%()))
    REM regs%(2,4,6) have not changed
    IF NOT failed
        entry0%=regs%(1)
        entry%=regs%(3)
        REM regs%(5) will equal entry%+addend%
    ELSE
        REM regs%(1,3,5) are undefined
        error%=regs%(1) and $FF00
    ENDIF
which returns much more information.


System calls
------------

Note that some system calls are deliberately not described.


Fn $80 Sub $00
SegFreeMemory
    AX: -> free memory
Returns the amount of free system memory, in units of 16 bytes.


Fn $80 Sub $01
SegCreate fails
    AL: segment type: ordinary processes should use 1.
    AX: -> segment handle
   eBX: (cstr) name of the segment
    CX: segment size in units of 16 bytes
Creates an additional memory segment. Each segment must be given a name, of the
form "8.3" (i.e. up to 8 characters, optionally followed by a dot and up to 3
more characters). If the name is already in use, the call will fail. Once
created, the segment may be used by the process as additional memory, either
via SegCopyFrom and SegCopyTo, or in assembler code (see the Psionics file
KERNEL).


Fn $80 Sub $02
SegDelete fails
   eBX: segment handle
Deletes an additional memory segment. If any other process has opened the
segment, the call will fail.


Fn $80 Sub $03
SegOpen fails
    AX: -> segment handle
   eBX: (cstr) name of the segment
Opens the additional memory segment with the given name (if no such segment
exists, the call will fail). The call will fail if the process has the segment
open already. Except where stated, all calls using additional memory segments
must be given handles from SegCreate or SegOpen calls.


Fn $80 Sub $04
SegClose fails
    BX: segment handle
Closes an additional memory segment which the process has open. If this was the
only process with the segment open, it is deleted. Open segments are closed
when a process terminates.


Fn $80 Sub $05
SegSize
    AX: -> segment size
    BX: segment handle
Returns the size of an additional memory segment in units of 16 bytes.


Fn $80 Sub $06
SegAdjustSize fails
    BX: segment handle
    CX: new size in units of 6 bytes
Changes the size of an additional memory segment. The memory will be added to
or removed from the end of the segment.


Fn $80 Sub $07
SegFind fails
    AX: -> segment handle
    BX: last segment handle
    SI: address of 14 byte buffer used by the call
   eDI: (cstr) pattern to search for
Finds the additional memory segments with names matching the search pattern
(use ? and * as wild cards). The first call should be made with the last
segment handle set to 0, and subsequent calls should set it to the handle
returned by the previous call. The call fails when there are no more segments
to return. It is not necessary to keep calling SegFind until this happens.


Fn $80 Sub $08
SegCopyTo
    BX: segment handle
    CX: number of bytes to copy
    DX: high half of start address in segment
    SI: address in process of first byte to copy
    DI: low half of start address in segment
Copies data from the current process to an additional memory segment.


Fn $80 Sub $09
SegCopyFrom
    BX: segment handle
    CX: number of bytes to copy
    DX: high half of start address in segment
    SI: address in process to copy first byte to
    DI: low half of start address in segment
Copies data from an additional memory segment to the current process.


Fn $80 Sub $0A
SegLock
    BX: segment handle
Locks an additional memory segment; a locked segment will not be deleted even
if no processes have it open.


Fn $80 Sub $0B
SegUnLock
    BX: segment handle
Unlocks an additional memory segment. The number of unlock calls should equal
the number of lock calls; additional unlocks may cause the segment to be
deleted while still open.


Fn $80 Sub $0C
SegRamDiskUsed
    AX: -> size of the ram disc in units of 16 bytes
Returns the size of the ram disc; this should be treated carefully, as it
can change without warning.


Fn $80 Sub $0D
SegCloseLockedOrDevice
    BX: segment handle
Unlocks an additional memory segment where the handle may be that for a
different process. See SegUnLock for more details.


Fn $81 Sub $00
HeapAllocateCell fails
    AX: -> allocated block
    CX: number of bytes to allocate
Allocates a block of memory from the heap. The returned block may be larger
than requested. Heap memory is part of the process's normal memory segment.


Fn $81 Sub $01
HeapReAllocateCell fails
    AX: -> new address of block
    BX: block to be reallocated, or zero
    CX: new size of block in bytes
Changes the size of a heap block; the block may have to be moved to do this.
The memory will be added or deleted to the end of the block. If the call fails,
the block is unaffected. If BX is zero, then a new cell is allocated. The new
block may be larger than requested.


Fn $81 Sub $02
HeapAdjustCellSize fails
    AX: -> new address of block
    BX: block to be adjusted (must not be zero)
    CX: number of bytes to add or remove
    DX: location within block of the change
Changes the size of a heap block; the block may have to be moved to do this.
If the call fails, the block is unaffected. The memory will be added or removed
at the offset given by DX. For example, if the block was 10 bytes long, CX is
3, and DX is 6, the new block will be 13 bytes, and consist of the first 6
bytes of the old block, then 3 random bytes, then the last 4 bytes of the old
block. The new block may be larger than requested.


Fn $81 Sub $03
HeapFreeCell
    BX: block to free
Frees a previously allocated heap block.


Fn $81 Sub $04
HeapCellSize
    AX: -> cell size in bytes
    BX: address of block
Returns the actual size of a heap block (which may be larger than requested
when the block was created or last resized).


Fn $81 Sub $05
HeapSetGranularity
    BX: new granularity in units of 16 bytes
When the application data space is not large enough to satisfy a heap request,
it is grown by the granularity. The default is 2kb (128 units), and the
maximum is 16k (1024 units).


Fn $81 Sub $06
HeapFreeMemory
    AX: -> maximum possible free space on heap
    BX: -> address of start of heap
Returns the amount of heap space which can be allocated (by using freed blocks
or by growing the data space, or both), plus the address of the base of the
heap.


Fn $82 Sub $00
SemCreate fails
    AX: -> semaphore handle
    BX: initial value of semaphore
Creates a new semaphore for process interlocking. Each semaphore has a list of
processes associated with it (this list is initially empty) and a value, which
must initially be zero or positive.


Fn $82 Sub $01
SemDelete
    BX: semaphore handle
Deletes a semaphore. Any processes on the semaphore's list will be restarted.
When a process terminates, any semaphore it created will be deleted.


Fn $82 Sub $02
SemWait
    BX: semaphore handle
If the value of the semaphore is positive or zero, one is subtracted from it.
If the value is now or initially -1, the current process is then blocked and
added to the end of the list for that semaphore.


Fn $82 Sub $03
SemSignalOnce
    BX: semaphore handle
If the list for the semaphore is not empty, the first process on the list is
removed and restarted. If the list is empty (either initially or after the
only process is removed), one is added to the value of the semaphore. If the
restarted process has a higher priority than the current one, a reschedule
will take place and the other process will start running (see the description
of priorities in the Psionics file PROCESS).


Fn $82 Sub $04
SemSignalMany
    BX: semaphore handle
    CX: number of calls to make (must be positive)
This is equivalent to making several calls to SemSignalOnce.


Fn $82 Sub $05
SemSignalOnceNoReSched
    BX: semaphore handle
This is identical to SemSignalOnce except that a reschedule never takes place
because of the call (though one may take place due to the current process using
up its time slot).


Fn $83 Sub $00
MessInit fails
    BX: number of message slots + 256 * maximum data length
Initialize the message system so that the current process can receive
inter-process messages. The call reserves the indicated number of message
slots, with each slot having room for the indicated amount of data. The slots
are allocated on the heap.


Fn $83 Sub $01
MessReceiveAsynchronous async
    BX: address of message slot pointer
    DI: address of the status word
When a message arrives, the message slot pointer is set to the address of the
message, the status word is set to zero, and the call completes. The message
has the format:
  Offset  0 to   3: used by the message system
  Offset  4 (word): message type
  Offset  6 (word): process sending the message
  Offset  8 onward: data in message


Fn $83 Sub $02
MessReceiveWithWait
    BX: address of message slot pointer
When a message arrives (this may have happened before the call; otherwise the
call waits until a message arrives), the message slot pointer is set to the
address of the message. The message format is as for MessReceiveAsynchronous.


Fn $83 Sub $03
MessReceiveCancel
Cancel any pending MessReceiveAsynchronous.


Fn $83 Sub $04
MessSend fails
    BX: process to receive the message
    CX: message type
    SI: address of first byte of message data
Send a message to a process. The call will block until there is a free message
slot in the receiving process. The receiving process determines the amount of
data sent. The reply is ignored.

If the sender has priority 128 or above, the message is placed at the front of
the queue of messages waiting for the recipient (if it is not already waiting
for a message). Otherwise it is placed at the back of the queue.


Fn $83 Sub $05
MessSendReceiveAsynchronous fails async
    BX: process to receive the message
    CX: message type
    SI: address of first byte of message data
    DI: address of the status word
Send a message to a process; when the recipient replies, the status word is
set to the reply and the process is sent an IOSIGNAL. The call will block until
there is a free message slot in the receiving process.


Fn $83 Sub $06
MessSendReceiveWithWait fails
    AX: -> reply
    BX: process to receive the message
    CX: message type
    SI: address of first byte of message data
Send a message to a process, and blocks until the recipient replies.


Fn $83 Sub $07
MessFree
    BX: address of received message
    CX: reply
The reply is sent to the recipient of the message, and the message slot is
freed and can be used for another incoming message.


Fn $83 Sub $08
MessSignal fails
    BX: process to watch
    CX: message type
Requests that, when the specified process terminates, the kernel sends a
message of the indicated type to the current process. The data in the message
has the format:
  Offset  0 (word): process id of terminating process
  Offset  2 (byte): reason code (see ProcKill) or panic code
  Offset  3 (byte):
    0 = process terminated or was killed
    1 = process caused a panic
    2 = a subtask of the process caused a panic in the process
If the message slots do not have room for 4 bytes of data, not all this
information is available.


Fn $83 Sub $09
MessSignalCancel fails
Fn $83 Sub $0A
MessSignalCancelX fails
    BX: process to watch
    CX: message type (MessSignalCancelX only)
Cancels a call to MessSignal for the indicated process. MessSignalCancel
ignores the message type and should not be used if more than one MessSignal
call has been made for the process.


Fn $84 is used to control dynamic libraries and is not described here.


Fn $85 Sub $00
IoOpen fails
    AX: -> handle of opened device
   eBX: (cstr) name of device driver
    CX: mode
    DX: handle of device being attached to
Opens a channel to a device driver. If the driver is a base driver, then
DX is ignored (and this call is equivalent to the IOOPEN keyword). If it is
a stacked driver (see the Psionics file DEVICES), then the handle to be
stacked on must be specified. The meaning of the mode is determined by the
device. A driver can support several channels at once, and each has its own
handle. The driver must be a logical device driver.


Fn $85 Sub $01 and $02 involve physical device drivers and should only be
called from within logical device drivers.


Fn $85 Sub $03 to $05 should only be used by the operating system.


Fn $85 Sub $06
DevLoadLDD fails
Fn $85 Sub $07
DevLoadPDD fails
   eBX: (cstr) name of file holding the driver
Loads a device driver into the system. A driver cannot be opened until it is
loaded. The correct call for the driver type must be used.


Fn $85 Sub $08
DevDelete fails
   eBX: (cstr) name of the device driver
    DX: $DD01 for logical device drivers, or $DD21 for physical device drivers
Unloads a device driver from the system. Open drivers and those in the ROM
cannot be unloaded.


Fn $85 Sub $09
DevQueryUnits fails
    AX: -> number of channels supported
   eBX: (cstr) name of the device driver, without a trailing colon
Returns the number of simultaneous open channels supported by a driver (which
must be a logical one); $FFFF indicates no limit.


Fn $85 Sub $0A
DevFind fails
    AX: -> find code
    BX: last find code
    DX: $DD01 for logical device drivers, or $DD21 for physical device drivers
    SI: address of 14 byte buffer
   eDI: (cstr) pattern to search for
Finds all devices with names matching the search pattern (use ? and * as wild
cards). The first call should be made with the last find code set to 0, and
subsequent calls should set it to the code returned by the previous call. The
call fails when there are no more drivers to return. It is not necessary to
keep calling DevFind until this happens. The names do not have a trailing
colon.


Fn $85 Sub $0B should only be used by the operating system.


Fn $85 Sub $0C is used for special operations on device drivers.


Fn $86 Sub $00
IoAsynchronous fails async
Fn $86 Sub $01
IoAsynchronousNoError async
Fn $86 Sub $02
IoWithWait fails
    AL: service number
    AX: -> result from driver
    BX: handle of driver
    CX: address of first argument
    DX: address of second argument
    DI: address of the status word (ignored by IoWithWait)
These calls are equivalent to the IOA, IOC, and IOW keywords respectively
[For those without documentation of IOC, this is the same as IOA, except that
errors are handled by setting the status word and calling IOSIGNAL, so that
IOC always succeeds, unlike IOA.]


Fn $86 Sub $03 and $04 should only be used by device drivers.


Fn $86 Sub $05
IoWaitForSignal
This call is equivalent to the IOWAIT keyword.


Fn $86 Sub $06
IoWaitForStatus
    DI: address of the status word
This call is equivalent to the IOWAIT keyword.


Fn $86 Sub $07
IoYield
    DI: address of the status word
This call is equivalent to the IOYIELD keyword.


Fn $86 Sub $08
IoSignal
Sends an IOSIGNAL to the current process. This call is equivalent to the
IOSIGNAL keyword.


Fn $86 Sub $09
IoSignalByPid fails
Fn $86 Sub $0A
IoSignalByPidNoReSched fails
    BX: process ID
Sends an IOSIGNAL to a process. With the latter call a reschedule never takes
place because of the call (though one may take place due to the current
process using up its time slot).


Fn $86 Sub $0B to $0F should only be used by device drivers.


Fn $86 Sub $10
IoClose fails
    AX: -> result from driver
    BX: handle
This call is equivalent to the IOCLOSE keyword.


Fn $86 Sub $11
IoRead fails
Fn $86 Sub $12
IoWrite fails
    AX: -> amount actually read or result from driver
    BX: handle
    CX: address of buffer
    DX: number of bytes read or written
These calls are equivalent to the IOREAD and IOWRITE keywords.


Fn $86 Sub $13
IoSeek fails
    AX: -> result from driver
    BX: handle
    CX: mode
    DX: address of long holding seek position
This call is equivalent to the IOSEEK keyword.


Fn $86 Sub $14 should only be used by the window manager.


Fn $86 Sub $15 to $17 should only by used from assembler.


Fn $86 Sub $18
IoShiftStates
    AL: modifiers
This call makes available the state of the various modifier keys:
  Bit 1: shift
  Bit 2: control
  Bit 3: psion


Fn $86 Sub $19
IoWaitForSignalNoHandler
This call should be used instead of IOSEEK by tasks (subsidiary processes of
a process).


Fn $86 Sub $1A
IoSignalKillAsynchronous fails async
    BX: process to watch
    DI: address of the status word
This call completes, and the status word is set to 0,  when the specified
process terminates.


Fn $86 Sub $1B
IoSignalKillCancel fails
    BX: process to watch
Cancel any pending IoSignalKillAsynchronous.


Fn $86 Sub $1C and $1D should only be used by the window manager.


Fn $86 Sub $1E
IoPlaySoundW v3
    AL: -> failure code
    BX: (cstr) sound file name
    CX: duration to play (in 1/32 second)
    DX: volume: 0 (loudest) to 5 (softest)
Plays a sound file. A duration of 0 means the file header specifies the
duration; otherwise, the sound is clipped or padded with space as needed.
The name may be either an ordinary filename, or a string of the form "*ABCD",
meaning the first found of the files:
    ROM::ABCD.WVE
    LOC::M:\WVE\ABCD.WVE
    LOC::A:\WVE\ABCD.WVE
    LOC::B:\WVE\ABCD.WVE
Note that this call does not fail in the usual way, but just returns a failure
code.


Fn $86 Sub $1F
IoPlaySoundA v3 async
    BX: (cstr) sound file name
    CX: duration to play (in 1/32 second)
    DX: volume: 0 (loudest) to 5 (softest)
    DI: address of the status word
Plays a sound file asynchronously; the call completes when the sound has
finished. The other arguments are as for IoPlaySoundW.


Fn $86 Sub $20
IoPlaySoundCancel v3
Cancel any pending IoPlaySoundA.


Fn $86 Sub $21
IoRecordSoundW v3
    AL: -> failure code
    BX: (cstr) sound file name
    CX: number of samples to record, in units of 2048 samples
Records a sound file. Note that 2048 samples are slightly more than a quarter
of a second. The file will be created before recording, and must not be on
a flash device. Note that this call does not fail in the usual way, but just
returns a failure code.


Fn $86 Sub $22
IoRecordSoundA v3 async
    BX: (cstr) sound file name
    CX: number of samples to record, in units of 2048 samples
    DI: address of the status word
Records a sound file asynchronously; the call completes when the recording has
finished. The other arguments are as for IoRecordSoundW.


Fn $86 Sub $23
IoRecordSoundCancel v3
Cancel any pending IoRecordSoundA.


Fn $86 Sub $24
IoPlaySoundAO v3.9 async
    BX: (cstr) sound file name
    CX: duration to play (in 1/32 second)
    DX: volume: 0 (loudest) to 5 (softest)
    DI: address of the status word
    SI: duration to skip (in 1/32 second)
Plays part of a sound file asynchronously, skipping some initial portion of
the sound; the call completes when the sound has finished. The other
arguments are as for IoPlaySoundA.


Fn $87 Sub $00 is carried out automatically for OPL programs.


Fn $87 Sub $01
FilExecute fails vsync
   eBX: (cstr) program file name
    CX: (qstr) program information
    DX: address of the status word
    DI: address of word to be filled with process ID of new process
Starts a new process and places it in "suspended" state. The program file
name will have the extension ".IMG" added if one is not specified. The program
information is a qstr whose interpretation depends on the program; it is
available from location 36 of the new process's data segment (see Psionics file
PROCESS). The process name will be set to the name part of the file (excluding
any extension). If another process of this name is already running, both must
execute the same code, or the call will fail.

@@ More in S3/S3a manual chapters 1 and 2.
@@ Program information often consists of the following catenated
together (note that all these elements except the first are cstrs):
(1) the character 'C' (create new file) or 'O' (open existing file);
(2) (cstr) the application name, with the first character uppercased and the
    rest lowercased;
(3) (cstr) one of:
    (a) the normal extension for filenames, including the leading dot;
    (b) the normal extension with dot, followed by a space and aliasing
        information;
    (c) an empty string
(4) (cstr) the data file path passed as the initial argument;
(5) (cstr) the application path (may be omitted if not required).

A binary application may be used to operate on a standard file type. Examples
include:
    Program                  Application  Extension
                             [item 2]     [item 3]
    "ROM::DATA.APP"          "Data"       ".DBF"
    "ROM::WORD.APP"          "Word"       ".WRD"
    "ROM::WORD.APP"          "Program"    ".OPL"
    "LOC::C:\APP\COMMS.APP"  "Comms"      ".SCO"

In each of these cases there is no aliasing information or application path.
An example program information qstr is "OData~.DBF~LOC::M:\DBF\MYDATA.DBF~"
(tilde indicates a zero byte).

@This section needs rewriting@
The word processor may also be used as a program editor, by making item 2
its name ("Program") and item 3 an extension (usually ".OPL") followed by the
necessary aliasing information: this is empty for normal Word, or:
* "O" for OPL editor, "S" for SCR editor, "$" for plain text editor (3a only)
  "/" for custom template (3a only); any letter uses translator
  SYS$PRG<letter>.IMG to translate, then
* then "R" indicates that the translator can execute resulting code, anything
  else means it can't, then
* extension and directory ("OPO" or "SCO" for example) of translated files,
* then on 3a only optional "*" to indicate compatibility mode exists.
An example program information qstr is
"Program~.OPL OROPO~LOC::M:\OPL\MYPROG.OPL~"

template mode for Word means there must be a \WDR\<template>.WRT file on the
current drive; template name is that if the application name. For example,
alias file of:
    Letter.LET
    \LET\
    1083
    Word
    /
uses template LETTER. Note mode 80 in application type in alias file.

Finally, a translator may be used to execute a translated file: in the case
of the translator "ROM::SYS$PRGO", it can execute either OPO or OPA files.
The application name is given in the APP ... ENDA clause for OPA files, and
is "RunOpl" for OPO files; there is no extension or aliasing information.
For OPA files, the data file is passed to the application, and the application
path shows which application is actually run. For OPO files, the data file
should name the OPO file itself, and there is no application path. Examples
are "RunOpl~~M:\OPO\MYPROG.OPO~" and "MyApp~~M:\DAT\MYDATA~M:\APP\MYAPP.OPA~".


Fn $87 Sub $02
FilParse fails vsync
    BX: (cstr) file name to be parsed
    CX: (cstr) file specification to be used
    DX: address of the status word
    SI: address of a 6 byte buffer to be filled in
    DI: address of 128 byte buffer to be filled with the parsed filename
This call is equivalent to the PARSE$ keyword. The buffer is filled as follows:
  Offset  0 (byte): length of node name
  Offset  1 (byte): length of device name
  Offset  2 (byte): length of path name
  Offset  3 (byte): length of base name
  Offset  4 (byte): length of extension
  Offset  5 (byte): flags
    Bit 0: the base name or extension contains a wildcard ("*" or "?")
    Bit 1: the base name contains a wildcard
    Bit 2: the extension contains a wildcard


Fn $87 Sub $03
FilPathGet fails vsync
    BX: 128 byte buffer
    DX: address of the status word
The buffer is filled with the current filing system default path (a cstr).


Fn $87 Sub $04
FilPathSet fails vsync
    BX: (cstr) new path
    DX: address of the status word
Sets the default path (equivalent to the SETPATH keyword).


Fn $87 Sub $05
FilPathTest fails vsync
    BX: (cstr) pathname to be tested
    DX: address of the status word
Equivalent to the EXIST keyword; the call succeeds if the file with that
pathname exists.


Fn $87 Sub $06
FilDelete fails vsync
    BX: (cstr) pathname to be deleted
    DX: address of the status word
Equivalent to the DELETE keyword; non-empty directories cannot be deleted.


Fn $87 Sub $07
FilRename fails vsync
    BX: (cstr) old pathname
    CX: (cstr) new pathname
    DX: address of the status word
Equivalent to the RENAME keyword.


Fn $87 Sub $08
FilStatusGet fails async
    BX: (cstr) filename
    CX: 16 byte buffer
    DX: address of the status word
The buffer is filled in with information about the file:
  Offset  0 (word): buffer format version: always 2
  Offset  2 (word): attributes
  Offset  4 (long): file size in bytes
  Offset  8 (long): time last modified

The attribute bits have the following meanings (question marks indicate that
the bit name was specified but the meaning is unknown; equals signs mean that
the bit can be set by FilStatusSet):
  = Bit  0: file is not ReadOnly
  = Bit  1: file is Hidden
  = Bit  2: file is a System file
    Bit  3: file is a Volume name
    Bit  4: file is a Directory
  = Bit  5: file is Modified
  ? Bit  8: file is a readable file
  ? Bit  9: file is an executable file
  ? Bit 10: file is a byte stream file
    Bit 11: file is a text file
The LOC:: node (see Psionics file FILEIO) does not distinguish text and binary
files, and always leaves bit 11 clear. Other nodes may distinguish the types of
files and set the bit where appropriate.


Fn $87 Sub $09
FilStatusSet fails vsync
    BX: (cstr) filename
    CX: mask of attributes to be changed (only specify settable bits)
    DX: address of the status word
    DI: new values for attributes to be altered
The attributes indicated in the mask of the specified file are altered to
the new values; all other attributes are left unchanged.


Fn $87 Sub $0A AL sync
FilStatusDevice fails vsync
    BX: (cstr) device name (such as "A:" or "LOC::A:")
    CX: 64 byte buffer
    DX: address of the status word
The buffer is filled in with information about the device:
  Offset  0 (word): buffer format version
  Offset  2 (byte): device type
    0 = unknown
    1 = floppy
    2 = hard disc
    3 = flash
    4 = ram
    5 = rom
    6 = write-protected
  Offset  3 (byte): device properties:
    Bit 3: formattable device
    Bit 4: dual density device
    Bit 5: internal device
    Bit 6: dynamically sizeable device
    Bit 7: compressible (worth compressing database files)
  Offset  4 (word): non-zero if the device contains removable media
  Offset  6 (long): total space on the device in bytes
  Offset 10 (long): free space on the device in bytes
  Offset 14 (cstr): volume name
  Offset 46 (word): device battery status
    0  = low battery
    1  = battery OK
    -4 = status not available for this device type
    This field is not valid if the format version (offset 0) is less than 3.


Fn $87 Sub $0B
FilStatusSystem fails vsync
    BX: (cstr) node name (such as "LOC::" or "REM::")
    CX: 32 byte buffer
    DX: address of the status word
The buffer is filled in with information about the node:
  Offset  0 (word): buffer format version (currently 2)
  Offset  2 (word): 0 = flat, 1 = hierarchical
  Offset  4 (word): non-zero if devices are formattable, and zero otherwise


Fn $87 Sub $0C
FilMakeDirectory fails vsync
    BX: (cstr) pathname
    DX: address of the status word
This is equivalent to the MKDIR keyword.


Fn $87 Sub $0D AL sync
FilOpenUnique fails vsync
   eBX: (cstr) pathname
    CX: open mode (format and access parts only)
    DX: address of the status word
Open a file with a unique name. This is equivalent to the IOOPEN keyword with
a mode of 4. The pathname is used to determine the directory to create
the file in, and will be modified to give the actual name (thus the pathname
should have room for 128 characters).


Fn $87 Sub $0E
FilSystemAttach fails vsync
    BX: (cstr) name of a file system PDD
    DX: address of the status word
The specified physical device driver will be attached to the filing system,
possible adding new nodes.


Fn $87 Sub $0F
FilSystemDetach fails vsync
    BX: (cstr) name of a filing system
    DX: address of the status word
Detaches a filing system. Built-in filing systems cannot be detached.


Fn $87 Sub $10
FilPathGetById fails vsync
    BX: process to examine
    CX: 128 byte buffer
    DX: address of the status word
The buffer is set to the current path of the specified process (a cstr).


Fn $87 Sub $11
FilChangeDirectory fails vsync
    BX: (cstr) pathname
    CX: 128 byte buffer
    DX: address of the status word
    SI: (cstr) name of subdirectory
    DI: 0 = get root directory, 1 = get parent directory, 2 = get subdirectory
The path name is modified in the requested way. This call should be used
instead of manipulating the directory part of a name directly, as it works on
all nodes, irrespective of the format that the node uses for path names.


Fn $87 Sub $12 has no effect on OPL processes.


Fn $87 Sub $13
FilSetFileDate fails vsync
    BX: (cstr) pathname
    CX: low word of new time
    DX: address of the status word
    DI: high word of new time
Sets the modification time of the specified file.


Fn $87 Sub $14
FilLocChanged fails vsync
    AX: -> channel change flags
    BX: channel to check
    DX: address of the status word
Specifies whether any directory in the LOC:: node has changed (i.e. a file
or directory has been created, destroyed, or renamed, but not changes to file
contents) since the last use of this system call with this channel. BX should
have exactly one bit set, corresponding to the channel to use; bits 8 to 15
are reserved by Psion. The corresponding bit in AX will be set if the node
has changed, and will be clear otherwise; the other 15 bits are unspecified.
This call can be used to determine whether to update a directory display.


Fn $87 Sub $15
FilLocDevice v3 fails vsync
    BX: local device indicator (%A to %H, or %I or %M)
    CX: address of word set to the media type
    DX: address of the status word
Provides the media type of a device on the LOC:: node (I and M both refer to
the internal ramdisc). The device type consists of:
  Bits 0 to 3:
    0 = unknown
    1 = floppy
    2 = hard disc
    3 = flash
    4 = ram
    5 = rom
    6 = write-protected
  Bits 7 to 8:
    0 = device battery measurement not supported
    1 = device battery measurement not supported
    2 = device battery voltage low
    3 = device battery voltage good


Fn $87 Sub $16
FilLocReadPDD v3 fails vsync
    BX: local device indicator (%A to %H, or %I or %M)
    CX: (long) location on the device
    DX: address of the status word
    SI: number of bytes to read
    DI: address in process to copy first byte to
Copies data from a device on the LOC:: node to the current process. This
call is very efficient, and accesses the raw device.



Further system calls are described in Psionics file SYSCALLS.2.
The Psionics Files

SYSCALLS.2

PSIONICS FILE - SYSCALLS.2
==========================
System calls (part 2)
Last modified 1998-11-07
========================

See part 1 for general notes and explanations.


Fn $88 Sub $00
ProcId
    AX: -> process ID of the current process
Gets the process ID of the current process.


Fn $88 Sub $01
ProcIdByName fails
    AX: -> process ID
   eBX: (cstr) pattern
Gets the process ID of a process whose name matches the pattern (usual
wildcards apply, and case is ignored).


Fn $88 Sub $02
ProcGetPriority fails
    AL: -> priority
    BX: process ID
Gets the priority of the specified process.


Fn $88 Sub $03
ProcSetPriority fails
    AL: new priority
    BX: process ID
Sets the priority of the specified process.


Fn $88 Sub $04 should only be called by the operating system.


Fn $88 Sub $05
ProcCreateTask
Tasks are processes which share the data segment of another process. They
cannot be conveniently handled in OPL.


Fn $88 Sub $06
ProcResume fails
    BX: process ID
Take a process out of the suspended state and start it executing.


Fn $88 Sub $07
ProcSuspend fails
    BX: process ID
Place a process in the suspended state. If the process is waiting for a system
service (e.g. a semaphore), then it will be suspended when the service has
been carried out.


Fn $88 Sub $08
ProcKill fails
    AL: reason code
    BX: process ID
Kills the specified process, without allowing it to execute any cleanup code.
Only use this on the current process or in emergencies.


Fn $88 Sub $09
ProcPanicById fails
    AL: panic code
    BX: process ID
Simulate the specified panic on the specified process.


Fn $88 Sub $0A
ProcNameById fails
    BX: process ID
   eDI: 13 byte buffer
Places the name (a cstr) of the specified process in the buffer.


Fn $88 Sub $0B
ProcFind fails
    AX: -> process ID
    BX: 0 or process ID
    SI: 14 byte buffer
   eDI: (cstr) pattern
Obtains process IDs for processes whose name matches the pattern ("?" and "*"
wildcards have their Unix meaning, and case is ignored). BX should be zero to
return the first matching process, or the process ID returned by a previous
call to return subsequent matching processes. Process are returned in *task*
ID order. The buffer is filled with a cstr giving the process name.


Fn $88 Sub $0C
ProcRename fails
    BX: process ID
   eDI: (cstr) new name
Rename the specified process; the new name must be between 1 and 8 characters.


Fn $88 Sub $0D
ProcTerminate fails
    BX: process ID
Terminates the indicated process. The process will be sent a termination
message if it has so requested, and will be killed otherwise.


Fn $88 Sub $0E
ProcOnTerminate
    BX: message type
When the current process is terminated, it will be sent a message of the
specified type; type 0 cancels the request. After receiving the message and
executing any clean-up code, the process should use ProcKill to kill itself.


Fn $88 Sub $0F is reserved for the Shell process.


Fn $88 Sub $10
ProcGetOwner fails
    AX: -> owning process ID
    BX: process ID
Gets the ID of the process owning the specified process (normally the
creator of that process).


Fn $89 Sub $00
TimSleepForTenths fails
    CX: high half of delay
    DX: low half of delay
Sleep for the specified delay (in units of 0.1 seconds). Changing the system
clock does not affect the call. Only time when the machine is switched on is
measured; any time when the machine is switched off will be in addition to
the requested delay.


Fn $89 Sub $01
TimSleepForTicks fails
    CX: high half of delay
    DX: low half of delay
Sleep for the specified delay (in system ticks; there are 32 ticks per second
on the Series 3 and 18.2 on the PC emulation). Changing the system clock does
not affect the call. Only time when the machine is switched on is measured;
any time when the machine is switched off will be in addition to the requested
delay.


Fn $89 Sub $02
TimGetSystemTime
    AX: -> high half of system clock
    BX: -> low half of system clock
Reads the system clock (an abstime).


Fn $89 Sub $03
TimSetSystemTime
    CX: high half of new system clock
    DX: low half of new system clock
Sets the system clock to the given abstime.


Fn $89 Sub $04
TimSystemTimeToDaySeconds
    CX: high half of abstime
    DX: low half of abstime
    DI: 8 byte buffer
Splits an abstime into a day number and an interval, placed in the buffer as
follows:
  Offset  0 (long): day number
  Offset  4 (long): interval


Fn $89 Sub $05
TimDaySecondsToSystemTime fails
    AX: -> high half of abstime
    BX: -> low half of abstime
    SI: 8 byte buffer
Converts a day number and an interval to an abstime. The former are in the
buffer, in the same format as TimSystemTimeToDaySeconds.


Fn $89 Sub $06
TimDaySecondsToDate fails
    SI: 8 byte buffer (day number and interval)
    DI: 8 byte buffer (broken down time)
Converts a day number and an interval to broken-down time information. The
former is in the same format as TimSystemTimeToDaySeconds. The latter is in
the format:
  Offset  0 (byte): year - 1900
  Offset  1 (byte): month (0 = January, 11 = December)
  Offset  2 (byte): day - 1
  Offset  3 (byte): hours
  Offset  4 (byte): minutes
  Offset  5 (byte): seconds
  Offset  6 (word): day number in year (0 to 364 or to 365)


Fn $89 Sub $07
TimDateToDaySeconds fails
    SI: 8 byte buffer (broken down time)
    DI: 8 byte buffer (day number and interval)
Converts broken-down time to a day number and an interval. The day number in
year (offset 6) is ignored.


Fn $89 Sub $08
TimDaysInMonth fails
    AX: -> number of days in month
    CX: month * 256 + year - 1900
Gets the number of days in the specified month (0 = January, 11 = December).


Fn $89 Sub $09
TimDayOfWeek
    AX: -> day of week (0 = Monday, 6 = Sunday)
    CX: high half of day number
    DX: low half of day number
Gets the day of the week of the given date.


Fn $89 Sub $0A
TimNameOfDay fails
    AL: day of week (0 = Monday, 6 = Sunday)
    BX: 33 byte buffer
The buffer is filled with a cstr giving the name of that day of the week.


Fn $89 Sub $0B
TimNameOfMonth fails
    AL: month (0 = January, 11 = December)
    BX: 33 byte buffer
The buffer is filled with a cstr giving the name of that month.


Fn $89 Sub $0C
TimWaitAbsolute fails
    CX: high half of abstime
    DX: low half of abstime
Sleep this process until the specified abstime. If the machine is turned off
at that time, it will turn back on. Changing the system clock will affect
when the call returns.


Fn $89 Sub $0D
TimWeekNumber fails
    AX: -> week number (1 to 53)
    CX: high half of day number
    DX: low half of day number
Gets the week number of the specified day.


Fn $89 Sub $0E
TimNameOfDayAbb v3 fails
    AL: day of week (0 = Monday, 6 = Sunday)
    BX: 4 byte buffer
The buffer is filled with a cstr giving the abbreviated name of that day of
the week. The length of the abbreviated name varies between languages, but
is the same for all days in a given language.


Fn $89 Sub $0F
TimNameOfMonthAbb v3 fails
    AL: month (0 = January, 11 = December)
    BX: 4 byte buffer
The buffer is filled with a cstr giving the abbreviated name of that month.
The length of the abbreviated name varies between languages, but is the same
for all months in a given language.


Fn $8A Sub $00
ConvUnsignedIntToBuffer
    AX: -> length of converted value
    BX: value to be converted
    CX: radix
   eDI: buffer to hold converted value
The value is converted to a string in the specified radix and written to the
buffer. No trailing zero byte is written; instead, the length of the string
is returned. The radix can be any value from 2 to 200. If the radix is 11 or
greater, digits greater than 9 are written as "A", "B", etc; characters other
than digits and uppercase letters are used when the radix is 37 or more.


Fn $8A Sub $01
ConvUnsignedLongIntToBuffer
    AX: -> length of converted value
    BX: low half of value to be converted
    CX: radix
    DX: high half of value to be converted
   eDI: buffer to hold converted value
The value is converted to a string, in the same way as ConvUnsignedIntToBuffer.


Fn $8A Sub $02
ConvIntToBuffer
    AX: -> length of converted value
    BX: value to be converted
   eDI: buffer to hold converted value
The value is converted to a string in radix 10 and written to the buffer. If
the value is negative, a leading "-" will be included. No trailing zero byte
is written; instead, the length of the string is returned.


Fn $8A Sub $03
ConvLongIntToBuffer
    AX: -> length of converted value
    BX: low half of value to be converted
    DX: high half of value to be converted
   eDI: buffer to hold converted value
The value is converted to a string in radix 10, as for ConvIntToBuffer.


Fn $8A Sub $04
ConvArgumentsToBuffer
    AX: -> length of converted format
    BX: buffer holding the format arguments
    SI: (cstr) format
   eDI: buffer to hold converted format
The format is written to the buffer, with certain sequences of characters -
"conversion specifiers" - being replaced by the values of arguments converted
to strings. No trailing zero byte is written; instead, the length of the string
is returned.

All conversion specifiers begin with a percent sign (to include a literal
percent in the output, use "%%"), followed by:
- an optional alignment code
- an optional width code (required if there is an alignment code)
- an optional length code
- a conversion code.

The alignment code consists of two characters. The first is:
- "-": left align (fill on the right)
- "=": centre align (fill at both ends)
- "+": right align (fill on the left).
The second is either the character to fill with, or "*". In the latter case,
the next word is taken from the arguments and used as the fill character.
The default alignment is to right align filling with spaces ("+ "). Also, the
alignment "+0" may be abbreviated to "0".

The width code gives the number of characters generated by the conversion. If
the output would be longer, it is truncated. The code is either an unsigned
decimal number (not beginning with a zero), or "*". In the latter case, the
next word is taken from the arguments and gives the (unsigned) width.

The length code can be "l" or "L" (equivalent); it is equivalent to making the
conversion code uppercase.

Each conversion code (apart from "f") takes an argument of the type stated,
and then converts it as described.

  Code  Type  Conversion

  "b"   word  convert to unsigned binary representation
  "B"   long  convert to unsigned binary representation
  "c"   word  output the character with that code
  "C"   long  output the character with that code
  "d"   word  convert to signed decimal representation
  "D"   long  convert to signed decimal representation
  "f"   ----  output an empty string filled with the fill character.
  "F"   ----  output an empty string filled with the fill character.
  "o"   word  convert to unsigned octal representation
  "O"   long  convert to unsigned octal representation
  "m"   word  output the value as 2 bytes, least significant first
  "M"   long  output the value as 4 bytes, least significant first
  "s"   cstr  output the cstr
  "S"   cstr  output the cstr
  "u"   word  convert to unsigned decimal representation
  "U"   long  convert to unsigned decimal representation
  "w"   word  output the value as 2 bytes, most significant first
  "W"   long  output the value as 4 bytes, most significant first
  "x"   word  convert to unsigned hexadecimal representation
  "X"   long  convert to unsigned hexadecimal representation
Codes "m", "M", "w", and "W" are available in EPOC v2.17 and later only.


Fn $8A Sub $05
ConvStringToUnsignedInt fails
    AX: -> converted value
    CX: radix
    SI: (cstr) string to convert -> pointer to first unused character
The string is converted to an unsigned integer in the specified radix. The
conversion ends at the first character which is not a valid digit for the
radix, which may be the terminating zero byte; if the first character of the
string is not valid, the call fails. The letters A to F, in either case, are
used for digits 10 to 15 if the radix is 11 or more. The radix may be greater
than 16, but the valid digits remain restricted to the range 0 to 15.


Fn $8A Sub $06
ConvStringToUnsignedLongInt fails
    AX: -> high half of converted value
    BX: -> low half of converted value
    CX: radix
    SI: (cstr) string to convert -> pointer to first unused character
The string is converted, in the same manner as ConvStringToUnsignedInt.


Fn $8A Sub $07
ConvStringToInt fails
    AX: -> converted value
    SI: (cstr) string to convert -> pointer to first unused character
The string is converted to an signed integer in radix 10. The conversion ends
at the first character which is not a valid digit or leading sign; this may
be the terminating zero byte. If the first character of the string is not a
digit or sign, the call fails.


Fn $8A Sub $08
ConvStringToLongInt
    AX: -> high half of converted value
    BX: -> low half of converted value
    SI: (cstr) string to convert -> pointer to first unused character
The string is converted, in the same manner as ConvStringToInt.


Fn $8A Sub $09
ConvFloatToBuffer fails
    AX: -> length of converted value
    DX: pointer to 6 byte conversion information block
    SI: address of real value to be converted
    DI: buffer to hold converted value
The real value is converted to a cstr and placed in the buffer. The exact
format of the string depends on the contents of the conversion information
block:
  Offset  0 (byte): 0 = fixed format, 1 = exponent format, 2 = variable format
  Offset  1 (byte): maximum length of converted value
  Offset  2 (byte): number of decimal digits (fixed and exponent formats only)
  Offset  3 (byte): radix character
  Offset  4 (byte): triad character (fixed format only)
  Offset  5 (byte): triad threshold (fixed format only)
If the converted value would be greater than the maximum length, or the real
to be converted has an exponent less than -99 or greater than 99, the call
fails and the contents of the buffer are undefined (note that the length
of the buffer need only be the maximum specified plus an extra byte for the
terminating zero).

For fixed format, the resulting string will take the form:
  * minus sign if the value is negative; nothing if it is positive
  * the integer part of the number, with no leading zeros (one zero if the
    integer part is zero); if the triad threshold is non-zero and there are
    more than that number of digits in the integer part, then the triad
    character is inserted between groups of 3 digits
  * if the number of decimal digits is non-zero:
    - the radix character
    - the specified number of digits
For example, the number 1234321.4731 is converted as follows (assuming that
the radix character is "." and the triad character is ","):
    0 decimal digits, triad threshold 0: "1234321"
    0 decimal digits, triad threshold 5: "1,234,321"
    0 decimal digits, triad threshold 7: "1234321"
    2 decimal digits, triad threshold 5: "1,234,321.47"
    6 decimal digits, triad threshold 1: "1,234,321.473100"

For floating format, the resulting string will take the form:
  * minus sign if the value is negative; nothing if it is positive
  * one non-zero digit
  * if the number of decimal digits is non-zero:
    - the radix character
    - the specified number of digits
  * the letter "E"
  * a plus or minus sign
  * two digits (using leading zeros if necessary)
For example, the number 1234321.4731 is converted as follows:
    0 decimal digits: "1E+06"
    2 decimal digits: "1.23E+06"
    7 decimal digits: "1.234321E+06"
   12 decimal digits: "1.234321473100E+06"
Zero (with either sign) is always converted as "0E+00" or "0.000E+00" etc.

For general format the resulting string will take a form depending on its
value. If the maximum width is W and the real value is R, then:
               R <= -1E+(W-1)  as for exponent format with W-7 decimal digits
  -1E+(W-1) <  R <= -1E+(W-2)  a string containing a minus sign and W-1 digits
  -1E+(W-2) <  E <= -1E+(W-1)  a string containing a minus sign and W-2 digits
  -1E+(W-3) <  R <= -1E-4      a string containing a minus sign and then W-2
                               significant digits with the radix character in
                               the appropriate position
  -1E-4     <  R <  0          as for exponent format with W-7 decimal digits
  0         =  R               the string "0"
  0         <  R < 1E-4        as for exponent format with W-6 decimal digits
  1E-4      <= R < 1E+(W-2)    a string containing W-1 significant digits with
                               the radix character in the appropriate position
  1E+(W-2)  <= E < 1E+(W-1)    a string containing W-1 digits
  1E+(W-1)  <= E < 1E+(W)      a string containing W digits
  1E+(W)    <= R               as for exponent format with W-7 decimal digits


Fn $8A Sub $0A
ConvStringToFloat fails
    DX: radix character
    SI: address of a word pointing to the start of the cstr to convert
    DI: address of real variable to be set
Converts a string representing a floating-point value and places it in the
variable. The string must have the form:
  * an optional sign
  * a mantissa containing at least one digit and an optional radix character
  * an optional exponent consisting of:
    - the letter "E" or "e"
    - an optional sign
    - an integer
The resulting value must have an exponent in the range -99 to 99 inclusive.
If it is outside this range, the call fails; for underflow the value 0 is
stored, while for overflow an undefined value is stored.

If the call succeeds, the pointer to the string is altered to point to the
first character beyond the converted number.


Fn $8B Sub $00
GenVersion
    AX: -> kernel version
Gets the version of the operating system. Version 1.23 is reported as:
    $123A for alpha release
    $123B for beta release
    $123F for final release


Fn $8B Sub $01
GenLcdType
    AL: -> display type
Gets the display type:
     0 = 640x400 LCD (MC)
     1 = 640x200 LCD small version (MC)
     2 = 640x200 LCD large version or CGA (PC emulation)
     3 = 720x348 LCD or Hercules graphics
     4 = 160x80  LCD (HC)
     5 = 240x80  LCD (Series 3t)
     6 = MDA (PC emulation)
     7 = EGA monochrome (PC emulation)
     8 = EGA colour     (PC emulation)
     9 = VGA monochrome (PC emulation)
    10 = VGA colour     (PC emulation)
    11 = 480x160 LCD (Series 3a and Series 3c)
    12 = 240x100 LCD (Workabout)
    14 = 240x160 LCD (Siena)
   255 = unknown


Fn $8B Sub $02
GenStartReason
    AL: -> reason code
Gets the reason for the last cold start:
    0 = system RAM invalid
    1 = forced power down
    2 = user reset (using reset button)
    3 = kernel fault
    4 = new operating system installed
The environment variables and the internal disc are valid after reasons 1 and
3, and are valid after reason 2 unless ESC was also pressed.

Reason 1 only happens if a faulty device driver delayed a normal battery-low
powerdown for too long.


Fn $8B Sub $03
GenParse fails
    BX: 18 byte buffer
Parse filenames according to certain basic rules. Unlike FilParse, this does
not invoke any device drivers. The buffer has the format:
  Offset  0 (word): address of file name 1 (a cstr)
  Offset  2 (word): address of file name 2 (a cstr)
  Offset  4 (word): address of file name 3 (a cstr)
  Offset  6 (word): address of buffer to be filled with final name (a cstr)
  Offset  8 (word): address of 6 byte buffer
  Offset 10 (byte): device separator
  Offset 11 (byte): path separator
  Offset 12 (byte): extension separator
  Offset 13 (byte): maximum length of device including separators
  Offset 14 (byte): maximum length of path including separators
  Offset 15 (byte): maximum length of name
  Offset 16 (byte): maximum length of extension including separator
The three filenames are split into 5 components, any of which may be missing.
  * node (ends with "::")
  * device (ends with device separator)
  * path (ends with last path separator)
  * name
  * extension (starts with extension separator)
The final name is constructed by taking, for each component, the value from
file name 1 if present, otherwise the value from file name 2 if present,
and otherwise the value from file name 3. The 6 byte buffer is then filled in
with the same data as for FilParse. File names 2 and 3 should be in different
places in memory.


Fn $8B Sub $04
LongUnsignedIntRandom
    AX: -> high half of random number
    BX: address of seed -> low half of random number
Generates a 32 bit unsigned random number from a seed; the number also replaces
the seed, so that the sequential calls with the same seed address will generate
a random sequence based on the initial seed.


Fn $8B Sub $05
GenGetCountryData
    BX: 40 byte buffer
Fills the buffer with country-specific data:
  Offset  0 (word): country code (e.g. UK is 44) of locale
  Offset  2 (word): current offset from GMT in minutes (+ is ahead)
  Offset  4 (byte): date format (0 = MDY, 1 = DMY, 2 = YMD)
  Offset  5 (byte): time format (0 = am-pm, 1 = 24 hour)
  Offset  6 (byte): currency symbol position (0 = before, 1 = after)
  Offset  7 (byte): currency symbol separated with space (0 = yes, 1 = no)
  Offset  8 (byte): currency decimal places
  Offset  9 (byte): currency negative format (0 = minus, 1 = brackets)
  Offset 10 (byte): currency triad threshold
  Offset 11 (byte): triad separator
  Offset 12 (byte): decimal separator
  Offset 13 (byte): date separator
  Offset 14 (byte): time separator
  Offset 15 to  23: currency symbol (cstr)
  Offset 24 (byte): start of week (0 = Mon, 1 = Tue, ... 6 = Sun)
  Offset 25 (byte): currently active summer times:
    Bit 0:       home
    Bit 1:       European
    Bit 2:       Northern
    Bit 3:       Southern
    Bits 4 to 7: unused, always zero
  Offset 26 (byte): clock type (0 = analogue, 1 = digital)
  Offset 27 (byte): number of letters in day abbreviation (0 to 6)
  Offset 28 (byte): number of letters in month abbreviation (0 to 255)
  Offset 29 (byte): workdays (the set bits indicate the workdays)
    Bit 0: Monday
    Bit 1: Tuesday
    Bit 2: Wednesday
    Bit 3: Thursday
    Bit 4: Friday
    Bit 5: Saturday
    Bit 6: Sunday
    Bit 7: always zero
  Offset 30 (byte): units (0 = inches, 1 = centimetres)

If the triad threshold is non-zero and there are more than that number of
digits in the integer part of an amount of money, then the triad character
should be inserted between groups of 3 digits. See ConvFloatToBuffer for a
way to do this.


Fn $8B Sub $06
GenGetErrorText
    AL: error number
    BX: 64 byte buffer
The buffer will be filled with a cstr giving an error message corresponding to
the error number (a generic message including the number is used when there is
no stored message in the current locale).


Fn $8B Sub $07
GenGetOsData
    CX: number of bytes to fetch
    SI: offset of first byte in kernel workspace
    DI: buffer to be filled in
Copy a number of bytes from the kernel workspace to the current process.
Within assembler code, this can also be done via GenDataSegment (see Psionics
file KERNEL).


Fn $8B Sub $08 only applies to MC systems.


Fn $8B Sub $09
GenNotify fails
    AL: -> option chosen (0 = first, 1 = second, 2 = third)
    BX: first message  (cstr, up to 63 characters plus the terminating zero)
    CX: second message (cstr, up to 63 characters plus the terminating zero)
    DX: first option   (cstr, up to 15 characters plus the terminating zero)
    SI: second option  (cstr, up to 15 characters plus the terminating zero)
    DI: third option   (cstr, up to 15 characters plus the terminating zero)
Sends a message to the notifier process and waits for a reply. The call fails
if there is no notifier process running. The two messages are displayed, and
the user is offered the three options. The chosen option is returned.

Any of the arguments except BX may be zero instead; for CX this means that
only one message is displayed, while for DX, SI, and DI it means that less
options are offered (if all are zero, the option "CONTINUE" is offered).


Fn $8B Sub $0A
GenNotifyError fails
    AL: error number -> option chosen (0 = first, 1 = second, 2 = third)
    BX: first message
    DX: first option
    SI: second option
    DI: third option
This call is equivalent to GenNotify with the second message derived from the
error number via GenGetErrorText.


Fn $8B Sub $0B and $0C are used by the notifier process.


Fn $8B Sub $0D
GenGetRamSizeInParas
    AX: -> system RAM size
Gets the amount of system RAM fitted, in units of 16 bytes. Note that this
is an unsigned value - $8000 represents 512 kb, not some negative amount.


Fn $8B Sub $0E
GenGetCommandLine
    AX: -> zero or command line
Gets a pointer to the command line if the program was started with program
information (see FilExecute). If so, the command line consists of a cstr giving
the program executed, immediately followed by the program information (a qstr).


Fn $8B Sub $0F
GenGetSoundFlags
    AX: -> sound flags
Gets the sound flags:
    Bit  0: keyboard clicks enabled
    Bit  1: sound via piezo buzzer enabled
    Bit  2: sound via SND: device driver enabled
    Bit  3: keyboard clicks: set=loud, clear=soft
    Bit  4: piezo buzzer: set=loud, clear=soft
    Bit 15: set=disable all sound, clear=obey individual flags


Fn $8B Sub $10
GenSetSoundFlags
    BX: sound flags
Sets the sound flags to new values (see GenGetSoundFlags).


Fn $8B Sub $11
GenSound
    BX: duration in ticks
    CX: pitch code (frequency=512kHz/code)
Makes a simple single-frequency note. Access to this call is sequenced; it
will wait until the piezo buzzer is not in use, and will return when the sound
has started to play. On the Series 3a, the piezo buzzer is emulated by the
SND: device, but the emulation is complete (for example, this call works
even when SND: is disabled by GenSetSoundFlags).


Fn $8B Sub $12
GenMarkActive
Fn $8B Sub $13
GenMarkNonActive

These two calls alter the state of the current process to "active" (the default
when the process starts) or "non-active". Whenever an active process restarts
execution after being idle (basically when keywords such as IOWAIT, IOW, GET
and so on return), the auto-off timer is reset; the machine switches off when
the timer reaches the appropriate value.


Fn $8B Sub $14
GenGetText fails
    AL: message number
   eBX: 64 byte buffer
Copies a message (a cstr) from the kernel message table to the buffer.


Fn $8B Sub $15
GenGetNotifyState
    AL: -> notify state (0=unattended, 1=notify)
Gets the notify state for the process. If this is "unattended", then the file
server will not call the notifier process when a correctable error occurs (such
as an SSD with open file being removed), but will simply return an error. If
it is "notify" (the initial state), then it will use GenNotify to request the
user to fix the problem.


Fn $8B Sub $16
GenSetNotifyState
    AL: notify state
Sets the notify state for the process. See GenGetNotifyState for details.


Fn $8B Sub $17
GenGetAutoSwitchOffValue
    AX: -> auto-off time in seconds, or $FFFF if disabled
Gets the auto-off time.


Fn $8B Sub $18
GenSetAutoSwitchOffValue
    BX: auto-off time in seconds, or $FFFF to disable
Sets the auto-off time. Times of less than 15 are adjusted to 15.


Fn $8B Sub $19 and $1A are for device drivers only.


Fn $8B Sub $1B
GenGetLanguageCode
    AX: -> current locale code
Gets the current locale code. Locale codes are listed in the Psionics file
LOCALES.


Fn $8B Sub $1C
GenGetSuffixes
   eBX: 93 byte buffer
The buffer is filled with 31 cstrs giving the correct suffix for each of the
31 days of the month. The suffix for day N is at offset (3*N-3).


Fn $8B Sub $1D
GenGetAmPmText
    AL: 0=AM, 1=PM
   eBX: 3 byte buffer
The buffer is filled with a cstr giving the correct suffix for "a.m." or
"p.m." times.


Fn $8B Sub $1E
GenSetCountryData
   eBX: 40 byte buffer
Sets the country-specific data to that in the buffer. See GenGetCountryData
for the format of the buffer.


Fn $8B Sub $1F
GenGetBatteryType
    AL: -> battery type
Gets the battery type from the following list:
    0 = Unknown
    1 = Alkaline
    2 = NiCaD (600 mAh)
    3 = NiCaD (1000 mAh)
    4 = NiCaD (500 mAh)
The battery type is used to control the warning thresholds.


Fn $8B Sub $20
GenSetBatteryType
    AL: battery type
Sets the battery type (see GenGetBatteryType).


Fn $8B Sub $21
GenEnvBufferGet fails
    AX: -> size of value
    DX: length of pattern
   eSI: buffer filled with value
   eDI: pattern to search for
Searches for an environment variable whose name matches the pattern (if there
is more than one, which one is chosen is unspecified). The buffer is filled
with the variable's value.


Fn $8B Sub $22
GenEnvBufferSet fails
    CX: size of value (0 to 255)
    DX: length of name (1 to 16)
   eSI: buffer holding value
   eDI: name of variable
Changes the value of the specified enviromment variable, creating it first if
necessary. The name may not contain wildcards.


Fn $8B Sub $23
GenEnvBufferDelete fails
    DX: length of name
   eDI: pattern to delete
Searches for an environment variable whose name matches the pattern and deletes
it (if there is more than one, which one is deleted is unspecified).


Fn $8B Sub $24
GenEnvBufferFind fails
    AX: -> new handle
    BX: previous handle (0 for first call)
    DX: length of pattern
   eSI: 273 byte buffer
   eDI: pattern to search for
Searches for each environment variable whose name matches the pattern. The
call is made multiple times until it fails; the same pattern must be used
each time. If the call succeeds, the buffer is filled with two qstrs, the
first being the name and the second the value of the variable found.


Fn $8B Sub $25
GenEnvStringGet fails
   eSI: 256 byte buffer
   eDI: pattern (cstr)
Searches for an environment variable whose name matches the pattern (if there
is more than one, which one is chosen is unspecified). The buffer is filled
with the variable's value followed by a zero byte (thus a cstr).


Fn $8B Sub $26
GenEnvStringSet fails
   eSI: value (cstr)
   eDI: name (cstr)
Changes the value of the specified enviromment variable, creating it first if
necessary. The name may not contain wildcards and is limited to 16 characters;
the value is limited to 255 characters.


Fn $8B Sub $27
GenEnvStringDelete fails
   eDI: pattern (cstr)
Searches for an environment variable whose name matches the pattern and deletes
it (if there is more than one, which one is deleted is unspecified).


Fn $8B Sub $28
GenEnvStringFind fails
    AX: -> new handle
    BX: previous handle (0 for first call)
   eCX: 256 byte buffer
   eSI: 17 byte buffer
   eDI: pattern to search for
Searches for each environment variable whose name matches the pattern. The
call is made multiple times until it fails; the same pattern must be used
each time. If the call succeeds, the 17 byte buffer is filled with the name
of the variable, as a cstr, and the 256 byte buffer is filled with the value
followed by a zero byte (thus also a cstr).


Fn $8B Sub $29
GenCrc
    AX: -> CRC
    CX: buffer length
    DX: previous CRC
    SI: buffer
Calculates the CCITT Cyclic Redundancy Checksum using the X^16+X^12+X^5+1
polynomial (e.g. the CRC of a single byte with value 1 is $1021). If the
buffer is to be checked standalone, use zero as the previous checksum. If
several blocks are to be checksummed as if they were one long block, use 0
as the previous CRC for the first block, and the previous result for the
remainder.


Fn $8B Sub $2A
GenRomVersion
    AX: -> rom version number
Gets the version of the system ROM (which includes both the operating system
and many files). Version 1.23 is reported as:
    $123A for alpha release
    $123B for beta release
    $123F for final release


Fn $8B Sub $2B and $2C are used by the alarm server process.


Fn $8B Sub $2D
GenAlarmId
    AX: -> alarm server pid
Gets the process ID of the alarm server process, or 0 if none is running.


Fn $8B Sub $2E
GenPasswordSet fails
   uSI: (qstr) current password
   uDI: (qstr) new password
Sets a new system password. The call will fail and take no action if the
current password is incorrect.


Fn $8B Sub $2F
GenPasswordTest fails
   uSI: (qstr) password to test
Succeeds if the system password is that provided.


Fn $8B Sub $30
GenPasswordControl fails
    AL: new state (0 = off, 1 = on)
   uSI: (qstr) current password
Turns the system password on and off. The call will fail and take no action
if the current password is not provided.


Fn $8B Sub $31
GenPasswordQuery
    AX: -> new state (0 = off, 1 = on)
Get the status of the system password.


Fn $8B Sub $32
GenTickle

Resets the auto-off timer. A non-active process (see GenMarkNonActive) can
use this to prevent auto-off.


Fn $8B Sub $33
GenSetConfig
@No documentation available at present@


Fn $8B Sub $34
GenMaskInit fails
    SI: (qstr) password
    DI: 18 byte encryption control block
Initializes an encryption control block according to the password given.

The contents of the control block for the current algorithm are:
  Offset  0 to   8: encryption key, generated from the password
  Offset  9 to  15: copy of offset 0 to 7
  Offset 16 (word): current location within the key (initially zero)
@The algorithm for generating the key from the password is unknown.

It is possible that future versions of this call may implement multiple
encryption algorithms, so AL, BX, CX, and DX - unused at present - should
be set to zero.


Fn $8B Sub $35
GenMaskEncrypt fails
    CX: length of buffer
    SI: encryption control block
    DI: buffer holding data to be encrypted
Encrypts a block of data according to the encryption control block, which
will be updated. The value of the encrypted data depend only on the original
data and on the contents of the control block, which should normally be
initialized by GenMaskInit. Provided that the control block is not modified
in any other way, encrypting a block of data in two or more parts yields the
same result as encrypting it all at once.

The current encryption algorithm operates on a byte by byte basis as follows.
For each data byte in turn, take the value of offset 16 in the control block
(which will be from 0 to 15) and use it to select one of the first 16 bytes
in the control block (that is, offset 16 = 0 selects offset 0, offset 16 = 1
selects offset 1, and so on). Add the selected byte to the data byte modulo
$100. Finally, add 1, modulo 16, to offset 16 of the control block.

An example of this algorithm in use can be found in the file WORD.FMT.

It is possible that future versions of this call may implement multiple
encryption algorithms, so AL, BX, and DX - unused at present - should be set
to zero.


Fn $8B Sub $36
GenMaskDecrypt fails
    CX: length of buffer
    SI: encryption control block
    DI: buffer holding data to be decrypted
Decrypts a block of data according to the encryption control block, which
will be updated. The data should have been encrypted with GenMaskEncrypt
with the same initial control block. All comments applying to the latter call
apply here.


Fn $8B Sub $37
GenSetOnEvents v2.28
    AL: 0=disable 1=enable
Enables or disables reporting of power-on events. By default this is enabled
on the Series 3 and disabled on other systems. Disabling may affect other
applications.


Fn $8B Sub $38
GenGetAutoMains v3
    AX: -> setting
Gets the setting of the external power auto-off flag. Zero means that auto-off
will take place even if external power is present, while non-zero means that
auto-off is suspended while external power is present.


Fn $8B Sub $39
GenSetAutoMains v3
    AL: new setting
Sets the external power auto-off flag. Zero means that auto-off will take
place even if external power is present (unless it has been disabled by
setting the auto-off time to $FFFF), while non-zero means that auto-off is
suspended while external power is present.


Fn $8C Sub $00
FloatSin fails   [sine]
Fn $8C Sub $01
FloatCos fails   [cosine]
Fn $8C Sub $02
FloatTan fails   [tangent]
Fn $8C Sub $03
FloatASin fails  [arc sine]
Fn $8C Sub $04
FloatACos fails  [arc cosine]
Fn $8C Sub $05
FloatATan fails  [arc tangent]
Fn $8C Sub $06
FloatExp fails   [exponentiation (base e)]
Fn $8C Sub $07
FloatLn fails    [natural logarithm (base e)]
Fn $8C Sub $08
FloatLog fails   [decimal logarithm (base 10)]
Fn $8C Sub $09
FloatSqrt fails  [square root]
    SI: argument (real)
    DI: result (real)
Calculates the specified function of the argument. The argument and result
may be stored in the same place; if not, the argument is not altered. The
trignometric functions operate in radians.


Fn $8C Sub $0A
FloatPow fails
    DX: power (real)
    SI: base (real)
    DI: result (real)
Calculates the result of raising the base to the indicated power. The result
may be stored in the same place as either argument; if not, neither argument
is altered.


Fn $8C Sub $0B
FloatRand
    SI: seed (long)
    DI: result (real)
Generates a random real number based on the unsigned long integer seed, which
is unaltered; the memory used for the two should not overlap.


Fn $8C Sub $0C
FloatMod fails
    DX: divisor (real)
    SI: dividend (real)
    DI: result (real)
Calculates the dividend modulo the divisor, using the formula:
    result = dividend - divisor * FloatInt (dividend/divisor)
The result may be stored in the same place as either argument; if not, neither
argument is altered.


Fn $8C Sub $0D
FloatInt fails
    SI: argument (real)
    DI: result (real)
Rounds the argument to the closest integer towards zero (i.e. zeros the
fractional part of the argument). The argument and result may be stored in the
same place; if not, the argument is not altered.



Further system calls are described in Psionics file SYSCALLS.3.
The Psionics Files

SYSCALLS.3

PSIONICS FILE - SYSCALLS.3
==========================
System calls (part 3)
Last modified 1998-07-22
========================

See part 1 for general notes and explanations.



Fn $8D is used for the Window Server, and is described in the Psionics file
WSERVER.


Fn $8E Sub $00 to $10 control various parts of the hardware, and should not
be used by OPL programs.


Fn $8E Sub $11
HwGetSupplyStatus
    BX: 6 byte buffer
Gets information about the power supply. The buffer is filled with the
following data:
  Offset  0 (word): main battery voltage in mV
  Offset  2 (word): backup battery voltage in mV
  Offset  4 (word): positive if external power is available, zero if not
                    available, and negative if the detector is disabled
                    because an SSD door is open.
The returned voltages should be taken with a grain of salt: I have observed
the following values:
    1800: no main batteries
    1800: low main batteries
    2056: new main batteries
    2300: no lithium battery
    2556: lithium battery fitted


Fn $8E Sub $12
HwLcdContrastDelta
    AL: step direction
Alters the LCD contrast by one step, upwards if AL is between 0 and 127, and
downwards if it is between 128 and 255 (all inclusive).


Fn $8E Sub $13
HwReadLcdContrast
    AL: -> setting
Gets the current LCD contrast setting. On a Series 3, only the bottom 4 bits
are significant.


Fn $8E Sub $14
HwSwitchOff
    CX: delay in quarter seconds
Switches the machine off for the specified time, then back on again ($FFFF
means never turn back on). The machine will also be turned on by external
events, alarms, and timers. The delay must be at least 9 (2.25 seconds).


Fn $8E Sub $15 should only be used by device drivers.


Fn $8E Sub $16
HwExit

Exits the emulation on PC systems; has no effect on actual Psion machines.


Fn $8E Sub $17 to $1A should only be used by device drivers.


Fn $8E Sub $1B
HwGetPsuType
    AL: -> PSU type
Gets the PSU type: 0 = old MC, 1 = MC "Maxim", 2 = Series 3t, 3 = Series 3a


Fn $8E Sub $1C
HwSupplyWarnings
    BX: 8 byte buffer
Gets information about the power supply. The buffer is filled with the
following data:
  Offset  0 (word): main battery good voltage threshold in mV
  Offset  2 (word): backup battery good voltage threshold in mV
  Offset  4 (word): main battery nominal maximum voltage in mV
  Offset  6 (word): backup battery nominal maximum voltage in mV
The values will depend on the battery type set by GenSetBatteryType.


Fn $8E Sub $1D
HwForceSupplyReading
@No documentation available at present@


Fn $8E Sub $1E
HwGetBackLight
    AX: -> current value
On systems fitted with a backlight, this value indicates control of the
backlight function. If the top bit is set, the operating system will ignore
the backlight toggle key. The remaining bits give the auto-light-off time in
ticks (1/32 second); zero means that auto-light-off is disabled.


Fn $8E Sub $1F
HwSetBackLight
    BX: new value
Sets the backlight control value (see HwGetBackLight).


Fn $8E Sub $20
HwBackLight fails
    AL: action -> status before call
This call fails if no backlight is fitted. Otherwise, the actions are:
    0 = switch backlight off
    1 = switch backlight on
    2 = toggle backlight
    3 = no action
The status returned is that of the backlight before the call: 0 = off, 1 = on.


Fn $8E Sub $21 controls various parts of the hardware, and should not be used
by OPL programs.


Fn $8E Sub $22
HwSupplyInfo v3
    BX: 22 byte buffer
Fills the buffer with additional information about the power supply:
  Offset  0 (byte): main battery status:
    0 = not present
    1 = very low voltage
    2 = low voltage
    3 = good voltage
  Offset  1 (byte): worst main battery status since batteries last inserted
  Offset  2 (byte): non-zero if backup battery voltage is good
  Offset  3 (byte): non-zero if external supply is present
  Offset  4 (word): warning flags
    Bit 0: set if power supply too low for sound
    Bit 1: set if power supply too low to use flash
    Bit 2: set   if offset 6 changed because system clock changed
           clear if offset 6 changed because the batteries were changed
  Offset  6 (long): abstime when batteries inserted
  Offset 10 (long): ticks running on battery
  Offset 14 (long): ticks running on external supply
  Offset 18 (long): mA-ticks (i.e. mAhours * 60 * 60 * 32)


Fn $8E Sub $28
HwGetScanCodes v3
    BX: 20 byte buffer
The buffer is filled with information describing the state of each key on
the keyboard. For the Series 3a, the offset and bit for each key are given
in the following table ("2:4" means offset 2, bit 4).
    System   9:1  Esc     15:0  Delete   4:0  1 14:1  A 12:2  N  0:6
    Data     7:1  Tab      0:2  Enter    0:0  2 14:2  B  8:6  O  4:5
    Word    11:1  Control  4:7  ShiftR   6:7  3 10:6  C 10:3  P  2:5
    Agenda   3:1  ShiftL   2:7  Up      14:5  4  8:2  D 10:4  Q 12:1
    Time     1:1  Psion    0:7  Left     0:4  5  8:3  E 10:5  R  8:1
    World    5:1  Menu    10:7  Down     0:5  6 14:3  F 10:1  S 12:4
    Calc     3:0  Diamond  8:7  Right    0:1  7  6:6  G  8:5  T  8:4
    Sheet    1:0  Space    8:0  Help     6:2  8  4:3  H 14:6  U  6:5
    + and =  2:3  - and _  2:2                9  4:4  I  4:2  V 10:2
    * and :  2:6  / and ;  2:1                0  2:4  J  6:4  W 12:5
    , and <  6:1  . and > 14:4                        K  4:1  X 12:6
                                                      L  4:6  Y  0:3
                                                      M  6:3  Z 12:3


Fn $8E Sub $29
HwGetSsdData

Nothing is known about this call except its name. @@@@@@


Fn $8E Sub $2A
HwResetBatteryStatus v3.9

The battery status is reset, exactly as if the main batteries had been
removed and then replaced.


Fn $8E Sub $2B
HwEnableAutoBatReset v3.9
    AX: -> (if querying) 1 = enabled, 0 = disabled
    BX: 1 = enable, 0 = disable, -1 = query
Enables, disables, or queries the current setting of the automatic reset
of the battery status. This is intended for use on the Workabout, where
the batteries can be recharged in situ.


Fn $8E Sub $2C
HwGetBatData v3.9
    AX: -> address of a data structure in kernel data space
The data is described in the KERNEL file.


Fn $8E Sub $2E
HwReLogPacks v3.9 fails

This has the same effect as opening and then closing the SSD doors.


Fn $8E Sub $2F
HwSetIRPowerLevel v3.9
    AX: -> previous level (0 = low, 1 = high)
    BX: new level (0 = low, 1 = high)
Sets the IR power level, returning the previous level.


Fn $8E Sub $30
HwReturnTickCount v3.9
    AX: tick count
Returns a tick count that is incremented 32 times per second.


Fn $8E Sub $31
HwReturnExpansionPortState v3.9
    AX: -> port type and state
    BX: -> zero
Returns the type and state of the expansion port:
  Bits 0 to 7:  non-zero if SSD doors are open, or something has just been
                plugged into or removed from the Honda expansion connector
  Bits 8 to 14: connector type: 0 = Series 3t/3a, 1 = Workabout LIF,
                2 = Siena Honda, 3 = Series 3c Honda, 4 = HC
  Bit 15:       1 = contains Condor chip, 0 = no Condor chip


Fn $8F
GenDataSegment

This call is only useful in assembler code; it sets ES to point to the start
of the kernel data space (accessible in OPL using GenGetOsData).


Fn $90
ProcPanic
    AL: reason
Panic the current process; this call never returns.


Fn $91
ProcCopyFromById fails
    BX: process ID
    CX: number of bytes to copy
    SI: remote address of first byte to copy
   eDI: local address of first byte to copy
Copy a number of bytes from the indicated process to the current process.


Fn $92
ProcCopyToById fails
    BX: process ID
    CX: number of bytes to copy
    SI: local address of first byte to copy
    DI: remote address of first byte to copy
Copies a number of bytes from the current process to the indicated process.


Fn $93
CharIsDigit
Fn $94
CharIsHexDigit
Fn $95
CharIsPrintable
Fn $96
CharIsAlphabetic
Fn $97
CharIsAlphaNumeric
Fn $98
CharIsUpperCase
Fn $99
CharIsLowerCase
Fn $9A
CharIsSpace
Fn $9B
CharIsPunctuation
Fn $9C
CharIsGraphic
Fn $9D
CharIsControl
    AL: character to test
    EQ: -> set if test fails, clear if test succeeds
Tests to see whether the character has the indicated property. These functions
are language dependent.


Fn $9E
CharToUpperChar
Fn $9F
CharToLowerChar
Fn $A0
CharToFoldedChar
    AL: character 1 -> converted character 1
    AH: character 2 -> converted character 2
Converts two characters to uppercase, lowercase, or folded (uppercase with no
accents). These functions are language dependent.


Fn $A1
BufferCopy
    CX: length to be copied
    SI: address of "from" buffer
   eDI: address of "to" buffer
Copies a number of bytes from one buffer to another. The case of the buffers
overlapping is handled correctly.


Fn $A2
BufferSwap
    CX: length to be swapped
    SI: address of buffer 1
   eDI: address of buffer 2
Swaps the contents of two buffers. The case of the buffers overlapping is
handled correctly.


Fn $A3
BufferCompare
Fn $A4
BufferCompareFolded
    BX: length of buffer 2
    CX: length of buffer 1
    SI: address of buffer 1
   eDI: address of buffer 2
    UL: -> set if buffer 1 less than buffer 2
    EQ: -> set if buffers are identical
The contents of the two buffers are compared byte-for-byte, using unsigned
comparisons, and the result flags set accordingly. BufferCompareFolded acts
as if each character had been passed to CharToFoldedChar before comparison.


Fn $A5
BufferMatch fails
Fn $A6
BufferMatchFolded fails
    CX: length of buffer
    DX: length of pattern
    SI: address of buffer
   eDI: address of pattern
The buffer is examined to determine whether it matches the pattern (using
the usual wildcards); the call fails if it does not. BufferMatchFolded acts
as if each character had been passed to CharToFoldedChar before comparison.


Fn $A7
BufferLocate fails
Fn $A8
BufferLocateFolded fails
    AH: character -> [undefined]
    AX: -> offset of character
    CX: length of buffer
    SI: address of buffer
The buffer is searched to determine if the character occurs within it; the
call fails if it does not. If it does, the offset from the start of the buffer
of the first occurence is returned. BufferLocateFolded acts as if each
character had been passed to CharToFoldedChar before comparison.


Fn $A9
BufferSubBuffer fails
Fn $AA
BufferSubBufferFolded fails
    AX: -> offset
    BX: length of buffer 2
    CX: length of buffer 1
    SI: address of buffer 1
   eDI: address of buffer 2
Buffer 1 is searched to determine if buffer 2 occurs within it; the call fails
if it does not. If it does, the offset from the start of buffer 1 of the first
occurence of buffer 2 is returned. BufferSubBufferFolded acts as if each
character had been passed to CharToFoldedChar before comparison.


Fn $AB
BufferJustify
    AX: -> address of first uncopied character
    BX: length of buffer 2
    CX: length of buffer 1
    DX: fill character * 256 + control code
    SI: address of buffer 1
   eDI: address of buffer 2
Buffer 1 is copied into buffer 2, and the remaining space filled with the fill
character according to the control code (0 = fill at end, 1 = fill at start,
2 = centre the copied data). If buffer 1 is longer than buffer 2, then the
contents will be truncated to fit. If the length of buffer 2 is negative, then
it is assumed to be the same as that of buffer 1 (and the data is just copied).


Fn $AC
StringCopy
Fn $AD
StringCopyFolded
    SI: cstr
   eDI: large enough buffer
The cstr is copied into the buffer. StringCopyFolded passes each character
through CharToFoldedChar during the copy.


Fn $AE
StringConvertToFolded
    SI: cstr
Each character of the cstr is passed through CharToFoldedChar.


Fn $AF
StringCompare
Fn $B0
StringCompareFolded
    SI: cstr 1
   eDI: cstr 2
    UL: -> set if cstr 1 less than cstr 2
    EQ: -> set if cstrs are identical
The contents of the two cstrs are compared byte-for-byte, using unsigned
comparisons, and the result flags set accordingly. StringCompareFolded acts
as if each character had been passed to CharToFoldedChar before comparison.


Fn $B1
StringMatch fails
Fn $B2
StringMatchFolded fails
    SI: cstr to be searched
   eDI: pattern (cstr)
The cstr is searched to determine if the pattern occurs within it (using
the usual wildcards); the call fails if it does not. StringMatchFolded acts
as if each character had been passed to CharToFoldedChar before comparison.


Fn $B3
StringLocate fails
Fn $B4
StringLocateFolded fails
Fn $B5
StringLocateInReverse fails
Fn $B6
StringLocateInReverseFolded fails
    AH: character -> [undefined]
    AX: -> offset of character
    SI: cstr
The cstr is searched to determine if the character occurs within it; the
call fails if it does not. If it does, the offset from the start of the cstr
of the first (for StringLocate and StringLocateFolded) or last (for the two
Reverse calls) occurence is returned. The two Folded calls act as if each
character had been passed to CharToFoldedChar before comparison.


Fn $B7
StringSubString fails
Fn $B8
StringSubStringFolded fails
    AX: -> offset
    SI: cstr 1
   eDI: cstr 2
Cstr 1 is searched to determine if cstr 2 occurs within it; the call fails
if it does not. If it does, the offset from the start of cstr 1 of the first
occurence of cstr 2 is returned. StringSubStringFolded acts as if each
character had been passed to CharToFoldedChar before comparison.


Fn $B9
StringLength
    AX: -> length of the cstr
   eDI: cstr
Returns the length of a cstr, excluding the terminating zero byte.


Fn $BA
StringValidateName fails
    AL: maximum number of characters permitted
    AH: non-zero if an extension is permitted
   eDI: cstr
The cstr is checked to see if it a valid name, and the call fails if it is
not. A name is valid if it:
* begins with a letter;
* contains only letters, digits, dollar signs ($), underscores (_), and at
  most one dot;
* if AH is zero, does not contain a dot;
* contains no more than the specified number of characters before the dot
  (if any); and
* contains no more than 4 characters after the dot, if any.
@The manual says 3 characters, but my tests accept 4.@


Fn $BB
LongIntCompare
    AX: high half of P
    BX: low half of P
    CX: high half of Q
    DX: low half of Q
    SL: -> set if P less than Q
    EQ: -> set if P equals Q
Compares P and Q (both signed longs) and sets the result flags accordingly.


Fn $BC
LongIntMultiply fails
    AX: high half of P -> high half of product
    BX: low half of P  -> low half of product
    CX: high half of Q
    DX: low half of Q
Multiples P and Q (both signed longs); the call fails if the result cannot
be represented as a signed long.


Fn $BD
LongIntDivide fails
    AX: high half of P -> high half of quotient
    BX: low half of P  -> low half of quotient
    CX: high half of Q -> high half of remainder
    DX: low half of Q  -> low half of remainder
Divides P by Q (both signed longs); the call fails if Q is zero. The remainder
will have the same sign as P.


Fn $BE
LongUnsignedIntCompare
    AX: high half of P
    BX: low half of P
    CX: high half of Q
    DX: low half of Q
    UL: -> set if P less than Q
    EQ: -> set if P equals Q
Compares P and Q (both unsigned longs) and sets the result flags accordingly.


Fn $BF
LongUnsignedIntMultiply fails
    AX: high half of P -> high half of product
    BX: low half of P  -> low half of product
    CX: high half of Q
    DX: low half of Q
Multiples P and Q (both unsigned longs); the call fails if the result cannot
be represented as a unsigned long.


Fn $C0
LongUnsignedIntDivide fails
    AX: high half of P -> high half of quotient
    BX: low half of P  -> low half of quotient
    CX: high half of Q -> high half of remainder
    DX: low half of Q  -> low half of remainder
Divides P by Q (both unsigned longs); the call fails if Q is zero.


Fn $C1
FloatAdd fails
Fn $C2
FloatSubtract fails
Fn $C3
FloatMultiply fails
Fn $C4
FloatDivide fails
    SI: address of Q
    DI: address of P
Calculates the specified one of P+Q, P-Q, P*Q, or P/Q, and places the result
in P. Both P and Q are reals.


Fn $C5
FloatCompare
    SI: address of Q
    DI: address of P
    SL: -> set if P is less than Q
    EQ: -> set if P equals Q
Compares two reals and sets the result flags appropriately.


Fn $C6
FloatNegate
    DI: address of P
Negates a real in-situ.


Fn $C7
FloatToInt fails
Fn $C8
FloatToUnsignedInt fails
    AX: -> result
    SI: address of real
Converts a real to a signed or unsigned int; the call fails if the result is
out of range. FloatToUnsignedInt ignores the sign of the real.


Fn $C9
FloatToLong fails
Fn $CA
FloatToUnsignedLong fails
    AX: -> high half of result
    BX: -> low half of result
    SI: address of real
Converts a real to a signed or unsigned long; the call fails if the result is
out of range. FloatToUnsignedLong ignores the sign of the real.


Fn $CB
IntToFloat
Fn $CC
UnsignedIntToFloat
    AX: value
    DI: address of real
Converts a signed or unsigned int to a real.


Fn $CD
LongToFloat
Fn $CE
UnsignedLongToFloat
    AX: high half of value
    BX: low half of value
    DI: address of real
Converts a signed or unsigned long to a real.


Fn $CF
LibSend
Fn $D0
LibSendSuper
    AX: -> method result
    BX: handle of object to receive the message
    CX: message number
    DX: argument 1
    SI: argument 2
    DI: argument 3
These functions send a message to an object and invoke a method on that object.
LibSend starts searching for the method in the class of the object, and
LibSendSuper in the superclass.


Fn $D1 to $D3 can only be used from assembler.


Fn $D4
Dummy

This function has no effect.


Fn $D5
GenIntByNumber
    AL: Fn -> error and result flags
    SI: argument block
    DI: result block
This call is equivalent to the OS keyword; it calls another system call with
the arguments and results stored in 12 byte blocks.


Fn $D6 is used for the Window Server, and is described in the Psionics file
WSERVER.


Fn $D7 is normally only used by the C library.


Fn $D8 is used for accessing DBF files. See the Psionics file DBF.FMT.


Fn $D9
LibEnterSend
    AX: -> method result
    BX: handle of object to receive the message
    CX: message number
    DX: argument 1
    SI: argument 2
    DI: argument 3
This is identical to LibSend, except that it also starts a new "entry-exit
region". The method description will state when this is needed.


Fn $DA
IoKeyAndMouseStatus
@No documentation available at present@


Fn $DB
StringCapitalise
    SI: cstr
The first character of the cstr is passed through CharToUpperChar, and the
remaining characters through CharToLowerChar.


Fn $DC
ProcIndStringCopyFromById fails
    BX: process ID
    CX: maximum length to copy
    SI: address of location holding address of cstr
   eDI: buffer
This copies a cstr from the indicated process to the current process. The
cstr is found via a pointer also in the memory of the indicated process, and
the address of this pointer is specified. This call is equivalent to making
two calls to ProcCopyFromById, the first to find the location of the cstr, and
the second to fetch it, except that the contents of the buffer beyond the
terminating zero are unspecified.


Fn $DD is reserved for the window server.


Fn $DE
IoSerManager
@No documentation available at present@
The Psionics Files

SYSCALLS.IDX

PSIONICS FILE - SYSCALLS.IDX
============================
Alphabetical index to system calls
Last modified 1997-09-14
==================================

In the file column:
    1   means Psionics file SYSCALLS.1
    2   means Psionics file SYSCALLS.2
    3   means Psionics file SYSCALLS.3
    DBF means Psionics file DBF.FMT


Function number   File  Name

Fn $A3              3   BufferCompare
Fn $A4              3   BufferCompareFolded
Fn $A1              3   BufferCopy
Fn $AB              3   BufferJustify
Fn $A7              3   BufferLocate
Fn $A8              3   BufferLocateFolded
Fn $A5              3   BufferMatch
Fn $A6              3   BufferMatchFolded
Fn $A9              3   BufferSubBuffer
Fn $AA              3   BufferSubBufferFolded
Fn $A2              3   BufferSwap
Fn $97              3   CharIsAlphaNumeric
Fn $96              3   CharIsAlphabetic
Fn $9D              3   CharIsControl
Fn $93              3   CharIsDigit
Fn $9C              3   CharIsGraphic
Fn $94              3   CharIsHexDigit
Fn $99              3   CharIsLowerCase
Fn $95              3   CharIsPrintable
Fn $9B              3   CharIsPunctuation
Fn $9A              3   CharIsSpace
Fn $98              3   CharIsUpperCase
Fn $A0              3   CharToFoldedChar
Fn $9F              3   CharToLowerChar
Fn $9E              3   CharToUpperChar
Fn $8A Sub $04      2   ConvArgumentsToBuffer
Fn $8A Sub $09      2   ConvFloatToBuffer
Fn $8A Sub $02      2   ConvIntToBuffer
Fn $8A Sub $03      2   ConvLongIntToBuffer
Fn $8A Sub $0A      2   ConvStringToFloat
Fn $8A Sub $07      2   ConvStringToInt
Fn $8A Sub $08      2   ConvStringToLongInt
Fn $8A Sub $05      2   ConvStringToUnsignedInt
Fn $8A Sub $06      2   ConvStringToUnsignedLongInt
Fn $8A Sub $00      2   ConvUnsignedIntToBuffer
Fn $8A Sub $01      2   ConvUnsignedLongIntToBuffer
Fn $D8 Sub $0C     DBF  DbfAbsRead
Fn $D8 Sub $0B     DBF  DbfAbsReadSense
Fn $D8 Sub $11     DBF  DbfAppend
Fn $D8 Sub $0E     DBF  DbfBackRead
Fn $D8 Sub $01     DBF  DbfClose
Fn $D8 Sub $05     DBF  DbfCompress
Fn $D8 Sub $04     DBF  DbfCopyDown
Fn $D8 Sub $06     DBF  DbfCopyFile
Fn $D8 Sub $16     DBF  DbfCount
Fn $D8 Sub $17     DBF  DbfDescRecordRead
Fn $D8 Sub $18     DBF  DbfDescRecordWrite
Fn $D8 Sub $12     DBF  DbfEraseRead
Fn $D8 Sub $08     DBF  DbfExtHeaderRead
Fn $D8 Sub $09     DBF  DbfExtHeaderWrite
Fn $D8 Sub $07     DBF  DbfFileSize
Fn $D8 Sub $14     DBF  DbfFindRead
Fn $D8 Sub $19     DBF  DbfFindReadField
Fn $D8 Sub $0F     DBF  DbfFirstRead
Fn $D8 Sub $02     DBF  DbfFlush
Fn $D8 Sub $10     DBF  DbfLastRead
Fn $D8 Sub $0D     DBF  DbfNextRead
Fn $D8 Sub $00     DBF  DbfOpen
Fn $D8 Sub $15     DBF  DbfSense
Fn $D8 Sub $03     DBF  DbfTrash
Fn $D8 Sub $13     DBF  DbfUpdate
Fn $D8 Sub $0A     DBF  DbfVersion
Fn $85 Sub $08      1   DevDelete
Fn $85 Sub $0A      1   DevFind
Fn $85 Sub $06      1   DevLoadLDD
Fn $85 Sub $07      1   DevLoadPDD
Fn $85 Sub $09      1   DevQueryUnits
Fn $D4              3   Dummy
Fn $87 Sub $11      1   FilChangeDirectory
Fn $87 Sub $06      1   FilDelete
Fn $87 Sub $01      1   FilExecute
Fn $87 Sub $14      1   FilLocChanged
Fn $87 Sub $15      1   FilLocDevice
Fn $87 Sub $16      1   FilLocReadPDD
Fn $87 Sub $0C      1   FilMakeDirectory
Fn $87 Sub $0D      1   FilOpenUnique
Fn $87 Sub $02      1   FilParse
Fn $87 Sub $03      1   FilPathGet
Fn $87 Sub $10      1   FilPathGetById
Fn $87 Sub $04      1   FilPathSet
Fn $87 Sub $05      1   FilPathTest
Fn $87 Sub $07      1   FilRename
Fn $87 Sub $13      1   FilSetFileDate
Fn $87 Sub $0A      1   FilStatusDevice
Fn $87 Sub $08      1   FilStatusGet
Fn $87 Sub $09      1   FilStatusSet
Fn $87 Sub $0B      1   FilStatusSystem
Fn $87 Sub $0E      1   FilSystemAttach
Fn $87 Sub $0F      1   FilSystemDetach
Fn $8C Sub $04      2   FloatACos
Fn $8C Sub $03      2   FloatASin
Fn $8C Sub $05      2   FloatATan
Fn $C1              3   FloatAdd
Fn $C5              3   FloatCompare
Fn $8C Sub $01      2   FloatCos
Fn $C4              3   FloatDivide
Fn $8C Sub $06      2   FloatExp
Fn $8C Sub $0D      2   FloatInt
Fn $8C Sub $07      2   FloatLn
Fn $8C Sub $08      2   FloatLog
Fn $8C Sub $0C      2   FloatMod
Fn $C3              3   FloatMultiply
Fn $C6              3   FloatNegate
Fn $8C Sub $0A      2   FloatPow
Fn $8C Sub $0B      2   FloatRand
Fn $8C Sub $00      2   FloatSin
Fn $8C Sub $09      2   FloatSqrt
Fn $C2              3   FloatSubtract
Fn $8C Sub $02      2   FloatTan
Fn $C7              3   FloatToInt
Fn $C9              3   FloatToLong
Fn $C8              3   FloatToUnsignedInt
Fn $CA              3   FloatToUnsignedLong
Fn $8B Sub $2D      2   GenAlarmId
Fn $8B Sub $29      2   GenCrc
Fn $8F              3   GenDataSegment
Fn $8B Sub $23      2   GenEnvBufferDelete
Fn $8B Sub $24      2   GenEnvBufferFind
Fn $8B Sub $21      2   GenEnvBufferGet
Fn $8B Sub $22      2   GenEnvBufferSet
Fn $8B Sub $27      2   GenEnvStringDelete
Fn $8B Sub $28      2   GenEnvStringFind
Fn $8B Sub $25      2   GenEnvStringGet
Fn $8B Sub $26      2   GenEnvStringSet
Fn $8B Sub $1D      2   GenGetAmPmText
Fn $8B Sub $38      2   GenGetAutoMains
Fn $8B Sub $17      2   GenGetAutoSwitchOffValue
Fn $8B Sub $1F      2   GenGetBatteryType
Fn $8B Sub $0E      2   GenGetCommandLine
Fn $8B Sub $05      2   GenGetCountryData
Fn $8B Sub $06      2   GenGetErrorText
Fn $8B Sub $1B      2   GenGetLanguageCode
Fn $8B Sub $15      2   GenGetNotifyState
Fn $8B Sub $07      2   GenGetOsData
Fn $8B Sub $0D      2   GenGetRamSizeInParas
Fn $8B Sub $0F      2   GenGetSoundFlags
Fn $8B Sub $1C      2   GenGetSuffixes
Fn $8B Sub $14      2   GenGetText
Fn $D5              3   GenIntByNumber
Fn $8B Sub $01      2   GenLcdType
Fn $8B Sub $12      2   GenMarkActive
Fn $8B Sub $13      2   GenMarkNonActive
Fn $8B Sub $36      2   GenMaskDecrypt
Fn $8B Sub $35      2   GenMaskEncrypt
Fn $8B Sub $34      2   GenMaskInit
Fn $8B Sub $09      2   GenNotify
Fn $8B Sub $0A      2   GenNotifyError
Fn $8B Sub $03      2   GenParse
Fn $8B Sub $30      2   GenPasswordControl
Fn $8B Sub $31      2   GenPasswordQuery
Fn $8B Sub $2E      2   GenPasswordSet
Fn $8B Sub $2F      2   GenPasswordTest
Fn $8B Sub $2A      2   GenRomVersion
Fn $8B Sub $39      2   GenSetAutoMains
Fn $8B Sub $18      2   GenSetAutoSwitchOffValue
Fn $8B Sub $20      2   GenSetBatteryType
Fn $8B Sub $33      2   GenSetConfig
Fn $8B Sub $1E      2   GenSetCountryData
Fn $8B Sub $16      2   GenSetNotifyState
Fn $8B Sub $37      2   GenSetOnEvents
Fn $8B Sub $10      2   GenSetSoundFlags
Fn $8B Sub $11      2   GenSound
Fn $8B Sub $02      2   GenStartReason
Fn $8B Sub $32      2   GenTickle
Fn $8B Sub $00      2   GenVersion
Fn $81 Sub $02      1   HeapAdjustCellSize
Fn $81 Sub $00      1   HeapAllocateCell
Fn $81 Sub $04      1   HeapCellSize
Fn $81 Sub $03      1   HeapFreeCell
Fn $81 Sub $06      1   HeapFreeMemory
Fn $81 Sub $01      1   HeapReAllocateCell
Fn $81 Sub $05      1   HeapSetGranularity
Fn $8E Sub $20      3   HwBackLight
Fn $8E Sub $2B      3   HwEnableAutoBatReset
Fn $8E Sub $16      3   HwExit
Fn $8E Sub $1D      3   HwForceSupplyReading
Fn $8E Sub $1E      3   HwGetBackLight
Fn $8E Sub $2C      3   HwGetBatData
Fn $8E Sub $1B      3   HwGetPsuType
Fn $8E Sub $28      3   HwGetScanCodes
Fn $8E Sub $29      3   HwGetSsdData
Fn $8E Sub $11      3   HwGetSupplyStatus
Fn $8E Sub $12      3   HwLcdContrastDelta
Fn $8E Sub $2E      3   HwReLogPacks
Fn $8E Sub $13      3   HwReadLcdContrast
Fn $8E Sub $2A      3   HwResetBatteryStatus
Fn $8E Sub $31      3   HwReturnExpansionPortState
Fn $8E Sub $30      3   HwReturnTickCount
Fn $8E Sub $1F      3   HwSetBackLight
Fn $8E Sub $2F      3   HwSetIRPowerLevel
Fn $8E Sub $22      3   HwSupplyInfo
Fn $8E Sub $1C      3   HwSupplyWarnings
Fn $8E Sub $14      3   HwSwitchOff
Fn $CB              3   IntToFloat
Fn $86 Sub $00      1   IoAsynchronous
Fn $86 Sub $01      1   IoAsynchronousNoError
Fn $86 Sub $10      1   IoClose
Fn $DA              3   IoKeyAndMouseStatus
Fn $85 Sub $00      1   IoOpen
Fn $86 Sub $1F      1   IoPlaySoundA
Fn $86 Sub $24      1   IoPlaySoundAO
Fn $86 Sub $20      1   IoPlaySoundCancel
Fn $86 Sub $1E      1   IoPlaySoundW
Fn $86 Sub $11      1   IoRead
Fn $86 Sub $22      1   IoRecordSoundA
Fn $86 Sub $23      1   IoRecordSoundCancel
Fn $86 Sub $21      1   IoRecordSoundW
Fn $86 Sub $13      1   IoSeek
Fn $DE              3   IoSerManager
Fn $86 Sub $18      1   IoShiftStates
Fn $86 Sub $08      1   IoSignal
Fn $86 Sub $09      1   IoSignalByPid
Fn $86 Sub $0A      1   IoSignalByPidNoReSched
Fn $86 Sub $1A      1   IoSignalKillAsynchronous
Fn $86 Sub $1B      1   IoSignalKillCancel
Fn $86 Sub $05      1   IoWaitForSignal
Fn $86 Sub $19      1   IoWaitForSignalNoHandler
Fn $86 Sub $06      1   IoWaitForStatus
Fn $86 Sub $02      1   IoWithWait
Fn $86 Sub $12      1   IoWrite
Fn $86 Sub $07      1   IoYield
Fn $D9              3   LibEnterSend
Fn $CF              3   LibSend
Fn $D0              3   LibSendSuper
Fn $BB              3   LongIntCompare
Fn $BD              3   LongIntDivide
Fn $BC              3   LongIntMultiply
Fn $CD              3   LongToFloat
Fn $BE              3   LongUnsignedIntCompare
Fn $C0              3   LongUnsignedIntDivide
Fn $BF              3   LongUnsignedIntMultiply
Fn $8B Sub $04      2   LongUnsignedIntRandom
Fn $83 Sub $07      1   MessFree
Fn $83 Sub $00      1   MessInit
Fn $83 Sub $01      1   MessReceiveAsynchronous
Fn $83 Sub $03      1   MessReceiveCancel
Fn $83 Sub $02      1   MessReceiveWithWait
Fn $83 Sub $04      1   MessSend
Fn $83 Sub $05      1   MessSendReceiveAsynchronous
Fn $83 Sub $06      1   MessSendReceiveWithWait
Fn $83 Sub $08      1   MessSignal
Fn $83 Sub $09      1   MessSignalCancel
Fn $83 Sub $0A      1   MessSignalCancelX
Fn $91              3   ProcCopyFromById
Fn $92              3   ProcCopyToById
Fn $88 Sub $05      2   ProcCreateTask
Fn $88 Sub $0B      2   ProcFind
Fn $88 Sub $10      2   ProcGetOwner
Fn $88 Sub $02      2   ProcGetPriority
Fn $88 Sub $00      2   ProcId
Fn $88 Sub $01      2   ProcIdByName
Fn $DC              3   ProcIndStringCopyFromById
Fn $88 Sub $08      2   ProcKill
Fn $88 Sub $0A      2   ProcNameById
Fn $88 Sub $0E      2   ProcOnTerminate
Fn $90              3   ProcPanic
Fn $88 Sub $09      2   ProcPanicById
Fn $88 Sub $0C      2   ProcRename
Fn $88 Sub $06      2   ProcResume
Fn $88 Sub $03      2   ProcSetPriority
Fn $88 Sub $07      2   ProcSuspend
Fn $88 Sub $0D      2   ProcTerminate
Fn $80 Sub $06      1   SegAdjustSize
Fn $80 Sub $04      1   SegClose
Fn $80 Sub $0D      1   SegCloseLockedOrDevice
Fn $80 Sub $09      1   SegCopyFrom
Fn $80 Sub $08      1   SegCopyTo
Fn $80 Sub $01      1   SegCreate
Fn $80 Sub $02      1   SegDelete
Fn $80 Sub $07      1   SegFind
Fn $80 Sub $00      1   SegFreeMemory
Fn $80 Sub $0A      1   SegLock
Fn $80 Sub $03      1   SegOpen
Fn $80 Sub $0C      1   SegRamDiskUsed
Fn $80 Sub $05      1   SegSize
Fn $80 Sub $0B      1   SegUnLock
Fn $82 Sub $00      1   SemCreate
Fn $82 Sub $01      1   SemDelete
Fn $82 Sub $04      1   SemSignalMany
Fn $82 Sub $03      1   SemSignalOnce
Fn $82 Sub $05      1   SemSignalOnceNoReSched
Fn $82 Sub $02      1   SemWait
Fn $DB              3   StringCapitalise
Fn $AF              3   StringCompare
Fn $B0              3   StringCompareFolded
Fn $AE              3   StringConvertToFolded
Fn $AC              3   StringCopy
Fn $AD              3   StringCopyFolded
Fn $B9              3   StringLength
Fn $B3              3   StringLocate
Fn $B4              3   StringLocateFolded
Fn $B5              3   StringLocateInReverse
Fn $B6              3   StringLocateInReverseFolded
Fn $B1              3   StringMatch
Fn $B2              3   StringMatchFolded
Fn $B7              3   StringSubString
Fn $B8              3   StringSubStringFolded
Fn $BA              3   StringValidateName
Fn $89 Sub $07      2   TimDateToDaySeconds
Fn $89 Sub $09      2   TimDayOfWeek
Fn $89 Sub $06      2   TimDaySecondsToDate
Fn $89 Sub $05      2   TimDaySecondsToSystemTime
Fn $89 Sub $08      2   TimDaysInMonth
Fn $89 Sub $02      2   TimGetSystemTime
Fn $89 Sub $0A      2   TimNameOfDay
Fn $89 Sub $0E      2   TimNameOfDayAbb
Fn $89 Sub $0B      2   TimNameOfMonth
Fn $89 Sub $0F      2   TimNameOfMonthAbb
Fn $89 Sub $03      2   TimSetSystemTime
Fn $89 Sub $00      2   TimSleepForTenths
Fn $89 Sub $01      2   TimSleepForTicks
Fn $89 Sub $04      2   TimSystemTimeToDaySeconds
Fn $89 Sub $0C      2   TimWaitAbsolute
Fn $89 Sub $0D      2   TimWeekNumber
Fn $CC              3   UnsignedIntToFloat
Fn $CE              3   UnsignedLongToFloat
The Psionics Files

TCPIP

PSIONICS FILE - TCPIP
=====================
Interface to TCP/IP
Last modified 1998-02-23
========================

The TCP/IP stack for the Psion 3 series is shipped as a separate product
called PsiMail; it comes with various utilities. This file describes the
programming interface to this stack. It assumes knowledge of the Unix
Berkeley Sockets interface, and terms not defined here have the same meaning
as there.


General conventions
-------------------

Most network functions are carried out by sending messages to objects. There
are two objects - the IP object and the DNS object.

Messages are sent to the objects with SEND. This takes from 2 to 5
arguments: the object handle, the message type number, and 0 to 2 additional
items. These items are called V1, V2, and V3 in this file, and are described
in OPL terms as an object. Thus, for example, given:

    Message 99 - Activate or deactivate network
    V1: 10 byte buffer described below
    V2: a word holding the value 8
    Returns: zero for success, non-zero for failure

typical code to make the call would be:

    LOCAL bufx%,bufy&,bufz&,x%
    x%=8
    IF SEND(ipobj%, 99, bufx%, x%)<>0
        ALERT("Can't activate network")
    ENDIF

and the variables bufx%, bufy&, and bufz& form the buffer.

Where a constant is given, exactly that value must be used. Where bits are
not mentioned in a value, they must be set to zero and ignored when read.

Network addresses are 16 bytes long, and have the following format:
  Offset 0 (word): must be 2
  Offset 2 (word): port number, in network order
  Offset 4 (long): IP address, in network order
  Offset 8 to  15: unused
Note that the address and port numbers are in network order (most
significant byte in the lowest offset).


Accessing the interface
-----------------------

The interface is provided by a library called SOCKDYL.DYL. If there is a
copy in the ROM, it will be in the file ROM::SOCKDYL.DYL and can be invoked
by:
    FINDLIB(tcpipch%, "SOCKDYL.DYL")
Otherwise it should be in a directory called \NET on a local drive. Programs
are recommended to look on all drives and determine the copy with the
highest version number (stored in a word at offset 24 of the file). Then
invoke the library by:
    LOADLIB(tcpipch%, "file", 1)
where the second parameter is the name of the file holding the copy used.
In either case, the command will return 0 for success; tcpipch% is the
category handle for the library.

When the program has finished with the network, it should unload the library
using UNLOADLIB.

Actual access to the network is carried out through two objects - the IP
object and the DNS object. The IP object is created by:
    ipobj%=NEWOBJH(tcpipch%,0)
    SEND(ipobj%,25,#0,#0)      : REM see below for explanation
The DNS object is created by:
    dnsobj%=NEWOBJH(tcpipch%,2)

Before unloading the library, these objects should be destroyed by sending
them message 0:
    SEND(ipobj%,0)
    SEND(dnsobj%,0)


The IP object
-------------

The IP object provides the following messages.

Messages 2 to 24 have two additional arguments with a standard meaning: the
first is a control block of some size, whose format is given instead of the
argument descriptions, and the second is a status word. These calls can be
made synchronously or asynchronously.

To make a synchronous call, set the status word to 0 beforehand. If the
call fails, -1 is returned and the error code is in the status word.
Otherwise the call succeeded and the returned value is as described.

To make an asynchronous call, set the status word to 1 beforehand. If
the call returns -1, it failed and the error code is in the status word.
Otherwise, the status word will have been set to -46; when the operation
finishes, the status word will be changed and the semaphore signalled.
The new status word should now be passed to message 1. If the operation
failed, -1 is returned and the status word holds the error code. Otherwise
the value returned is the result of the operation.


Message 1 - interpret asynchronous result
V1: status word

See above for how to use this message.


Message 2 - create socket
The control block is 6 bytes:
  Offset 0 (word): must be 2
  Offset 2 (word): socket type: 1 = TCP stream, 2 = UDP datagram, 3 = raw
  Offset 4 (word): must be 0
Returns: socket handle for a new socket

Creates a new socket.


Message 3 - bind socket
The control block is 6 bytes:
  Offset 0 (word): socket handle
  Offset 2 (word): address of a 16 byte network address block
  Offset 4 (word): must be 16

Binds a socket. Within the address, IP address 0 may be used to bind to
any local interface, and port number 0 may be used to request that a port
is assigned on connection.


Message 4 - listen on socket
The control block is 4 bytes:
  Offset 0 (word): socket handle
  Offset 2 (word): length of the backlog queue

Starts a bound TCP socket listening for new connections.


Message 5 - accept a connection
The control block is 6 bytes:
  Offset 0 (word): socket handle
  Offset 2 (word): address of a 16 byte network address block
  Offset 4 (word): must be 16 (may be changed by the call)
Returns: handle of new socket

Accepts a connection from a remote client, placing it on a new socket. The
original socket remains open for connections; the new socket can be used
for data transfer. The address block will be filled in with the address of
the remote client.


Message 6 - make a connection
The control block is 6 bytes:
  Offset 0 (word): socket handle
  Offset 2 (word): address of a 16 byte network address block
  Offset 4 (word): must be 16

Connects a socket to a remote service. The address block should specify
the address of the remote service.


Message 7 - get peer name
Message 8 - get socket name
The control block is 6 bytes:
  Offset 0 (word): socket handle
  Offset 2 (word): address of a 16 byte network address block
  Offset 4 (word): must be 16 (may be changed by the call)

Obtains the address of the remote or local end (respectively) of a socket.
The address block will be filled with the relevant address.


Message  9 - get socket option
Message 10 - set socket option
The control block is 10 bytes:
  Offset 0 (word): socket handle
  Offset 2 (word): must be $FFFF
  Offset 4 (word): option code
  Offset 6 (word): address of the area the value is taken from or put in
  Offset 8 (word): size in bytes of the area (for message 9, this will be
                   changed to the actual size of the value)

Gets or sets an option on a socket. In the following table, "bool" means a
word that is either zero (for false or disabled) or non-zero (for true or
enabled).

Available options are:
  option   size   meaning
  $0004    bool   local address can be reused
  $0008    bool   keep connections alive
  $0010    bool   don't route outgoing messages
  $0020    bool   broadcasting permitted
  $0080      4    linger control block
  $0100    bool   out of band data will be received in-band
  $1001      2    output buffer size
  $1002      2    input buffer size
  $1003      2    transmit low water mark
  $1004      2    receive low water mark
  $1005      2    transmit timeout
  $1006      2    receive timeout
  $1007      2    pending error (will clear the error) [can't be set]
  $1008      2    socket type [can't be set]

The linger control block has the format:
  Offset 0 (word): 0 to disable lingering, 1 to enable
  Offset 2 (word): linger time in seconds
Lingering affects the behaviour of a TCP socket where data is waiting to
be sent when the socket is closed. If it is enabled, the close will wait
up to the linger time for the data to be sent. If it is disabled, the close
will return as soon as possible.


Message 11 - receive data
Message 12 - receive data
The control block is 8 bytes (message 11) or 12 bytes (message 12):
  Offset  0 (word): socket handle
  Offset  2 (word): address of buffer to store data in
  Offset  4 (word): maximum number of bytes to receive
  Offset  6 (word): flags:
    Bit 0: set to process out of band data
    Bit 1: if set, the data remains in the input stream and can be received
           a second time
  Offset  8 (word): address of a 16 byte network address block
  Offset 10 (word): must be 16 (may be changed by the call)
Returns: number of bytes received

Receives data from the socket and places them in memory. Either message can
be used with any socket, but message 12 stores the sender's address in the
block, and so is more useful with datagram sockets that are not connected to
a single peer.


Message 13 - receive data
@@@@ Documentation not available


Message 14 - select
@@@@ Documentation not available


Message 15 - send data
Message 16 - send data to specified address
The control block is 8 bytes (message 15) or 12 bytes (message 16):
  Offset  0 (word): socket handle
  Offset  2 (word): address of first byte to send
  Offset  4 (word): number of bytes to send
  Offset  6 (word): flags:
    Bit 0: set for out of band data
    Bit 2: set to bypass routing
  Offset  8 (word): address of a 16 byte network address block
  Offset 10 (word): must be 16
Returns: number of bytes actually sent

Sends data to the remote peer of a connected socket (message 15) or to the
specified address with an unconnected socket (message 16).


Message 17 - send data
@@@@ Documentation not available


Message 18 - partially close a socket
The control block is 4 bytes:
  Offset  0 (word): socket handle
  Offset  2 (word): 0 = end reception, 1 = end transmission, 2 = end both

Performs a close on one or both directions of a connected TCP socket.


Message 19 - close a socket
The control block is 2 bytes:
  Offset  0 (word): socket handle

Close a socket; the handle may no longer be used.


Message 20 - asynchronous action
@@@@ Documentation not available


Message 21 - configuration
@@@@ Documentation not available


Message 22 - control network
The control block is 6 bytes:
  Offset  0 (long): action:
    1 = connect to network,
    2 = disconnect from network,
    3 = return network status,
    4 = get length of time connected, in seconds
    5 = get local IP address, in network order
  Offset  4 (word): address of a long to store any fetched value in
Returns: network status (action 3 only, see below)

Performs some network control action. Note that it is not necessary to use
this function to set up a connection; the first attempt to use the network
will do so automatically.

For action 2 only, the returned value gives the current status:
0 = disconnected, 1 = connecting, 2 = connected.

For actions 3 and 4, the result is stored in the long pointed to by
offset 4; the result is only valid if the call was made while connected to
the network.


Message 23 - cancel a pending operation on a socket
The control block is 2 bytes:
  Offset  0 (word): socket handle

Cancels any pending operation on a socket. This call should only be made in
synchronous mode, with the status word initialized to zero.


Message 24 - assign socket
@@@@ Documentation not available
@@@@ socket, pid


Message 25 - register network client
No additional arguments
Returns: 0 for success, a negative error code for failure

This call registers the current process as a client of the network system.
It must be made when the IP object is created (see above), and can be
called additional times, in which case the calls are counted by the network
server process. Programs do not normally need to make additional calls.


Message 26 - deregister network client
No additional arguments
Returns: 0 for success, a negative error code for failure

This call cancels a registration of the current process as a client of the
network system, decrementing the count held by the network server. One such
cancellation is made when the IP object is destroyed, and all registrations
are cancelled when the current process terminates. Programs do not normally
need to call this directly.


The DNS object
--------------

The DNS object provides the following messages.


Message 1 - convert host to network (long)
Message 2 - convert network to host (long)
Message 3 - convert host to network (word)
Message 4 - convert network to host (word)
V1: 2 byte or 4 byte buffer holding the value

Each of these converts a value between host and network ordering; the
conversion is done in situ.


Message 5 - convert dotted quad to IP address
V1: long to hold resulting address
V2: cstr to be converted
Returns: zero for success or a non-zero error code

Converts a dotted quad name (such as "158.152.1.222") to an IP address
such as $9E9801DE, but in network order. The dotted quad may have two or
three components, and each component may be a C decimal, octal, or hex
number (so another form for the above is "0x9E.230.478").


Message 6 - test for valid IP address
@@@@ Documentation not available


Message 7 - get host by name
V1: 10 byte buffer which is filled in with the host information
V2: cstr of host name to be looked up
V3: status word
Returns: zero for success or a non-zero error code

This call is always asynchronous. It looks up a host in the DNS, and, if
found, the buffer is filled with the following information:
  Offset 0 (word): address of the canonical name (a cstr)
  Offset 2 (word): address of a zero-terminated list of words, each holding
                   the address of a cstr giving an alias, or zero if there
                   are no aliases
  Offset 4 (long): unused
  Offset 8 (word): address of a zero-terminated list of words, each holding
                   the address of a block holding a network address
The data pointed to is stored in an area which may be overwritten by any
other call to the interface module.


Message 8 - get host by address
V1: 10 byte buffer which is filled in with the host information
V2: 6 byte control block
V3: status word
Returns: zero for success or a non-zero error code

This call is always asynchronous. It looks up a host in the DNS, and, if
found, the buffer is filled with the same information as for message 7. The
control block has the following format:
  Offset 0 (word): address of a long holding the IP address in network order
  Offset 2 (word): must be 4
  Offset 4 (word): must be 2


Message 9 - cancel a pending get host operation
V1: 10 byte buffer provided to the get host operation

This call cancels any outstanding get host operation (messages 7 and 8).
The V1 value must be that provided to the original operation.


Message 10 - extract local component of IP address
Message 11 - construct IP address from local and network components
Message 12 - extract network component of IP address

These calls are intended to split and recombine IP addresses treated as
network and local components, using the old class A, B, and C network
concepts. They are not documented here, partly because subnets and CIDR
have made them obsolete, and partly because the interfaces are flawed.


Message 13 - convert IP address to dotted quad
V1: long holding the IP address in network order
V2: 16 byte buffer filled in with the dotted quad as a cstr

This call converts an IP address such as $9E9801DE (but in network order)
to a dotted quad name such as "158.152.1.222".


Error codes
-----------

The IP object generates the following error codes:

   -33  TCP/IP is not installed on the system
   -32  Incompatible versions of TCP/IP are being used simultaneously
   -16  sockdyl.dyl is corrupt
   -10  Insufficient memory to initialize
     9  Bad socket handle
    11  Out of resources
    14  Bad argument to operation (e.g. not a valid ADDR)
    22  Invalid argument (e.g. attempting to re-bind a bound socket)
    35  Operation would block and socket is non-blocking
    36  Non-blocking operation in progress but not completed
    37  Previous non-blocking operation still in progress
    38  Socket operation on non-socket
    39  Destination address required and socket not connected
    40  Message too long and socket type does not allow it to be split
    41  Wrong protocol type for this socket type
    42  Unknown option for this protocol level
    43  Protocol not supported in this address domain
    44  Socket type not supported
    45  Operation not supported on this socket type
    46  Protocol family not supported
    47  Address family not supported by protocol family
    48  Address already in use
    49  Can't assign requested address
    50  Network is down
    51  Network is unreachable
    52  Network dropped connection on reset
    53  Software caused connection abort
    54  Connection reset by peer
    55  No buffer space available in the socket server
    56  Socket is already connected
    57  Socket is not connected
    58  Can't send after socket shutdown
@@  59  Too many references: can't splice
    60  Connection timed out
    61  Connection refused
    64  Host is down
    65  No route to host
    66  Network has not been initialized
  1001  Syntax error in connection script
  1002  Got abort string while connecting
  1004  Error in configuration
  1005  Serial port is in use
  1006  Error with serial port
  1007  Error reading connection script file
  1008  Timer timed out while connecting
  1009  Not enough memory to connect
  1010  Couldn't find connection script dyl
  1011  Couldn't load connection script dyl
  1012  ISP modem busy
  1013  No carrier
  1014  No answer from ISP modem
  1015  Couldn't read dial settings

The DNS object generates the following error codes:

     1  insufficient memory in DNS process
     2  failure creating socket in DNS process
     3  failure during connect to DNS server
     4  failure during send to DNS server
     5  failure during receive from DNS server
     6  DNS lookup returned "no such entry"
     7  timeout waiting for DNS server
     8  bad arguments
The Psionics Files

WORD.FMT

PSIONICS FILE - WORD.FMT
========================
Format of Word files
Last modified 1996-01-18
========================

Word files can be encrypted with a password. Encryption affects only the
header and data record type 8 (see below).

A word file begins with a header of the following form (U indicates values
for unencrypted files, and E values for encrypted files):
  Offset  0 (cstr): "PSIONWPDATAFILE"
  Offset 16 (word): format version number (U: 1, E: 256)
  Offset 18 (word): encryption algorithm version (U: 0, E: 1)
  Offset 20 to  28: encryption key check value (all $EA if unencrypted)
  Offset 29 to  35: copy of offset 20 to 26
  Offset 36 (word): U: $EAEA, E: 0
  Offset 38 (word): unused

The rest of the file consists of records. All records have the form:
  Offset  0 (word): record type
  Offset  2 (word): size of data portion (L)
  Offset  4 to L+3: data portion

Word files have record types 1 to 9; the word processor application creates
them in numerical order of type. Exactly one record of each type is used,
except that there may be more than one record of types 6 and 7.

All distances and font sizes are in units of 0.05 points (i.e. a value of
1440 represents one inch). All font names are represented by standard code
numbers:
    -1 = Inherited (where permitted)
     0 = Courier              17 = Emperor              40 = Greek
     1 = Pica                 18 = Madeleine            41 = Kana
     2 = Elite                19 = Zapf Humanist        42 = Hebrew
     3 = Prestige             20 = Classic              44 = Russian
     4 = Letter Gothic        24 = Times Roman          48 = Narrator
     5 = Gothic               25 = Century              49 = Emphasis
     6 = Cubic                26 = Palatino             50 = Zapf Chancery
     7 = Lineprinter          27 = Souvenir             52 = Old English
     8 = Helvetica            28 = Garamond             55 = Cooper Black
     9 = Avant Garde          29 = Caledonia            56 = Symbol
    10 = Spartan              30 = Bodoni               57 = Line Draw
    11 = Metro                31 = University           58 = Math 7
    12 = Presentation         32 = Script               59 = Math 8
    13 = APL                  33 = Script PS            60 = Dingbats
    14 = OCR A                36 = Commercial Script    61 = EAN
    15 = OCR B                37 = Park Avenue          62 = PC Line
    16 = Standard Roman       38 = Coronet

Record type 1 holds information about the file. It is always 10 bytes:
  Offset  0 (word): cursor position within text record (type 8)
  Offset  2 (byte): each set bit indicates a character type should be shown
                    as symbols:
    Bit 0: tabs
    Bit 1: spaces
    Bit 2: carriage returns
    Bit 3: soft hyphens
    Bit 4: forced line breaks
  Offset  3 (byte): (Series 3a only)
    Bits 0 to 1: status window: 0=none, 1=narrow, 2=wide
    Bits 4 to 5: zoom state: 0=smallest, ... 3=largest
  Offset  4 (byte): 0=style bar off, 1=style bar on
  Offset  5 (byte): 0=file type is paragraph, 1=file type is line
  Offset  6 (byte): outlining level
  Offset  7 (byte): unused
  Offset  8 (word): unused

Record type 2 holds information about printer set-up. It is
always 58 bytes:
  Offset  0 (word): page width
  Offset  2 (word): page height
    (Note: the above fields assume that the paper orientation is "portrait")
  Offset  4 (word): left margin
  Offset  6 (word): top margin
  Offset  8 (word): width of printing area
  Offset 10 (word): height of printing area
    (Note: these four fields have only been checked for portrait)
  Offset 12 (word): header offset (bottom of header to top of text)
  Offset 14 (word): footer offset (bottom of footer to bottom of text)
  Offset 16 (word): paper orientation: 0=portrait, 1=landscape
  Offset 18 (word): unknown
  Offset 20 (word): first page to print (1=first page)
  Offset 22 (word): last page to print ($FFFF=end of file)
  Offset 24 (word): header font code number
  Offset 26 (byte): header style
    Bit 0: underline
    Bit 1: bold
    Bit 2: italic
    Bit 3: superscript
    Bit 4: subscript
  Offset 27 (byte): unused
  Offset 28 (word): header font size
  Offset 30 (byte): header alignment:
    0 = left
    1 = right
    2 = centered
    3 = justified
    4 = two column
    5 = three column
  Offset 31 (byte): header on first page: 0=no, 1=yes
  Offset 32 to  39: as 24 to 31, but apply to footer, not header
  Offset 40 (word): page number of first page minus 1
  Offset 42 (word): number of pages
  Offset 44 (word): page number style: 0="1,2,3", 1="I,II,III", 2="i,ii,iii"
  Offset 46 (word): base font code number
  Offset 48 (byte): base style (as offset 26)
  Offset 49 (byte): unused
  Offset 50 (word): base font size
  Offset 52 (byte): paper size code:
    0 = A4        (11906 x 16838)
    1 = Custom
    2 = Executive (10440 x 15120)
    3 = Legal     (12240 x 20160)
    4 = Letter    (12240 x 15840)
    5 = Monarch   ( 5580 x 10800)
    6 = DL        ( 6236 x 12472)
  Offset 53 (byte): widows/orphans allowed: 0=no, 1=yes
  Offset 54 (long): unused
The base font code, style, and font size are unused by Word (and should be set
to code 0, style 0, size 240). Other applications using this record layout may
use them and provide means to set them.

Record type 3 holds information about the printer driver:
  Offset  0 (byte): printer driver model number
  Offset  1 (cstr): printer driver library
A printer driver library can support several similar printers; the model number
specifies which is selected.

Record types 4 and 5 hold cstrs giving the header and footer text respectively.

Record types 6 and 7 have a similar layout. Record type 6 describes a style
and uses all 80 bytes. Record type 7 describes an emphasis and uses only the
first 28 bytes.
  Offset  0 to   1: short code, as uppercase letters
  Offset  2 (cstr): full name
  Offset 18 (byte):
    Bit 0: 0=style, 1=emphasis
    Bit 1: set if style or emphasis undeletable
    Bit 2: set for default style or emphasis
  Offset 19 (byte): unused
  Offset 20 (word): font code number (can be inherited)
  Offset 22 (byte): style (bits inherited must be clear in this byte)
    Bit 0: underline
    Bit 1: bold
    Bit 2: italic
    Bit 3: superscript (available in emphasis only)
    Bit 4: subscript   (available in emphasis only)
  Offset 23 (byte): unused
  Offset 24 (word): font size
  Offset 26 (byte):
    Bit 0: inherit underline setting
    Bit 1: inherit bold setting
    Bit 2: inherit italic setting
    Bit 3: inherit superscript setting (available in emphasis only)
    Bit 4: inherit subscript setting   (available in emphasis only)
  Offset 27 (byte): unused
  Offset 28 (word): left indent
  Offset 30 (word): right indent
  Offset 32 (word): first line indent
  Offset 34 (word): alignment: 0=left, 1=right, 2=centred, 3=justified
  Offset 36 (word): line spacing
  Offset 38 (word): space above paragraph
  Offset 40 (word): space below paragraph
  Offset 42 (byte): spacing controls:
    Bit 0: set to keep with next
    Bit 1: set to keep together
    Bit 2: set to start new page
  Offset 43 (byte): unused
  Offset 44 (word): Outline level (1 to 9)
  Offset 46 (word): number of tab stops set
  Offset 48 (word): position of first tab stop
  Offset 50 (word): type of first tab stop: 0=left, 1=right, 2=centred
  Offset 52 to  55: as offsets 48 to 51 for second tab stop
  Offset 56 to  79: as offsets 48 to 51 for third to eighth tab stops

Record type 8 holds the actual text. The following bytes have special
meanings:
   0 = paragraph separator
   7 = unbreakable hyphen
  14 = soft hyphen (displayed only if used to break line)
  15 = unbreakable space
The record is modified in encrypted files.

Record type 9 consists of a sequence of blocks giving the style and emphasis
for the text; each block covers some number of consecutive bytes, and the
blocks between them cover the entire text. No block crosses a paragraph
boundary, but the last block of the paragraph includes the zero byte separating
it from the next paragraph. Each block is 6 bytes:
  Offset  0 (word): number of bytes covered
  Offset  2 to   3: shortcode of style applied
  Offset  4 to   5: shortcode of emphasis applied
The last block should cover an extra byte (an imaginary extra zero separator),
so that the sum of the bytes covered is one more than the size of the type 8
record.


Encryption
----------

Word files can be encrypted with a password. If so, this fact is indicated
in the header (see above), and the type 8 record is modified.

The password is used to generate two 9 byte sequences, called the key value
and the key check value; there is no obvious relationship between the two
sequences. The key check value is written into the header, while the key
value is used for the actual encryption. The key value is generated with the
system call GenMaskInit; there is no documentation of the algorithm used to
generate the check value.

[Note: different passwords may generate the same key value but different key
check values, or vice versa (passwords "AA" and "AAA" are an example of the
latter). This can confuse Word badly.]

Encryption is carried out using the system call GenMaskEncrypt. For
convenience, the description is repeated here with an example.

The first 7 bytes of the key value are appended to all 9 to generate a 16
byte sequence. This is then repeated to generate a sequence of the same size
as the type 8 record, and placed in 1-to-1 correspondence with it. In other
words, for byte N of the type 8 record, the corresponding key byte is given
by byte N AND $F of the 16 byte sequence, counting from 0 (or, in C notation,
byte N % 16 % 9 of the 9 byte sequence). The key byte is then added to the
plain text byte, modulo $100, to get the encrypted byte.

For example, suppose that the text is a single paragraph containing:
    Jackdaws love my 21 big sphinxes of quartz.
and the key value is:
    $91 $20 $E3 $92 $42 $F9 $5C $57 $A9
(which corresponds to the password "AA") then the encrypted type 8 record
is determined as follows:

    Text: J  a  c  k  d  a  w  s     l  o  v  e     m  y
          4A 61 63 6B 64 61 77 73 20 6C 6F 76 65 20 6D 79
    Key:  91 20 E3 92 42 F9 5C 57 A9 91 20 E3 92 42 F9 5C
    Encr: DB 81 46 FD A6 5A D3 CA C9 FD 8F 59 F7 62 66 D5

    Text:    2  1     b  i  g     s  p  h  i  n  x  e  s
          20 32 31 20 62 69 67 20 73 70 68 69 6E 78 65 73
    Key:  91 20 E3 92 42 F9 5C 57 A9 91 20 E3 92 42 F9 5C
    Encr: B1 52 14 B2 A4 62 C3 77 1C 01 88 4C 00 BA 5E CF

    Text:    o  f     q  u  a  r  t  z  .
          20 6F 66 20 71 75 61 72 74 7A 2E
    Key:  91 20 E3 92 42 F9 5C 57 A9 91 20
    Encr: B1 8F 49 B2 B3 6E BD C9 1D 0B 4E

Of course, standard Kerchoffs techniques can be used to break the encryption.
The Psionics Files

WSERVER

PSIONICS FILE - WSERVER
=======================
Window server calls
Last modified 1997-04-10
========================

SPECIAL NOTICE:

This file wouldn't have appeared for much longer if it weren't for Dan Ramage,
who sent me enough material to convince me to restart after many months of
neglect.

This file is dedicated to the memory of Felicia Hatunen (see
<http://www.stdc.demon.co.uk/felicia/>). Most of it was written travelling
to and from a memorial service for her (in California).

There is a lot of missing and incomplete material in this file. While Psion
have provided me with an SDK and other data, there are a number of gaps in
what I have, particularly the mapping of registers to C function arguments.
Therefore this file contains more than the usual number of @ signs indicating
missing material. Assistance in filling these gaps would be greatly appreciated
(though I don't promise credit).



Processes on the Psion do not have direct access to the screen and
keyboard. Instead, they send messages to a special process called the
Window Server. This process then handles the screen and keyboard,
arbitrating between the various requests - for example, it ensures that
only the current foreground process gets keystrokes, and handles the
case of different application windows overlapping.

Many calls to the Window Server are buffered; the individual commands
are stored in a buffer, and then sent to the server in a batch. This is
done whenever the buffer is full, by any command requiring a response
from the server, whenever waiting for an event, and by the wFlush call.
The calls that return a value but do not flush the command buffer are:
gTextCount, gFontInfo, and wCheckBitmapid.

If an error occurs when a buffered command is executed, all further
commands are ignored until one that requires a response. This command is
also ignored, and the error is returned instead.

Clients of the window server can be in the foreground or background. On
machines with a small screen, only one client can be in the foreground, and
it occupies the whole screen. On machines with a large screen, more than one
client can be in the foreground or be visible at a time.


See the file SYSCALLS.1 for the notation used in this file. In the case of
function $8D, bit 7 of the sub-function number is set to indicate that the
function obtains a response from the server; this bit is ignored in ordering
the functions in the following list of descriptions. Furthermore, in the
case of Fn $8D Sub $7E and Sub $FF, there are several different functions
depending on the value of AL.

If a call is marked "fails" then:
- if it fails, the resulting behaviour depends on the error handling flag set
  by wDisableLeaves;
- if no new value is shown for AX, it is set to 0 on success.


A common data structure is the "standard rectangle structure". This is defined
here:
  Offset 0 (word): x coordinate of left edge of the rectangle
  Offset 2 (word): y coordinate of top edge of the rectangle
  Offset 4 (word): x coordinate of left edge plus width
  Offset 6 (word): y coordinate of top edge plus height


Graphics Contexts
-----------------

Many window server calls are described as using a "graphics context". This is
a data structure associated with a specific window or bitmap and stored in the
window server itself. It determines various features about the call, such as
the font used in text operations. At any time there is a "current GC"; calls
labelled "cgc" use that to determine appropriate properties.

A graphics context is specified using a GC description block. This is a block
of memory in the client laid out as follows:
  Offset 0 (byte): graphics mode (0=set, 1=clear, 2=invert)
  Offset 1 (byte): text mode (0=set, 1=clear, 2=invert, 4=copy with background)
  Offset 2 (byte): text style
    Bit 0: bold
    Bit 1: underline
    Bit 2: inverse
    Bit 3: double height
    Bit 4: monospaced
    Bit 5: italic
    Bit 6: subscript   (v4 only, and only with appropriate font groups)
    Bit 7: superscript (v4 only, and only with appropriate font groups)
  Offset 3 (byte): additional graphics options (v4 only)
    Bits 0 and 1: 0 = black plane, 1 = grey plane, 2 = both planes
    Bit 2:        set = double pixel mode, clear = normal
  Offset 4 (word): font or font group
Wherever a font is required, one of the ROM-based fonts beginning at $4000
can be used. The value $4099 always means the system font.

GC description blocks are normally provided in association with a GC selector
mask. This is a word which is used to determine which values are taken from
the description block, as follows:
  Bit 1: graphics mode
  Bit 2: text mode
  Bit 3: text style
  Bit 4: font
  Bit 5: bits 0 and 1 of additional graphics options (v4 only)
  Bit 6: bit 2 of additional graphics options (v4 only)
When creating a new GC, values not taken from the description block are set
to zero, except the font which is set to the system font.


Events
------

An event is a message sent from the window server to a client to inform it that
something has happened that is not directly related to a function call; for
example, that a key has been pressed when the client is the foreground client.
The event is between 2 and @@ bytes long depending on its type. Offset 0 is
always a word giving the event type.


In many types of event the words at offsets 2 and 4 have a standard meaning.
* "window handle" (offset 2) - this is the value passed to wCreateWindow. It
  is not the same as the window identifier, and is commonly set to the address
  of a structure including the latter.
* "connection handle" (offset 2) - @@@ the value specified to wConnect
* "tick count" (offset 4) - the window server maintains this value, which it
  increments every tick (1/32 second).


Type 1 - WM_KEY
  Offset  0 (word): type, set to 1
  Offset  2 (word): connection handle
  Offset  4 (word): tick count
  Offset  6 (word): keycode
  Offset  8 (byte): keyboard modifiers and mouse state
  Offset  9 (byte): unused
  Offset 10 (word): repeat count
Sent when a key is pressed and the client is the one connected to the keyboard
(usually because it owns the frontmost foreground window). The keycode is
defined by the key and modifiers. For example, the 'A' key will generate:
    $0061  alone
    $0041  if shift is pressed or caps lock is on
    $0001  if control is pressed
    $0261  if Psion or alt is pressed
The window server will handle control-plus-number combinations and generate a
single event. @@@@ special cases
The modifiers are:
  Bit 1: shift key pressed
  Bit 2: control key pressed
  Bit 3: Psion or alt key pressed
  Bit 4: caps lock is on
  Bit 5: num lock is on
  Bit 7: mouse button down
The repeat count is 1 for a single key press. If a key is held down and is
autorepeating faster than the client accepts new events, the repeat count will
be set to the number of repeats since the last key event.


Type 2 - WM_MOUSE
  Offset  0 (word): type, set to 2
  Offset  2 (word): window handle
  Offset  4 (word): tick count
  Offset  6 (byte): 1=release, 2=press, 3=motion
  Offset  7 (byte): keyboard modifiers and mouse state
  Offset  8 (word): mouse position x coordinate
  Offset 10 (word): mouse position y coordinate
Sent when the mouse button is pressed or released, or the mouse moves and
the appropriate window has requested motion events. The modifiers are as for
WM_KEY, plus:
  Bit 6: mouse position is outside the visible portion of the window
This can happen through grabs and mouse capture.


Type 3 - WM_REDRAW
  Offset  0 (word): type, set to 3
  Offset  2 (word): window handle
  Offset  4 (word): tick count
  Offset  6 (word): left edge
  Offset  8 (word): top edge
  Offset 10 (word): @@@ right edge or width or what ?
  Offset 12 (word): @@@ bottom edge or height or what ?
Sent when no other events (except WM_USER_MSG) are pending and a window has
an area that needs redrawing (an "update region"). The rectangle describes 
some portion (possibly all) of the update region.


Type 5 - WM_BACKGROUND
  Offset 0 (word): type, set to 5
Sent to a client in the foreground when it moves to the background.


Type 6 - WM_FOREGROUND
  Offset 0 (word): type, set to 6
Sent to a client in the background when it moves to the foreground.


Type 7 - WM_RUBBER
  Offset 0 (word): type, set to 7
  Offset 2 (word): window handle
  Offset 4 (word): tick count
  Offset 6 (word): final status
  Offset 8 to  15: standard rectangle structure giving the final size
The final status can be:
  0 = the final rectangle is the same as the initial one
  1 = the rubber band moved but was not resized
  2 = the rubber band was resized
  3 = the rubber band was cancelled; the rectangle is undefined
  4 = the rubber band was not displayed because the parameters were wrong


Type 8 - WM_USER_MSG
  Offset 0 (word): type, set to 8
Sent to a client following a call to wUserMsg if no other events are pending
(and so can be used to check that condition).


Type 9 - WM_ACTIVE
  Offset 0 (word): type, set to 9
@@@@


Type 11 - WM_CANCELLED
  Offset 0 (word): type, set to 11
Sent to a client following a call to wCancelGetEvent.


Type 12 - WM_KEYBOARD_STATE_CHANGE
Sent to the system shell only.


Type 13 - WM_RUBBER_BAND_INIT
  Offset  0 (word): type, set to 13
  Offset  2 (word): window handle
  Offset  4 (word): tick count
  Offset  6 (byte): set to 2
  Offset  7 (byte): keyboard modifiers and mouse state
  Offset  8 (word): mouse position x coordinate
  Offset 10 (word): mouse position y coordinate
Sent to a client on a button press when the window is configured so that
pressing a mouse button starts rubber banding. The window server will suspend
all mouse and keyboard processing for all clients until this client calls
wRubberBand. If rubber banding is not desired, the cancel flag can be used in
the call.


Type 14 - WM_DEICONISE
  Offset 0 (word): type, set to 14
Sent to an iconised client when it moves to the foreground.


Type 15 - WM_ATTACHED
  Offset 0 (word): type, set to 15
  Offset 2 (word): @@@@
  Offset 4 (word): tick count
  Offset 6 (word): attached client
Sent to a client when another client has attached itself on top. Note that
the notifer process attaches itself to a client when that client uses the
p_notify@@@ system call.


Type 16 - WM_DETACHED
  Offset 0 (word): type, set to 16
  @@@@
Sent to a client when a previously attached client detaches itself.


Type 17 - WM_COMMAND v3.5
  Offset 0 (word): type, set to 17
Sent to a client that is the target of a wSendCommand call, and indicates that
wGetCommand should be called.


Type 18 - WM_TASK_KEY Series 3 only
  Offset  0 (word): type, set to 18
  Offset  2 (word): connection handle
  Offset  4 (word): tick count
  Offset  6 (word): application key code @@@
  Offset  8 (word): modifiers ? @@@
  Offset 10 (word): repeat count ? @@@
@@@@


Type 19 - WM_TASK_UPDATE v3.5
  Offset 0 (word): type, set to 19
Sent to the shell process if any process terminates, whether or not a client
of the window server.


Type 20 - WM_ON v3.5
  Offset 0 (word): type, set to 20
Sent to a client when the machine is switched on and the client has either
called wInformOnAll, or has called wInformOn and is in the foreground.


Type 21 - WM_ESCAPE
  Offset 0 (word): type, set to 21
  @@@@
Sent on if key events are not selected using wGetEventSpecial. The event is
sent when the ESC key is pressed; all pending keystrokes are thrown away.


Type 22 - WM_DATE_CHANGED v4
  Offset 0 (word): type, set to 22
Sent to any client which is not in Series 3t compatibility mode and is in the
foreground, whenever either the date changes, or the machine is switched on
on a different date to when it was switched off.


System calls
------------

Fn $8D Sub $00
wEndRedraw
Ends redrawing, as started by wBeginRedrawWin or related calls.


Fn $8D Sub $01
wEraseTextCursor
Makes the text cursor invisible.


Fn $8D Sub $02
wReleaseMouse
Cancels any call to wCaptureMouse.


Fn $8D Sub $03
gFreeTempGC
Destroys the temporary graphics context, and makes the remembered current
graphics context be current again.


Fn $8D Sub $04
wCancel
@@@


Fn $8D Sub $85
wDisconnect
@@@


Fn $8D Sub $06
wDetachClient
Detaches the client from any process it is attached to (see wAttachToClient)
and moves it to the back.


Fn $8D Sub $07
wCleanUp
Returns the window server to a standard state. This frees any temporary
graphics context, ends any redraws taking place, and invalidates any
window that has an attached graphics context.


Fn $8D Sub $08
wAttachToForegroundClient
Attaches the client to the current foreground client, if different. See
wAttachToClient for details.


Fn $8D Sub $09
wUserMsg
Instructs the window server to send the client a WM_USER_MSG event when there
are no other events to deliver. Only one such event can be pending for a
client.


Fn $8D Sub $8A
wStartCompute
Inform the window server that the client is about to start intensive
computation, and its priority should be set to 112 (background) even if
it is in the foreground. Ignored if the client has not selected server-
controlled priority handling (see wSetPriorityControl).


Fn $8D Sub $8B
wEndCompute
Cancel the effect of wStartCompute; if the client is in the foreground, 
sets its priority back to 128 (foreground). Ignored if the client has
not selected server-controlled priority handling.


Fn $8D Sub $8C
wClientInfo fails
    AX: -> information about the process
    BX: process to be checked
Returns information about a process:
  Bit 0: set if the process is connected the window server
  Bit 1: returns the setting specified at connection time
  Bit 2: the client is system modal
  Bit 7: server-controlled priority handing is active
If the process is not a client of the window server, the call may return zero
or may fail.


Fn $8D Sub $0D
wCloseWindowTree
    BX: window
Destroys the window and all its descendants.


Fn $8D Sub $8E
wInquireWindow
    BX: window
    SI: address of 14 byte information block (see wCreateWindow)
The first 10 bytes of the block are set to the flags, position, and size of
the specified window. The last 4 bytes of the block are set to unspecified
values.


Fn $8D Sub $0F
wCaptureMouse
    BX: window
Captures the mouse within the window and its descendants. It will cancel any
active capture in another window.


Fn $8D Sub $10
wBeginRedrawWin
    BX: window
Validate the window for redrawing. Validation causes all pixels to be set or
cleared if the background mode is 1 or 2 (this applies to black and grey
separately), and all future drawing is clipped to the update region (which
is set to the entire window in this case). Normal drawing resumes when
wEndRedraw is called.


Fn $8D Sub $11
wFree
    BX: identifier
Destroy an object and free all the related resources. The identifier can be
any of:
  * bitmap file handle
  * bitmap identifier (will also destroy any associated graphics context)
  * bitmap sequence identifier
  * clock identifier
  * font identifier
  * graphics context
  * mouse icon identifier
  * sprite identifier


Fn $8D Sub $12
wMakeInvisible
    BX: window
The window is marked as invisible; a window will not appear on the screen if
it or any of its ancestors is invisible.


Fn $8D Sub $93
wAttachtoClient fails
    BX: process to attach to
Attaches the current process to the specified one. This will cause its
windows to stay just in front of those of the client it is attached to.
Applies only on large screen servers.


Fn $8D Sub $14
wInitialiseWindowTree
    BX: window
The specified window and its descendants are initialized. This may only be
done once for any given window, and must be done before it is first drawn on.


Fn $8D Sub $15
wInvalidateWin
    BX: window
Add the entire window to its own update region. This will cause a redraw
event, which can be used to trigger redrawing of the window.


Fn $8D Sub $16
wValidateWin
    BX: window
Validate the window (causing all pixels to be set or cleared if the background
mode is 1 or 2 - this applies to black and grey separately), and the update
region is deleted.


Fn $8D Sub $17
wMakeVisible
    BX: window
Cancels wMakeInvisible on the window.


Fn $8D Sub $18
wClientIconised
    BX: action (0 = deiconise, 1 = iconise)
Iconises or deiconises the current process. Iconisation only works on large
screen systems.


Fn $8D Sub $19
wClientPosition
    BX: position
    CX: process ID
Move the specified process (zero means the current process) to the given
position in the window server task list. Position 0 is the front of the
list; any position greater than or equal to the number of processes attached
to the window server puts the process at the very back of the list.


Fn $8D Sub $9A
wInquireWindowOffset fails
    BX: window A (0 = screen)
    CX: window B
    SI: address of a 4 byte buffer
The buffer is filled in with the position of window B relative to window A:
  Offset 0 (word): x offset
  Offset 2 (word): y offset


Fn $8D Sub $1B
wWindowPosition
    BX: window
    CX: position (0 = front)
Moves the window to the specified position within the sibling list (the list
of windows with the same parent).


Fn $8D Sub $1C
wScrollRect
    BX: window
    CX: address of a standard rectangle structure
    DX: address of offset structure
The pixels defined by the rectangle are copied to a new rectangle offset by
the indicated distance. The offset structure is:
  Offset 0 (word): x offset of new rectangle
  Offset 2 (word): y offset of new rectangle
Copying does not go outside the window, and does not appear in areas obscured
by other windows or in "invalid" areas waiting for update.


Fn $8D Sub $1D
wRubberBand
    BX: window to be sent the WM_RUBBER event
    CX: window limiting the rubber band (0 = whole screen)
    DX: address of an information block
Starts rubber banding, with the rubber band limited to the specified window
or allowed to roam over the screen. When the user completes the rubber banding,
a WM_RUBBER event is sent to the window given. The information block is:
  Offset  0 to   7: standard rectangle structure giving the initial rectangle
  Offset  8 to  15: standard rectangle structure giving the inner bounds
  Offset 16 to  23: standard rectangle structure giving the outer bounds
  Offset 24 (word): flags
  Offset 26 (word): minimum width
  Offset 28 (word): minimum height
  Offset 30 (word): maximum width
  Offset 32 (word): maximum height
  Offset 34 (word): x grid snap value
  Offset 36 (word): y grid snap value
@@@@@@@@
A window can be set so that pressing a mouse button starts rubber banding. In
this case, the press event is sent as a WM_RUBBER_BAND_INIT event instead. The
client must call wRubberBand (use the @@@@@@ flag to cancel rubber banding if
necessary).


Fn $8D Sub $1E
gCopyRect cgc
    BX: standard rectangle structure
    CX: address of point definition block
    DX: mode (see gFillPattern)
Copies a rectangular block from one part of a bitmap to another (the current
graphics context should refer to a bitmap). The top left corner of the
rectangle is copied to the point given by the definition block:
  Offset 0 (word): x
  Offset 2 (word): y


Fn $8D Sub $9F
gPeekBit
    BX: bitmap identifier, window identifier, or zero (see gSaveBit)
    CX: address of point definition block
    DX: number of pixels
    SI: address of buffer
Copies a horizontal row of pixels into the buffer. The point definition block
gives the first pixel to be copied:
  Offset 0 (word): x
  Offset 2 (word): y
The pixels are packed 8 per byte of the buffer, in LSB-first order ?@@@@@@
In version 4, the grey plane can be used by setting bit 15 of BX.


Fn $8D Sub $20
gDrawPolyLine cgc
    BX: x coordinate of start point
    CX: y coordinate of start point
    DX: address of poly-line control block
Draws a sequence of lines according to the control block, which has the
format:
  Offset     0 (word): number of line segments (N)
  Offsets    2 to   5: line segment 1 control block
  Offsets    6 to   9: line segment 2 control block
  ...
where the block is 4N+2 bytes long. The control block for segment M has the
format:
  Offset 4M-2 (word): 2 times x offset, plus 0 for draw or 1 for don't draw
  Offset 4M   (word): y offset
Each control block causes a line to be drawn, or not drawn, from the previous
end point (or the start point, for the first control block) to a new point
specified as a relative offset. In version 2 of the window server there is a
limit of 61 control blocks.


Fn $8D Sub $21
gFillPattern cgc
    BX: standard rectangle structure
    CX: bitmap ($4000 = chequered 1 and 0 pixels)
    DX: mode
Fills the specified rectangle with copies of the bitmap. The mode can be:
    0 = set each pixel where the bitmap has a 1 pixel
    1 = clear each pixel where the bitmap has a 1 pixel
    2 = invert each pixel where the bitmap has a 1 pixel
    4 = copy the bitmap to the rectangle
In version 3 and above, CX can also be a window with black plane redraw
method 3, indicating that the backup bitmap of that window is to be used. In
version 4, if both planes have redraw method 3, the appropriate plane is used
for each selected plane in the target window or bitmap.


Fn $8D Sub $22
gCreateTempGC
    BX: window or bitmap
    CX: GC selector mask
    DX: GC description block
Creates a new temporary graphics context associated with the window or bitmap,
and makes it the current GC. The previous current GC is remembered. While a
temporary graphics context exists, the following calls are forbidden:
    gCreateGC
    gCreateTempGC
    gSetGC (unless modifying the temporary graphics context)
    wBeginRedrawGC
    wBeginRedrawWinGC
    wFree for any graphics context


Fn $8D Sub $A3
gCreateGC fails
    AX: -> graphics context identifier
    BX: window or bitmap
    CX: GC selector mask
    DX: GC description block
Creates a new graphics context associated with the window or bitmap, and makes
it the current GC.


Fn $8D Sub $24
gSetGC
    BX: graphics context (for v3 and above, 0=current GC)
    CX: GC selector mask
    DX: GC description block
Makes the specified graphics context current, and modifies those properties
specified in the selector mask.


Fn $8D Sub $25
wSetWindow
    BX: window to change
    CX: flags
    DX: address of a block of information about the window
Changes various properties of a window. The flags are as follows:
  Bits 2 to 6, 8, and 10: set the indicated property to the corresponding bit
    of the flags within the information block
  Bit 12: if set, move and resize the window
  Bit 13: if set, change the pointer symbol
  Bit 14: if set, change the background method
New values are taken from the information block, which is as for wCreateWindow.


Fn $8D Sub $26
wBeginRedrawWinGC
    BX: window
    CX: @@@@
    DX: GC selector mask
    DI: address of a GC description block
Validate the window for redrawing (see wBeginRedrawWin) but using a temporary
graphics context which will be destroyed by wEndRedraw.


Fn $8D Sub $27
gDrawLine cgc
    BX: x coordinate of first end
    CX: y coordinate of first end
    DX: x coordinate of second end
    DI: y coordinate of second end
Draws a line between the two locations. If horizontal or vertical, the line
includes the end with the lower coordinates. If diagonal, the line includes
all pixels intersected by the diagonal of a rectangle including the top and
left edges but not the bottom and right edges. Note that, in all cases, the
order of the two ends does not affect the line drawn.


Fn $8D Sub $28
gPrintText cgc
    BX: x coordinate of starting point
    CX: y coordinate of baseline
    DX: (text) string
    DI: length of string (maximum 246)
Prints the string at the indicated location. Characters not found in the font
will be treated as if they were the highest character code.


Fn $8D Sub $29
gCopyBit cgc
    BX: address of point definition block
    CX: bitmap identifier or window identifier
    DX: standard rectangle structure
    DI: mode (see gFillPattern)
Copies a rectangular block from a bitmap or a backed-up window (see gSaveBit).
The top left corner of the rectangle is copied to the point given by the
definition block:
  Offset 0 (word): x
  Offset 2 (word): y
The function cannot copy from a bitmap to itself. If the destination is in
grey plane mode, the grey plane of the source is used if there is one. If the
destination is in both planes mode, a single plane source is copied to both
planes, and a double plane source has each plane copied to the corresponding
plane.


Fn $8D Sub $AA
wCreateWindow fails
    AX: -> new window identifier
    BX: parent window (0 = parent is the entire screen)
    CX: flags
    DX: address of a block of information about the window
    DI: handle for the new window (must not be zero)
Creates a new window which is a child of the specified window, and gives it
the indicated id and handle (note that the two are not the same, and the former
is used in other calls except where explicitly stated otherwise). The window
cannot be drawn to until wInitialiseWindowTree has initialised it. The flags
are:
  Bits 0 to 11: if set, use the corresponding bit from the flags word of the
                information block; if clear, bits 1, 2, 7, 8, and 9 are
                cleared, the remainder are inherited from the parent window.
  Bit 12: set = use coordinates and size, clear = covers entire parent
  Bit 13: set = use pointer symbol in information block, clear = use parent's
  Bit 14: set = new background method, clear = same method as parent
The information block contains the following:
  Offset  0 (word): flags
    Bit  0: this window is input-only (and therefore invisible)
    Bit  1: pressing a mouse button starts rubber-banding (see wRubberBand)
    Bit  2: ignore the mouse when it is within this window
    Bit  3: send mouse events when the mouse button is up
    Bit  4: send mouse events when the mouse button is down
    Bit  5: grab the mouse when its button is pressed
    Bit  6: draw in double pixel mode (v4 only)
    Bit  7: visible only when client is in foreground (large screen only)
    Bit  8: send redraw events to windows with this bit set bfore those with
            it clear
    Bit  9: do not send redraw events
    Bit 10: activate the window if it receives a mouse click
    Bit 11: rubber banding will terminate when the mouse button is released
  Offset  2 (word): x coordinate within parent
  Offset  4 (word): y coordinate within parent
  Offset  6 (word): width
  Offset  8 (word): height
  Offset 10 (word): identifier of the pointer symbol, where relevant
  Offset 12 (byte): background redraw method
    Bits 0 and 1: black plane method (0 = do nothing, 1 = set pixels,
                  2 = clear pixels, 3 = keep an off-screen bitmap)
    Bit 3: if set, attempts to draw on the black plane are ignored (v4 only)
    Bits 4 and 5: grey plane method (0 = do nothing, 1 = set pixels,
                  2 = clear pixels, 3 = keep an off-screen bitmap)
    Bit 7: if clear, attempts to draw on the grey plane are ignored
The choice of keeping an off-screen bitmap cannot be changed after the window
has been created, while the other options can be changed using wSetWindow.


Fn $8D Sub $2B
wBeginRedrawGC
    BX: window
    CX: address of a standard rectangle structure
    DX: graphics context fields to be set
    DI: address of a graphics context information block
Validate the window for redrawing (see wBeginRedrawWin) with the update region
set to the indicated rectangle and using a temporary graphics context which
will be destroyed by wEndRedraw (see wBeginRedrawWinGC).


Fn $8D Sub $AC
gPrintClipText cgc
    AX: -> number of characters printed
    BX: x coordinate of starting point
    CX: y coordinate of baseline
    DX: (text) string
    DI: length of string (maximum 244)
    SI: maximum number of pixels
Prints the string at the indicated location as gPrintText, but only enough
characters are printed to fit within the specified number of pixels.


Fn $8D Sub $2D
gPrintBoxText cgc
    BX: address of a standard rectangle structure
    SI: distance from top of rectangle to baseline
    AX: alignment (1=right, 2=left, 4=centre)
    CX: margin
    DX: (text) string
    DI: length of string (maximum 236)
Clears the specified rectangle, then prints the string within it using text
mode 0 (set pixels). The text is clipped to fit within the rectangle. The
string is printed in the part of the rectangle excluding a margin area, whose
position depends on the alignment:
  left or right: CX must be >= 0, margin is on the same side, width is CX
  centre and CX >= 0: margin is on the left, width is CX
  centre and CX <  0: margin is on the right, width is -CX


Fn $8D Sub $AE
gOpenBit fails
    AX: -> bitmap identifier
    BX: (cstr) filename
    CX: bitmap number (0 = first or only)
    DX: flags
    SI: address of an information block
Loads a specified bitmap from a file. The flags are:
  Bit 0: set for a writeable bitmap, clear for a shared read-only bitmap
  Bit 1: place the bitmap in a separate memory segment
  Bit 2: write the segment name in the information block
  Bit 3: must be clear
The information block is written to as follows:
  Offset 0 (word): set to the width of the bitmap
  Offset 2 (word): set to the height of the bitmap
  Offset 4 to  17: set to the segment name (cstr), only if flag bit 2 is set


Fn $8D Sub $AF
gOpenMouseIcon fails
    AX: -> mouse icon identifier
    BX: (cstr) file name
    CX: number of icon within file
Loads a specified mouse icon from a file.


Fn $8D Sub $B0
gOpenFont fails
    AX: -> font identifier
    BX: (cstr) filename
Opens the specified font file.


Fn $8D Sub $31
gDrawBox cgc
    BX: address of a standard rectangle structure
Draws a box of the appropriate size. Note that a box with width and height of
3 will have exactly one empty pixel inside it.


Fn $8D Sub $B2
wLoadDYL fails
    AX: -> dyl identifier
    BX: (cstr) DYL segment name
Load a DYL into the window server. The DYL must already have been loaded into
memory with @@@@@@@


Fn $8D Sub $B3
gCreateBit fails
    AX: -> bitmap identifier
    @@: flags
    @@: address of an information block
Creates an uninitialized writeable bitmap. The flags are:
  Bit 0: must be clear
  Bit 1: place the bitmap in a separate memory segment
  Bit 2: write the segment name in the information block
  Bit 3: make the bitmap zero-sized
If the bitmap is zero-sized, nothing can be written to it; the size can be
increased later. The information block is:
  Offset 0 (word): width
  Offset 2 (word): height
  Offset 4 to  17: set to the segment name (cstr), only if flag bit 2 is set


Fn $8D Sub $34
wScrollWin
    BX: window or bitmap
    CX: address of offset structure
Identical to wScrollRect with the rectangle structure set to (0, 0, width,
height).


Fn $8D Sub $35
wDrawTextCursor
    BX: window
    CX: address of text cursor information
As wTextCursor, but the properties byte is ignored and treated as zero.


Fn $8D Sub $36
wInvalidateRect
    BX: window
    CX: address of a standard rectangle structure
Add the rectangle to the update region of the window. This will generate a
redraw event if necessary.


Fn $8D Sub $37
wBeginRedraw
    BX: window
    CX: address of a standard rectangle structure
Validate the window for redrawing (see wBeginRedrawWin) with the update region
set to the rectangle.


Fn $8D Sub $38
wValidateRect
    BX: window
    CX: address of a standard rectangle structure
Validate the indicated rectangle of the window (causing all pixels to be set
or cleared if the background mode is 1 or 2 - this applies to black and grey
separately), and remove that rectangle from the update region of the window.


Fn $8D Sub $B9
gSaveBit fails
    BX: (cstr) filename
    CX: bitmap identifier, window identifier, or zero
Writes a bitmap to the named file. A window identifier must be for a window
with a background redraw method of 3, in which case its off-screen bitmap is
used. Zero for the bitmap causes the entire screen to be saved. If the window
off-screen bitmap, or the screen, has a grey plane then a double-plane bitmap
is written.


Fn $8D Sub $3A
gClrRect cgc
    BX: standard rectangle structure
    CX: 0=set, 1=clear, 2=invert
Sets, clears, or inverts all pixels in the specified rectangle.


Fn $8D Sub $3B
wCallDYL
    BX: dyl identifier
    CX: function number
    DX: number of bytes of data to be passed
    DI: address of data to be passed
Call a function in a DYL loaded into the window server that has no result.


Fn $8D Sub $BC
wCallDYLreply fails
    AX: -> result
    BX: dyl identifier
    CX: function number
    DX: number of bytes of data to be passed
    DI: address of data to be passed
    SI: address of area to store a result in
Call a function in a DYL loaded into the window server that has a result. The
main result is returned in AX (a negative value is a failure), and other data
(depending on the function) may be written into the area pointed to by SI.


Fn $8D Sub $BD
wSetWinBitmap fails
    AX: -> sequence identifier
    BX: window
    CX: number of bitmaps (1 to 12)
    DX: address of a sequence of information blocks
Attaches an animated sequence of bitmaps to the background of a window. Each
time the background changes the client will be sent a redraw event unless an
appropriate background mode has been selected. There must be an information
block for each bitmap in the sequence; the blocks are immediately adjacent
in memory. Each block has the form:
  Offset  0 (word): bitmap identifier
  Offset  2 (word): x coordinate of location in the window to display bitmap
  Offset  4 (word): y coordinate of location in the window to display bitmap
  Offsets 6 to  13: standard rectangle structure giving the part of the bitmap
                    to be displayed
  Offset 14 (byte): graphics mode used to copy bitmap
                    (0=set, 1=clear, 2=invert, 4=copy with background)
  Offset 15 (byte): plane to write to (0=white, 128=grey) (v4 only)
  Offset 16 (long): delay in 0.1 seconds before next bitmap is shown


Fn $8D Sub $3E
wChangeWinBitmap
    BX: bitmap sequence identifier
    CX: position of bitmap (0 to 11)
    DX: address of an information block
Replace the appropriate bitmap in a sequence (see wSetWinBitmap) with the new
information in the block.


Fn $8D Sub $BF
wEscapeon
@@@


Fn $8D Sub $40
@@@ RConnect


Fn $8D Sub $C1
wEscapeoff
@@@


Fn $8D Sub $C2
wGetWindowPosition v3 @@@@ ???? [ was = GetPosition] fails
    AX: -> position
    BX: window
Returns the position of the window in its sibling list (the windows with the
same parent). Has the side effects of wCheckPoint.


Fn $8D Sub $C3
gSaveRect fails
    BX: (cstr) filename
    CX: bitmap identifier, window identifier, or zero
    DX: standard rectangle structure
Saves a rectangle from a bitmap, backed-up window, or the screen (see
gSaveBit for details).


Fn $8D Sub $44
wReassignRootWindow v3
    BX: window (0 = screen)
All future calls within this client will treat the specified window as it it
were the whole screen (e.g. this window will be the parent for those whose
parent is specified as 0).


Fn $8D Sub $C5
wCaptureKey v3 fails
    BX: keycode
    CX: modifier state
    DX: modifier mask
Captures certain key combinations; from now on, these key presses will be sent
to this client whether or not it is in the foreground. The key combinations
captured are those that will generate the specified keycode, and for which
those modifiers given in DX have the value given in CX (all other bits in
CX must be clear). For example, to only depend on the settings of shift and
control:
  shift  control     CX       DX
   up       up        0        6
   up      down       4        6
   up     either      0        2
  down      up        2        6
  down     down       6        6
  down    either      2        2
 either     up        0        4
 either    down       4        4
 either   either      0        0   (if CX is not 0, nothing is captured)
However, it should be borne in mind that most modifier combinations affect
the keycode as well. The call fails if the same combination is already
captured; if two different combinations capture the same key, the client that
made the earlier request receives the event.


Fn $8D Sub $C6
wCancelCaptureKey v3 fails
    BX: keycode
    CX: modifier state
    DX: modifier mask
Cancels a call to wCaptureKey with identical arguments. The call fails if the
client has not captured this combination.


Fn $8D Sub $47
wSystemModal v3
    BX: position in task list (0 = front)
Makes the current client system modal and sets its position in the task list.
Task switching only applies to clients that are in front of the frontmost
system modal task.


Fn $8D Sub $48
wCancelSystemModal v3
    BX: position in task list (0 = front)
Cancels a call to wSystemModal and re-positions the client.


Fn $8D Sub $49
gBorder v3 cgc
    BX: border type
Draws a border just inside the window or bitmap of the current graphics
context. The border type is:
  Bit  0: if set, draw the border 1 pixel from the edge
  Bit  1: set for 4 pixel corner, clear for 1 or 2 pixel corner
  Bits 2 to 4: allowance for shadow
    0 = no shadow
    1 = remove (but leave space for) single width shadow
    2 = remove (but leave space for) double width shadow
    5 = draw single width shadow
    6 = draw double width shadow
  Bit  5: set for special top-of-menu border
  Bit  6: set for 1 pixel corner, clear for 2 or 4 pixel corner
  Bit  7: remove any arrow at top right, and repair the border
  Bit  8: remove any arrow at bottom right, and repair the border
  Bit  9: include an arrow at top right
  Bit 10: include an arrow at bottom right


Fn $8D Sub $4A
gBorderRect v3 cgc
    BX: standard rectangle structure
    CX: border type
Draws a border just inside the indicated rectangle. The border type is as for
gBorder.


Fn $8D Sub $4B
gXPrintText v3 cgc
    BX: x coordinate of starting point
    CX: y coordinate of baseline
    DX: (text) string
    DI: length of string (maximum 244)
    SI: embellishments
Prints the text, as gPrintText in mode 4 (copy with background), but with
embellishments:
     0 = none
     1 = inverted
     2 = inverted except the four corners
     4 = underlined
     8 = inverted and no descenders
     9 = inverted except the four corners, and no descenders
    12 = underlined and no descenders
Embellishments with "no descenders" stop on the row below the baseline, on the
assumption that no characters in the string descend below that point.


Fn $8D Sub $4C
gInvObloid v3 cgc
    BX: address of information block
Inverts all the pixels, except the four corner pixels, of the rectangle
specified by the block:
  Offset 0 (word): left edge
  Offset 2 (word): top edge
  Offset 4 (word): width
  Offset 6 (word): height


Fn $8D Sub $4D
wEnablePauseKey v3
Allows the program to be paused by the user by pressing CTRL-S; this is
initially turned on. When paused, the window server will not process any
requests from the client (they will be held until the pause is released
by pressing any key).


Fn $8D Sub $CE
wDisablePauseKey v3
Disallow the program from being paused by the use of CTRL-S.


Fn $8D Sub $4F
wsEnable
Turns on the permanent status window. This lies behind any other windows of
this client and so, to be seen, all overlaying windows must be resized or
moved.


Fn $8D Sub $50
wsDisable
Turns off the permanent status window.


Fn $8D Sub $51
wInformOn v3.5
Instructs the window server to send WM_ON events when the client is in the
foreground.


Fn $8D Sub $52
wsUpdate
    BX: reason (1 = name, 2 = time)
Updates the contents of the status window to reflect a change elsewhere.
A reason of "name" means that the process name has changed; a reason of
"time" indicates that the clock format has changed.


Fn $8D Sub $D3
wsCreateClock fails
    AX: -> clock identifier
    BX: window
    CX: flags
    DX: x coordinate
    SI: difference in minutes between clock and system time @@@
    DI: y coordinate
Creates a clock. See wsCreateClock2, which includes all the functionality of
this call together with additional features.


Fn $8D Sub $54
wsSetClock
    BX: clock identifier
    CX: difference in minutes between clock and system time
Changes the difference between clock and system time for a clock.


Fn $8D Sub $D5
wSetBusyMsg
   eBX: (cstr) text to be displayed
    CX: location and delay:
      Bits 0-5: delay in half seconds before displaying
      Bit  6:   0 = top, 1 = bottom
      Bit  7:   0 = left, 1 = right
Waits for the required time (during which another call can cancel the
previous request) and then displays the text, flashing, in the indicated
corner; the text remains until replaced or cancelled (by an empty
string). Equivalent to the BUSY keyword. The text is limited to 20 characters.


Fn $8D Sub $56
wsDisableTemp
Disable the display of a temporary status window via the PSION-MENU keypress.
This is a system-wide setting and is initially on.


Fn $8D Sub $57
wsEnableTemp
Enable the display of a temporary status window via the PSION-MENU keypress.
This is a system-wide setting and is initially on.


Fn $8D Sub $D8
wSystem
    BX: settings to be changed
    CX: new values for settings
Changes settings within the window server (thus affecting all clients). For
each bit that is set in BX, the property is set to the corresponding bit in
CX. The meanings of the bits are:
  Bit @: do not restart the shell (SYS$SHLL) when the window server terminates
  Bit @: do not restart the notifier (SYS$NTFY) when the window server
         terminates (v4 only)
  Bit @: attempt to become the notifier process [H4]
  Bit @: if the window server is also the notifier, do not report processes
         which terminate abnormally
  Bit @: send task update events to the shell when any process terminates [H4]
  Bit @: test battery and display low battery warnings if necessary each time
         the machine is switched on [H4]
  Bit @: report clients that are failing to respond to events [H4]
  Bit @: disable low battery indicator in the status window [v4]
  Bit @: disable SSD indicators in the status window [v4]
  Bit @: disable link indicator in the status window [v4]
  Bit @: disable caps lock indicator in the status window [v4]
Those bits marked [H4] apply only to HC machines and version 4 of the server;
Series 3t machines will act as if the bit is always set. Those marked [v4]
apply only in version 4. The initial values of all settings are taken from
the $WS_FL environment variable.


Fn $8D Sub $D9
wGetProcessList v3.5
    SI: address of a 44 byte buffer
The buffer is filled with a list of all the processes connected to the window
server; the list is in front-to-back order, and is terminated by a zero word.


Fn $8D Sub $DA
wSendCommand v3.5 fails
    BX: process
    CX: address of the first byte of the data
    DX: number of bytes of data (1 to 127)
Sends command data to the specified process. The process will receive a
WM_COMMAND event, and should then call wGetCommand.


Fn $8D Sub $DB
wGetCommand v3.5 fails
    SI: address of a 127 byte buffer
Reads the last command data sent by wSendCommand into the buffer. Only one
pending command is held.


Fn $8D Sub $5C
wTextCursor
    BX: window
    CX: address of text cursor information
Make the text cursor visible if it is not, and move it to the window and
location given. The information is:
  Offset 0 (word): x coordinate of baseline
  Offset 2 (word): y coordinate of left edge
  Offset 4 (byte): height of cursor
  Offset 5 (byte): distance from baseline to top of cursor
  Offset 6 (byte): width
  Offset 7 (byte): properties (v4 only)
    Bit 0: clear=rectangle, set=rounded
    Bit 1: clear=flashing, set=steady
    Bit 2: clear=black, set=grey
The distance from baseline to cursor top is 2's complement signed. That is,
0 means the top is the baseline, 1 means it is the pixel above, 255 means the
pixel below, and so on.


Fn $8D Sub $DD
wAppKeyHandler
@@@


Fn $8D Sub $DE
wInfoMsgCorner
   eBX: (cstr) text to be displayed
    CX: location:
      Bit 6: 0 = top, 1 = bottom
      Bit 7: 0 = left, 1 = right
Displays the text in the indicated corner for 2 to 2.5 seconds; an empty
string clears any existing text. Equivalent to the GIPRINT keyword. The text
is limited to 64 characters.


gSetOpenAddress
Fn $8D Sub $5F
    BX: 0=cancel, 1=direct, 2=indirect long, 3=indirect word
    CX: file offset low  word ??? it's declared as ULONG
    DX: file offset high word ??? it's declared as ULONG
Modifies the next call to any of:
    gInitBit
    gOpenBit
    gOpenFont
    gOpenFontIndex
    gOpenMouseIcon
to change the place within the file that reading starts; this is used where
the font, bitmap, or icon file is embedded in another file. The meaning of BX
is:
    0: equivalent to BX=1, CX=0, DX=0
    1: DX/CX is the starting position within the file
    2: DX/CX is the position within the file of a long giving the start point
    3: DX/CX is the position within the file of a word giving the start point


Fn $8D Sub $60
wDrawButton cgc
    BX: standard rectangle structure
    CX: (cstr) string in button (maximum length 240)
    DX: button state (0 = normal, 1 = pressed)
Draws a button containing a string.


Fn $8D Sub $E1
wSetTaskKey v3.5 fails
    BX: keycode
    CX: modifier state
    DX: modifier mask
Causes the relevant keypresses (see wCaptureKey) to be treated as the "task
key". The task key causes the current foreground task to be moved to the back
of the list. There can be any number of task keys. On the HC and MC, the TASK
key is preassigned as a task key; on the Series 3 SHIFT-SYSTEM is assigned by
the shell process.


Fn $8D Sub $E2
wSetBackTaskKey v3.5 fails
    BX: keycode
    CX: modifiers
    DX: modifier mask
Identical to wSetTaskKey, except that it sets a "reverse task key" which brings
the rearmost process to the foreground. On the Series 3 SHIFT-PSION-SYSTEM is
preassigned as the reverse task key.


Fn $8D Sub $E3
wCancelTaskKey v3.5 fails
    BX: keycode
    CX: modifiers
    DX: modifier mask
Cancels a previous call to wSetTaskKey with the same arguments.


Fn $8D Sub $E4
wCancelBackTaskKey v3.5 fails
    BX: keycode
    CX: modifiers
    DX: modifier mask
Cancels a previous call to wSetBackTaskKey with the same arguments.


Fn $8D Sub $E5
@@@ SwExt


Fn $8D Sub $E6
gOpenFontIndex v4 fails
    AX: -> font identifier
    @@: (cstr) filename
    @@: font number within file (0 = first or only font)
Opens the specified font from a multiple-font file.


Fn $8D Sub $E7
gInitBit v4 fails
    AX: -> bitmap file handle
    @@: (cstr) filename
    @@: address of a word
Opens a file containing one or more bitmaps, ready for gGetBit and gDrawBit.
The word pointed to by @@ is set to the number of bitmaps in the file. Using
this facility is more efficient than using gOpenBit several times.


Fn $8D Sub $E8
gGetBit v4 fails
    @@: bitmap file handle
    @@: bitmap number (0 = first or only)
    @@: flags
    @@: address of an information block
Loads a bitmap from the file given by the handle (which must have been
returned by gInitBit). The other parameters are as for gOpenBit.
@@@@ Manual says returns 0. gOpenBit returns a bitmap identifier !


Fn $8D Sub $E9
gDrawBit v4 fails cgc
    @@: address of point definition block
    @@: bitmap file handle
    @@: standard rectangle structure
    @@: mode (see gFillPattern)
    @@: bitmap number (0 = first or only)
Copies a rectangle from a bitmap in a file to the window or bitmap given by
the current graphics context. Effectively does gGetBit, gCopyBit, and then
wFree on the bitmap, only much more efficiently.


Fn $8D Sub $EA
gQueryBit v4 fails
    @@: bitmap file handle
    @@: bitmap number (0 = first or only)
    @@: address of 4 byte buffer
The buffer is filled with the size of the specified bitmap:
  Offset 0: width
  Offset 2: height


Fn $8D Sub $6B
wsStatusWindow v4
    BX: window format (0 = off, 1 = small, 2 = large, 3 = Series 3t)
Sets the format of the status window.


Fn $8D Sub $6C
wInformOnAll v4
    @@: new state (0 = don't send, 1 = send)
Instructs the window server to send or not send WM_ON events.


Fn $8D Sub $ED
wsCreateClock2 v4 fails
    AX: -> clock identifier
    BX: address of clock information
    CX: (cstr) clock format for type 5 clocks, must be 0 for all others
Creates a clock, which will then tick automatically. The clock information
has the following form:
  Offset  0 (word): window
  Offset  2 (word): clock type
    0 = Series 3t small digital
    1 = Series 3t medium variable (36 x 32 pixels)
    2 = Series 3t large analogue (66 x 60 pixels)
    3 = Series 3a medium variable (58 x 51 pixels)
    4 = Series 3a large analogue (99 x 99 pixels)
    5 = Formatted digital (v4 only)
    6 = Series 3c/Siena medium variable
    7 = Series 3c large analogue
  Offset  4 (word): x coordinate of position
  Offset  6 (word): y coordinate of position
  Offset  8 (word): difference in minutes between clock and system time
  Offset 10 (word): flags [apply only to the types in brackets]
    Bit  4: display the date [0, 1, 3]
    Bit  5: display seconds [0, 2, 3 (analogue), 4]
    Bit  6: force analogue [1, 3]
    Bit  7: force digital [1, 3]
    Bit  8: add AM/PM indicator if system is in 12 hour mode [0, 1]
    Bit  9: centre text within space added when bit 8 set [0]
    Bit 10: add AM/PM indicator if system is in 12 hour mode [0, 1 (digital)]
    Bit 10: @@@ CLOCK_WITH_DATE_EXTRA
    Bit 11: use grey plane [0, 1, 2, 5?]
    Bit 12: @@@ DBL_PLANE
    Bit 13: right align [@@@]
    Bit 14: @@@ SUMMER_TIME
    Bit 15: enclose in a box [5]
  Offset 12 (word): font (type 5 only)
  Offset 14 (word): style (type 5 only)
    Bit 0: bold
    Bit 1: underline
    Bit 2: inverse
    Bit 3: double height
    Bit 4: monospaced
Clock types described as "variable" can be either digital or analogue according
to the system settings or additional bits. For type 5 clocks, the format string
@@@


Fn $8D Sub $EE
wSetPriorityControl v4
    BX: new state (0 = off, 1 = on)
Sets server-controlled priority handling. When on, the server will change the
priority of a process to 112 when it is in the background or has called
wStartCompute, and 128 when in the foreground. The client must not set its
own priority when this is on.


Fn $8D Sub $EF
gConfigureFonts v4 fails
    AX: -> font group identifier
    @@: number of fonts
    @@: address of a sequence of information blocks
Creates a font group, which is a set of fonts intended for use in various
styles (for example, roman, bold, italic, and bold-italic versions of a
basic font would be combined to form a font group). There must be an
information block for each font in the group; the blocks are immediately
adjacent in memory. Each block has the form:
  Offset 0 (word): font
  Offset 2 (word): style of this font
  Offset 4 (word): style to be applied to this font
  Offset 6 (word): vertical adjustment
When using a font group and a style for output, the following process is used.
The "best" block is set to the first block. The list of blocks is then scanned
in order; whenever a block is found where all the styles in offset 2 are part
of the required style *and* include all the styles in offset 2 of the best
block, that block becomes the best block. When all blocks have been scanned,
the font in offset 0 of the best block is selected, the styles in offset 2 are
removed from those to be used, and then the styles in offset 4 are added. The
resulting styles are applied to the font, and the text is moved vertically by
the distance given in offset 6.


Fn $8D Sub $F0
wInquireStatusWindow v4
    AX: -> current format (0 = off, 1 = small, 2 = large, 3 = Series 3t)
    BX: format of interest (as for AX, or -1 for current format)
    SI: address of 8 byte buffer
The buffer is filled in with the coordinates the status window would
have if it had the indicated format; the current format is also returned.
The contents of the buffer are:
  Offset 0 (word): x coordinate of left edge
  Offset 2 (word): y coordinate of top edge
  Offset 4 (word): width
  Offset 6 (word): height
(When the window is off, it has zero width but full height, at the right
hand edge of the screen.)


Fn $8D Sub $F1
wInquireCompatibility
    AX: -> compatibility flag
Returns the state of the Compatibility mode. See wCompatibilityMode for
details.


Fn $8D Sub $F2
gReadFontHeader v4 fails
    AX: -> length of header actually read (up to 128)
    @@: (cstr) filename
    @@: font number within file (0 = first or only font)
    @@: address of 128 byte buffer
The font header of the specified font is read into the buffer.


Fn $8D Sub $F3
gReadFontGroupHeader v4 fails
    AX: -> length of header actually read (up to 126)
    @@: (cstr) filename
    @@: address of 128 byte buffer
The file must be a multiple font file. The number of fonts is placed in the
word at offset 0 of the buffer, and the font group header is read into the
rest of the buffer.


Fn $8D Sub $F4
wSetSystemFont v4 fails
    @@: system font to be set
    @@: font, font group, or internal font identifier
    @@: text style (internal fonts only)
Changes the font in use for one of the four standard system fonts.
    0 = Series 3a system font
    1 = Series 3t compatibility system font
    2 = Series 3a internal font
    3 = Series 3t compatibility internal font


Fn $8D Sub $F5
wSetSprite v4 fails
    @@: sprite identifier
    @@: address of a position structure, or 0 to leave it in the same place
    @@: number of bitmap set to change (0 = first set in the sequence)
    @@: address of an information block, or 0 if all sets remain unchanged
Moves the sprite, or change a bitmap set, or both. The position structure and
information block, if provided, have the same format as for wCreateSprite.


Fn $8D Sub $F6
wCreateSprite v4 fails
    AX: -> sprite identifier
    @@: window
    @@: address of a position structure
    @@: child window behaviour (0=sprite over windows, 1=sprite under windows)
    @@: number of bitmap sets in the sprite
    @@: address of a sequence of information blocks
Attaches an animated sequence of bitmap sets to a window as a sprite; the
sprite will appear in front of everything else in the window. Only one window
of a client may have a sprite at any time. The position structure gives the
initial position of the sprite:
  Offset 0 (word): x coordinate
  Offset 2 (word): y coordinate
There must be an information block for each bitmap set in the sequence; the
blocks are immediately adjacent in memory. Each block has the form:
  Offset  0 (word): bitmap for black pixels to be set
  Offset  2 (word): bitmap for black pixels to be cleared
  Offset  4 (word): bitmap for black pixels to be inverted
  Offset  6 (word): bitmap for grey pixels to be set
  Offset  8 (word): bitmap for grey pixels to be cleared
  Offset 10 (word): bitmap for grey pixels to be inverted
  Offset 12 (word): x coordinate of bitmap position relative to the sprite
  Offset 14 (word): y coordinate of bitmap position relative to the sprite
  Offset 16 (long): delay in 0.1 seconds before next bitmap set is shown
Any of the bitmaps can be 0 to indicate that there is no such bitmap. All
non-zero bitmaps must be the same size.


Fn $8D Sub $F7
wsSetList v4 fails
    BX: number of strings in the new list (or -1 to show an icon)
   eCX: an array of cstrs
    DX: position in list to be selected (0 = first string, -1 = none)
Sets the "mode", or "diamond" list in the status window. CX should hold
the address of an array of words, each of which holds the address of the
start of a cstr. If BX is -1, the list is replaced by the application
icon; in this case CX and DX are ignored.


Fn $8D Sub $F8
wsSelectList v4
    BX: position in list to be selected (0 = first string, -1 = none)
Sets the position of the diamond in the status window.


Fn $8D Sub $79
gShadowText v4 cgc
    @@: x coordinate of starting point
    @@: y coordinate of baseline
    @@: address of information block
    @@: (text) string
    @@: length of string (maximum 234)
Prints the text, ignoring the text mode, but applying shadow and lighting
effects according to the information block:
  Offset  0 (byte): body colour   ) 0 = black,     1 = white
  Offset  1 (byte): shadow colour ) 2 = grey,      3 = none
  Offset  2 (byte): light colour  ) 4 = dark grey, 5 = light grey
  Offset  4 (word): link to shadow (0 = disconnected, 1 = connected)
  Offset  6 (word): shadow effect width
  Offset  8 (word): shadow effect height
  Offset 10 (word): lighting effect width
  Offset 12 (word): lighting effect height
  Offset 14 (word): additional horizontal gap between characters


Fn $8D Sub $7A
gDrawObject v4 cgc
    @@: object type
    @@: standard rectangle structure
    @@: flags
Draws a special object just inside the specified rectangle. Available object
types are:
    0 = 3-dimensional box
and the available flags are:
  Bit 1: set for 4 pixel corner, clear for 1 or 2 pixel corner
  Bit 3: double thickness
  Bit 6: set for 1 pixel corner, clear for 2 or 4 pixel corner


Fn $8D Sub $7B
gBorder2 v4 cgc
    @@: 0 = as gBorder, 1 = black/white/grey 3-D effect
    @@: border type
Draws a border as gBorder, except that it can also generate a 3-D effect on
screens with grey available. @@@ arrows are not documented as available


Fn $8D Sub $7C
gBorder2Rect v4 cgc
    @@: 0 = as gBorderRect, 1 = black/white/grey 3-D effect
    @@: standard rectangle structure
    @@: border type
Draws a border as gBorderRect, except that it can also generate a 3-D effect
on screens with grey available. @@@ arrows are not documented as available


Fn $8D Sub $FD
wCompatibilityMode
    BX:  new state (0 = off, 1 = on)
    SI:  *the same* pointer to a WSERV_SPEC structure as for
         wConnect @@@@
Changes the compatibility mode state. When the mode is off, drawing is done
in the usual way. When it is on, drawing is done in double pixel mode on
those machines that support it. The initial state is off.


Fn $8D Sub $7E AL $00
wDrawButton2 v4 cgc
    @@: standard rectangle structure
    @@: (cstr) string in button (maximum length 240)
    @@: button type (0 = Series 3t, 1 = Series 3a)
    @@: button state (0 = normal, 1 = pressed, 2 = deeply pressed)
Draws a button containing a string. Series 3a buttons require the window to
have a grey plane. Series 3t buttons must not be deeply pressed.


Fn $8D Sub $7E AL $01
@@@ InformInactivity


Fn $8D Sub $7E AL $02
wDisableKeyClick v4
    BX: 0 = enable, 1 = disable
Enables or disables key clicks for the current process.


Fn $8D Sub $FF AL $00
gInitMultiSave v4 fails
    AX: -> multisave file handle
    @@: (cstr) filename
    @@: number of bitmaps
Creates a file capable of holding the specified number of bitmaps, for use with
gSaveMultiBit and gSaveMultiRect.


Fn $8D Sub $FF AL $01
gSaveMultiBit v4 fails
    @@: multisave file handle
    @@: bitmap identifier, or zero for the whole screen
Saves the specified bitmap as the next bitmap in the multisave file created by
gInitMultiSave. If the save fails, all further saves to the file will also
fail (but the file must still be closed with gEndMultiSave).


Fn $8D Sub $FF AL $02
gSaveMultiRect v4 fails
    @@: multisave file handle
    @@: bitmap identifier, or zero for the whole screen
    @@: address of a standard rectangle structure
Saves a rectangle from the specified bitmap as the next bitmap in the multisave
file, as for gSaveMultiBit.


Fn $8D Sub $FF AL $03
gEndMultiSave v4 fails
    @@: multisave file handle
Closes the multisave file, making it unavailable for further saves.


Fn $8D Sub $FF AL $04
gInquireChecksum v4
    @@: bitmap identifier, window identifier, or zero
    @@: address of a word
Checksums the specified bitmap and writes the checksum to the word pointed to
by @@. A window identifier must be for a window with a background redraw
method of 3, in which case its off-screen bitmap is used. Zero for the bitmap
causes the entire screen to be checksumed.


Fn $8D Sub $FF AL $05
gCreateFontHeader
@@@@


Fn $8D Sub $FF AL $06
wSupportInfo v4
    @@: address of a 32 byte buffer
The buffer is filled in with information about supported features:
  Offset 0 (word): flags
    Bit 0: set if grey is available
    Bit 1: set if Series 3t compatibility mode is available
The remaining flag bits, and the rest of the buffer, is currently set to 0.


@@@@@@@@@


Fn $8D Sub $@@
wsScreenExt
    @@: address of 8 byte buffer
The buffer is filled in with the size of the screen *excluding* the current
status window. The format of the buffer is as for wInquireStatusWindow,
which should be used for preference.


Fn $D6 Sub $00 (wConnect) is used to connect to the window server. All
OPL programs, and all programs using the console device CON: are
connected automatically, and must not use this call.


Fn $D6 Sub $01
gPlayback
    @@: @@@@
@@@


Fn $D6 Sub $02
gCloseMetafile
    @@: @@@@
@@@


Fn $D6 Sub $03
gRecordToMetafile
    @@: @@@@
    @@: @@@@
    @@: @@@@
@@@


Fn $D6 Sub $04
wFlush
Sends any buffered commands to the server.


Fn $D6 Sub $05
wCloseDown
@@@


Fn $D6 Sub $06
wSelect
    @@: @@@@
@@@


Fn $D6 Sub $07
wPanic
    @@: @@@@
@@@


Fn $D6 Sub $08
wGetEvent
    @@: address of a 16 byte buffer
@@@@ This is async. How does the sync version work ? Is it vsync ?
This call may be made synchronously or asynchronously. If made synchronously,
it waits until the window server sends an event to the process, and then copies
the event into the buffer. If called asynchronously, it writes the value -46
into the word at offset 0 of the buffer and returns; when an event is sent from
the window server, it is written to the buffer and the I/O semaphore is
signalled. Further information about events is given below.


Fn $D6 Sub $09
wDisconnect
Disconnects from the window server and frees all associated resources.
All programs are automatically disconnected upon exit, so this call is
generally not used by the programmer.


Fn $D6 Sub $0A
wCheckPoint fails
Sends any buffered commands to the server (as wFlush) and reports any
errors immediately (see wDisableLeaves).


Fn $D6 Sub $0B
gTextWidth fails
    AX: -> width in pixels
    DX: font or font group
    SI: style adjustments
    DI: (text) string
    CX: length of string
Returns the width in pixels of the specified string when displayed in the
specified font and style adjustments. The latter are:
    Bit 0: bold
    Bit 1: underline
    Bit 2: inverse
    Bit 3: double height
    Bit 4: monospaced
    Bit 5: italic
    Bit 8: subscript
    Bit 9: superscript


Fn $D6 Sub $0C
gFontInfo fails
    DX: font or font group
    CX: style adjustments (see gTextWidth)
    DI: address of 32 byte buffer
Fills the buffer with information about the font modified by the style:
  Offset  0 (word): minimum character code
  Offset  2 (word): maximum character code
  Offset  4 (word): height (affected by style)
  Offset  6 (word): ascent (affected by style)
  Offset  8 (word): descent (affected by style)
  Offset 10 (word): width of a digit (affected by style)
  Offset 12 (word): width of widest common character (affected by style)
  Offset 14 (word): flags:
    Bit 0: contains standard ASCII
    Bit 1: contains IBM code page 850
    Bit 2: looks bold
    Bit 3: looks italic
    Bit 4: has serifs
    Bit 5: monospaced
    Bit 6: has a "hang table" @@@@
  Offset 16 to  31: name
The widest common character is usually an M or W, and is not necessarily the
widest character in the font.


Fn $D6 Sub $0D
wDisableLeaves
    AX: -> previous value of the flag
    @@: error handling flag
Sets the error handling mechanism used by the window server calls. If the
flag is zero, then an error in a command calls the "leave" operation. If it
is non-zero, calls that can fail return an error number in AX. The initial
setting is zero; OPL programs should always make it non-zero.


Fn $D6 Sub $0E
gCheckBitmapID v3 fails
    @@: bitmap identifier
Succeeds (returning 0) if the bitmap identifier is valid. Fails otherwise.


Fn $D6 Sub $0F
@@@ Alert


Fn $D6 Sub $10
@@@ AlertCancel


Fn $D6 Sub $11
gTextCount fails
    AX: -> number of characters
    DX: font or font group
    SI: style adjustments (see gTextWidth)
    DI: (text) string
    CX: length of string
    @@: address of a word holding the available width
AX is set to the length of the longest initial substring that will fit in the
number of pixels stored in the word pointed to by @@ when displayed in the
specified font and style adjustments (see gTextWidth). The word is altered to
hold the number of pixels that would be left over.


Fn $D6 Sub $12
gGetWidthTable fails
    DX: font or font group
    SI: style adjustments (see gTextWidth)
    DI: address of a buffer
Fills the buffer with the widths of each character in the font as adjusted.
The first byte of the buffer corresponds to the minimum character code, and
the last byte to  the maximum character code (see gFontInfo).


Fn $D6 Sub $13
wGetEventSpecial v4
    @@: address of a 16 byte buffer
    @@: event type mask
Starts looking asynchronously for an event as wGetEvent, but only accepts
events of specific types. @@@ what happens to the rest ? @@@ based on the
event type mask:
  Bit  0: key and task key events
  Bit  1: redraw events
  Bit  2: foreground, background, and power on events
  Bit  3: mouse and rubber band events
  Bit  4: all other events
  Bit 15: escape events
Calling wGetEvent is equivalent to calling this function with a mask of $1F.
Escape events are sent only if key events are not selected; in this case, if
the ESC key is pressed, all pending keystrokes are thrown away and the client
is sent an escape event.


Fn $D6 Sub $14
wGetEventUpdate v4
    @@: event type mask
If there is an asynchronous call to wGetEvent or wGetEventSpecial outstanding,
it changes the mask specifying the events being looked for. If no call is
outstanding, it has no effect.

The Psion FAQ

The Psion FAQ

Psion FAQ Part 1

Original author: Chris Wesley 
Actual author & maintainer: Daniel Pfund

Jun97 - v2.6

Welcome to the FAQ for the comp.sys.psion.* Usenet hierarchy. Find the contents table below. Questions and constructive comments are welcome. Send them to me at: Pfund3@uni2a.unige.ch

IMPORTANT NOTE: this article does not contain any software infos on the Series 3c or the Siena. I will NOT include specific information concerning these new machines (except hardware stuff). Maybe there will be a Series3c/Siena FAQ written by someone else in the future?


-CHANGE-Indicates a change since last version 
- NEW! -Indicates an addition since last version


Contents

part 1

I. DISCLAIMER
II. CREDITS
III. COPYRIGHT
IV. FAQ UPDATES
V. WHERE CAN I GET THIS FAQ?
VI. NEWSGROUP NETIQUETTE

1. INTRODUCTORY INFORMATION

1.1 What is the Psion Series 3/3a?
1.2 Which model should I buy?
-CHANGE-1.3 When will the "new" Psion come out?
-CHANGE-1.4 What other machines does Psion make?
1.5 What other palmtop alternatives are there?

part 2

- NEW! -1.6 Where can I purchase a Psion?
1.7 How can I contact Psion?

2. HARDWARE

2.1 Hardware specifications
2.2 What batteries does the Psion use?
2.3 How long do the batteries last?
2.4 How does the Psion measure the battery usage?
2.5 How can I make my batteries last longer?
2.6 Can I use an external power supply?
2.7 Can I upgrade my Solid State Disk (SSD)?
2.8 Can I upgrade my internal RAM?
2.9 Can I change the keyboard?
2.10 Can I use a big (normal) keyboard?
2.11 How can I build a serial link?
2.12 How can I build a parallel link?
2.13 What is this "soap on a rope" thing?
2.14 How do I print with my Psion?
2.15 Can I take my Psion through an X-Ray machine?
2.16 Can my Psion wipe out magnetic data?

3. SOFTWARE

3.1 How do I reset my Psion?
3.2 What is killing a process?
3.3 How can I save what's on the screen?
3.4 What is the soak test?
3.5 How can I find a text in my memos with Agenda?
3.6 How can I make the cursor bigger?
3.7 How can I take out the "hum" when I record sounds?
3.8 How safe is password protection?
3.9 How can I change the icon of a program?

part 3

3.10 How can I permanently change the distance units in World?
3.11 Why do some programs crash with an "Invalid arguments" error?
3.12 Why is my Psion not switching itself off automatically anymore?
3.13 How can I change the fonts in the system applications?
3.14 Is Perl ported to the Psion?
3.15 How do I undelete a file if I've accidentaly deleted it?
3.16 How can I synchronize my desktop agenda with my Psion's?

4. TIPS & TRICKS FOR GENERAL USE

4.1 Known hardware problems & solutions
4.2 Known software problems & solutions
4.3 Other official Psion repair centres
4.4 User groups
4.5 Online services
4.6 Bulletin boards (BBSes)
4.7 Magazines
4.8 "Anti-thief" tips
4.9 Lost/stolen Psions

5. SHAREWARE AND FREEWARE

5.1 Relevant FTP sites
5.2 WWW internet sites
5.3 Shareware for those without online access

part 4

6. CONNECTING YOUR PSION

6.1 With an IBM or clone
6.2 With an Amiga
-CHANGE-6.3 With a UNIX machine
6.4 With a Macintosh
6.5 With an Atari
6.6 With an Acorn Archimedes or Risc PC
6.7 With a serial modem
6.8 With a PCMCIA modem
6.9 With a packet radio TNC
6.10 With a cellular phone
6.11 Via the IrDA port (3c/Siena)
6.12 Terminal emulation
6.13 TCP/IP stack

part 5

7. THE EMULATOR

7.1 Limitations & bugs
7.2 Tips & tricks
7.3 Changing permanently the keyboard mapping

8. PROGRAMMING

8.1 Overview of development possibilities
8.2 OPL programming directly on the Psion
8.3 OPL programming from a PC
8.4 C Development on PC
8.5 Advanced C Development on a PC
8.6 Available books
8.7 How to do various things: tips & tricks

A. SHAREWARE/FREEWARE AVAILABLE SOFTWARE

A.1 Applications
A.2 Games

part 6

B. COMMERCIALLY AVAILABLE SOFTWARE, SERVICES & ACCESSORIES


I. DISCLAIMER

This article is provided "as is" without any express or implied warranties. While every effort has been taken to ensure the accuracy of the information contained in this article, neither the authors, the maintainer or the contributors will assume responsibility for errors or omissions, or for damages resulting from the use of the information contained herein. This document is compiled in spare time for free, and I cannot resource thorough checking of all its contents. However, I am interested in making the FAQ as good as it can be, so your constructive feedback is welcome.

This FAQ is not sponsored or endorsed by Psion PLC or any subsidiary companies they may own in any way.

This FAQ is *NOT* intended as a replacement of the User Guide which comes with each Psion. Be sure to read that first and - most important - please double read the manual and this FAQ before posting any questions to the comp.sys.psion.* hierarchy!

II. CREDITS

To create this document Chris (the original FAQ author) reviewed the Newsgroup activity of the old comp.sys.psion (it has split on the 19th of June 1996) group over some months, used that to generate a list of Frequently Asked Questions, used THAT to generate a FAQ structure, then populated it with extracted wisdom from the news traffic. So a lot of information here is provided by the newsgroup contributors, who are too numerous to credit individually. (Chris said "I'm just the clerk that put it all in one place.") Special thanks go to Markus Illenseer, who owned the first (Series 3) FAQ - from which Chris also extracted useful information. Chris also thanked Clive D.W. Feather, Daniel Senie, Roger Burton-West, for extensive helpful comments on his preliminary FAQ. I would like to thank Mark Gould and Jason Savage for their precious help and comments. Other contributors are credited in the sections they provided special help in compiling.

If you have a question which is not answered in the actual FAQ, please Email it to me (Daniel Pfund, see address at the top of this FAQ), otherwise if you want more information from one specific section of this FAQ, please try to contact the author of that section first. All the Email addresses of people mentioned in this FAQ are listed here for convenience (in alphabetical order):

        Andrew Baldwin          Andrew-Baldwin@psion.com
	Michael Baas 		Michael@psiologic.com
        Daron M. Brewood        dbrewood@nest.demon.co.uk
        Roger Burton-West       rburtonw@nyx10.cs.du.edu
        Mark Chapman            mavc@cix.compulink.co.uk
        Steve Clack             sclack@cix.compulink.co.uk
        Nick Craig-Wood         ncw@axis.demon.co.uk
        Alban Debeaupuis        A.Debeau@ellis.fdn.org
        Mike Dolan              m.dolan@bcs.org.uk
        Tom Dolbilin            tdolby@ncsa.uiuc.edu
        Paul DuBois             dubois@primate.wisc.edu
        Clive D.W. Feather      clive@demon.net
        Mark Gould              Mark.Gould@bris.ac.uk
        Roman Habrat            romek@robix.comp.waw.pl
        Steve Hawtin            steve@tsort.demon.co.uk
        Jochen Hollmann         jnhollma@immd4.informatik.uni-erlangen.de
        Charlotte Holmquist     ch@advivum.se
        Markus Illenseer        Markus@tiger.teuto.de
        Erik Johansen           ej@it.dtu.dk
        Uwe Kallmeyer           uwek@yedik.escape.de
        Edwin Klement           eklement@crcg.edu
        Dan Ko                  daniel@danielko.demon.co.uk
        Philippe Lebreton       lebreton.p@ccmail.cgi.fr
        Steve Litchfield        slitchfield@cix.compulink.co.uk
        Neil Masson             nmasson@datlog.co.uk
        Roger Muggleton         hzk@cix.compulink.co.uk
        Blake Nancarrow         blaken@computer-ease.com
        Daniel Pfund            Pfund@POBoxes.com
        Angus Rae               angusr@festival.ed.ac.uk
        Dan Ramage              Damage@juno.com
        Alan Roberts            alanr@rd.bbc.co.uk
        Konstantin I. Saliy     kis@ipmce.ru
        Jason Savage            Jason_Savage@mbnet.mb.ca
        Daniel Senie            dts@world.std.com
        Jochen Siegenthaler     jochen.siegenthaler@alcatel.ch
        Bruce Stephens          stephens@math.ruu.nl
        Toby Smith              tcs@cs.bham.ac.uk
        Oliver Wagner           owagner@lsd.wupper.de
        Lloyd Wasser            LWasser@infowave.net
        John A. Watson          JAWatson@thelcastle.win-uk.net
        Chris Wesley            Chris@people.demon.co.uk
        Walter Wright           wally@ceemore.demon.co.uk

If you happen to change addresses or know the new address of someone on this list, please Email it to me, thanks!

IV. FAQ UPDATES

For the time being, I (Daniel) am the keeper of the FAQ. If you have comments or suggestions, corrections, or you have some information you want to see added or a request that I find some new answers, please let me know. Please contact me via the Email address at the top of the FAQ, or if that address doesn't work anymore (will stop working around the 20th of October 1997), then contact me at: pfund@poboxes.com which (should) work all the time by forwarding me my mail to my current account. If all else fails, do a web search on my name or check out my current homepage for more info at: http://www.geocities.com/SiliconValley/8130/

V. WHERE CAN I GET THIS FAQ?

You're reading it aren't you? SAVE it :-). This FAQ is part of the "official" news.answers FAQs and is posted monthly to comp.sys.psion.announce and cross-posted to comp.sys.palmtops, comp.answers, and news.answers. If you don't have reliable Usenet access, you can also retrieve the FAQ by:

FTP
This article is archived at any site that archives news.answers.
News.answers' main archive is at rtfm.mit.edu, and this article is available there via anonymous ftp in the directory /usenet/news.answers/psion-faq/partX
Other news.answers FAQ archives are:
You probably will find a location closer to you with the help of archie or some other search tool. Usually, the news.answers FAQs are held in a directory like "usenet/usenet-by-group/news.answers/" and you would be looking for the "psion-faq" subdirectory in there.
EMail
You can use the mailserver at rtfm: send a message containing the lines "send usenet/news.answers/psion-faq/*" to receive all parts or send a message containing "help" and "index" to mail-server@rtfm.mit.edu for more information on how to obtain seperate parts.
WWW
There is a HTMLized version of this FAQ on my homepage at http://www.geocities.com/SiliconValley/8130/faq.htm (Note that there is no "l" at the end of "htm", this is not a typo!) Please use this site for any reference from your own web pages because it is under my direct control and easily changeable. It contains links to all the Psion HTML FAQ mirrors available in the world as well as an archive file of both the text and the HTML versions of the FAQ for easy downloading and offline reading.
There are also numerous WWW sites archiving all the news.answers FAQs. My favorite site is in Oxford at: http://www.lib.ox.ac.uk/internet/news/

Please do NOT Email me or anybody else mentioned in this FAQ for the latest version. We simply cannot handle such matters effectively.

If the date at the top of this FAQ is more than a couple months old, there is probably a new version available online.

If you're interested to learn how I prepare this FAQ, you can check out my page about that at: http://www.geocities.com/SiliconValley/8130/howfaq.htm

VI. NEWSGROUP NETIQUETTE

I thought it might be useful to include a few words about using the comp.sys.psion.* newsgroup hierarchy. We get a steady trickle of transgressions and the ensuing admonishments. Maybe we can fix these before they happen in future. Egg-sucking grannies may skip this section. (Does that work outside the UK?)

  1. READ THE FRIENDLY MANUAL (RTFM) and then the FAQ before posting any questions! Remember that thes groups are here to help you out but only if the answer can't be found by yourself. Also remember that each time you're posting a question to the group, hundreds (if not thousands) of people will read your question. If the same questions come up again and again, people will just get bored and not answer anymore...
  2. DON'T BE RUDE. Obvious? Apparently not. Our newsgroup is an oasis of civilization in a sea of adolescent vitriol and worse. Let's keep it that way. Say it nicely or don't say it at all. If you need to be uncomfortably direct, do it in personal mail - don't post it.
  3. When responding to a post, most handlers will give you an edit pad with the original post inserted. Delete most of this, leaving only the part which will set the context for your reply. This is more effective communication, it cuts down on crud to scan through, and reduces phone bills for those that pay them.
  4. Official NETIQUETTE says you should not use the net for advertising, but the prevalent view here is that the current level of activity is useful without being obtrusive.
  5. Posting binaries is definitively not recommended in the comp.sys.psion.* usenet groups! There is a seperate Psion binaries group called comp.binaries.psion which is a moderated group. The moderator is Erik Johansen. If you wish to post to this group, either Email your binary directly to the news group's Email address: psion-binaries@it.dtu.dk and it will arrive to the moderator or if your news program is configured correctly, post it directly to the group. You will receive a message in return usually in a laps of 2-3 days maximum to confirm your binary. It has been agreed that very large programs which are not Psion specific (ie: don't run directly on the Psion) should NOT be posted there but to the relevant computer group. But you should send a small message to the comp.binaries.psion group stating that you have just posted your program. It is also common practice to send a description of your binary; it helps to know if it's worth downloading it or not! Usually, this description has the same subject line but with part0(/x) suffix. All postings to this group have been archived and are indexed on the following FTP site: ftp.it.dtu.dk/pub/psion/index.html
  6. Consider whether you should be mailing or posting. PING-PONG personal dialogues may - or may not - be of interest to others. If not, please don't post.
  7. Post to the relevant newsgroup, and please don't cross-post! Here's a guide to help you:
    • comp.binaries.psion
      Used for ALL Psion binaries. Also used for large source code.
    • comp.sys.psion.announce
      Used for posting announcements about new programs/hardware; the FAQ is also posted to this group. This is a low volume group and it's moderated, that means that all postings must get approved first by the moderator (Michael L. Kaufman). If your news server does not send your post to the moderator (but they all do generally), you can send it yourself directly for approval at psion@acm.org.
    • comp.sys.psion.apps
      Used for posting questions/answers to all Psion related programs; frequented by all Psion programmers to get your feedback and ideas of course ;-)
    • comp.sys.psion.marketplace
      Used for selling/buying Psion articles
    • comp.sys.psion.misc
      Used for any subject which does not fall into one of the other categories...
    • comp.sys.psion.programmer
      Used for posting programming questions ( OPL / C / ... ), NOT programs!
    • comp.sys.psion.reviews
      Used for posting reviews about Psion programs/hardware. This group is also moderated by Michael L. Kaufman and again, if your news server is not set up correctly, you can also send your postings directly to him at psion@acm.org.

1. INTRODUCTORY INFORMATION

1.1 What is the Psion Series 3/3a?

I will describe the more advanced 3a here. Refer to the hardware section to see what you lose on the Series 3.

The Psion Series 3 and 3a are palmtop computers. Though packaged as personal organisers, they are fully general, programmable, powerful computers. The quality of the built-in applications, coupled with the power saving hardware make Series 3's excellent personal organisers. The sophisticated operating system, the hardware, the built-in programming language, and the options to program in C and assembler make them excellent general-purpose computers, with the major benefits of compactness and battery endurance.

The built-in applications include a database manager, a sophisticated word processor, time manager, world date/time and dialling codes database, calculator and spreadsheet. The latest models (1Mb and 2Mb RAM models) also include the spell checker/thesaurus and a patience game (solitaire card game). Many other applications are available commercially and from shareware outlets. More details in the last part of this FAQ.

The built-in OPL programming system provides a structured BASIC-like programming language with access to all the features of the machine. This includes the ability to program polished Windows/Icons/Menus interfaces like those found in the built-in applications.

The sound interface can record and playback digital sound. DTMF dialling tones can be created which allow the Series 3a to dial numbers directly through a telephone.

1.2 Which model should I buy?

This question is really a personal matter. I would definitively suggest getting a Series3a (and not 3) because of the greater screen resolution. As for which memory model, this depends entirely of your needs and what you plan on doing with your Psion. In general, the more memory the better (and keep in mind also that the 1/2Mb models offer the spell checker/thesaurus and solitaire game which you might need). If you're reading this, you probably have access to Psion free/shareware also. You will see that these programs will quickly fill up your memory ;-) so I would suggest to get the biggest model (2Mb). If on the other hand, money is tight and you don't plan on using much more than the Agenda and the built-in apps, then I think a 512k is big enough for you. As you can see, there is no simple solution to this answer!

1.3 When will the "new" Psion come out?

Good question... next please!

Joke apart, nobody really knows. So please folks, just stop asking! Before the 3c was announced, people didn't expect a new Psion until 1997, but Psion was 3 months early (just in time for Christmas, heh?!).

The reason no one knew exactly is that Psion is quite relunctant to give such information simply because they've learned from the past (from Osborne computers to be more precise ;-) .

Psion have formally announced that their will be new machines during the year 1997. By the time you read this, the new "Series 5" will probably be available as it has been rumoured to come out during June 97. That will mean the end of this FAQ... as I'm sure the Series 5 will be a must-have fantastic palmtop!

People were hoping for Infrared comms (IrDa compliant), PCMCIA (most debated!), RISC (ARM 7100) 32bits, pen for navigation (but hopefully still a keyboard!), backlight ... You see that Psion have added most of these features into the 3c!

1.4 What other machines does Psion make?

1.4.1 WorkAbout

This is the latest Psion machine. Very comparable to a Psion Series 3a, it is more robust and has an A-Z keyboard for size reasons. One nice point: a back lit screen is present. Targeted at the vertical market, thus not so well known to the general public.

1.4.2 Acorn Pocket Book (by Acorn)

Re-badged Series 3a, aimed at education-related markets. Contains all the 3a applications, though named differently, plus a spell checker, thesaurus and a graph plotting application in a 2MB ROM. Password protection capability is removed. Costs about 20 GBP more than a 3a.

1.4.3 Series 3

The immediate predecessor to the Psion Series 3a is the Series 3. It is the same machine in size and concept, but is more limited in many respects. See the hardware comparison table in section 2a for a list of differences.

1.4.4 Series 3c

The immediate sucessor to the Psion Series3a; was launched 05Sep96 (same time as the Siena). It has the following added features:

But, it must also be noted that the 3c does NOT have the definitions in it's spelling checker/thesaurus application. Psion didn't have enough room in the ROM to keep them.

1.4.5 Siena

This is not really a palmtop computer, but should more be classified as a "PDA" (Personal Digital Assistant). It is basically the same as a 3a but available only in 512k/1Mb RAM versions with a half-sized screen (240*160 pixels). It also includes Jotter but not Files nor Oval. Next to the top half of the screen you can find a numeric keypad. Unexpandable (no SSD slots built-in, but you can buy an SSD adapter); has built-in RS-232 port. See Psion's web site for more infos.

1.4.6 Organiser II series:

There is an Organiser II homepage at http://homepages.enterprise.net/djw/psion/psion.html

1.5 What other palmtop alternatives are there? (by Jason Savage)

See section 2.1 for the Psion Series 3 and 3a hardware specifications.

Make: Apple 
Model: Newton MessagePad 120

Processor
Model: ARM 610
Speed: 20 Mhz
Bit size: 32-bit
Display
Type: Monochrome, reflective LCD
Pixel Screen size: 320 x 240
Memory
Size: 1MB RAM (385K user data & 639K system) or 2MB RAM (1,361K user data & 687K system)
Expansion slots
Type: Type II PC-Card (PCMCIA 2.0)
Number: 1
Dimensions
Size (W x D x H): 10.16 x 20.32 x 2.9 cm (4.0" x 8.0" x 1.2")
Weight: 480 grams (16 ounces)
Power Requirements
Batteries: 4 x AA (main) & 1 x CR2032 (backup)
Battery Life (Approx): Up to 22 hours
Provision for AC Adaptor: Yes
Input/Output Ports
Serial (max speed): Yes, RS-422 8-pin DIN (230,000 bps)
Parallel: No
Infrared: Yes, (38,400 bps)
Other: Optional FAX modem
Keyboard: Yes, Popup virtual keyboard (QWERTY, Numeric, & Phone pad)
Included Applications:
  • Newton Intelligence (Handwriting Recognition, Object Oriented Database Programming language and Communications services)
  • Calendar (like Agenda)
  • NewtonMail (email client)
  • To-Do Lists (like Agenda)
  • Rolodex-like Address Book (like Data)
  • Digital Ink ScratchPad
  • Calculator (like Calc)
  • World Time Clock (like World)
  • Dictionary (13,000 words)
  • Notion List Manager (like Data)

Make: Casio 
Model: Z-7000 (AKA: Zoomer, Tandy Z-PDA, AST GRiDPad 2390)

Processor
Model: NEC V20
Speed: 7.7Mhz
Bit size: 16-bit
Display
Type: Monochrome reflective, touchscreen
Pixel Screen size: 320 x 256
Memory
Size: 1 Mb (384K user data & 640K system)
Expansion slots
Type: Type II PC-Card (PCMCIA 2.0)
Number: 1
Dimensions
Size (W x D x H): 10.76 x 17.62 x 2.6 cm (4.2" x 6.8" x 1")
Weight: 430 grams (15.2 ounces)
Power Requirements
Batteries: 3 x AA (main) & 2 x CR2032 (backup)
Battery Life (Approx): 100 hours (catalog: 90 hours)
Provision for AC Adaptor: Yes
Input/Output Ports
Serial (max speed): Yes, 10-pin, (19,200 bps)
Parallel: No
Infrared: Yes, (9600, Casio)
Other: Round telescoping pen
Keyboard: Yes, Virtual Pop-up software QWERTY, A-Z or International
Included Applications:
  • Date Book (like Agenda)
  • Address Book (like Data)
  • Note Book (Digital Ink Scratchpad & Document Manager with outliner)
  • Pocket Quicken (Financial Organiser)
  • America Online (Access software for the service provider of the same name)
  • Calculator (like Calc)
  • Forms Calculator
  • World Clock (like World)
  • Language Translator (26 languages & up 1000 words per language)
  • Games (Solitaire, Pyramid Solitaire & UKI)
  • File Manager
  • Consumer Information
  • U.S. Information
  • World Information

Make: Hewlett Packard 
Model: 200LX

Processor
Model: variable speed Hornet
Speed: 7.91 MHz
Bit size: 16-bit
Display
Type: CGA-compatible FTN liquid crystal
Pixel Screen size: 640 x 200
Memory
Size: 1 or 2MB of RAM
Expansion slots
Type: Type II PC-Card (PCMCIA 2.0)
Number: 1
Dimensions
Size (W x D x H): 16 x 8.64 x 2.54 cm (6.3" x 3.4" x 1")
Weight: 312 grams (11 ounces)
Power Requirements
Batteries: 2xAA (main) & 1xCR2032 (backup)
Battery Life (Approx): 80 hours
Provision for AC Adaptor: Yes
Input/Output Ports
Serial (max speed): Yes, 9-wire (115K?)
Parallel: No
Infrared: Yes
Other: No
Keyboard: Yes, QWERTY
Included Applications:
  • Pocket Quicken (Financial Organiser)
  • cc:Mail (E-mail client)
  • Data Communications (VT-100, ANSI & TTY emulation)
  • Lotus 1-2-3 r.2.4 (like Sheet)
  • Laplink (like Remote Link) for file transfers
  • Appointment Book (like Agenda)
  • Phone Book (like Data)
  • HP financial calculator (like Calc)
  • Memo editor with outliner (like Word)
  • Notetaker (like Notepad)
  • Database (like Data)
  • Filer (like File Manager)
  • Worldtime & Stopwatch (like World)
  • System Macros
  • Application Manager
  • Setup Utility
See also the following WWW site for a more complete comparaison of Psion3a-HP200lx with over 170 articles:
http://www.primate.wisc.edu/people/dubois/psion/index.html

Make: Hewlett Packard 
Model: OmniGo 100 Organizer Plus

Processor
Model: Intel 80C186 compatible
Speed: 16 Mhz
Bit size: 16-bit
Display
Type: FSTN LCD with Touchscreen
Pixel Screen size: 240 x 240
Memory
Size: 1MB RAM
Expansion slots
Type: Type II PC-Card (PCMCIA 1.0: SRAM memory cards no Flash or Modems)
Number: 1
Dimensions
Size (W x D x H): 15.3 x 9.5 x 2.6 cm (6" x 3.7" x 1")
Weight: 329 grams (11.6 ounces)
Power Requirements
Batteries: 2 x AA (main) & 1 x CR2032 (backup)
Battery Life (Approx): ?
Provision for AC Adaptor: No
Input/Output Ports
Serial (max speed): Yes, 10-wire, (?)
Parallel: No
Infrared: No
Other: Yes, Pen
Keyboard: Yes, QWERTY (5 function keys)
Included Applications:
  • Appointment book (like Agenda)
  • Phonebook (like Data)
  • Notepad (like Word)
  • Database (like Data)
  • Worldtime and stopwatch (like World)
  • Jotter (Digital Ink Scratchpad)
  • Geoworks Book Reader
  • Financial Tools
  • Spreadsheet (like Sheet)
  • Emulated HP 12C financial calculator (like Calc)
  • Graffiti handwriting system (handwriting recognition)
  • Transfer (like Remote Link)
  • Setup Utility (like Install)
  • Solitaire

Make: Motorola 
Model: Envoy Communicator

Processor
Model: Motorola Dragon 68349
Speed: 16 Mhz
Bit size: 32-bit
Display
Type: Reflective FSTN Touch Screen
Pixel Screen size: 480 x 320
Memory
Size: 1 MB
Expansion slots
Type: Type II PC-Card (PCMCIA 2.0) slots
Number: 2
Dimensions
Size (W x D x H): 14.8 x 19.2 x 2.9 cm (5.8" x 7.6" x 1.2")
Weight: 770 grams (1.7 pounds)
Power Requirements
Batteries: Rechargeable Ni-Cad (main) & 1 x CR2032 (backup)
Battery Life (Approx): 8 hours
Provision for AC Adaptor: Yes, combined with Charger
Input/Output Ports
Serial (max speed): Yes, 14-pin MagicBus (38,400 bps)
Parallel: Yes, MagicBus
Infrared: Yes, FSK compliant
Other: 2 round full length pens, 4800 bps send/receive radio packet modem, 9600 bps FAX send modem & 2400 bps data modem
Keyboard: Optional, QWERTY
Included Applications:
  • Date Book (like Agenda)
  • World Time Clock (like World)
  • Address Book (like Data)
  • Notebook (like Agenda To-Do List)
  • Calculator (like Calc)
  • America Online (connection software for the service provider of the same name)
  • AT&T PersonaLink (connection software for the service provider of the same name)
  • SmartWallet

Make: Sharp 
Model: ZR-5000 & ZR-5000FX AKA: Zaurus K-PDA

Processor
Model: Sharp Proprietary
Speed: ?
Bit size: 16-bit
Display
Type: DFSTN LCD, Touch screen (finger or stylus)
Pixel Screen size: 320 x 240
Memory
Size: 1MB RAM (750k user data & 250K system)
Expansion slots
Type: Type II PC-Card (PCMCIA 2.0)
Number: 1
Dimensions
Size (W x D x H): 17.0 x 10.0 x 2.54 cm (6.7" x 3.9" x 1.0")
Weight: 385 grams (13.6 ounces approx.)
Power Requirements
Batteries: 2 x AA (main) & 1 x CR-2032 (backup)
Battery Life (Approx): Up to 60 hours (~2 months)
Provision for AC Adaptor: Yes
Input/Output Ports
Serial (max speed): Yes, 15-pin proprietary, (19,200 bps)
Parallel: No
Infrared: Yes, (IrDA & ASK Compliant)
Other: Round pen & FAX modem with ZR-5000FX
Keyboard: Yes, QWERTY configuration
Included Applications:
  • Activities (like Agenda)
  • Contacts (like Data) limited to 3 files
  • Data Files (also like Data) limited to 3 files
  • Notes (Digital Ink Scratchpad)
  • Documents (like Word) with Spell Checker
  • Outline (like Outline mode in Word)
  • Home & World Clocks (like Time & World)
  • Calculator (like Calc)
  • Filer (Manages Printing, Faxing, Email & File transfers)
  • Messaging (E-mail client)
  • FAX/Sending (FAX client)
  • Terminal Mode (ASCII & VT-100 emulation)

Make: USR 
Model: Pilot

Specs thanks to David Richards at dr@rci.ripco.com

Processor
Model: Motorola 68328 "Dragonball"
Speed: 16 MHz?
Bit size: 16-bit
Display
Type: Monochrome, reflective LCD
Pixel Screen size: 160 x 160
Memory
Size: 512K ROM
128K RAM (Pilot 1000), 512K (Pilot 5000), or 1Mb upgrade
Expansion slots
Type: Proprietary memory (replaces RAM)
Number: 1
Dimensions
Size (W x D x H): 3.2" x .7" x 4.7"
Weight: 385 grams (5.7 ounces approx.)
Power Requirements
Batteries: 2 x AAA (main)
Battery Life (Approx): 30 hours
Provision for AC Adaptor: No
Input/Output Ports
Serial (max speed): Yes, Proprietary edge connector (57,600 bps)
Parallel: No
Infrared: No
Keyboard: Yes, Popup virtual keyboard (QWERTY, Numeric, accent)
Included Applications:
  • Date book
  • Address book
  • To Do List
  • Memo pad
  • Calculator

End of part 1/6

Extended OPL Calls

  Extended OPL CallsExtended OPL Calls
                                   
                                    Introduction
  This document is an attempt to list the may possible options available to the OPL-Programmer, which are normally only to be found in the SIBO 'C'-Programming Guides.
  
  The various tips and tricks are illustrated with examples in Standard OPL.
  
  There is no particular order to the points listed.  The information can be freely distributed, but is   Psion GmbH.  Thanks to David Wood at Psion PLC for helping me with these routines over the past few months.
  
  Neither the Author, nor Psion GmbH, takes any responsibility for and damage or loss of data which occurs as result of using information in this document.  The information is subject to change without notice.
  
                    Comments are shown in italics.
                                    
    Use of CALL and OS
  
  CALLs and OSs take a particular format.  This is briefly explained in the OPL Programming Manual, but is repeated here for reference.
  
  Using the 'Service' and 'Interrupt' reference in the 'C'-Programming Guide, it is possible to access the specific operating system call desired.
  
  
  Format for Call:
     ret%=CALL($xxyy,...,) xx = Service, yy = Interrupt
  
  Format for OS:
     LOCAL ax%,bx%,cx%,dx%,si%,di% keep these together
     LOCAL flags%
     ax%=$xxyy xx = Service, yy = AL (parameter)
     flags%=OS($zz,addr(ax%)) zz = Interrupt
  
  If an error occurs when using OS, (flags% AND 1) will be true,
  the error code is given by ax% AND $ff00.
  
    Starting another process
  
  Here we start another process, and specify the name of the file to be opened.  The command line starts with 'C' for create, or 'O' for open.  The filename is stored in f$.  The 'Record' at the beginning of the command line in this example is the name of the icon under which the filename will appear in the System Screen.  If this is not a valid (ie. installed) icon, then the filename will appear under RunImg.
  
  
  eg. Recorder with a filename
  
  PROC Record:(f$)
     LOCAL cmdl$(128),helpnm$(128),hpid%,ret%
     cmdl$="CRecord"+chr$(0)+".WVE"+" "+chr$(0)+f$+chr$(0) command line
     helpnm$="rom::record.app"+chr$(0)
     ret%=call($0187,addr(helpnm$)+1+addr(cmdl$),0,0,addr(hpid%)
     call($0688,pid%) ProcResume
  ENDP
  
  
  Get Process ID
  
  Each process has an ID number.  Here we read the ID number for a specific process.
  
  eg. Get the process ID for the system shell.  pid% is defined globally to hold this variable.
  
     name$="sys$shll.*"
     pid%=call($0188,addr(name$)+1) ProcIdByName
  
  
  Getting the Process ID for the current process
  
  This short piece of code reads the ID for the current process.
  
     LOCAL pid%
     pid%=CALL($0088)
  
  
    Setting the priority of the process
  
  Once we have the ID for a process, we can change the priority of this process.
  
     LOCAL ax%,bx%,cx%,dx%,si%,di% keep these together
     LOCAL flags% NB: pid% must be defined to be the process id
  
     bx%=pid%
     ax%=$0398
  
     flags%=OS($88,addr(ax%)) ProcSetPriority
  
  
  Changing the position of a process
  
  We can also change the position of this process, ie. whether it is in foreground or background.
  
     CALL($998d,pos%,pid%)
  
     For the current process, pid% can be set to zero.
     For foreground, use pos%=0, for background, pos%=100.
  
    Language Code
  
  Programs written by Psion are in the majority Multi-lingual.  This means that if they run on an English machine, they run in English, on a German machine they run in German, and so on.
  
  Each language is assigned a number, which is used to recognise the machine in use.
  
  This example returns a string containing the number of the code for the resource file.
  
  PROC Lang$:
     LOCAL ax%,bx%,cx%,dx%,si%,di% Keep these variables together
     LOCAL flags%,a$(2)
  
     ax%=$1B00 GetLangData
  
     flags%=OS($008B,ADDR(ax%)) General Services
  
     IF flags% AND 1
          RETURN("01") an error occured
     ELSE
          a$=NUM$(ax%,2)
          IF LEN(a$)<2 :a$="0"+a$ :ENDIF makes two digits for filenames
     ENDIF
  ENDP
  
  The numbers currently in use are:
        1   English
        2   French
        3   German
        4   Spanish
        5   Italian
        6   Swedish
        7   Danish
        8   Norwegen
        9   Finish
        10  American
        11  Swiss French
        12  Swiss German
        13  Portuguese
        14  Turkish
        15  Icelandic
        16  Russian
        17  Hungarian
        18  Dutch
        19  Belgian Flemish
        20  Australian
        21  New Zealand
        22  Austrian
        23  Belgian French
    
     Simulating a key press
  
  There is a technique for the Series3a to simulate a keypress in another application.  This method only works for Object-oriented applicaitions.
  
  The following must be globally defined:
     GLOBAL k%,m% keep these two together
  
  pid% is the process id, k% is the keycode, m% is the modifier
     CALL($0483,pid%,$31,0,addr(k%)) MessSend
  
  
  Capturing a key in background
  
  We can also when a particular key is pressed, even if the process requiring this key is not current.
  
     call($c58d,26,$404) wCaptureKey
     This example captures key 26, ie. Ctrl-Z.
  
     
  Capturing the off key
  
  The following parameters will capture the 'OFF' key.
  
     call($c58d,$2003,$e08)
     
     keya(kstat%,k%(1) queues for a key press
  
     The value returned in kstat% will NOT be -46 if a key is pressed, and for the off key,
     k%(1) will be $2003.
  
    Reading an environment variable
  
  Environment variables are used to store data which is used by all applications.  Space for these variables is limited, and should normally not be used by OPL applications.
  
  PROC EnvGet:
     LOCAL ax%,bx%,cx%,dx%,si%,di% keep these together
     LOCAL flags%
  
     LOCAL env$(6),penv%,lenenv%
     LOCAL buff$(255),pbuff%,lenbuff%
  
     env$="$WP_PW" name of the variable to search for, eg. $WP_PW
     penv%=ADDR(env$+1)
     lenenv%=LEN(env$)
  
     pbuff%=ADDR(buff$)+1
  
     ax%=$2100
     bx%=0
     di%=penv%
     dx%=lenenv%
     si%=pbuff%
  
     flags%=OS($008b,ADDR(ax%)) GenEnvBufferGet
  
     IF flags% AND 1
          An error has occured, error code: ax% OR $ff00
     ELSE
          lenbuff%=ax%
          POKEB ADDR(buff$),lenbuff% Insert leading count
     ENDIF
  ENDP
  
  Reading the user details
  User details are stored in environment variable $WS_PW.
  Bytes 4, 8, 12, and 16 contain the length (in bytes) of each of the four lines.
  The first line begins at byte 19.
  
  Reading the current printer driver
  The printer destination is stored in environment variable P$D. Zero for parallel, one for serial, and two for file.
  The printer driver is stored in environment variable P$M.  This is generally a filename.
  If printing to a file, the name is stored in P$F.
  
    Asynchronous WVE Playing
  
  This procedure will play a .WVE file asynchronously.
  
  PROC Play:(inname$,ticks%,vol%)
     LOCAL name$(128),pstat%
     name$=inname$+CHR$(0)
     CALL($1E86,UADD(ADDR(name$),1),ticks%,vol%,0,pstat%)
     IOWAITSTAT pstat%
  ENDP
  
  
  Cancelling Asynchronous Wave Playing
  PROC Playc:
     CALL($2086)
  ENDP
  
    Window Server os-calls
  
  This is a list of the Window Server os-calls, given here for reference purposes only.
  
  gSetOpenAddress(bx,cx,dx)   $5f8d
  wCancelCaptureKey(bx,cl,ch) $c68d
  wCancelSystemModal(bx) $c88d
  wCaptureKey(bx,cl,ch)  $c58d
  wClientInfo(bx)     $8c8d
  wClientPosition(bx,cx) $998d
  wDisableLeaves(dx)  $0dd6
  wDisablePauseKey()  $ce8d
  wDrawButton(bx,cx,dx)  $608d
  wEnablePauseKey()   $4d8d
  wEndCompute()       $8b8d
  wGetProcessList(si) $d98d
  wSendCommand(bx,cx,dx) $da8d
  wStartCompute()     $8a8d
  wsUpdate(bx)        $528d
  wSystemModal(bx)    $c78d
  
    Power Status
  
  This code will return TRUE if the mains is plugged in, and FALSCH if not.
  
  PROC mainsin%:
     LOCAL esup%(3)
     CALL($118e,addr(esup%(1)))   HwGetSupplyStatus
     RETURN esup%(3)
  ENDP
  
  Auto-off settings
  
  This code will return TRUE if the Series3a is NOT going to turn off, eg. because the external power is plugged in.
  
  PROC notifm%:
     IF (PEEKB(PEEKW($18)+13) and $f <2
          return 0 This is not a 3a
     ELSEIF (CALL($388b) AND $FF) <> 1 GenGetAutoMains
          return 0
     ELSE
          return(mainsin%:)
     ENDIF
  ENDP
  
  Now we can read the number of seconds to go before the Auto-off turns the machine off.  Note: In OPL  this will only work if we first call GenMarkNotActive and wEndCompute.
  
     ie.  CALL($138b) GenMarkNotActive
          CALL($8b8d) wEndCompute
  
  PROC timelft%:
     LOCAL gooff%,timeoff% keep these together
     IF notifm%:
          RETURN -1
     ENDIF
     CALL($078b,0,4,0,$40a,ADDR(gooff%)) GenGetOsData
     IF gooff%<0
          RETURN -1
     ELSE
          RETURN(timeoff%)
     ENDIF
  ENDP
    Asynchronous reading
  
  It is possible to read keys and timers asynchronously.  Firstly, a key:
  
  PROC quekey:
     keya(kstat%,k%(1))
  ENDP
  
  kstat% and k%(2) are globally defined.  Kstat% will by -46 if no key was pressed.  If the off key is pressed (and has been captured), then k%(1) will be $2003, otherwise the values in k%() will be similar to those returned using GETEVENT.
  
  Now the timer:
  
  Firstly we need to globally define timh%, timstat%, and then we open the channel to the timer function.
  
     IOOPEN(timh%,"TIM:",-1)
  
  Now we can queue the timer.
  
  PROC quetim:
     LOCAL t&,t%
     t%=2 This is the number of seconds before the timer should expire
     t&=int(t%*10)
     ioa(timh%,1,timstat%,t&,#0)
  ENDP
    Further Reading
  
  This has been only a brief guide to some of the functions available on the Series3a.  For more information, see the SIBO 'C'-Programming Guide.