The <system.h> header file
This header file contains the following functions:
AB_prodid AB_prodname AB_serno ASM_call
ASM_fastcall CB_fetchTEXT CB_replaceTEXT CU_restore
CU_start CU_stop enter_ghost_space EX_patch
HelpKeys idle kbd_queue NeedStack
off OSCheckBreak OSClearBreak OSContrastDn
OSContrastUp OSdequeue OSDisableBreak OSEnableBreak
OSenqueue OSFreeTimer OSqclear OSqhead
OSqinquire OSSetSR OSRegisterTimer OSReset
OSTimerCurVal OSTimerExpired OSTimerRestart OSVFreeTimer
OSVRegisterTimer QModeKey QSysKey SumStoChkMem
WordInList XR_stringPtr
and the following predefined types:
Bool DEF_QUEUE QUEUE Timers
Functions
Calls a subroutine located on absolute address.
ASM_fastcall calls an assembly subroutine located at absolute address base_addr.
As ASM_fastcall is a macro, not a function, base_addr need not to be a pointer. It
can also be an unsigned (long) integer. In fact,
ASM_fastcall (base_addr);
is the same as
((void(*)(void))(base_addr))();
but much more readable. It performs just "jsr" to base_addr; it does not perform any
relocation of relocatable items (to do this, see EX_patch).
ASM_fastcall assumes that called subroutine will not destroy any registers. If this
assumption is not valid, use ASM_call instead. In fact, if you are
not very sure about behaviour of called subroutine, it is highly recommended to avoid
ASM_fastcall and to use ASM_call. In releases of TIGCCLIB prior
to 2.1, ASM_call does exactly what ASM_fastcall does in this release.
NOTE: This function should be used with great care, because on HW2 calculators a stupid
protection device does not allow that the program counter may be on arbitrary place, except
if some special precausions are performed. Anyway, this function is not designed for common
use: it is intended for very experienced system programmers. Don't use it if you don't know
very well what are you doing!
Calls a subroutine located on absolute address, with saving/restoring all registers.
ASM_call pushes all registers onto the stack, performs ASM_factcall,
then restores all saved registers from the stack. Use ASM_call whenever you are not sure about
behaviour of called subroutine. If you are sure that the called subroutine will preserve all
registers, you can use ASM_factcall: it generates smaller and
faster code.
Relocates an assembly program.
EX_patch relocates relocatable items in the assembly program (.89z or .9xz file), where
tag_ptr points to the "PROGRAM" signature (tag) byte (byte 0xF3), and
base_addr is the address from where the assembly program will be started.
So, if handle is a handle of an .89z (or .9xz) file, you can execute it using
len = * (unsigned short*) (base_ptr = HLock (handle));
EX_patch (base_ptr + 2, base_ptr + len + 1);
ASM_call (base_ptr + 2);
HeapUnlock (handle);
In practice, some protection devices in HW2 calculators make the whole thing much more
complicated (see the FAQ list for more info).
Note that the relocation table begins just below the signature byte.
Transfers the execution into a "ghost address space".
enter_ghost_space transfers the program control into the "ghost address space" (i.e. into the
area above address 0x40000, which does not exist physically on the calculator, but represents
a "ghost" of the regular RAM space). This function is introduced to bypass some protections
introduced in AMS 2.04 and AMS 2.05 (the protection device does not protect the "ghost space",
so you have greater rights there). From the logical aspect of view, enter_ghost_space simply
adds 0x40000 to the program counter. In practice, this is performed on very awkward way,
because some new protections in AMS 2.04 and AMS 2.05 does not allow us to do this directly
under all conditions. See the Frequently Asked Question list for the
only example where you really should use this function. You should not to know anything more
about it.
Sets the processor status register
OSSetSR sets the processor status register to SR. Supervisor and
trace bits cannot be set up using this routine. For example, use
OSSetSR (0x0700);
to disable all interrupts, and
OSSetSR (0x0000);
to enable them again. Note that any call to keyboard input routines
like ngetchx etc. will enable interrupts
again.
NOTE: Disabling Auto-Int 1 is often used for making the status line indicators
not visible on the screen so that the status indicators do not mess up your graphics
(status line indicators are updated from this interrupt). In this case, you need to
read the keyboard using _rowread function, because
functions like ngetchx are based on Auto-Int 1.
However, if you disable interrupts, the grayscale will not work, because the grayscale
is also based on Auto-Int 1. To solve this problem, instead of disabling
Auto-Int 1, you may redirect it to nothing. See DUMMY_HANDLER
in intr.h header file for more info.
Resets the calculator.
OSReset resets the calculator without any warnings.
Increases the contrast.
OSContrastUp increases the display contrast.
Decreases the contrast.
OSContrastDn decreases the display contrast.
Enables the BREAK key.
OSEnableBreak enables the BREAK key (of course, NOT during execution of
assembly programs)! However, BREAK key may be read from assembly programs
using OSCheckBreak.
NOTE: Although the BREAK (i.e. ON) key is disabled during execution of assembly
programs, execution of some TIOS functions may be breaked by pressing BREAK key
(usually functions which executes some internal loops with long or undeterminate duration,
like various high-level linking functions, etc.). Usage of
OSDisableBreak will disable BREAK key even in
such cases.
Disables the BREAK key.
OSDisableBreak disables the BREAK key. See also OSEnableBreak.
Checks pressing of BREAK key.
OSCheckBreak returns TRUE if BREAK key was pressed
(for this, BREAK must be enabled using OSEnableBreak),
else returns FALSE. Note that OSCheckBreak will
remain true until explicite call of OSClearBreak.
Clears "BREAK key pressed" flag.
OSClearBreak clears "BREAK key pressed" flag. See
OSCheckBreak for more info.
Determines the product ID code.
AB_prodid fills the buffer with the product ID code of the calculator.
The ID string is in the form "p-h-r-b", where "p" is the product number (01 for TI-92 Plus, 03
for TI-89), "h" is the hardware revision level, "r" is the software revision level and
"b" is the build number. All the above fields consist of hexadecimal digits.
buffer must be at least 12 bytes long to accept the product ID string.
Determines the product name.
AB_prodname fills the buffer with the product name, i.e. the name of the operating
system software running on the calculator. This is the same name that appears on the second
line of the "About" window. Not very useful, because
it seems that so far the product name is always "Advanced Mathematics Software".
buffer must be at least 40 bytes long to accept the product name.
Determines the serial number.
AB_prodname tries to fill the buffer with the serial number of the calculator.
The serial number is constructed from the string returned from
cgetsn function (with one space inserted in the middle), and from
the hexadecimal value returned from FL_getVerNum
function. Note that these routines are very cryptic, and do some ugly things with the Flash
memory, so this probably works only on real TI (at least, it does not work under VTI).
AB_serno returns
TRUE if determining the serial number was successful, else returns
FALSE (this is a case on VTI, for example).
The serial number has the form "pphnn nnnnn vvvv", where "pp" is the platform number
(01 for TI-92 Plus, 03 for TI-89), "h" is hardware revision level, "nnnnnnn" is an ID number
which is unique to each calculator, and "vvvv" is a verification number.
All the above fields consist of hexadecimal digits.
buffer must be at least 17 bytes long to accept the serial number.
Turns the calculator off.
off turns the calculator off. asm("trap #4") does exactly same thing, but calling
this routine is more official.
Switches the calculator to "idle" state for a while.
While idle is running, the calculator rests. idle turns the calculator in "low
power" state until the next interrupt occurs (then "low power" state will be
disabled, and idle returns).
While calculator is in "idle" state, the power consumption decreases significantly.
TIOS very often calls idle, whenever it is in a kind of "idle loop". So it is very
useful to be used in programs which waits in a loop for something (waiting for
specific keypress, timer expiring, etc.). Many programs should use idle to save the
batteries (editors, reflexive games, explorers, debuggers etc.). Thanks to Julien
Muchembled for this info.
NOTE: Thomas Nussbaumer informed me that idle interfere with the grayscale graphic,
so usage of idle while grayscale mode is active is not recommended.
Registers a notify (countdown) timer.
TIOS has a 6 notify (countdown) timers, numbered from 1 to 6. OSRegisterTimer initializes the
timer which ID number is timer_no, and sets its initial value to T.
Every time the Auto-Int 5 is triggered (20 times per second if you didn't change the
programable rate generator), the current value of the timer is decremented by 1. When
the current value reaches zero, nothing special happens, but a flag is set which
indicates that the timer is expired. This flag may be check using function
OSTimerExpired.
OSRegisterTimer returns timer_no if the registration was successful, else
returns zero. This happens if you give wrong parameters, or if the timer timer_no
is already in use. So, you must first free the timer using OSFreeTimer.
Notify timers 2, 3, 4 and sometimes 5 are used in TIOS for internal purposes, and it seems that
timers 1 and 6 are free for use (especially I expected that 6 are surely
unused, and I am not so sure for timer 1). Timer 5 is sometimes used for measuring
time in some TI-Basic functions like CyclePic. Timer 4 is used for cursor blinking.
Timer 3 is used for link communication. Timer 2 is used for automatic power-down (APD)
counting, so this is an official method to change APD rate to, for example, 100 seconds:
OSFreeTimer (APD_TIMER);
OSRegisterTimer (APD_TIMER, 100*20);
Legal timer numbers (like APD_TIMER) are defined in enum Timers, to make a
program more readable. See also other timer functions for more info.
Frees a notify (countdown) timer.
OSFreeTimer deactivates and frees the notify (countdown) timer timer_no.
OSFreeTimer must be called
before registering a timer using OSRegisterTimer if
the timer was already in use. Returns FALSE in a case of error,
else returns TRUE.
Determines a current value of a notify (countdown) timer.
OSTimerCurVal returns a current value of the timer timer_no.
Determines whether a notify (countdown) timer expired.
OSTimerExpired returns TRUE if the notify (countdown) timer timer_no
expired, else returns FALSE. See OSRegisterTimer
for more info. For example, a legal way to make a 5-second delay is:
OSFreeTimer (USER_TIMER);
OSRegisterTimer (USER_TIMER, 5*20);
while (!OSTimerExpired (USER_TIMER));
OSTimerExpired also resets flag which tells that the timer was expired, so the calling
this function again will return FALSE.
Restarts a notify (countdown) timer.
OSTimerRestart resets the timer timer_no to its initial value, and
returns the current value of the timer as was before reseting.
Registers an event (vectored) timer.
Before release 2.04 of the AMS, TIOS also had two event (vectored) timers numbered as 1 and 2
(in addition to 6 notify timers which may be registered using
OSRegisterTimer). In AMS 2.04, Texas Instruments decided
from some strange reasons to remove vectored timer from the TIOS. I was very angry due to
this decision, so I decided to reimplement these timers indepentently of the TIOS, to
make them working on any AMS version. Well, now you have it. More precise, you now have
two event (vetcored) timers which are numbered as 1 and 2, which works on any AMS release
(TIOS based implementation as implemented in TIGCCLIB releases prior to 2.2 did not work
on AMS 2.04 and AMS 2.05).
OSVRegisterTimer initializes the event timer which ID number
is timer_no, and sets its initial value to T. Every time the
Auto-Int 5 is triggered (20 times per second if you didn't change the programable
rate generator), the current value of the timer is decremented by 1. When the
current value reaches zero, a procedure specified by user will be called, then
the timer starts counting again from its initial value. The parameter
Action is the pointer to the procedure which will be triggered every
time the timer reaches zero. So, the procedure Action will be called
periodically, with a period determined by T.
Action need not to be an assembly language procedure; it may be any
user-defined function written in C. Its body will be executed in the
supervisor CPU mode and with disabled interrupts (th information is probably
not important from the user point of view).
If the function Action changes any global variable
in the program, such global variable must be declared as "volatile" to inform
the compiler that its value may be changed asynchronously, i.e. in a way which
is unexpected for the normal program flow.
OSVRegisterTimer returns a nonzero value if the registration was successful, else
returns zero. This happens if you give wrong parameters, or if the timer timer_no
is already in use. So, you must first free the timer using
OSVFreeTimer (as I completely rewrote these routines, I
also corrected some bugs in them which were presented in TIOS routines; you know about
them if you read the documentation about OSVRegisterTimer in earlier releases of
TIGCCLIB). As event timers now work indepentently of TIOS timers, both event timers
(1 and 2) are free for use. Here is a simple example of the program which installs
both event timers:
#include <tigcclib.h>
int _ti89, _ti92plus;
void Action1 (void)
{
static int Counter = 0;
printf_xy (50, 50, "Counter1=%d ", ++Counter);
}
void Action2 (void)
{
static int Counter = 0;
printf_xy (70, 70, "Counter2=%d ", ++Counter);
}
void _main(void)
{
OSVRegisterTimer (1, 3, Action1);
OSVRegisterTimer (2, 10, Action2);
ngetchx ();
OSVFreeTimer (1);
OSVFreeTimer (2);
}
In this implementation of OSVRegisterTimer, it is not necessary to free timers using
OSVFreeTimer before first usage of them, because they are
free by default at the begining. However, nothing wrong will happen if you try to free
them explicitely (which was necessary in previous releases of TIGCCLIB).
NOTE: As already mentioned above, all TIOS bugs in timer routines (dependence between
notify and event timers, etc.) are now removed, because these routines are rewritten to
be independent of
the TIOS.
Frees an event (vectored) timer.
OSVFreeTimer deactivates and frees the event (vectored) timer timer_no. OSVFreeTimer must
be called before registering a timer using OSVRegisterTimer if
the timer was already in use.
Returns FALSE in a case of error, else returns TRUE.
NOTE: Don't forget to free an event timer which was registered before exiting the program;
else very bad things may happen later. I expect that you know why...
Insert a new element into a queue.
OSenqueue inserts the element data in a queue (FIFO - First In First Out) structure pointed
to by Queue. Queue is usually a pointer to the structure of the type
QUEUE or DEF_QUEUE. OSenqueue returns
TRUE if the operation was sucessful, else return FALSE
(for example, if the queue is full). See destription of queue types
QUEUE and DEF_QUEUE for an example
of usage.
Removes an element from a queue.
OSdequeue removes an element from a queue structure pointed to by Queue and stores
them in the variable pointed to by dest. As queue is a FIFO structure, first removed element
is the first element inserted in the queue; the next removed element is the second element
inserted in the queue, etc. OSdequeue returns TRUE if the queue was
empty, else returns FALSE. See also OSenqueue.
NOTE: This function may be used for fast keyboard reading: see kbd_queue.
Checks whether an element is waiting in a queue.
OSqinquire returns TRUE if the queue pointed to by Queue is not empty
(i.e. if there is an element waiting in it), else returns FALSE. If the
queue is not empty, OSqinquire also stores the first element which will be removed from the
queue in the variable pointed to by dest, but in opposite to OSdequeue
the element itself will not be removed from the queue. See also OSenqueue.
Gets an element from the head of a queue.
OSqhead returns an element from the head of a queue structure pointed to by Queue without
removing it from the queue (the head element is the last element inserted in the queue,
not the first one). dummy is the dummy parameter: it is not used in the routine.
See also OSenqueue.
Clears a queue.
OSqclear empties and resets the queue structure pointed to by Queue. More precise, it
resets the structure to {0, 0, 2, 0}. See also OSenqueue.
Returns a pointer to the keyboard queue.
kbd_queue returns a pointer to the queue used in TIOS for keyboard handling. It may be used as
an argument to other queue-related functions. The main purpose of accessing to keyboard queue
is to make a fast replacement for ngetchx and
kbhit functions. This may be achieved using
OSdequeue function. For example, suppose that you have the following
declarations:
void *kbq = kbd_queue ();
int key;
Then, statements like
if (kbhit ())
{
key = ngetchx ();
// Do something with key
}
may be replaced with much faster equivalent:
if (!OSdequeue (&key, kbq))
{
// Do something with key
}
NOTE: On the first look, it seems that the key repetition feature
does not work with OSdequeue. But, Marcos
Lopez informed me that this is not exactly true. Key repetition feature
works even with OSdequeue, but it will not
return the keycode itself for the repeated key, but sets an additional
bit in the keycode, so value becomes value + 0x800.
If you use standard ngetchx function, this
additional bit is masked out and your program will get the keycodes it expects.
But, it is very simple to mask out this bit manually and make the key repetition
feature working even with OSdequeue.
Searches for a word in the list.
WordInList is an useful short routine which returns TRUE if the
word Word is a member of the list (i.e. array) of words pointed to by
List, otherwise returns FALSE. The list of words is
terminaded by word 0.
Checks for a space on the stack.
NeedStack throws a memory error if there is no enough space on the processor stack for Size bytes
(the hardware stack is 16K in size; when a function calls another function the system will throw an
error if there is not enough hardware stack to make the call).
Although this routine is used mainly internally in TIOS, sometimes it may be useful even
in user programs. For example, a function may have a complex set of operations that may not be
easily undone in a ONERR block. The function may also require
that all of the operations do not fail due to a lack of hardware stack. In this case, the
function can be started with a call to NeedStack to at least guarantee that
the hardware stack will not overflow during the critical section of the function.
Critical operations may be, say, direct modifying elements of the VAT table. So, if the
function calls NeedStack first, this insures
that none of the critical operations are partially completed due to a lack of
hardware stack thus leaving the VAT table (for example) in an undefined state. The
TI-Basic interpreter uses the hardware stack to make recursive calls and
so all TI-Basic commands and functions cannot rely on the hardware
stack being at any particular level.
Returns a pointer to a TIOS system message (XR string).
XR_stringPtr returns a pointer to the TIOS system message which number is given
in XR_string_no. It is not recommended to make use of these ID's as they are not
consistent across ROM versions, and are mainly used interally for efficiency (although
it seems that these ID numbers are the same in all AMS versions starting from AMS 2.00).
For example, dialog structures and EV_sendString use them.
All tokens (like "sin" etc.) are also XR strings.
Displays a keyboard help screen.
HelpKeys displays a keyboard help on the screen (the help screen which may be
called by pressing Diamond+EE on TI-89), waits for a keypress, then restores
the screen to the previous state.
Checks whether argument is code of a system key.
QSysKey returns TRUE if code is code of a system key,
else returns FALSE. It assumes that code is
code as the function ngetchx for reading the keyboard
returns. System keys are keys which opens menus, which may have as the result inserting
characters or tokens in the editor. The following keys are system keys on the TI-89:
MATH, CATALOG, CHAR and CUSTOM (codes 4149, 278, 4139 and 4373).
Checks whether argument is code of a mode key.
QModeKey returns TRUE if code is code of a mode key,
else returns FALSE. It assumes that code is
code as the function ngetchx for reading the keyboard
returns. Mode keys are keys which may cause change of the current application or
the configuration of the calculator. The following keys are mode keys on the TI-89:
HOME, APPS, MODE, VAR-LINK, SWITCH (2nd+APPS), MEM, QUIT, Y=, WINDOW, GRAPH,
TblSet, TABLE and OFF (codes 277, 265, 266, 4141, 4361, 4150, 4360, 16652, 16653,
16654, 16655, 16656 and 4363). Note that codes returned by
ngetchx are mostly equal like codes returned by
BASIC command GetKey, but codes of arrow keys, and keys pressed together with
Diamond keys are different. See ngetchx for more info.
Checks memory content by making a checksum.
SumStoChkMem calculates a checksum of the user portion of the RAM memory (more precise,
from address 0x400 to 0xFFF and from the bottom of the heap to the end of the RAM), and
stores the calculated value in one internal system variable. Returns
TRUE is calculated checksum is equal to the previous value of this
system variable, else returns FALSE. So, SumStoChkMem may be used
for checking whether the content of the memory was changed since the last call of
SumStoChkMem (i.e. between two calls of SumStoChkMem).
Starts the cursor.
CU_start restarts the cursor timer and sets an internal flag which tell that cursor is
active. This does not mean that the cursor will be displayed on the screen immidiately.
This mean only that if some routine wants to display cursor, it will be permitted.
The main usage of this function is in conjuction with text editor functions
(see textedit.h header file). CU_start returns
TRUE or FALSE, depending of whether the cursor
was enabled or disabled before calling this function.
Stops the cursor.
CU_stop resets an internal flag which tell that cursor is active, so after this function,
displaying of the cursor will be denied. This function is called often from event driven
and interrupt driven applications to stop the cursor blinking for a while.
CU_stop returns TRUE or FALSE, depending of whether the cursor
was enabled or disabled before calling this function.
Restores the previous cursor state.
CU_restore restores the previous cursor state (active or inactive). Parameter State
should be a value returned from CU_start or CU_stop
function.
Puts a text into the clipboard.
CB_replaceTEXT puts len bytes starting from the address text to the
clipboard. TIOS only uses clipboard for storing text, but it is capable to store other types
too. strip_CR is Boolean parameter: if it is TRUE, each byte
which follows immidiately after '\r' character (0xD) will not be stored in the clipboard
(this in fact stripes out command characters in text editor: see textedit.h
header file). CB_replaceTEXT returns TRUE if the operation was successful,
else returns FALSE (e.g. no enough memory). This routine may cause heap
compression.
short CB_fetchTEXT (HANDLE *hText, unsigned long *len);
Fetches a text from the clipboard.
CB_fetchTEXT stores in the variable pointed to by hText the handle of the text stored
in the clipboard (use HeapDeref to get actual pointer to
the text). It also stores the length of the text in the variable pointed to by len.
See also CB_replaceTEXT.
CB_fetchTEXT returns TRUE if the operation was successful,
else returns FALSE (i.e. if the clipboard is empty or trashed).
Predefined types
Bool is enumerated type for describing true or false values. It is defined as
enum Bool {FALSE, TRUE};
Timers is enumerated type for describing timer ID numbers. It is defined as
enum Timer {BATT_TIMER = 1, APD_TIMER = 2, LIO_TIMER = 3, CURSOR_TIMER = 4,
MISC_TIMER = 5, USER_TIMER = 6};
See timer functions (OSRegisterTimer etc.) for more info.
DEF_QUEUE is a structure which describes a header of a variable-sized queue. It is defined as
typedef struct
{
unsigned short Head; // Offset to the head of the queue
unsigned short Tail; // Offset to the tail of the queue
unsigned short Size; // Max number of entries in the queue
unsigned short Used; // Actual number of entries in the queue
unsigned short Buffer[0];
} DEF_QUEUE;
Note that Buffer[0] is a GNU C extension for variable-sized arrays (TIGCC is GNU C). The
main usage of DEF_QUEUE structure is when you want to allocate a queue dynamically on
the heap (using malloc). The operator sizeof
treats variable-sized arrays as zero-length arrays (this is a sense of zero in square brackets).
So, the following example ilustrates correct allocating of a queue with 100-byte long buffer on the
heap (note that 100-byte long buffer can store 50 entries, because each int entry is 2 bytes long):
DEF_QUEUE *qptr = malloc (sizeof (DEF_QUEUE) + 100);
OSqclear (qptr);
qptr->Size = 50;
OSenqueue (some_data, qptr);
From this example you can see that you need to fill field Size of the queue
structure manually.
QUEUE(n) is a structure which describes a queue with n-byte long buffer. Strictly
speaking, QUEUE(n) is not a type but a macro defined as
#define QUEUE(n) struct {unsigned short Head, Tail, Size, Used, Buffer[n/2];}
although it works exactly as a type, so you can treat it as a type. It is useful for
definining a queue without dynamic allocation (i.e. without calling
malloc), like in following example:
QUEUE(100) q;
OSqclear (&q);
q.Size = 50;
OSenqueue (some_data, &q);
Note that QUEUE(n) works exactly like type, so it can be used anywhere where type
name is expected, for example in pointer declarations, and even as the argument of
sizeof etc. This is ilustrated in following example:
QUEUE(100) *qptr = malloc (sizeof (QUEUE(100)));
OSqclear (qptr);
qptr->Size = 50;
OSenqueue (some_data, qptr);
See also DEF_QUEUE for more info.