home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Simtel MSDOS 1992 June
/
SIMTEL_0692.cdr
/
msdos
/
ddjmag
/
ddj8606.arc
/
BPROTO.LST
next >
Encoding:
Amiga
Atari
Commodore
DOS
FM Towns/JPY
Macintosh
Macintosh JP
Macintosh to JP
NeXTSTEP
RISC OS/Acorn
Shift JIS
UTF-8
Wrap
File List
|
1986-06-30
|
26.4 KB
|
1,488 lines
/**
* Copyright (c) 1985 by Steve Wilhite, Worthington, Ohio
*
* Permission is granted to use or distribute this software without any
* restrictions as long as this entire copyright notice is included intact.
* You may include it in any software product that you sell for profit.
*
* This software is distributed as is, and is not guaranteed to work on any
* given hardware/software configuration. Furthermore, no liability is
* granted with this software.
*
* ABSTRACT:
*
* The function, Transfer_File, implements error-free file transfer using
* CompuServe's "B" protocol.
*
* It has been assumed that the start-of-packet sequence, DLE "B", has
* been detected and the next byte not received yet is the packet
* sequence number (an ASCII digit).
*
* ENVIRONMENT: Lattice "C", machine independent.
*
* AUTHOR: Steve Wilhite, CREATION DATE: 21-Jul-85
*
* REVISION HISTORY:
*
* Steve Wilhite, 17-Jan-86
* - included a virtual file interface.
**/
/*** Feature Test ***/
/* Strip_CR and Strip_LF are mutual exclusive!! */
#define Strip_CR 0 /* If true, strip CR's before writing to disk.
Add CR before sending */
#define Strip_LF 0 /* If true, strip LD's before writing to disk.
Add LF before sending */
/* External Functions */
extern Delay(); /* Sleep for "n" milliseconds */
extern Put_Char(); /* Write a character to the display */
extern Start_Timer(); /* Enable the timer for the specified number
seconds */
extern int Timer_Expired(); /* Returns "true" if the timer has expired,
"false" otherwise */
extern int Wants_To_Abort(); /* Returns "true" if the user wants to abort
the file transfer, "false" otherwise */
extern int Read_Modem(); /* Read a character from the comm port.
Returns -1 if no character available */
extern int Write_Modem(); /* Send a character to the comm port. Returns
"true" is successful, "false" otherwise */
/* File I/O Interface */
extern int Create_File(), Open_File(), Close_File();
extern int Read_File(), Write_File();
#define NUL 0x00
#define ETX 0x03
#define ENQ 0x05
#define DLE 0x10
#define XON 0x11
#define XOFF 0x13
#define NAK 0x15
#define True 1
#define False 0
#define Success -1
#define Failure 0
#define Packet_Size 512
#define Max_Errors 10
#define Max_Time 10
#define Max_Xoff_Time 10
#define WACK ';' /* wait acknowledge */
/* Sender actions */
#define S_Send_Packet 0
#define S_Get_DLE 1
#define S_Get_Num 2
#define S_Get_Seq 3
#define S_Get_Data 4
#define S_Get_Checksum 5
#define S_Timed_Out 6
#define S_Send_NAK 7
#define S_Send_ACK 8
/* Receiver actions */
#define R_Get_DLE 0
#define R_Get_B 1
#define R_Get_Seq 2
#define R_Get_Data 3
#define R_Get_Checksum 4
#define R_Send_NAK 5
#define R_Send_ACK 6
static int
Ch,
Checksum,
Seq_Num,
R_Size, /* Size of receiver buffer */
XOFF_Flag,
Seen_ETX,
Seen_ENQ;
static char
S_Buffer[Packet_Size], /* Sender buffer */
R_Buffer[Packet_Size]; /* Receiver buffer */
static Put_Msg(Text)
char *Text;
{
while (*Text != 0)
Put_Char(*Text++);
Put_Char('\015');
Put_Char('\012');
}
static Send_Byte(Ch)
int Ch;
{
int TCh;
/* Listen for XOFF from the network */
Start_Timer(Max_Xoff_Time);
do
{
while ((TCh = Read_Modem()) >= 0)
if (TCh == XON)
XOFF_Flag = False;
else if (TCh == XOFF)
{
XOFF_Flag = True;
Start_Timer(Max_Xoff_Time);
}
}
while (XOFF_Flag && !Timer_Expired());
while (!Write_Modem(Ch));
}
static Send_Masked_Byte(Ch)
int Ch;
{
/* Mask any protocol or flow characters */
if (Ch == NUL || Ch == ETX || Ch == ENQ || Ch == DLE || Ch == NAK || Ch == XON || Ch == XOFF)
{
Send_Byte(DLE);
Send_Byte(Ch + '@');
}
else
Send_Byte(Ch);
}
static Send_ACK()
{
Send_Byte(DLE);
Send_Byte(Seq_Num + '0');
}
static Read_Byte()
{
if ((Ch = Read_Modem()) < 0)
{
Start_Timer(Max_Time);
do
{
if (Timer_Expired())
return Failure;
}
while ((Ch = Read_Modem()) < 0);
}
return Success;
}
static Read_Masked_Byte()
{
Seen_ETX = False;
Seen_ENQ = False;
if (Read_Byte() == Failure)
return Failure;
if (Ch == DLE)
{
if (Read_Byte() == Failure)
return Failure;
Ch &= 0x1F;
}
else if (Ch == ETX)
Seen_ETX = True;
else if (Ch == ENQ)
Seen_ENQ = True;
return Success;
}
static Do_Checksum(Ch)
int Ch;
{
Checksum <<= 1;
if (Checksum > 255)
Checksum = (Checksum & 0xFF) + 1;
Checksum += Ch & 0xFF;
if (Checksum > 255)
Checksum = (Checksum & 0xFF) + 1;
}
static int Read_Packet(Action)
/**
* Function:
* Receive a packet from the host.
*
* Inputs:
* Action -- the starting action
*
* Outputs:
* R_Buffer -- contains the packet just received
* R_Size -- length of the packet
*
* Returns:
* success/failure
**/
int Action;
{
int
Errors,
Next_Seq;
Errors = 0;
while (Errors < Max_Errors)
switch (Action)
{
case R_Get_DLE:
if (Read_Byte() == Failure)
Action = R_Send_NAK;
else if (Ch == DLE)
Action = R_Get_B;
else if (Ch == ENQ)
Action = R_Send_ACK;
break;
case R_Get_B:
if (Read_Byte() == Failure)
Action = R_Send_NAK;
else if (Ch == 'B')
Action = R_Get_Seq;
else
Action = R_Get_DLE;
break;
case R_Get_Seq:
if (Read_Byte() == Failure)
Action = R_Send_NAK;
else
{
Checksum = 0;
Next_Seq = Ch - '0';
Do_Checksum(Ch);
R_Size = 0;
Action = R_Get_Data;
}
break;
case R_Get_Data:
if (Read_Masked_Byte() == Failure)
Action = R_Send_NAK;
else if (Seen_ETX)
Action = R_Get_Checksum;
else if (Seen_ENQ)
Action = R_Send_ACK;
else if (R_Size == Packet_Size)
Action = R_Send_NAK;
else
{
R_Buffer[R_Size++] = Ch;
Do_Checksum(Ch);
}
break;
case R_Get_Checksum:
Do_Checksum(ETX);
if (Read_Masked_Byte() == Failure)
Action = R_Send_NAK;
else if (Checksum != Ch)
Action = R_Send_NAK;
else if (Next_Seq == Seq_Num)
Action = R_Send_ACK; /* Ignore duplicate packet */
else if (Next_Seq != (Seq_Num + 1) % 10)
Action = R_Send_NAK;
else
{
Seq_Num = Next_Seq;
return Success;
}
break;
case R_Send_NAK:
Put_Char('-');
Errors++;
Send_Byte(NAK);
Action = R_Get_DLE;
break;
case R_Send_ACK:
Send_ACK();
Action = R_Get_DLE;
break;
}
return Failure;
}
static int Send_Packet(Size)
/**
* Function:
* Send the specified packet to the host.
*
* Inputs:
* Size -- length of the packet
* S_Buffer -- the packet to send
*
* Outputs:
*
* Returns:
* success/failure
**/
int Size;
{
int
Action,
Next_Seq,
RCV_Num,
I,
Errors;
Next_Seq = (Seq_Num + 1) % 10;
Errors = 0;
Action = S_Send_Packet;
while (Errors < Max_Errors)
switch (Action)
{
case S_Send_Packet:
Checksum = 0;
Send_Byte(DLE);
Send_Byte('B');
Send_Byte(Next_Seq + '0');
Do_Checksum(Next_Seq + '0');
for (I = 0; I < Size; I++)
{
Send_Masked_Byte(S_Buffer[I]);
Do_Checksum(S_Buffer[I]);
}
Send_Byte(ETX);
Do_Checksum(ETX);
Send_Masked_Byte(Checksum);
Action = S_Get_DLE;
break;
case S_Get_DLE:
if (Read_Byte() == Failure)
Action = S_Timed_Out;
else if (Ch == DLE)
Action = S_Get_Num;
else if (Ch == ENQ)
Action = S_Send_ACK;
else if (Ch == NAK)
{
Errors++;
Action = S_Send_Packet;
}
break;
case S_Get_Num:
if (Read_Byte() == Failure)
Action = S_Timed_Out;
else if (Ch >= '0' && Ch <= '9')
{
if (Ch == Seq_Num + '0')
Action = S_Get_DLE; /* Ignore duplicate ACK */
else if (Ch == Next_Seq + '0')
{
/* Correct sequence number */
Seq_Num = Next_Seq;
return Success;
}
else if (Errors == 0)
Action = S_Send_Packet;
else
Action = S_Get_DLE;
}
else if (Ch == WACK)
{
Delay(5000); /* Sleep for 5 seconds */
Action = S_Get_DLE;
}
else if (Ch == 'B')
Action = S_Get_Seq;
else
Action = S_Get_DLE;
break;
case S_Get_Seq:
/**
* Start of a "B" protocol packet. The only packet that makes
* any sense here is a failure packet.
**/
if (Read_Byte() == Failure)
Action = S_Send_NAK;
else
{
Checksum = 0;
RCV_Num = Ch - '0';
Do_Checksum(Ch);
I = 0;
Action = S_Get_Data;
}
break;
case S_Get_Data:
if (Read_Masked_Byte() == Failure)
Action = S_Send_NAK;
else if (Seen_ETX)
Action = S_Get_Checksum;
else if (Seen_ENQ)
Action = S_Send_ACK;
else if (I == Packet_Size)
Action = S_Send_NAK;
else
{
R_Buffer[I++] = Ch;
Do_Checksum(Ch);
}
break;
case S_Get_Checksum:
Do_Checksum(ETX);
if (Read_Masked_Byte() == Failure)
Action = S_Send_NAK;
else if (Checksum != Ch)
Action = S_Send_NAK;
else if (RCV_Num != (Next_Seq + 1) % 10)
Action = S_Send_NAK;
else
{
/**
* Assume the packet is failure packet. It makes no
* difference since any other type of packet would be
* invalid anyway. Return failure to caller.
**/
Errors = Max_Errors;
}
break;
case S_Timed_Out:
Errors++;
Action = S_Get_DLE;
break;
case S_Send_NAK:
Put_Char('-');
Errors++;
Send_Byte(NAK);
Action = S_Get_DLE;
break;
case S_Send_ACK:
Send_ACK();
Action = S_Get_DLE;
break;
}
return Failure;
}
static Send_Failure(Code)
/**
* Function:
* Send a failure packet to the host.
*
* Inputs:
* Code -- failure code
*
* Outputs:
*
* Returns:
**/
char Code;
{
S_Buffer[0] = 'F';
S_Buffer[1] = Code;
Send_Packet(2);
}
static int Receive_File(Name)
/**
* Function:
* Download the specified file from the host.
*
* Inputs:
* Name -- ptr to the file name string
*
* Outputs:
*
* Returns:
* success/failure
**/
char *Name;
{
int Data_File; /* file descriptor */
if ((Data_File = Create_File(Name, 0)) == -1)
{
Put_Msg("Cannot create file");
Send_Failure('E');
return Failure;
}
Send_ACK();
for (;;)
if (Read_Packet(R_Get_DLE) == Success)
switch (R_Buffer[0])
{
case 'N': /* Data packet */
if (Write_File(Data_File, &R_Buffer[1], R_Size - 1) != R_Size - 1)
{
/* Disk write error */
Put_Msg("Disk write error");
Send_Failure('E');
Close_File(Data_File);
return Failure;
}
if (Wants_To_Abort())
{
/* The user wants to kill the transfer */
Send_Failure('A');
Close_File(Data_File);
return Failure;
}
Send_ACK();
Put_Char('+');
break;
case 'T': /* Transfer packet */
if (R_Buffer[1] == 'C') /* Close file */
{
Send_ACK();
Close_File(Data_File);
return Success;
}
else
{
/**
* Unexpected "T" packet. Something is rotten on the
* other end. Send a failure packet to kill the
* transfer cleanly.
**/
Put_Msg("Unexpected packet type");
Send_Failure('E');
Close_File(Data_File);
return Failure;
}
case 'F': /* Failure packet */
Send_ACK();
Close_File(Data_File);
return Failure;
}
else
{
Close_File(Data_File);
return Failure;
}
}
static int Send_File(Name)
/**
* Function:
* Send the specified file to the host.
*
* Inputs:
* Name -- ptr to the file name string
*
* Outputs:
*
* Returns:
* success/failure
**/
char *Name;
{
int
Data_File, /* file descriptor */
N;
if ((Data_File = Open_File(Name, 0)) == -1)
{
Put_Msg("Cannot access that file");
Send_Failure('E');
return Failure;
}
do
{
S_Buffer[0] = 'N';
N = Read_File(Data_File, &S_Buffer[1], Packet_Size - 1);
if (N > 0)
{
if (Send_Packet(N + 1) == Failure)
{
Close_File(Data_File);
return Failure;
}
if (Wants_To_Abort())
{
Send_Failure('A');
Close_File(Data_File);
return Failure;
}
Put_Char('+');
}
}
while (N > 0);
if (N == 0) /* end of file */
{
Close_File(Data_File);
S_Buffer[0] = 'T';
S_Buffer[1] = 'C';
return Send_Packet(2);
}
else
{
Put_Msg("Disk read error");
Send_Failure('E');
return Failure;
}
}
int Transfer_File()
/**
* Function:
* Transfer a file from/to the micro to/from the host.
*
* Inputs:
*
* Outputs:
*
* Returns:
* success/failure
**/
{
int I, N;
char Name[64]; /* holds the file name */
XOFF_Flag = False;
Seq_Num = 0;
if (Read_Packet(R_Get_Seq) == Success)
{
if (R_Buffer[0] == 'T') /* transfer packet */
{
/* Check the direction */
if (R_Buffer[1] != 'D' && R_Buffer[1] != 'U')
{
Send_Failure('N'); /* not implemented */
return Failure;
}
/* Check the file type */
if (R_Buffer[2] != 'A' && R_Buffer[2] != 'B')
{
Send_Failure('N');
return Failure;
}
/* Collect the file name */
N = R_Size - 3 > 63 ? 63 : R_Size - 3;
for (I = 0; I < N; I++)
Name[I] = R_Buffer[I + 3];
Name[I] = 0;
/* Do the transfer */
if (R_Buffer[1] == 'U')
return Send_File(Name);
else
return Receive_File(Name);
}
else
{
Send_Failure('E'); /* wrong type of packet */
return Failure;
}
}
else
return Failure;
}
title Keyboard Driver
include \lc\dos.mac
pseg
public Read_Keyboard
Read_Keyboard proc
;++
; Function:
; Read a "raw" character from the keyboard.
;
; Inputs: none
;
; Outputs: none
;
; Returns:
; -1 if no character is available; otherwise a 16-bit code.
; If the high byte is zero, then the low byte is an ASCII character,
; else the low byte is an "extended" character (scan code).
;--
mov AH,1
int 16H ; Scan the keyboard
jz Read_Keyboard_1 ; No character available
mov AH,0 ; Yes
int 16H ; Read keyboard
cmp AL,0 ; Extended character
je Read_Keyboard_2 ; Yes
mov AH,0 ; No, normal character
ret
Read_Keyboard_1:
mov AX,-1 ; Denote "no character available"
ret
Read_Keyboard_2: ; Extended character
mov AL,AH
mov AH,01H ; Set the "function key" flags
ret
Read_Keyboard endp
endps
end
/*
* This program emulates a dumb terminal with file transfer support using
* CompuServe's B-Protocol. This program is just a sample of how to interface
* the BP module (BP.C) with the rest of the terminal emulator.
*/
#define IBM_PC 1
extern int Transfer_File(); /* Transfer a file using the "B" protocol */
extern int Read_Keyboard(); /* Get a "raw" character from the keyboard */
extern Open_Modem(); /* Initialize the comm port */
extern int Read_Modem(); /* Read a character from the comm port */
extern int Write_Modem(); /* Send a character to the comm port */
extern Close_Modem(); /* Release the comm port */
#define True 1
#define False 0
#define Baud_300 1 /* Baud rate codes used by Open_Modem */
#define Baud_450 2
#define Baud_1200 3
#define Baud_1800 4
#define Baud_2400 5
#define Baud_4800 6
#define Baud_9600 7
#ifdef IBM_PC /* for IBM style keyboards */
#define Exit_Key 0x012D /* Alt-X */
#else
#define Exit_Key 0x001D /* control-] */
#endif
#define Is_Function_Key(C) ((C) > 127)
#define ENQ 0x05
#define DLE 0x10
#define ESC 0x1B
/*
* We only support the B-protocol file transfer. No other VIDTEX features.
*/
static char VIDTEX_Response[] = "#DTE,PB,DT\015";
static int
Old_Break_State,
I,
Ch, /* 16-bit "raw" character */
Want_7_Bit, /* true if we want to ignore the parity bit */
ESC_Seq_State; /* Escape sequence state variable */
int Wants_To_Abort()
{
return Read_Keyboard() == ESC;
}
main()
{
char *cp;
Want_7_Bit = True;
ESC_Seq_State = 0;
#ifdef MSDOS
Old_Break_State = Get_Break();
Set_Break(0);
#endif
Open_Modem(0, Baud_1200, False);
puts("[ Terminal Mode ]");
Ch = Read_Keyboard();
while (Ch != Exit_Key)
{
if (Ch > 0)
{
if (Is_Function_Key(Ch))
{
/* Here to process any local function keys. */
}
else
Write_Modem(Ch & 0x7F);
}
if ((Ch = Read_Modem()) >= 0)
{
if (Want_7_Bit) Ch &= 0x7F;
switch (ESC_Seq_State)
{
case 0:
switch (Ch)
{
case ESC:
ESC_Seq_State = 1;
break;
case ENQ:
/* Enquiry -- send ACK for packet 0 */
Write_Modem(DLE);
Write_Modem('0');
break;
case DLE:
ESC_Seq_State = 2;
break;
default:
Put_Char(Ch);
}
break;
case 1:
/* ESC -- process any escape sequences here */
switch (Ch)
{
case 'I':
/*
* Reply to the VIDTEX "ESC I" identify sequence
*/
cp = VIDTEX_Response;
while (*cp != 0) Write_Modem(*cp++);
ESC_Seq_State = 0;
break;
default:
Put_Char(ESC);
Put_Char(Ch);
ESC_Seq_State = 0;
}
break;
case 2:
/* DLE */
if (Ch == 'B')
{
/* Start of "B" protocol packet. Go into protocol
* mode and transfer the file as requested.
*/
if (!Transfer_File()) puts("Transfer failed!");
}
else
{
Put_Char(DLE);
Put_Char(Ch);
}
ESC_Seq_State = 0;
}
}
Ch = Read_Keyboard();
}
Close_Modem();
#ifdef MSDOS
Set_Break(Old_Break_State);
#endif
}
title Screen
include \lc\dos.mac
Video equ 10H ; IBM BIOS call
TTY_Write equ 14
pseg
public Put_Char
Put_Char proc
;++
; Function:
; Write a character to the screen in "normal" TTY-style output.
;
; Inputs:
; 4[BP] - the character to write
;
; Outputs: none
;
; Returns: nothing
;--
push BP
mov BP,SP
mov AL,4[BP] ; Character to write
mov BH,0 ; Current page
mov AH,TTY_Write
int Video
pop BP
ret
Put_Char endp
endps
end
include \lc\dos.mac
dseg
Timer dw ?
Old_Second db ?
endds
pseg
public Start_Timer
Start_Timer proc
push BP
mov BP,SP
mov AX,[BP+4] ; Get the number of seconds
mov Timer,AX
mov AX,2C00H
int 21H ; Get current time
mov Old_Second,DH
pop BP
ret
Start_Timer endp
public Timer_Expired
Timer_Expired proc
mov AX,2C00H
int 21H ; Get current time
cmp DH,Old_Second ; Has the clock ticked?
je Timer_Expired_1 ; No
mov Old_Second,DH ; Yes, update Old_Second
dec Timer
cmp Timer,0
jle Timer_Expired_2 ; Timer expired?
Timer_Expired_1:
xor AX,AX ; No, return "false"
ret
Timer_Expired_2:
mov AX,1 ; Yes, return "true"
ret
Timer_Expired endp
endps
end
#define Loops_Per_Millisecond 9
Delay(N)
/**
* Delay for N milliseconds
**/
int N;
{
long K;
for (K = Loops_Per_Millisecond * (long) N; K > 0; K--);
}
page 57,132
title FileIO
;++
; FACILITY: DTE
;
; ABSTRACT:
;
; This module contains the interface routines to the MS-DOS file
; service. All disk operations are done thru this module.
;
; ENVIRONMENT: MS-DOS, V2.0 or later
;
; AUTHOR: Steve Wilhite, CREATION DATE: 8-May-85
;
; REVISION HISTORY:
;
;--
include \lc\dos.mac
pseg
@ab = 4 ; argument base
page
public Create_File
Create_File proc near
;+
; Functional Description:
;
; Creates a new file or truncates an old to zero length in
; preparation for writing.
;
; Calling Sequence:
;
; handle = Create_File(pathname, attribute)
;
; Parameters:
;
; pathname ptr to ASCIZ pathname
; attribute file attribute(s)
;
; Return Value:
;
; -5 access denied
; -4 too many open files
; -3 path not found
; else file handle number
;-
Pathname equ @ab[BP]
Attribute equ @ab+2[BP]
push BP
mov BP,SP
mov DX,Pathname
mov CX,Attribute
mov AH,3CH
int 21H
jnc Create_1
neg AX
Create_1:
pop BP
ret
Create_File endp
page
public Open_File
Open_File proc near
;+
; Functional Description:
;
; Opens a file.
;
; Calling Sequence:
;
; handle = Open_File(pathname, access)
;
; Parameters:
;
; pathname ptr to ASCIZ pathname
; access access code (0 = read, 1 = write, 2 = read and write)
;
; Return Value:
;
; -12 invalid access
; -5 access denied
; -4 too many open files
; -2 file not found
; >0 file handle number
;-
Access equ @ab+2[BP]
push BP
mov BP,SP
mov AH,3DH
mov DX,Pathname
mov AL,Access
int 21H
jnc Open_1
neg AX
Open_1: pop BP
ret
Open_File endp
page
public Close_File
Close_File proc near
;+
; Functional Description:
;
; Closes the file associated with a specified file handle.
;
; Calling Sequence:
;
; status = Close_File(handle)
;
; Parameters:
;
; handle file handle for file to close
;
; Return Value:
;
; -6 invalid handle
; 0 no error
;-
Handle equ @ab[BP]
push BP
mov BP,SP
mov AH,3EH
mov BX,Handle
int 21H
jnc Close_1
neg AX
jmp Close_2
Close_1:
mov AX,0
Close_2:
pop BP
ret
Close_File endp
page
public Read_File
Read_File proc near
;+
; Functional Description:
;
; Transfers a specified number of bytes from a file into a buffer
; location. If the returned value for number of bytes read is
; zero, then the program tried to read from the end of file.
;
; Calling Sequence:
;
; bytes_read = Read_File(handle, buffer, bytes_to_read)
;
; Parameters:
;
; handle file handle for the file to read
; buffer ptr to buffer
; bytes_to_read number of bytes to read
;
; Return Value:
;
; -6 invalid handle
; -5 access denied
; 0 end of file
; >0 number of bytes actually read
;-
Buffer equ @ab+2[BP]
Count equ @ab+4[BP]
push BP
mov BP,SP
mov AH,3FH
mov BX,Handle
mov CX,Count
mov DX,Buffer
int 21H
jnc Read_1
neg AX
Read_1: pop BP
ret
Read_File endp
page
public Write_File
Write_File proc near
;+
; Functional Description:
;
; Transfers a specified number of bytes from a buffer into a file.
; If the number of bytes written is not the same as the number
; requested, then an error has occurred.
;
; Calling Sequence:
;
; status = Write_File(handle, buffer, bytes_to_write)
;
; Parameters:
;
; handle file handle for file to write
; buffer ptr to buffer
; bytes_to_write number of bytes to write
;
; Return Value:
;
; -6 invalid handle
; -5 access denied
; else number of bytes written
;-
push BP
mov BP,SP
mov AH,40H
mov BX,Handle
mov CX,Count
mov DX,Buffer
int 21H
jnc Write_1
neg AX
Write_1:
pop BP
ret
Write_File endp
public Move_To_EOF
Move_To_EOF proc
push BP
mov BP,SP
mov AX,4202H
mov BX,4[BP] ; file handle
xor CX,CX
xor DX,DX
int 21H
pop BP
ret
Move_To_EOF endp
endps
end
Title Serial
include \lc\dos.mac
pseg
;+
; Table of Contents:
;-
public Open_Modem
public Read_Modem
public Write_Modem
public Close_Modem
public Send_Break
dseg
Comm_Params equ this byte
db 11H ; XON
db 13H ; XOFF
db ? ; Baud rate code
db 0 ; Parity = none
db 1 ; Word length = 8
db 0 ; stop bits = 1
endds
extrn AS_Init:near ; Initialize
extrn AS_Set_Mode:near ; Set XON/XOFF mode
extrn AS_Set_Port:near ; Initialize the port
extrn AS_Open:near ; Open the port
extrn AS_IReady:near ; Test input status
extrn AS_IChar:near ; Input character
extrn AS_OReady:near ; Test output status
extrn AS_OChar:near ; Output character
extrn AS_Send_Break:near ; Send a break signal
extrn AS_OIdle:near ; Test output idle status
extrn AS_Close:near ; Close the comm port
extrn AS_Term:near ; Terminate async I/O
;+
; Function:
; Open the comm port.
;
; Calling Sequence:
;
; Open_Modem(Port, Rate, Auto_XOFF)
;
; Parameters:
; Port: 0 = COM1, 1 = COM2
;
; Rate: 0 110 baud
; 1 300
; 2 450
; 3 1200
; 4 1800
; 5 2400
; 6 4800
; 7 9600
;
; Auto_XOFF: if true, enable auto XOFF/XON flow-of-control
;-
Open_Modem proc
push BP
mov BP,SP
mov AX,4[BP] ; Get port number
call AS_Init ; Initialize async
mov AX,8[BP] ; Get XOFF/XON flags
cmp AX,0 ;
je Init_1
mov AX,3
Init_1:
call AS_Set_Mode ; Set them
mov AL,6[BP] ; Get baud rate code
mov Comm_Params[2],AL ; and store
mov SI,offset Comm_Params
call AS_Set_Port ; Initialize the port
call AS_Open ; Open the comm port
pop BP
ret
Open_Modem endp
;+
; Function:
; Read a character from the comm port.
;
; Calling Sequence:
;
; ret_value = Read_Modem()
;
; Returns:
; -1 if no character is available; otherwise the character.
;-
Read_Modem proc
call AS_IReady ; Test input status
cmp AX,-1 ; Ready?
jne Read_1 ; Yes
ret ; No, return -1
Read_1:
call AS_IChar ; Input character
mov AH,0
ret
Read_Modem endp
;+
; Function:
; Write a character to the comm port.
;
; Calling Sequence:
;
; status = Write_Modem(Char)
;
; Returns:
; 0 if could not send the character; otherwise -1
;-
Write_Modem proc
push BP
mov BP,SP
call AS_OReady ; Test output status
not AX
cmp AX,0 ; Ready?
je Write_1 ; No, return failure
mov AX,[BP+4] ; Get character to send
call AS_OChar ; Send it
mov AX,-1 ; Success
Write_1:
pop BP
ret
Write_Modem endp
;+
; Function:
; Close the comm port.
;
; Calling Sequence:
;
; status = Close_Modem()
;
; Returns:
;-
Close_Modem proc
Close_1:
call AS_OIdle ; Test output idle status
cmp AX,0 ; Done?
jne Close_1 ; No
call AS_Close
call AS_Term
ret
Close_Modem endp
;+
; Function:
; Send a break "character" to the comm port.
;
; Calling Sequence:
;
; Send_Break();
;-
Send_Break proc
mov AX,50 ; milliseconds
call AS_Send_Break
ret
Send_Break endp
endps
end
title Break
include \lc\dos.mac
pseg
public Set_Break, Get_Break
Set_Break proc
push BP
mov BP,SP
mov DL,4[BP] ; Get state to set
mov AX,3301H
int 21H
pop BP
ret
Set_Break endp
Get_Break proc
mov AX,3300H
int 21H
mov AL,DL
xor AH,AH
ret
Get_Break endp
endps
end