home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Simtel MSDOS 1992 December
/
simtel1292_SIMTEL_1292_Walnut_Creek.iso
/
msdos
/
c
/
xlib.arc
/
XLIB.MAN
< prev
Wrap
Text File
|
1987-07-12
|
16KB
|
529 lines
Communications and Multitasking Library
For Datalight C
by
Matt Brandt
Overview
This library contains a multitasking kernel and a
communications kernel. The communications kernel allows you
to control the com ports of a PC in a simple way but allows
any speed the com port is capable of running. The
communications routines are interrupt driven so that even in
very fast transfers a program will not have any trouble
keeping up. The multitasking kernel allows a program to have
several apparently simultaneous execution threads. This is
especially usefull in communications because there is
usually traffic in both directions. A small terminal program
"mini.c" is included in this archive to demonstrate the
concepts. While you may use the communications routines
without worring about the multitasking I urge you to take
the time to understand the multasking kernel. It will make
your life much easier for many applications, not just
communications. In the following pages I will discuss the
concepts of the communications and multitasking routines and
demonstrate how each routine is called. The last section
deals with the example program mini.c and shows how it
works.
This package is being distributed as shareware. You may try
it out, see if it is what you want, and if it fits a need
you have then I ask that you send me 20 dollars. For your
twenty dollars you will get the complete source code, a
license to use any and all of these routines in your own
code for profit without any royalties, and the other three
models (P,D, and L) of the library. If you do not need this
package and do not use it then you are under no obligation
to send me any money. Please feel free to pass this archive
on in it's original form to friends and BBS's that you think
might be interested.
If you want to send in a contribution send your check to:
Matt Brandt
PO Box 920337
Norcross, GA 30092
Your comments and suggestions are also welcome.
Multitasking Concepts
This library implements what is called a non-preemptive
scheduler. This means that when one task is running it will
not be "preempted" by a task of higher priority. A task is
only suspended when it makes one of two tasking calls. It is
up to the programmer to make sure that all tasks get a
chance to run. Each task has it's own stack area. The global
and static data of the program is available to all tasks.
The task scheduler does not "hook" any interrupts or take
over any of the machine resources so any task can return to
DOS at any time. This will have the effect of killing all of
the other tasks.
There can be up to 32 seperate tasks. The main program is
assigned task number zero at program startup. The tasks are
prioritized by task number with task zero being the highest
priority task and task 31 being the lowest priority. You do
not need to assign task numbers sequentially. It is
perfectly acceptable to have only tasks zero and ten for
instance. The scheduler will perform slightly better,
however, when there are a minimum number of "holes" in the
task assignments.
Tasks can syncronize and communicate through signals. It is
also possible for interrupt service routines to send signals
to tasks. There are 32 signals available [0..31]. Any task
can wait for a signal. It will then be suspended until that
signal is sent by another task or an interrupt routine. If a
signal is sent and there is nobody waiting for it then it
will be saved until the next wait is performed. That wait
will not suspend the task but instead will receive the
signal that was previously sent. Only one occurance of each
signal can be saved. Multiple unwaited occurrances are the
same as one unwaited occurrance. More that one task may wait
for a given signal. In this case the highest priority
waiting task will be readied when the signal is sent.
The task calls are as follows:
t_create(tasknum,func,stk,stksiz);
int tasknum;
void (*func)();
int *stk;
int stksiz;
This call creates a task whose task number is given by
tasknum. If a task is already running at that task
number it is replaced by the new task. func should be
the address of a function to be executed as the new
task. stk should point to an area of memory and stksiz
should be the size of the task's stack area in bytes.
If a task function returns the task is deleted. The new
task is placed in a ready to run state but is not given
control until scheduling occurs by way of a t_wait or
t_yield call. If the new task number is the same as the
currently running task then this call will have no
effect.
EXAMPLE:
int t1stk[512];
task1()
{
..code to do a job
}
.
t_create(1,task1,t1stk,sizeof(t1stk));
t_kill(tasknum)
int tasknum;
This call will delete the task whose task number is
given by tasknum. If tasknum matches the task number of
the currently running task the current task will be
killed and rescheduling will occur.
t_wait(signo)
int signo;
The task issuing this call will wait until signal
number signo is issued by another task or an interrupt
service routine. If the signal was already issued then
the current task will continue unhindered. When a task
suspends then the highest priority ready task is
continued at the point where it left off.
t_signal(signo)
This call causes an occurrance of signal number signo.
The highest priority task waiting for that signal will
be made ready. This call will NOT cause scheduling to
occur. That must be done by a call to t_wait or
t_yield.
t_yield()
This call will allow any higher priority tasks to
execute. If the current task is the highest priority
ready task then it will continue. Note that a yield
from the main program (task zero) will always have no
effect because it is always the highest priority task.
Communications overview
The communications module contains procedures to initialize
either (or both) com ports, send and receive characters on
the ports, and set the mode and baud rates for the ports.
Each routine is shown below with a description. These
routines use the task scheduler to suspend tasks and signal
when new input is available. Signals two thru five are used
by these routines. You may ignore the multitasking, however,
with no ill effects since the main task will be the only one
running.
int copen(portno,ibufsiz,obufsiz)
int portno;
int ibufsiz;
int obufsiz;
Open a com port and return a port handle. The portno
should be 0 for com1 and 1 for com2. This sets up the
input and output buffers and "hooks" the interrupt
vector used to service the port. ibufsiz is the input
buffer size in bytes and obufsiz is the output buffer
size in bytes. Note that the input buffer should
normally be much larger than then output buffer.
cbaud(phand,br)
int phand;
int br;
This routine will set the port described by phand to
the specified baud rate. Note that any baud rate can be
used, not just the normal ones. The maximum allowed by
the port is about 50K. Normally, of course, you should
stick to the standard baud rates for compatability with
other programs.
cmode(phand,par,bits,stopb)
int phand, par, bits, stopb;
This sets the mode of a port. parity is described by
the par argument and can be one of ['n','e','o']. bits
describes the number of bits in each byte transmitted
(either 7 or 8) and stopb tells how many stop bits
(either 1 or 2).
cclose(phand)
int phand;
This routine turns the port off and unhooks the
interrupt vector. It is important to do this before
exiting your program so that a spurious interrupt does
not occur.
cputc(phand,c)
int phand, c;
outputs a character to the port described by phand. If
the output buffer is full then the task making this
call will be suspended until there is room for the
character.
int cgetc(phand)
int phand;
reads a character from the port described by phand. If
there are no characters available then the task making
this call will be suspended until one becomes
available.
int cpoll(phand)
returns the number of characters available in the input
buffer for the port described by phand. You can use
this to keep from waiting for input if you don't want
to use the multitasking facility.
MiniTerminal program discussion
The file "mini.c" contains an example of the use of this
library to do a standard job in an elegant way. The main
program of mini opens com1 and sets the port to 1200 baud.
It then intercepts the keyboard interrupt and creates a new
task (task1) and starts an infinite loop. The main program
then becomes a receiver task which just gets a character
from the port and puts it on the screen. Meanwhile, task1 is
getting a character from the keyboard, checking whether or
not it is the key designated to terminate the program (F1)
and if not sending the character out the com port. When
task1 tries to get a character from the keyboard it first
checks to see if there is a character available, if not it
waits for signal zero which is sent by kbsvc when the next
keyboard interrupt happens. Likewise, when the main task
tries to get a character from the port it will wait till one
is available. The multitasking makes the program a lot
easier to follow.
But wait, you say! I could do the same thing without a
multitasking kernel and all of that bruhaha. In that case
you would check to see if a key was available, if so process
it, then check to see if a com character was available, and
if so process it, in a single loop. That works out ok for
the simple case but think of what you would have to do to do
the job of the routine escseq which interprets incomming
ansi escape sequences. Remember, you don't want to hold up
keyboard input while all the rest of the characters come in!
At 300 baud that would be a noticable delay. You would have
to keep track of what had been received already in an escape
sequence and what the current state was. The multitasker
takes a lot of the bother out of the job. You can just write
the receiver routine as though no keyboard work had to be
done at all.
To compile and link mini.c do the following command:
dlc mini.c xlib.lib
Well, that about wraps it up. Remember, for just twenty
bucks you get the source code, all four memory models (this
is just the small model) and an unlimited license to use
this nifty library in your own programs. Sorry, no ginsu
knives.