Dec 132017
Very nice set of communication routines written for TP 5.0. No source, only TPU. Written by Jim Berg. | |||
---|---|---|---|
File Name | File Size | Zip Size | Zip Type |
COMMTEST.PAS | 6114 | 667 | deflated |
JBCOMM50.DOC | 34274 | 8459 | deflated |
JBCOMM50.TPU | 9792 | 4220 | deflated |
MODEM7.PAS | 31163 | 6813 | deflated |
Download File JBCOMM50.ZIP Here
Contents of the JBCOMM50.DOC file
JBCOMM: v5.0 by Jim Berg, (c)Copyright 1988,1989
The following procedures and functions are to assist the general
public with communications programming in Turbo Pascal v5.0. Feel
free to use these routines in your private programs or programs
intended for the Public Domain. If you intend to use these routines
in a program that you will receive money for, be it Shareware,
Commercial, or part of your professional program library, you must
send $50 to (note: if you already sent, or offered to send, the
previously requested $15, additional money is not neccassary, but would
be appreciated):
Jim Berg
650 Minnetonka Highland Lane
Long Lake, MN 55356
If you find any bugs or have any suggestions, please feel free to
write me a letter. And please, if you dig up my phone number somewhere,
don't call me on the weekends. I may be around after 6pm CST on the
weekdays, but don't call after 9pm either. I have to make a living too.
I may also be reached through the National Pascal Echo Mail area.
********* DISCLAIMER *************
If something goes wrong with your hardware while using this library,
I hereby free myself from any liability with this disclaimer. As far
as I know, these routines work. If something does go wrong, please
contact me anyway so I may attempt to fix the program.
Name: porttype
Usage: cp : porttype;
Description:
type porttype = (com0, com1, com2, com3, com4,
com5, com6, com7, com8);
This is the type declaration for com port numbers. JBCOMM
now supports COM0 through COM8. COM0 is a dummy com port
that I have used for local operation of a multiuser BBS. It
works the same as the others, but you must insert the data
into the receive buffer of the port with the c_insertc and
c_inserts commands.
Name: parityt
Usage: parity : parityt;
Description:
type parityt = (p_none,p_even,p_odd,p_even_stick,p_odd_stick);
This is the type declaration for parity. See c_set_uart for
more information on parity. I won't describe the last two since
those who know what they can be used for already know enough not
to have it explained.
Name: checkstr
Usage: checklist : array [1..n] of checkstr;
Description:
type checkstr = string[80];
See c_waitsn.
Name: com_info_rec
Usage: info : com_info_rec;
Description:
type
com_info_rec = record
offset, Base address of serial port.
speed : word; Current speed setting.
parity : parityt; Current Parity Setting.
data, Current Data size.
stops : byte; Current Stop bits.
active, TRUE if port is active.
ints_on : boolean TRUE if interrupts are active.
end;
See c_port_info and accompanying program example.
Name: ESC_ON
Usage: ESC_ON:=TRUE; or ESC_ON:=FALSE;
Description:
var ESC_ON : boolean;
If ESC_ON is set to TRUE, it will allow you to exit out of
c_getb and c_waitsn if the user hits ESC. The default is
ESC_ON:=TRUE.
See c_getb and c_waitsn.
Name: c_set_speed
Usage:
procedure c_set_speed (cp : porttype;
speed : word );
Description:
C_set_speed will set the current speed that your serial
port will operate at.
Returns: Nothing
Example:
If you want to set COM1 to operation at 2400 baud, you
would use it the following way:
c_set_speed(com1,2400);
Name: c_set_uart
Usage:
procedure c_set_uart (cp : porttype;
parity : parityt;
data,
stops : byte );
Description:
C_set_uart sets the current operating format of the serial
port. This includes the parity, data size, and stop bits
used.
Data Bits explained:
Most BBSes you call allow you to download binary files. These
files are made up of a byte which are 8 bits wide. In order
for your program to download these types of files, you have to
set your serial port for 8 data bits. If you are calling a board
that only allows text transfers because it only uses the first
128 characters of the ASCII set, you may want to only use 7 data
bits, since that is all that is required for this type of use.
Anything less than 7 is very uncommon.
Parity explained:
Parity is a very simple way of doing error correction. If you
were to select EVEN parity, this means that it will send an equal
number of 1 bits as it does 0 bits. If you receive a character
that has more 1 bits, or more 0 bits than its opposite, they you
can assume that the character was sent wrong. The serial port
will set some bits in the Line Status Register to inform you of
these type of errors.
ODD is the opposite of EVEN obviously. This means that an odd
number of bits will be sent.
NONE means that there is no parity at all. This has to be used if
you are using 8 data bits.
Stop bits explained:
A stop bit tells when a character is finished. There is
no real difference between 1 and 2, but most people use 1.
Returns: Nothing
Example:
Say you wanted to write a program to call your local Opus board
and you wanted to get all of the special text graphic characters
and be able to download a binary game. You would then have to
set your serial port 1 to use 8 data bits, No Parity, and 1 stop
bit. To do this you would use:
c_set_uart(com1,p_none,8,1);
Name: c_open
Usage:
procedure c_open (cp : porttype;
speed : word;
parity : parityt;
data,
stops : byte;
ibuffs,
obuffs : word );
Description:
C_open starts the ball rolling for communications. It sets
up the serial port to use interrupts and sets the size of
the input buffer and output buffer. You should call this
procedure before using any of the other communication
routines. If a command can be used without calling this
first, I will let you know.
Speed, parity, data and stops are pretty much explained above.
C_open calls those routines. IBUFFS and OBUFFS are the only
things really new here. JBCOMM uses both an output and input
buffer.
If your program does a lot of extra things before grabbing the
character from the serial port, that character may be lost if
you do not grab it before a new character comes in. To get
around this JBCOMM uses the ability of the serial port to cause
and interrupt. What this means is that when a character is
received, the computer will save your spot in the program, then
jump automatically to a routine to grab the character and then
puts that character into a buffer to store it until you need it.
This is what IBUFFS is for. It sets aside the number of bytes you
specify for an input buffer.
The serial port also has the ability to cause an interrupt when
its transmit register becomes empty. This makes it possible
for you to load characters into a buffer and the interrupt routine
will send them when it is able. This makes it so you are not
always having to wait for your character to be sent. OBUFFS is
used to tell JBCOMM how much space to set aside for your output
buffer.
Example:
You want to communicate with an Opus system and you want an input
buffer of 4096 bytes and an output buffer of 256 bytes. You would
then use.
c_open(com1,2400,p_none,8,1,4096,256);
Name: c_close
Usage:
procedure c_close (cp : porttype;
dropdtr : boolean );
Description:
C_close turns off interrupts and releases memory reserved with
c_open. See c_open. Dropdtr tells whether you want to leave
the port active, or to turn it off completely. If you leave
the port active by passing dropdtr as FALSE, you can leave your
program without hanging up or disconnecting. This may be useful
if you are writing a BBS that uses doors, or if you want to write
a COMM program that uses external protocals. When you come back
into the program, you can do another call to c_open.
Returns: Nothing.
Example:
You are all done with communications and you want to shutdown the
serial port and interrupts. You would then use.
c_close(com1,TRUE);
You want to execute or leave your program to run a program that
has its own communication handler so you want to turn off your
interrupts but leave the port active. You would then use.
c_close(com1,FALSE);
Name: c_inready
Usage:
function c_inready( cp : porttype ) : word;
Description:
C_inready is a function that returns the number of characters
waiting in the input buffer.
Returns: Number of characters waiting to be read in input buffer.
Example:
C_inready can be used much like Keypressed. C_inready returns
more information however. If you want to use it just like
Keypressed, you can use.
if c_inready(com1)>0 then { get character from buffer}
C_inready can also be used to wait for a certain number of
characters are in the buffer before you do something. Say
you needed to wait for 30 characters, then you would use.
repeat until c_inready(com1)>=30;
Name: c_outready
Usage:
function c_outready( cp :porttype ):word;
Description:
Will return the number of characters waiting in the output
buffer to be sent. This is much like c_inready except it
is for the outgoing characters.
Returns: Number of characters waiting in output buffer.
Example:
C_outready can be useful for monitoring how communications are
going, or if you don't want to overflow the outgoing buffer.
You could use it if you want to make sure you don't try to add
more characters to the output buffer if it is already half full.
Say you have a 1k output buffer, you could use.
repeat until c_outready(com1)<512;
{ Send characters }
Name: c_putc
Usage:
procedure c_putc(cp : porttype;
ch : char );
Description:
Sends character ch out through the serial port. If the buffer
is full, it will wait 2 seconds for space to become available
and then exit after the 2 seconds. It would be best to check
the port with c_outready to make sure room is available so
characters wont be lost.
Returns: Nothing.
Example:
Use it if you simply want to send a character through the serial
port.
c_putc(com1,^M);
The above sends a carriage return through the serial port.
Name: c_insertc
Usage:
procedure c_insertc(cp : porttype;
ch : char );
Description:
This procedure will put a character in the input buffer as if
it were received from the serial port.
Returns: Nothing.
Example:
C_insertc has an advanced usage. I use it for a multi-user
BBS I am working on. I have several tasks running at the same
time and one of them is a local sysop task. What it does is to
monitor the keyboard to see if a normal key has been pressed, and
if one is, it grabs the character and inserts it into the input
buffer of the currently selected active BBS task. If it is a
function key, I just execute the sysop command that goes with it.
It is something like this.
var ch : char;
active_port : porttype;
begin
repeat
if keypressed then
begin
ch:=readkey;
if ch=#0 then
begin
ch:=readkey;
case ch of
#59:{function key 1 thing};
#60:{function key 2 thing};
. . .
end
end
else c_insertc(active_port,ch)
end
until {whatever is needed to exit};
end.
When the character is inserted, it will be read from the
serial port as if it came over the modem or from some other
form of serial device.
Name: c_inserts
Usage:
procedure c_inserts(cp : porttype;
outstr : comstr );
Description:
This does pretty much the same as c_insertc except that it
sends a whole string rather than a single character. If
you put a | in the string, it will be interpreted as a
carriage return.
Returns: Nothing.
Example:
The example is pretty much the same as for c_insertc except
it can be used to fool your program into thinking a certain
string has been sent. I use it to fool the modem into thinking
a CONNECT has been sent from the modem.
c_inserts(com1,'CONNECT|'#10);
Name: c_getc
Usage:
function c_getc(cp : porttype ) : char;
Description:
Gets a character from the input buffer. This is much like
readkey except it is for the serial port. If character is
not in input buffer, it will wait for a character to be
available.
Returns: Character that has been received by serial port and stored
in input buffer.
Example:
This is pretty basic. Use it when you want to get a character
from the serial port.
var ch : char;
begin
...
ch:=c_getc(com1);
end;
Name: c_peekc
Usage:
function c_peekc(cp : porttype ) : char;
Description:
This is much like c_getc except that it will return the character
waiting in the input buffer, but will not remove it. It will
allow you to "peek" at the character before you "get" the character.
Returns: It will return the value of the next character waiting in input
buffer.
Example:
Use it to watch incoming characters and dispose of unwanted
characters until the one you want is found. Maybe there is
a string that begins with and ESC that you want to get, but
you don't want any of the characters before the escape. You
could use
var ch : char;
begin
. . .
while peekc(com1)<>#27 then ch:=c_getc(com1);
. . .
end.
Yes, I know, this isn't the best example, but it does have a
use. The keyboard BIOS has something similar.
Name: c_flush_in
Usage:
procedure c_flush_in(cp : porttype );
Description:
Clears the input buffer. Removes characters that may be
waiting in the input buffer.
Returns: Nothing.
Example:
In an Xmodem transfer you may get more characters then you
wanted and the extra characters are most likely unwanted
so you would use c_flush_in to clear the input buffer.
c_flush_in(com1);
Name: c_flush_out
Usage:
procedure c_flush_out(cp : porttype );
Description:
Clears the output buffer of any characters that have not been
sent yet.
Returns: Nothing.
Example:
If you are sending out a file and you receive a ^C to cancel it,
you may want to flush the buffer to make it act more quickly.
c_flush_out(com1);
Name: c_carrier
Usage:
function c_carrier(cp : porttype ):boolean;
Description:
Tells you if your serial port detects that a carrier is present.
Returns: TRUE if there is a carrier present.
Example:
In a BBS program, this would be used to monitor whether someone
is still online, or if they hangup.
if c_carrier(com1) then
{person is still connected}
else
{person has hung up}
Name: c_toggle_DTR
Usage:
procedure c_toggle_DTR (cp : porttype );
Description:
Turn DTR bit on if it is off, or off if it is on.
Returns: Nothing.
Example:
The DTR is what keeps a port active. When you open the
serial port the DTR is set on. If you wanted to disconnect
someone, you would clear the DTR to off for a certain amount
of time, then turn it back on.
c_toggle_DTR(com1);
delay(500); {half second}
c_toggle_DTR(com1);
NOTE: This will not work correctly if your modem is set so
that the DTR is always on.
Name: c_send_break
Usage:
procedure c_send_break (cp : porttype;
duration : word );
Description:
This sends a break signal over the serial port for
duration hundreds of a second.
Returns: Nothing.
Example:
Sometimes certain systems require you to send a break
signal to stop something, or to disconnect properly.
c_send_break(com1,100);
The above example sends a break signal for 1 second.
Name: c_puts
Usage:
procedure c_puts(cp : porttype;
outstr : comstr );
Description:
This sends a string out through the serial port. A | is
sent as a carriage return and a ~ is used as a 1/4 second
delay. This is a lot like a lot of terminal init strings.
Returns: Nothing.
Example:
Use this to send init strings or dialing commands.
c_puts(com1,'ATDT 555-5555|~~~');
The above sends the dialing command followed by a carriage
return and a 3 quarters of a second delay.
Name: c_getb
Usage:
function c_getb(cp : porttype;
timeout : word ) : integer;
Description:
This waits timeout hundreds of a second for a character.
Returns: ASCII value character received, or a -1 if it times out, or
a -2 if ESC is hit.
Example:
Use this for download procedures. There are times when you
have to wait a certain amount of time for a character, and
if it doesn't arrive, you return and error.
var inch : integer;
begin
. . .
inch:=c_getb(com1,100); { Wait 1 second for character}
if inch=-1 then
writeln('Timeout')
else
begin
{chr(lo(inch)) equals character you received.'}
end
end;
Name: c_waits
Usage:
function c_waits(cp : porttype;
chkstr : checkstr;
timeout : word ) : boolean;
Description:
This function will wait timeout hundreds of a second for
string chkstr to be received from the serial port.
Returns: TRUE if string is received. FALSE if it times out.
Example:
Sometimes you may want to wait for a certain string to be
returned through the serial port. I had to write a program
once that checked to see if the modem supported 2400 baud or
not. The only way I could check was to set the serial port for
2400 baud, enter an AT
If it didn't, I knew it didn't like 2400 baud.
c_set_speed(com1,2400);
c_puts(com1,'AT|~');
if c_waits(com1,'OK',500) then
writeln('Modem supports 2400 baud.')
else
writeln('Modem doesn''t support 2400 baud.');
NOTE: Some modems will communicate with the serial port at speeds
that the modem does not support.
Name: c_waitsn
Usage:
function c_waitsn(cp : porttype;
var clst;{:array[1..n] of checkstr}
n : byte;
timeout : word ) : integer;
Description:
This will wait timeout hundreds of a second for a string
in clst to be returned from the modem. n tells you the
number of strings in clst.
Returns: -2 if ESC is hit, -1 if it times out, or the number of the
string that matched.
Example:
This is one of the most useful commands of JBCOMM. Use it for
autodialing.
var checklist : array [1..5] of checkstr;
result : integer;
begin
. . .
checklist[1]:='CONNECT'#13#10;
checklist[2]:='CONNECT 1200'#13#10;
checklist[3]:='CONNECT 2400'#13#10;
checklist[4]:='NO CARRIER'#13#10;
checklist[5]:='BUSY'#13#10;
repeat
c_puts(com1,'ATDT 555-5555|~~');
result:=c_waitsn(com1,checklist,5,6000);
case result of
-2:writeln('Dialing aborted');
-1:writeln('Timeout');
1:writeln('Connected at 300 baud');
2:writeln('Connected at 1200 baud');
3:writeln('Connected at 2400 baud');
4:writeln('No Carrier');
5:writeln('Busy')
end;
until ((result<4) and (result>0)) or (result=-1);
. . .
end.
Name: c_get_stream
Usage:
function c_get_stream (cp : porttype;
var getbuf;
n : word ) : word;
Description:
This will grab n bytes out of the input buffer and store
them in getbuf. If n bytes are not available, it will
return with whatever bytes were available.
Returns: Actual number of bytes grabbed.
Example:
This is useful for getting blocks of data from the serial
port. Say you wanted to get 131 characters from the input
buffer, you could use:
var buffer : array [1..131] of byte;
received : word;
begin
. . .
received:=c_get_stream(com1,buffer,131);
if received<131 then
writeln('All data not received.')
else
writeln('Data received.');
. . .
end.
CAUTION: Make sure you have the correct amount of space
reserved for getbuf, or it may overwrite some important data.
Name: c_tget_stream
Usage:
function c_tget_stream(cp : porttype;
var getbuf;
n,
timeout : word ) : word;
Description:
This is similar to c_get_stream, except that it will wait
timeout hundreds of a second to receive each byte of the
data. This means that if there is no data received within
timeout hundreds of a second, it will exit with what it was
able to get.
Returns: Number of bytes received.
Example:
This is useful for getting blocks of data from the serial
port in transfer protocals. Say you wanted to get 131
characters from the input buffer like in c_get_stream, but
you wanted it to wait 1 second before it timed out, you would
use:
var buffer : array [1..131] of byte;
received : word;
begin
. . .
received:=c_tget_stream(com1,buffer,131,100);
if received<131 then
writeln('All data not received. Timed out.')
else
writeln('Data received.');
. . .
end.
CAUTION: Make sure you have the correct amount of space
reserved for getbuf, or it may overwrite some important data.
Name: c_put_stream
Usage:
function c_put_stream (cp : porttype;
var putbuf;
n : word ) : word;
Description:
This will put n number of characters in putbuf in to the output
buffer. If the output buffer is full, it will just quit.
Returns: Number of characters successfully put in output buffer.
Example:
This is useful for putting blocks of data to the serial
port in transfer protocals. Say you wanted to send 131
characters to the output buffer, you would use:
var buffer : array [1..131] of byte;
sent : word;
begin
. . .
sent:=c_put_stream(com1,buffer,131);
if sent<131 then
writeln('All data not sent. Buffer is full.')
else
writeln('Data sent.');
. . .
end.
Name: c_statusm
Usage:
function c_statusm(cp : porttype ) : byte;
Description:
Gets the contents of the Modem Status Register at last
modem status interrupt.
c_DCTS = 1; Delta CTS. This means that CTS status
has changed.
c_DDSR = 2; Delta DSR. This means that DSR status
has changed.
c_TERI = 4; Tail End Ring Indicator. This tells you
whether the phone is ringing.
c_DRLSD = 8; Delta Received Line Signal Detect. This
tells you if the carrier status has changed.
c_CTS = 16; Current status of CTS.
c_DSR = 32; Current status of DSR.
c_RI = 64; Current status of Ring Indicator.
c_RLSD = 128; Current Carrier Status.
Returns: Contents of Modem Status Register.
Example: None of this is all that useful, but if you need to use it you
can check if a certain bit is set by ANDing the CONST you want
with the result of c_statusm.
var result : byte;
begin
. . .
result:=c_statusm(com1);
if result and c_RLSD>0 then
writeln('Carrier was on at last Modem Status Interrupt.');
. . .
end.
Name: c_statusl
Usage:
function c_statusl(cp : porttype ) : byte;
Description:
Gets the contents of the Line Status Register at last
line status register interrupt.
c_DR = 1; Data waiting in Receive buffer register.
c_OR = 2; Data overun error.
c_PE = 4; Parity Error.
c_FE = 8; Framing Error.
c_BI = 16; Break Interrupt.
c_THRE = 32; Transmitter Holding Register empty.
c_TSRE = 64; Transmitter Shift Register empty.
c_BO = 128; Buffer Overflow.
Returns: Value of LSR at last line status interrupt.
Example: None of this is all that useful, but if you need to use it you
can check if a certain bit is set by ANDing the CONST you want
with the result of c_statusl. The reason this isn't very useful
is that JBCOMM takes care of most of this. c_OR, c_PE, c_FE, c_BI
and c_BO may be some things you would want to check.
var result : byte;
begin
. . .
result:=c_statusl(com1);
if result and c_BI>0 then
writeln('Break was sent.');
. . .
end.
Name: c_lastint
Usage:
function c_lastint(cp : porttype ):byte;
Description:
Gets the contents of the interrupt ID register at last interrupt.
c_NONE = 1; There was no interrupt.
c_DATA_READY = 4; Data came in through serial port.
c_THR_EMPTY = 2; Data sent through serial port.
c_LINE_STATUS = 6; Line Status has changed.
c_MODEM_STATUS = 0; Modem Status has changed.
Returns: Value of Interrupt ID register at last interrupt.
Example: None of this is all that useful, but if you need to use it you
can check if a certain bit is set by ANDing the CONST you want
with the result of c_lastint.
var result : byte;
begin
. . .
result:=c_lastint(com1);
if result and c_DATA_READY>0 then
writeln('The last interrupt was a data ready interrupt.');
. . .
end.
Name: c_port_info
Usage:
procedure c_port_info(cp : porttype;
var info : com_info_rec);
Description:
Returns current status of serial port in a record of type:
com_info_rec = record
offset, Base address of serial port.}
speed : word; Current speed setting. }
parity : parityt; Current Parity Setting.
data, Current Data size.
stops : byte; Current Stop bits.
active, TRUE if port is active.
ints_on : boolean TRUE if interrupts are active.
end;
Returns: Information in info.
Example:
See accompanying program example.
Name: c_port_data
Usage:
procedure c_port_data(cp : porttype;
offset : word;
irql : byte );
Description:
Sets up the additional information needed to access ports beyond
COM2. This procedure is for the advanced user who wants to be
able to open more than the standard 2 serial ports. Certain
multiport serial cards give you the ability to set what port
offsets you wish to use and what IRQ levels to use. This
procedure is used to tell JBCOMM what these values are.
Returns: Nothing.
Example:
The code to set up COM1 would look like this:
c_port_data(com1,$3F8,4);
Note that it is not neccassary to set up COM1 or COM2, I use COM1
as an example because you are probably already familiar with the
values it uses.
Name: CRC_update
Usage:
function CRC_update(crc : word;
b : byte ) : word;
Description:
Calculates b into a CRC.
Returns: Updated CRC.
Example:
This is for doing Xmodem CRC transfers.
var CRC : word;
buffer : array [1..128] of byte;
i : word;
begin
. . .
CRC:=0;
for i:=1 to 128 do CRC:=CRC_update(CRC,buffer[i]);
CRC:=CRC_update(CRC,0);
CRC:=CRC_update(CRC,0);
. . . {CRC now contains the CRC of the 128 byte block.}
end.
Name: block_CRC
Usage:
function block_CRC(var block;
n : word ) : word;
Description:
Calculates a CRC for n bytes of memory starting with block.
Returns: CRC for n bytes of memory pointed to by block.
Example:
This is for doing Xmodem CRC transfers. block_CRC does the
same as the example for CRC_update.
var CRC : word;
buffer : array [1..128] of byte;
i : word;
begin
. . .
CRC:=block_CRC(buffer,128);
. . . {CRC now contains the CRC of the 128 byte block.}
end.
December 13, 2017
Add comments