4220 lines
132 KiB
Plaintext
4220 lines
132 KiB
Plaintext
_KERMIT FOR OS/2_
|
||
by Brian R. Anderson
|
||
|
||
[LISTING ONE]
|
||
|
||
|
||
MODULE PCKermit;
|
||
(**************************************************************************)
|
||
(* *)
|
||
(* PCKermit -- by Brian R. Anderson *)
|
||
(* Copyright (c) 1990 *)
|
||
(* *)
|
||
(* PCKermit is an implementation of the Kermit file transfer protocol *)
|
||
(* developed at Columbia University. This (OS/2 PM) version is a *)
|
||
(* port from the DOS version of Kermit that I wrote two years ago. *)
|
||
(* My original DOS version appeared in the May 1989 issue of DDJ. *)
|
||
(* *)
|
||
(* The current version includes emulation of the TVI950 Video Display *)
|
||
(* Terminal for interaction with IBM mainframes (through the IBM 7171). *)
|
||
(* *)
|
||
(**************************************************************************)
|
||
|
||
FROM SYSTEM IMPORT
|
||
ADR;
|
||
|
||
FROM OS2DEF IMPORT
|
||
HAB, HWND, HPS, NULL, ULONG;
|
||
|
||
FROM PMWIN IMPORT
|
||
MPARAM, HMQ, QMSG, CS_SIZEREDRAW, WS_VISIBLE, FS_ICON,
|
||
FCF_TITLEBAR, FCF_SYSMENU, FCF_SIZEBORDER, FCF_MINMAX, FCF_ACCELTABLE,
|
||
FCF_SHELLPOSITION, FCF_TASKLIST, FCF_MENU, FCF_ICON,
|
||
SWP_MOVE, SWP_SIZE, SWP_MAXIMIZE,
|
||
HWND_DESKTOP, FID_SYSMENU, SC_CLOSE, MIA_DISABLED, MM_SETITEMATTR,
|
||
WinInitialize, WinCreateMsgQueue, WinGetMsg, WinDispatchMsg, WinSendMsg,
|
||
WinRegisterClass, WinCreateStdWindow, WinDestroyWindow, WinWindowFromID,
|
||
WinDestroyMsgQueue, WinTerminate, WinSetWindowText,
|
||
WinSetWindowPos, WinQueryWindowPos;
|
||
|
||
FROM KH IMPORT
|
||
IDM_KERMIT;
|
||
|
||
FROM Shell IMPORT
|
||
Class, Title, Child, WindowProc, ChildWindowProc,
|
||
FrameWindow, ClientWindow, SetPort, Pos;
|
||
|
||
|
||
CONST
|
||
QUEUE_SIZE = 1024; (* Large message queue for async events *)
|
||
|
||
VAR
|
||
AnchorBlock : HAB;
|
||
MessageQueue : HMQ;
|
||
Message : QMSG;
|
||
FrameFlags : ULONG;
|
||
hsys : HWND;
|
||
MP1, MP2 : MPARAM;
|
||
|
||
|
||
BEGIN (* main *)
|
||
AnchorBlock := WinInitialize(0);
|
||
|
||
IF AnchorBlock # 0 THEN
|
||
MessageQueue := WinCreateMsgQueue (AnchorBlock, QUEUE_SIZE);
|
||
|
||
IF MessageQueue # 0 THEN
|
||
(* Register the parent window class *)
|
||
WinRegisterClass (
|
||
AnchorBlock,
|
||
ADR (Class),
|
||
WindowProc,
|
||
CS_SIZEREDRAW, 0);
|
||
|
||
(* Register a child window class *)
|
||
WinRegisterClass (
|
||
AnchorBlock,
|
||
ADR (Child),
|
||
ChildWindowProc,
|
||
CS_SIZEREDRAW, 0);
|
||
|
||
(* Create a standard window *)
|
||
FrameFlags := FCF_TITLEBAR + FCF_MENU + FCF_MINMAX +
|
||
FCF_SYSMENU + FCF_SIZEBORDER + FCF_TASKLIST +
|
||
FCF_ICON + FCF_SHELLPOSITION + FCF_ACCELTABLE;
|
||
|
||
FrameWindow := WinCreateStdWindow (
|
||
HWND_DESKTOP, (* handle of the parent window *)
|
||
WS_VISIBLE + FS_ICON, (* the window style *)
|
||
FrameFlags, (* the window flags *)
|
||
ADR(Class), (* the window class *)
|
||
NULL, (* the title bar text *)
|
||
WS_VISIBLE, (* client window style *)
|
||
NULL, (* handle of resource module *)
|
||
IDM_KERMIT, (* resource id *)
|
||
ClientWindow (* returned client window handle *)
|
||
);
|
||
|
||
IF FrameWindow # 0 THEN
|
||
(* Disable the CLOSE item on the system menu *)
|
||
hsys := WinWindowFromID (FrameWindow, FID_SYSMENU);
|
||
MP1.W1 := SC_CLOSE; MP1.W2 := 1;
|
||
MP2.W1 := MIA_DISABLED; MP2.W2 := MIA_DISABLED;
|
||
WinSendMsg (hsys, MM_SETITEMATTR, MP1, MP2);
|
||
|
||
(* Expand Window to Nearly Full Size, And Display the Title *)
|
||
WinQueryWindowPos (HWND_DESKTOP, Pos);
|
||
WinSetWindowPos (FrameWindow, 0,
|
||
Pos.x + 3, Pos.y + 3, Pos.cx - 6, Pos.cy - 6,
|
||
SWP_MOVE + SWP_SIZE);
|
||
WinSetWindowText (FrameWindow, ADR (Title));
|
||
|
||
SetPort; (* Try to initialize communications port *)
|
||
|
||
WHILE WinGetMsg(AnchorBlock, Message, NULL, 0, 0) # 0 DO
|
||
WinDispatchMsg(AnchorBlock, Message);
|
||
END;
|
||
|
||
WinDestroyWindow(FrameWindow);
|
||
END;
|
||
WinDestroyMsgQueue(MessageQueue);
|
||
END;
|
||
WinTerminate(AnchorBlock);
|
||
END;
|
||
END PCKermit.
|
||
|
||
[LISTING TWO]
|
||
|
||
DEFINITION MODULE Shell;
|
||
|
||
FROM OS2DEF IMPORT
|
||
USHORT, HWND;
|
||
|
||
FROM PMWIN IMPORT
|
||
MPARAM, MRESULT, SWP;
|
||
|
||
EXPORT QUALIFIED
|
||
Class, Child, Title, FrameWindow, ClientWindow,
|
||
ChildFrameWindow, ChildClientWindow, Pos, SetPort,
|
||
WindowProc, ChildWindowProc;
|
||
|
||
CONST
|
||
Class = "PCKermit";
|
||
Child ="Child";
|
||
Title = "PCKermit -- Microcomputer to Mainframe Communications";
|
||
|
||
|
||
VAR
|
||
FrameWindow : HWND;
|
||
ClientWindow : HWND;
|
||
ChildFrameWindow : HWND;
|
||
ChildClientWindow : HWND;
|
||
Pos : SWP; (* Screen Dimensions: position & size *)
|
||
comport : CARDINAL;
|
||
|
||
|
||
PROCEDURE SetPort;
|
||
|
||
PROCEDURE WindowProc ['WindowProc'] (
|
||
hwnd : HWND;
|
||
msg : USHORT;
|
||
mp1 [VALUE] : MPARAM;
|
||
mp2 [VALUE] : MPARAM) : MRESULT [LONG, WINDOWS];
|
||
|
||
PROCEDURE ChildWindowProc ['ChildWindowProc'] (
|
||
hwnd : HWND;
|
||
msg : USHORT;
|
||
mp1 [VALUE] : MPARAM;
|
||
mp2 [VALUE] : MPARAM) : MRESULT [LONG, WINDOWS];
|
||
|
||
END Shell.
|
||
|
||
[LISTING THREE]
|
||
|
||
DEFINITION MODULE Term; (* TVI950 Terminal Emulation For Kermit *)
|
||
|
||
EXPORT QUALIFIED
|
||
WM_TERM, WM_TERMQUIT,
|
||
Dir, TermThrProc, InitTerm, PutKbdChar, PutPortChar;
|
||
|
||
CONST
|
||
WM_TERM = 4000H;
|
||
WM_TERMQUIT = 4001H;
|
||
|
||
|
||
PROCEDURE Dir (path : ARRAY OF CHAR);
|
||
(* Displays a directory *)
|
||
|
||
PROCEDURE TermThrProc;
|
||
(* Thread to get characters from port, put into buffer, send message *)
|
||
|
||
PROCEDURE InitTerm;
|
||
(* Clear Screen, Home Cursor, Get Ready For Terminal Emulation *)
|
||
|
||
PROCEDURE PutKbdChar (ch1, ch2 : CHAR);
|
||
(* Process a character received from the keyboard *)
|
||
|
||
PROCEDURE PutPortChar (ch : CHAR);
|
||
(* Process a character received from the port *)
|
||
|
||
END Term.
|
||
|
||
[LISTING FOUR]
|
||
|
||
DEFINITION MODULE Screen;
|
||
(* Module to perform "low level" screen functions (via AVIO) *)
|
||
|
||
FROM PMAVIO IMPORT
|
||
HVPS;
|
||
|
||
EXPORT QUALIFIED
|
||
NORMAL, HIGHLIGHT, REVERSE, attribute, ColorSet, hvps,
|
||
White, Green, Amber, Color1, Color2,
|
||
ClrScr, ClrEol, GotoXY, GetXY,
|
||
Right, Left, Up, Down, Write, WriteLn, WriteString,
|
||
WriteInt, WriteHex, WriteAtt;
|
||
|
||
|
||
VAR
|
||
NORMAL : CARDINAL;
|
||
HIGHLIGHT : CARDINAL;
|
||
REVERSE : CARDINAL;
|
||
attribute : CARDINAL;
|
||
ColorSet : CARDINAL;
|
||
hvps : HVPS; (* presentation space used by screen module *)
|
||
|
||
|
||
PROCEDURE White;
|
||
(* Sets up colors: Monochrome White *)
|
||
|
||
PROCEDURE Green;
|
||
(* Sets up colors: Monochrome Green *)
|
||
|
||
PROCEDURE Amber;
|
||
(* Sets up colors: Monochrome Amber *)
|
||
|
||
PROCEDURE Color1;
|
||
(* Sets up colors: Blue, Red, Green *)
|
||
|
||
PROCEDURE Color2;
|
||
(* Sets up colors: Green, Magenta, Cyan *)
|
||
|
||
PROCEDURE ClrScr;
|
||
(* Clear the screen, and home the cursor *)
|
||
|
||
PROCEDURE ClrEol;
|
||
(* clear from the current cursor position to the end of the line *)
|
||
|
||
PROCEDURE Right;
|
||
(* move cursor to the right *)
|
||
|
||
PROCEDURE Left;
|
||
(* move cursor to the left *)
|
||
|
||
PROCEDURE Up;
|
||
(* move cursor up *)
|
||
|
||
PROCEDURE Down;
|
||
(* move cursor down *)
|
||
|
||
PROCEDURE GotoXY (col, row : CARDINAL);
|
||
(* position cursor at column, row *)
|
||
|
||
PROCEDURE GetXY (VAR col, row : CARDINAL);
|
||
(* determine current cursor position *)
|
||
|
||
PROCEDURE Write (c : CHAR);
|
||
(* Write a Character, Teletype Mode *)
|
||
|
||
PROCEDURE WriteString (str : ARRAY OF CHAR);
|
||
(* Write String, Teletype Mode *)
|
||
|
||
PROCEDURE WriteInt (n : INTEGER; s : CARDINAL);
|
||
(* Write Integer, Teletype Mode *)
|
||
|
||
PROCEDURE WriteHex (n, s : CARDINAL);
|
||
(* Write a Hexadecimal Number, Teletype Mode *)
|
||
|
||
PROCEDURE WriteLn;
|
||
(* Write <cr> <lf>, Teletype Mode *)
|
||
|
||
PROCEDURE WriteAtt (c : CHAR);
|
||
(* write character and attribute at cursor position *)
|
||
|
||
END Screen.
|
||
|
||
[LISTING FIVE]
|
||
|
||
DEFINITION MODULE PAD; (* Packet Assembler/Disassembler for Kermit *)
|
||
|
||
FROM PMWIN IMPORT
|
||
MPARAM;
|
||
|
||
EXPORT QUALIFIED
|
||
WM_PAD, PAD_Quit, PAD_Error, PacketType, yourNPAD, yourPADC, yourEOL,
|
||
Aborted, sFname, Send, Receive, DoPADMsg;
|
||
|
||
CONST
|
||
WM_PAD = 5000H;
|
||
PAD_Quit = 0;
|
||
PAD_Error = 20;
|
||
|
||
TYPE
|
||
(* PacketType used in both PAD and DataLink modules *)
|
||
PacketType = ARRAY [1..100] OF CHAR;
|
||
|
||
VAR
|
||
(* yourNPAD, yourPADC, and yourEOL used in both PAD and DataLink *)
|
||
yourNPAD : CARDINAL; (* number of padding characters *)
|
||
yourPADC : CHAR; (* padding characters *)
|
||
yourEOL : CHAR; (* End Of Line -- terminator *)
|
||
sFname : ARRAY [0..20] OF CHAR;
|
||
Aborted : BOOLEAN;
|
||
|
||
PROCEDURE Send;
|
||
(* Sends a file after prompting for filename *)
|
||
|
||
PROCEDURE Receive;
|
||
(* Receives a file (or files) *)
|
||
|
||
PROCEDURE DoPADMsg (mp1, mp2 [VALUE] : MPARAM);
|
||
(* Output messages for Packet Assembler/Disassembler *)
|
||
|
||
END PAD.
|
||
|
||
[LISTING SIX]
|
||
|
||
DEFINITION MODULE DataLink; (* Sends and Receives Packets for PCKermit *)
|
||
|
||
FROM PMWIN IMPORT
|
||
MPARAM;
|
||
|
||
FROM PAD IMPORT
|
||
PacketType;
|
||
|
||
EXPORT QUALIFIED
|
||
WM_DL, FlushUART, SendPacket, ReceivePacket, DoDLMsg;
|
||
|
||
CONST
|
||
WM_DL = 6000H;
|
||
|
||
PROCEDURE FlushUART;
|
||
(* ensure no characters left in UART holding registers *)
|
||
|
||
PROCEDURE SendPacket (s : PacketType);
|
||
(* Adds SOH and CheckSum to packet *)
|
||
|
||
PROCEDURE ReceivePacket (VAR r : PacketType) : BOOLEAN;
|
||
(* strips SOH and checksum -- returns status: TRUE= good packet *)
|
||
(* received; FALSE = timed out waiting for packet or checksum error *)
|
||
|
||
PROCEDURE DoDLMsg (mp1, mp2 [VALUE] : MPARAM);
|
||
(* Process DataLink Messages *)
|
||
|
||
END DataLink.
|
||
|
||
[LISTING SEVEN]
|
||
|
||
(*************************************************************)
|
||
(* *)
|
||
(* Copyright (C) 1988, 1989 *)
|
||
(* by Stony Brook Software *)
|
||
(* *)
|
||
(* All rights reserved. *)
|
||
(* *)
|
||
(*************************************************************)
|
||
|
||
DEFINITION MODULE CommPort;
|
||
|
||
TYPE
|
||
CommStatus = (
|
||
Success,
|
||
InvalidPort,
|
||
InvalidParameter,
|
||
AlreadyReceiving,
|
||
NotReceiving,
|
||
NoCharacter,
|
||
FramingError,
|
||
OverrunError,
|
||
ParityError,
|
||
BufferOverflow,
|
||
TimeOut
|
||
);
|
||
|
||
BaudRate = (
|
||
Baud110,
|
||
Baud150,
|
||
Baud300,
|
||
Baud600,
|
||
Baud1200,
|
||
Baud2400,
|
||
Baud4800,
|
||
Baud9600,
|
||
Baud19200
|
||
);
|
||
|
||
DataBits = [7..8];
|
||
StopBits = [1..2];
|
||
Parity = (Even, Odd, None);
|
||
|
||
|
||
PROCEDURE InitPort(port : CARDINAL; speed : BaudRate; data : DataBits;
|
||
stop : StopBits; check : Parity) : CommStatus;
|
||
|
||
PROCEDURE StartReceiving(port, bufsize : CARDINAL) : CommStatus;
|
||
|
||
PROCEDURE StopReceiving(port : CARDINAL) : CommStatus;
|
||
|
||
PROCEDURE GetChar(port : CARDINAL; VAR ch : CHAR) : CommStatus;
|
||
|
||
PROCEDURE SendChar(port : CARDINAL; ch : CHAR; modem : BOOLEAN) : CommStatus;
|
||
|
||
END CommPort.
|
||
|
||
[LISTING EIGHT]
|
||
|
||
DEFINITION MODULE Files; (* File I/O for Kermit *)
|
||
|
||
FROM FileSystem IMPORT
|
||
File;
|
||
|
||
EXPORT QUALIFIED
|
||
Status, FileType, Open, Create, CloseFile, Get, Put, DoWrite;
|
||
|
||
TYPE
|
||
Status = (Done, Error, EOF);
|
||
FileType = (Input, Output);
|
||
|
||
PROCEDURE Open (VAR f : File; name : ARRAY OF CHAR) : Status;
|
||
(* opens an existing file for reading, returns status *)
|
||
|
||
PROCEDURE Create (VAR f : File; name : ARRAY OF CHAR) : Status;
|
||
(* creates a new file for writing, returns status *)
|
||
|
||
PROCEDURE CloseFile (VAR f : File; Which : FileType) : Status;
|
||
(* closes a file after reading or writing *)
|
||
|
||
PROCEDURE Get (VAR f : File; VAR ch : CHAR) : Status;
|
||
(* Reads one character from the file, returns status *)
|
||
|
||
PROCEDURE Put (ch : CHAR);
|
||
(* Writes one character to the file buffer *)
|
||
|
||
PROCEDURE DoWrite (VAR f : File) : Status;
|
||
(* Writes buffer to disk only if nearly full *)
|
||
|
||
END Files.
|
||
|
||
[LISTING NINE]
|
||
|
||
IMPLEMENTATION MODULE Shell;
|
||
|
||
FROM SYSTEM IMPORT
|
||
ADDRESS, ADR;
|
||
|
||
IMPORT ASCII;
|
||
|
||
FROM OS2DEF IMPORT
|
||
HWND, HDC, HPS, RECTL, USHORT, NULL, ULONG;
|
||
|
||
FROM Term IMPORT
|
||
WM_TERM, WM_TERMQUIT,
|
||
Dir, TermThrProc, InitTerm, PutKbdChar, PutPortChar;
|
||
|
||
FROM PAD IMPORT
|
||
WM_PAD, PAD_Quit, PAD_Error, DoPADMsg, Aborted, sFname, Send, Receive;
|
||
|
||
FROM DataLink IMPORT
|
||
WM_DL, DoDLMsg;
|
||
|
||
FROM Screen IMPORT
|
||
hvps, ColorSet, White, Green, Amber, Color1, Color2, ClrScr, WriteLn;
|
||
|
||
FROM DosCalls IMPORT
|
||
DosCreateThread, DosSuspendThread, DosResumeThread, DosSleep;
|
||
|
||
FROM PMAVIO IMPORT
|
||
VioCreatePS, VioAssociate, VioDestroyPS, VioShowPS, WinDefAVioWindowProc,
|
||
FORMAT_CGA, HVPS;
|
||
|
||
FROM PMWIN IMPORT
|
||
MPARAM, MRESULT, SWP, PSWP,
|
||
WS_VISIBLE, FCF_TITLEBAR, FCF_SIZEBORDER, FCF_SHELLPOSITION,
|
||
WM_SYSCOMMAND, WM_MINMAXFRAME, SWP_MINIMIZE, HWND_DESKTOP,
|
||
WM_PAINT, WM_QUIT, WM_COMMAND, WM_INITDLG, WM_CONTROL, WM_HELP,
|
||
WM_INITMENU, WM_SIZE, WM_DESTROY, WM_CREATE, WM_CHAR,
|
||
BM_SETCHECK, MBID_OK, MB_OK, MB_OKCANCEL,
|
||
KC_CHAR, KC_CTRL, KC_VIRTUALKEY, KC_KEYUP,
|
||
SWP_SIZE, SWP_MOVE, SWP_MAXIMIZE, SWP_RESTORE,
|
||
MB_ICONQUESTION, MB_ICONASTERISK, MB_ICONEXCLAMATION,
|
||
FID_MENU, MM_SETITEMATTR, MM_QUERYITEMATTR, MIA_DISABLED, MIA_CHECKED,
|
||
WinCreateStdWindow, WinDestroyWindow,
|
||
WinOpenWindowDC, WinSendMsg, WinQueryDlgItemText, WinInvalidateRect,
|
||
WinDefWindowProc, WinBeginPaint, WinEndPaint, WinQueryWindowRect,
|
||
WinSetWindowText, WinSetFocus, WinDlgBox, WinDefDlgProc, WinDismissDlg,
|
||
WinMessageBox, WinPostMsg, WinWindowFromID, WinSendDlgItemMsg,
|
||
WinSetWindowPos, WinSetActiveWindow;
|
||
|
||
FROM PMGPI IMPORT
|
||
GpiErase;
|
||
|
||
FROM KH IMPORT
|
||
IDM_KERMIT, IDM_FILE, IDM_OPTIONS, IDM_SENDFN, ID_SENDFN,
|
||
IDM_DIR, IDM_CONNECT, IDM_SEND, IDM_REC, IDM_DIRPATH, ID_DIRPATH,
|
||
IDM_DIREND, IDM_QUIT, IDM_ABOUT, IDM_HELPMENU, IDM_TERMHELP,
|
||
IDM_COMPORT, IDM_BAUDRATE, IDM_DATABITS, IDM_STOPBITS, IDM_PARITY,
|
||
COM_OFF, ID_COM1, ID_COM2, PARITY_OFF, ID_EVEN, ID_ODD, ID_NONE,
|
||
DATA_OFF, ID_DATA7, ID_DATA8, STOP_OFF, ID_STOP1, ID_STOP2,
|
||
BAUD_OFF, ID_B110, ID_B150, ID_B300, ID_B600, ID_B1200, ID_B2400,
|
||
ID_B4800, ID_B9600, ID_B19K2,
|
||
IDM_COLORS, IDM_WHITE, IDM_GREEN, IDM_AMBER, IDM_C1, IDM_C2;
|
||
|
||
FROM CommPort IMPORT
|
||
CommStatus, BaudRate, DataBits, StopBits, Parity, InitPort,
|
||
StartReceiving, StopReceiving;
|
||
|
||
FROM Strings IMPORT
|
||
Assign, Append, AppendChar;
|
||
|
||
|
||
CONST
|
||
WM_SETMAX = 7000H;
|
||
WM_SETFULL = 7001H;
|
||
WM_SETRESTORE = 7002H;
|
||
NONE = 0; (* no port yet initialized *)
|
||
STKSIZE = 4096;
|
||
BUFSIZE = 4096; (* Port receive buffers: room for two full screens *)
|
||
PortError = "Port Is Already In Use -- EXIT? (Cancel Trys Another Port)";
|
||
ESC = 33C;
|
||
|
||
|
||
VAR
|
||
FrameFlags : ULONG;
|
||
TermStack : ARRAY [1..STKSIZE] OF CHAR;
|
||
Stack : ARRAY [1..STKSIZE] OF CHAR;
|
||
TermThr : CARDINAL;
|
||
Thr : CARDINAL;
|
||
hdc : HDC;
|
||
frame_hvps, child_hvps : HVPS;
|
||
TermMode : BOOLEAN;
|
||
Path : ARRAY [0..60] OF CHAR;
|
||
Banner : ARRAY [0..40] OF CHAR;
|
||
PrevComPort : CARDINAL;
|
||
Settings : ARRAY [0..1] OF RECORD
|
||
baudrate : CARDINAL;
|
||
databits : CARDINAL;
|
||
parity : CARDINAL;
|
||
stopbits : CARDINAL;
|
||
END;
|
||
MP1, MP2 : MPARAM;
|
||
|
||
|
||
PROCEDURE SetFull;
|
||
(* Changes window to full size *)
|
||
BEGIN
|
||
WinSetWindowPos (FrameWindow, 0,
|
||
Pos.x + 3, Pos.y + 3, Pos.cx - 6, Pos.cy - 6,
|
||
SWP_MOVE + SWP_SIZE);
|
||
END SetFull;
|
||
|
||
|
||
PROCEDURE SetRestore;
|
||
(* Changes window to full size FROM maximized *)
|
||
BEGIN
|
||
WinSetWindowPos (FrameWindow, 0,
|
||
Pos.x + 3, Pos.y + 3, Pos.cx - 6, Pos.cy - 6,
|
||
SWP_MOVE + SWP_SIZE + SWP_RESTORE);
|
||
END SetRestore;
|
||
|
||
|
||
PROCEDURE SetMax;
|
||
(* Changes window to maximized *)
|
||
BEGIN
|
||
WinSetWindowPos (FrameWindow, 0,
|
||
Pos.x + 3, Pos.y + 3, Pos.cx - 6, Pos.cy - 6,
|
||
SWP_MOVE + SWP_SIZE + SWP_MAXIMIZE);
|
||
END SetMax;
|
||
|
||
|
||
PROCEDURE SetBanner;
|
||
(* Displays Abbreviated Program Title + Port Settings in Title Bar *)
|
||
|
||
CONST
|
||
PortName : ARRAY [0..1] OF ARRAY [0..5] OF CHAR =
|
||
[["COM1:", 0C], ["COM2:", 0C]];
|
||
BaudName : ARRAY [0..8] OF ARRAY [0..5] OF CHAR =
|
||
[["110", 0C], ["150", 0C], ["300", 0C],
|
||
["600", 0C], ["1200", 0C], ["2400", 0C],
|
||
["4800", 0C], ["9600", 0C], ["19200", 0C]];
|
||
ParityName : ARRAY [0..2] OF CHAR = ['E', 'O', 'N'];
|
||
|
||
BEGIN
|
||
WITH Settings[comport - COM_OFF] DO
|
||
Assign (Class, Banner);
|
||
Append (Banner, " -- ");
|
||
Append (Banner, PortName[comport - COM_OFF]);
|
||
Append (Banner, BaudName[baudrate - BAUD_OFF]);
|
||
AppendChar (Banner, ',');
|
||
AppendChar (Banner, ParityName[parity - PARITY_OFF]);
|
||
AppendChar (Banner, ',');
|
||
AppendChar (Banner, CHR ((databits - DATA_OFF) + 30H));
|
||
AppendChar (Banner, ',');
|
||
AppendChar (Banner, CHR ((stopbits - STOP_OFF) + 30H));
|
||
WinSetWindowText (FrameWindow, ADR (Banner));
|
||
END;
|
||
END SetBanner;
|
||
|
||
|
||
PROCEDURE SetPort;
|
||
(* Sets The Communications Parameters Chosen By User *)
|
||
|
||
VAR
|
||
status : CommStatus;
|
||
rc : USHORT;
|
||
|
||
BEGIN
|
||
IF PrevComPort # NONE THEN
|
||
StopReceiving (PrevComPort - COM_OFF);
|
||
END;
|
||
|
||
WITH Settings[comport - COM_OFF] DO
|
||
status := InitPort (
|
||
comport - COM_OFF,
|
||
BaudRate (baudrate - BAUD_OFF),
|
||
DataBits (databits - DATA_OFF),
|
||
StopBits (stopbits - STOP_OFF),
|
||
Parity (parity - PARITY_OFF),
|
||
);
|
||
END;
|
||
|
||
IF status = Success THEN
|
||
StartReceiving (comport - COM_OFF, BUFSIZE);
|
||
PrevComPort := comport;
|
||
ELSE
|
||
rc := WinMessageBox (HWND_DESKTOP, FrameWindow, ADR (PortError),
|
||
0, 0, MB_OKCANCEL + MB_ICONEXCLAMATION);
|
||
IF rc = MBID_OK THEN
|
||
WinPostMsg (FrameWindow, WM_QUIT, MPARAM (0), MPARAM (0));
|
||
ELSE (* try the other port *)
|
||
IF comport = ID_COM1 THEN
|
||
comport := ID_COM2;
|
||
ELSE
|
||
comport := ID_COM1;
|
||
END;
|
||
SetPort; (* recursive call for retry *)
|
||
END;
|
||
END;
|
||
SetBanner;
|
||
END SetPort;
|
||
|
||
|
||
PROCEDURE MakeChild (msg : ARRAY OF CHAR);
|
||
(* Creates a child window for use by send or receive threads *)
|
||
|
||
VAR
|
||
c_hdc : HDC;
|
||
|
||
BEGIN
|
||
WinPostMsg (FrameWindow, WM_SETFULL, MPARAM (0), MPARAM (0));
|
||
|
||
Disable (IDM_CONNECT);
|
||
Disable (IDM_SEND);
|
||
Disable (IDM_REC);
|
||
Disable (IDM_DIR);
|
||
Disable (IDM_OPTIONS);
|
||
Disable (IDM_COLORS);
|
||
|
||
(* Create a client window *)
|
||
FrameFlags := FCF_TITLEBAR + FCF_SIZEBORDER;
|
||
|
||
ChildFrameWindow := WinCreateStdWindow (
|
||
ClientWindow, (* handle of the parent window *)
|
||
WS_VISIBLE, (* the window style *)
|
||
FrameFlags, (* the window flags *)
|
||
ADR(Child), (* the window class *)
|
||
NULL, (* the title bar text *)
|
||
WS_VISIBLE, (* client window style *)
|
||
NULL, (* handle of resource module *)
|
||
IDM_KERMIT, (* resource id *)
|
||
ChildClientWindow (* returned client window handle *)
|
||
);
|
||
|
||
WinSetWindowPos (ChildFrameWindow, 0,
|
||
Pos.cx DIV 4, Pos.cy DIV 4,
|
||
Pos.cx DIV 2, Pos.cy DIV 2 - 3,
|
||
SWP_MOVE + SWP_SIZE);
|
||
|
||
WinSetWindowText (ChildFrameWindow, ADR (msg));
|
||
|
||
WinSetActiveWindow (HWND_DESKTOP, ChildFrameWindow);
|
||
|
||
c_hdc := WinOpenWindowDC (ChildClientWindow);
|
||
hvps := child_hvps;
|
||
VioAssociate (c_hdc, hvps);
|
||
ClrScr; (* clear the hvio window *)
|
||
END MakeChild;
|
||
|
||
|
||
PROCEDURE Disable (item : USHORT);
|
||
(* Disables and "GREYS" a menu item *)
|
||
|
||
VAR
|
||
h : HWND;
|
||
|
||
BEGIN
|
||
h := WinWindowFromID (FrameWindow, FID_MENU);
|
||
MP1.W1 := item; MP1.W2 := 1;
|
||
MP2.W1 := MIA_DISABLED; MP2.W2 := MIA_DISABLED;
|
||
WinSendMsg (h, MM_SETITEMATTR, MP1, MP2);
|
||
END Disable;
|
||
|
||
|
||
PROCEDURE Enable (item : USHORT);
|
||
(* Enables a menu item *)
|
||
|
||
VAR
|
||
h : HWND;
|
||
atr : USHORT;
|
||
|
||
BEGIN
|
||
h := WinWindowFromID (FrameWindow, FID_MENU);
|
||
MP1.W1 := item; MP1.W2 := 1;
|
||
MP2.W1 := MIA_DISABLED; MP2.W2 := MIA_DISABLED;
|
||
atr := USHORT (WinSendMsg (h, MM_QUERYITEMATTR, MP1, MP2));
|
||
atr := USHORT (BITSET (atr) * (BITSET (MIA_DISABLED) / BITSET (-1)));
|
||
MP1.W1 := item; MP1.W2 := 1;
|
||
MP2.W1 := MIA_DISABLED; MP2.W2 := atr;
|
||
WinSendMsg (h, MM_SETITEMATTR, MP1, MP2);
|
||
END Enable;
|
||
|
||
|
||
PROCEDURE Check (item : USHORT);
|
||
(* Checks a menu item -- indicates that it is selected *)
|
||
|
||
VAR
|
||
h : HWND;
|
||
|
||
BEGIN
|
||
h := WinWindowFromID (FrameWindow, FID_MENU);
|
||
MP1.W1 := item; MP1.W2 := 1;
|
||
MP2.W1 := MIA_CHECKED; MP2.W2 := MIA_CHECKED;
|
||
WinSendMsg (h, MM_SETITEMATTR, MP1, MP2);
|
||
END Check;
|
||
|
||
|
||
PROCEDURE UnCheck (item : USHORT);
|
||
(* Remove check from a menu item *)
|
||
|
||
VAR
|
||
h : HWND;
|
||
atr : USHORT;
|
||
|
||
BEGIN
|
||
h := WinWindowFromID (FrameWindow, FID_MENU);
|
||
MP1.W1 := item; MP1.W2 := 1;
|
||
MP2.W1 := MIA_CHECKED; MP2.W2 := MIA_CHECKED;
|
||
atr := USHORT (WinSendMsg (h, MM_QUERYITEMATTR, MP1, MP2));
|
||
atr := USHORT (BITSET (atr) * (BITSET (MIA_CHECKED) / BITSET (-1)));
|
||
MP1.W1 := item; MP1.W2 := 1;
|
||
MP2.W1 := MIA_CHECKED; MP2.W2 := atr;
|
||
WinSendMsg (h, MM_SETITEMATTR, MP1, MP2);
|
||
END UnCheck;
|
||
|
||
|
||
PROCEDURE DoMenu (hwnd : HWND; item [VALUE] : MPARAM);
|
||
(* Processes Most Menu Interactions *)
|
||
|
||
VAR
|
||
rcl : RECTL;
|
||
rc : USHORT;
|
||
|
||
BEGIN
|
||
CASE CARDINAL (item.W1) OF
|
||
IDM_DIR:
|
||
SetFull;
|
||
WinQueryWindowRect (hwnd, rcl);
|
||
WinDlgBox (HWND_DESKTOP, hwnd, PathDlgProc, 0, IDM_DIRPATH, 0);
|
||
hvps := frame_hvps;
|
||
VioAssociate (hdc, hvps);
|
||
Dir (Path);
|
||
WinDlgBox (HWND_DESKTOP, hwnd, DirEndDlgProc, 0, IDM_DIREND, 0);
|
||
VioAssociate (0, hvps);
|
||
WinInvalidateRect (hwnd, rcl, 0);
|
||
| IDM_CONNECT:
|
||
TermMode := TRUE;
|
||
Disable (IDM_CONNECT);
|
||
Disable (IDM_SEND);
|
||
Disable (IDM_REC);
|
||
Disable (IDM_DIR);
|
||
Disable (IDM_OPTIONS);
|
||
Disable (IDM_COLORS);
|
||
(* MAXIMIZE Window -- Required for Terminal Emulation *)
|
||
SetMax;
|
||
hvps := frame_hvps;
|
||
VioAssociate (hdc, hvps);
|
||
DosResumeThread (TermThr);
|
||
InitTerm;
|
||
| IDM_SEND:
|
||
WinDlgBox (HWND_DESKTOP, hwnd, SendFNDlgProc, 0, IDM_SENDFN, 0);
|
||
MakeChild ("Send a File");
|
||
DosCreateThread (Send, Thr, ADR (Stack[STKSIZE]));
|
||
| IDM_REC:
|
||
MakeChild ("Receive a File");
|
||
DosCreateThread (Receive, Thr, ADR (Stack[STKSIZE]));
|
||
| IDM_QUIT:
|
||
rc := WinMessageBox (HWND_DESKTOP, ClientWindow,
|
||
ADR ("Do You Really Want To EXIT PCKermit?"),
|
||
ADR ("End Session"), 0, MB_OKCANCEL + MB_ICONQUESTION);
|
||
IF rc = MBID_OK THEN
|
||
StopReceiving (comport - COM_OFF);
|
||
WinPostMsg (hwnd, WM_QUIT, MPARAM (0), MPARAM (0));
|
||
END;
|
||
| IDM_COMPORT:
|
||
WinDlgBox (HWND_DESKTOP, hwnd, ComDlgProc, 0, IDM_COMPORT, 0);
|
||
SetPort;
|
||
| IDM_BAUDRATE:
|
||
WinDlgBox (HWND_DESKTOP, hwnd, BaudDlgProc, 0, IDM_BAUDRATE, 0);
|
||
SetPort;
|
||
| IDM_DATABITS:
|
||
WinDlgBox (HWND_DESKTOP, hwnd, DataDlgProc, 0, IDM_DATABITS, 0);
|
||
SetPort;
|
||
| IDM_STOPBITS:
|
||
WinDlgBox (HWND_DESKTOP, hwnd, StopDlgProc, 0, IDM_STOPBITS, 0);
|
||
SetPort;
|
||
| IDM_PARITY:
|
||
WinDlgBox (HWND_DESKTOP, hwnd, ParityDlgProc, 0, IDM_PARITY, 0);
|
||
SetPort;
|
||
| IDM_WHITE:
|
||
UnCheck (ColorSet);
|
||
ColorSet := IDM_WHITE;
|
||
Check (ColorSet);
|
||
White;
|
||
| IDM_GREEN:
|
||
UnCheck (ColorSet);
|
||
ColorSet := IDM_GREEN;
|
||
Check (ColorSet);
|
||
Green;
|
||
| IDM_AMBER:
|
||
UnCheck (ColorSet);
|
||
ColorSet := IDM_AMBER;
|
||
Check (ColorSet);
|
||
Amber;
|
||
| IDM_C1:
|
||
UnCheck (ColorSet);
|
||
ColorSet := IDM_C1;
|
||
Check (ColorSet);
|
||
Color1;
|
||
| IDM_C2:
|
||
UnCheck (ColorSet);
|
||
ColorSet := IDM_C2;
|
||
Check (ColorSet);
|
||
Color2;
|
||
| IDM_ABOUT:
|
||
WinDlgBox (HWND_DESKTOP, hwnd, AboutDlgProc, 0, IDM_ABOUT, 0);
|
||
ELSE
|
||
(* Don't do anything... *)
|
||
END;
|
||
END DoMenu;
|
||
|
||
|
||
PROCEDURE ComDlgProc ['ComDlgProc'] (
|
||
(* Process Dialog Box for choosing COM1/COM2 *)
|
||
hwnd : HWND;
|
||
msg : USHORT;
|
||
mp1 [VALUE] : MPARAM;
|
||
mp2 [VALUE] : MPARAM) : MRESULT [LONG, WINDOWS];
|
||
BEGIN
|
||
CASE msg OF
|
||
WM_INITDLG:
|
||
WinSendDlgItemMsg (hwnd, comport, BM_SETCHECK,
|
||
MPARAM (1), MPARAM (0));
|
||
WinSetFocus (HWND_DESKTOP, WinWindowFromID (hwnd, comport));
|
||
RETURN 1;
|
||
| WM_CONTROL:
|
||
comport := mp1.W1;
|
||
RETURN 0;
|
||
| WM_COMMAND:
|
||
WinDismissDlg (hwnd, 1);
|
||
RETURN 0;
|
||
ELSE
|
||
RETURN WinDefDlgProc (hwnd, msg, mp1, mp2);
|
||
END;
|
||
END ComDlgProc;
|
||
|
||
|
||
PROCEDURE BaudDlgProc ['BaudDlgProc'] (
|
||
(* Process Dialog Box for choosing Baud Rate *)
|
||
hwnd : HWND;
|
||
msg : USHORT;
|
||
mp1 [VALUE] : MPARAM;
|
||
mp2 [VALUE] : MPARAM) : MRESULT [LONG, WINDOWS];
|
||
BEGIN
|
||
WITH Settings[comport - COM_OFF] DO
|
||
CASE msg OF
|
||
WM_INITDLG:
|
||
WinSendDlgItemMsg (hwnd, baudrate, BM_SETCHECK,
|
||
MPARAM (1), MPARAM (0));
|
||
WinSetFocus (HWND_DESKTOP, WinWindowFromID (hwnd, baudrate));
|
||
RETURN 1;
|
||
| WM_CONTROL:
|
||
baudrate := mp1.W1;
|
||
RETURN 0;
|
||
| WM_COMMAND:
|
||
WinDismissDlg (hwnd, 1);
|
||
RETURN 0;
|
||
ELSE
|
||
RETURN WinDefDlgProc (hwnd, msg, mp1, mp2);
|
||
END;
|
||
END;
|
||
END BaudDlgProc;
|
||
|
||
|
||
PROCEDURE DataDlgProc ['DataDlgProc'] (
|
||
(* Process Dialog Box for choosing 7 or 8 data bits *)
|
||
hwnd : HWND;
|
||
msg : USHORT;
|
||
mp1 [VALUE] : MPARAM;
|
||
mp2 [VALUE] : MPARAM) : MRESULT [LONG, WINDOWS];
|
||
BEGIN
|
||
WITH Settings[comport - COM_OFF] DO
|
||
CASE msg OF
|
||
WM_INITDLG:
|
||
WinSendDlgItemMsg (hwnd, databits, BM_SETCHECK,
|
||
MPARAM (1), MPARAM (0));
|
||
WinSetFocus (HWND_DESKTOP, WinWindowFromID (hwnd, databits));
|
||
RETURN 1;
|
||
| WM_CONTROL:
|
||
databits := mp1.W1;
|
||
RETURN 0;
|
||
| WM_COMMAND:
|
||
WinDismissDlg (hwnd, 1);
|
||
RETURN 0;
|
||
ELSE
|
||
RETURN WinDefDlgProc (hwnd, msg, mp1, mp2);
|
||
END;
|
||
END;
|
||
END DataDlgProc;
|
||
|
||
|
||
PROCEDURE StopDlgProc ['StopDlgProc'] (
|
||
(* Process Dialog Box for choosing 1 or 2 stop bits *)
|
||
hwnd : HWND;
|
||
msg : USHORT;
|
||
mp1 [VALUE] : MPARAM;
|
||
mp2 [VALUE] : MPARAM) : MRESULT [LONG, WINDOWS];
|
||
BEGIN
|
||
WITH Settings[comport - COM_OFF] DO
|
||
CASE msg OF
|
||
WM_INITDLG:
|
||
WinSendDlgItemMsg (hwnd, stopbits, BM_SETCHECK,
|
||
MPARAM (1), MPARAM (0));
|
||
WinSetFocus (HWND_DESKTOP, WinWindowFromID (hwnd, stopbits));
|
||
RETURN 1;
|
||
| WM_CONTROL:
|
||
stopbits := mp1.W1;
|
||
RETURN 0;
|
||
| WM_COMMAND:
|
||
WinDismissDlg (hwnd, 1);
|
||
RETURN 0;
|
||
ELSE
|
||
RETURN WinDefDlgProc (hwnd, msg, mp1, mp2);
|
||
END;
|
||
END;
|
||
END StopDlgProc;
|
||
|
||
|
||
PROCEDURE ParityDlgProc ['ParityDlgProc'] (
|
||
(* Process Dialog Box for choosing odd, even, or no parity *)
|
||
hwnd : HWND;
|
||
msg : USHORT;
|
||
mp1 [VALUE] : MPARAM;
|
||
mp2 [VALUE] : MPARAM) : MRESULT [LONG, WINDOWS];
|
||
BEGIN
|
||
WITH Settings[comport - COM_OFF] DO
|
||
CASE msg OF
|
||
WM_INITDLG:
|
||
WinSendDlgItemMsg (hwnd, parity, BM_SETCHECK,
|
||
MPARAM (1), MPARAM (0));
|
||
WinSetFocus (HWND_DESKTOP, WinWindowFromID (hwnd, parity));
|
||
RETURN 1;
|
||
| WM_CONTROL:
|
||
parity := mp1.W1;
|
||
RETURN 0;
|
||
| WM_COMMAND:
|
||
WinDismissDlg (hwnd, 1);
|
||
RETURN 0;
|
||
ELSE
|
||
RETURN WinDefDlgProc (hwnd, msg, mp1, mp2);
|
||
END;
|
||
END;
|
||
END ParityDlgProc;
|
||
|
||
|
||
PROCEDURE AboutDlgProc ['AboutDlgProc'] (
|
||
(* Process "About" Dialog Box *)
|
||
hwnd : HWND;
|
||
msg : USHORT;
|
||
mp1 [VALUE] : MPARAM;
|
||
mp2 [VALUE] : MPARAM) : MRESULT [LONG, WINDOWS];
|
||
BEGIN
|
||
IF msg = WM_COMMAND THEN
|
||
WinDismissDlg (hwnd, 1);
|
||
RETURN 0;
|
||
ELSE
|
||
RETURN WinDefDlgProc (hwnd, msg, mp1, mp2);
|
||
END;
|
||
END AboutDlgProc;
|
||
|
||
|
||
PROCEDURE SendFNDlgProc ['SendFNDlgProc'] (
|
||
(* Process Dialog Box that obtains send filename from user *)
|
||
hwnd : HWND;
|
||
msg : USHORT;
|
||
mp1 [VALUE] : MPARAM;
|
||
mp2 [VALUE] : MPARAM) : MRESULT [LONG, WINDOWS];
|
||
BEGIN
|
||
CASE msg OF
|
||
WM_INITDLG:
|
||
WinSetFocus (HWND_DESKTOP, WinWindowFromID (hwnd, ID_SENDFN));
|
||
RETURN 1;
|
||
| WM_COMMAND:
|
||
WinQueryDlgItemText (hwnd, ID_SENDFN, 20, ADR (sFname));
|
||
WinDismissDlg (hwnd, 1);
|
||
RETURN 0;
|
||
ELSE
|
||
RETURN WinDefDlgProc (hwnd, msg, mp1, mp2);
|
||
END;
|
||
END SendFNDlgProc;
|
||
|
||
|
||
PROCEDURE PathDlgProc ['PathDlgProc'] (
|
||
(* Process Dialog Box that obtains directory path from user *)
|
||
hwnd : HWND;
|
||
msg : USHORT;
|
||
mp1 [VALUE] : MPARAM;
|
||
mp2 [VALUE] : MPARAM) : MRESULT [LONG, WINDOWS];
|
||
BEGIN
|
||
CASE msg OF
|
||
WM_INITDLG:
|
||
WinSetFocus (HWND_DESKTOP, WinWindowFromID (hwnd, ID_DIRPATH));
|
||
RETURN 1;
|
||
| WM_COMMAND:
|
||
WinQueryDlgItemText (hwnd, ID_DIRPATH, 60, ADR (Path));
|
||
WinDismissDlg (hwnd, 1);
|
||
RETURN 0;
|
||
ELSE
|
||
RETURN WinDefDlgProc (hwnd, msg, mp1, mp2);
|
||
END;
|
||
END PathDlgProc;
|
||
|
||
|
||
PROCEDURE DirEndDlgProc ['DirEndDlgProc'] (
|
||
(* Process Dialog Box to allow user to cancel directory *)
|
||
hwnd : HWND;
|
||
msg : USHORT;
|
||
mp1 [VALUE] : MPARAM;
|
||
mp2 [VALUE] : MPARAM) : MRESULT [LONG, WINDOWS];
|
||
BEGIN
|
||
IF msg = WM_COMMAND THEN
|
||
WinDismissDlg (hwnd, 1);
|
||
RETURN 0;
|
||
ELSE
|
||
RETURN WinDefDlgProc (hwnd, msg, mp1, mp2);
|
||
END;
|
||
END DirEndDlgProc;
|
||
|
||
|
||
PROCEDURE HelpDlgProc ['HelpDlgProc'] (
|
||
(* Process Dialog Boxes for the HELP *)
|
||
hwnd : HWND;
|
||
msg : USHORT;
|
||
mp1 [VALUE] : MPARAM;
|
||
mp2 [VALUE] : MPARAM) : MRESULT [LONG, WINDOWS];
|
||
BEGIN
|
||
IF msg = WM_COMMAND THEN
|
||
WinDismissDlg (hwnd, 1);
|
||
RETURN 0;
|
||
ELSE
|
||
RETURN WinDefDlgProc (hwnd, msg, mp1, mp2);
|
||
END;
|
||
END HelpDlgProc;
|
||
|
||
|
||
PROCEDURE KeyTranslate (mp1, mp2 [VALUE] : MPARAM; VAR c1, c2 : CHAR) : BOOLEAN;
|
||
(* Translates WM_CHAR message into ascii keystroke *)
|
||
|
||
VAR
|
||
code : CARDINAL;
|
||
fs : BITSET;
|
||
VK, KU, CH, CT : BOOLEAN;
|
||
|
||
BEGIN
|
||
fs := BITSET (mp1.W1); (* flags *)
|
||
VK := (fs * BITSET (KC_VIRTUALKEY)) # {};
|
||
KU := (fs * BITSET (KC_KEYUP)) # {};
|
||
CH := (fs * BITSET (KC_CHAR)) # {};
|
||
CT := (fs * BITSET (KC_CTRL)) # {};
|
||
IF (NOT KU) THEN
|
||
code := mp2.W1; (* character code *)
|
||
c1 := CHR (code);
|
||
c2 := CHR (code DIV 256);
|
||
IF ORD (c1) = 0E0H THEN (* function *)
|
||
c1 := 0C;
|
||
END;
|
||
IF CT AND (NOT CH) AND (NOT VK) AND (code # 0) THEN
|
||
c1 := CHR (CARDINAL ((BITSET (ORD (c1)) * BITSET (1FH))));
|
||
END;
|
||
RETURN TRUE;
|
||
ELSE
|
||
RETURN FALSE;
|
||
END;
|
||
END KeyTranslate;
|
||
|
||
|
||
PROCEDURE WindowProc ['WindowProc'] (
|
||
(* Main Window Procedure -- Handles message from PM and elsewhere *)
|
||
hwnd : HWND;
|
||
msg : USHORT;
|
||
mp1 [VALUE] : MPARAM;
|
||
mp2 [VALUE] : MPARAM) : MRESULT [LONG, WINDOWS];
|
||
|
||
VAR
|
||
ch : CHAR;
|
||
hps : HPS;
|
||
pswp : PSWP;
|
||
c1, c2 : CHAR;
|
||
NullRectl [0:0] : RECTL;
|
||
|
||
BEGIN
|
||
CASE msg OF
|
||
WM_HELP:
|
||
IF TermMode THEN
|
||
WinDlgBox (HWND_DESKTOP, hwnd, HelpDlgProc,
|
||
0, IDM_TERMHELP, 0);
|
||
ELSE
|
||
WinDlgBox (HWND_DESKTOP, hwnd, HelpDlgProc,
|
||
0, IDM_HELPMENU, 0);
|
||
END;
|
||
RETURN 0;
|
||
| WM_SETFULL:
|
||
SetFull;
|
||
RETURN 0;
|
||
| WM_SETRESTORE:
|
||
SetRestore;
|
||
RETURN 0;
|
||
| WM_SETMAX:
|
||
SetMax;
|
||
RETURN 0;
|
||
| WM_MINMAXFRAME:
|
||
pswp := PSWP (mp1);
|
||
IF BITSET (pswp^.fs) * BITSET (SWP_MINIMIZE) # {} THEN
|
||
(* Don't Display Port Settings While Minimized *)
|
||
WinSetWindowText (FrameWindow, ADR (Title));
|
||
ELSE
|
||
WinSetWindowText (FrameWindow, ADR (Banner));
|
||
IF TermMode AND
|
||
(BITSET (pswp^.fs) * BITSET (SWP_RESTORE) # {}) THEN
|
||
(* Force window to be maximized in terminal mode *)
|
||
|
||
WinPostMsg (FrameWindow, WM_SETMAX,
|
||
MPARAM (0), MPARAM (0));
|
||
ELSIF (NOT TermMode) AND
|
||
(BITSET (pswp^.fs) * BITSET (SWP_MAXIMIZE) # {}) THEN
|
||
(* Prevent maximized window EXCEPT in terminal mode *)
|
||
WinPostMsg (FrameWindow, WM_SETRESTORE,
|
||
MPARAM (0), MPARAM (0));
|
||
ELSE
|
||
(* Do Nothing *)
|
||
END;
|
||
END;
|
||
RETURN WinDefWindowProc (hwnd, msg, mp1, mp2);
|
||
| WM_CREATE:
|
||
hdc := WinOpenWindowDC (hwnd);
|
||
VioCreatePS (frame_hvps, 25, 80, 0, FORMAT_CGA, 0);
|
||
VioCreatePS (child_hvps, 16, 40, 0, FORMAT_CGA, 0);
|
||
DosCreateThread (TermThrProc, TermThr, ADR (TermStack[STKSIZE]));
|
||
DosSuspendThread (TermThr);
|
||
RETURN 0;
|
||
| WM_INITMENU:
|
||
Check (ColorSet);
|
||
RETURN 0;
|
||
| WM_COMMAND:
|
||
DoMenu (hwnd, mp1);
|
||
RETURN 0;
|
||
| WM_TERMQUIT:
|
||
TermMode := FALSE;
|
||
DosSuspendThread (TermThr);
|
||
VioAssociate (0, hvps);
|
||
(* Restore The Window *)
|
||
SetRestore;
|
||
Enable (IDM_CONNECT);
|
||
Enable (IDM_SEND);
|
||
Enable (IDM_REC);
|
||
Enable (IDM_DIR);
|
||
Enable (IDM_OPTIONS);
|
||
Enable (IDM_COLORS);
|
||
RETURN 0;
|
||
| WM_TERM:
|
||
PutPortChar (CHR (mp1.W1)); (* To Screen *)
|
||
RETURN 0;
|
||
| WM_CHAR:
|
||
IF TermMode THEN
|
||
IF KeyTranslate (mp1, mp2, c1, c2) THEN
|
||
PutKbdChar (c1, c2); (* To Port *)
|
||
RETURN 0;
|
||
ELSE
|
||
RETURN WinDefAVioWindowProc (hwnd, msg, mp1, mp2);
|
||
END;
|
||
ELSE
|
||
RETURN WinDefWindowProc (hwnd, msg, mp1, mp2);
|
||
END;
|
||
| WM_PAINT:
|
||
hps := WinBeginPaint (hwnd, NULL, NullRectl);
|
||
GpiErase (hps);
|
||
VioShowPS (25, 80, 0, hvps);
|
||
WinEndPaint (hps);
|
||
RETURN 0;
|
||
| WM_SIZE:
|
||
IF TermMode THEN
|
||
RETURN WinDefAVioWindowProc (hwnd, msg, mp1, mp2);
|
||
ELSE
|
||
RETURN WinDefWindowProc (hwnd, msg, mp1, mp2);
|
||
END;
|
||
| WM_DESTROY:
|
||
VioDestroyPS (frame_hvps);
|
||
VioDestroyPS (child_hvps);
|
||
RETURN 0;
|
||
ELSE
|
||
RETURN WinDefWindowProc (hwnd, msg, mp1, mp2);
|
||
END;
|
||
END WindowProc;
|
||
|
||
|
||
PROCEDURE ChildWindowProc ['ChildWindowProc'] (
|
||
(* Window Procedure for Send/Receive child windows *)
|
||
hwnd : HWND;
|
||
msg : USHORT;
|
||
mp1 [VALUE] : MPARAM;
|
||
mp2 [VALUE] : MPARAM) : MRESULT [LONG, WINDOWS];
|
||
|
||
VAR
|
||
mp : USHORT;
|
||
hps : HPS;
|
||
c1, c2 : CHAR;
|
||
NullRectl [0:0] : RECTL;
|
||
|
||
BEGIN
|
||
CASE msg OF
|
||
WM_PAINT:
|
||
hps := WinBeginPaint (hwnd, NULL, NullRectl);
|
||
GpiErase (hps);
|
||
VioShowPS (16, 40, 0, hvps);
|
||
WinEndPaint (hps);
|
||
RETURN 0;
|
||
| WM_CHAR:
|
||
IF KeyTranslate (mp1, mp2, c1, c2) AND (c1 = ESC) THEN
|
||
Aborted := TRUE;
|
||
RETURN 0;
|
||
ELSE
|
||
RETURN WinDefWindowProc (hwnd, msg, mp1, mp2);
|
||
END;
|
||
| WM_PAD:
|
||
mp := mp1.W1;
|
||
IF (mp = PAD_Error) OR (mp = PAD_Quit) THEN
|
||
WriteLn;
|
||
IF mp = PAD_Error THEN
|
||
WinMessageBox (HWND_DESKTOP, hwnd,
|
||
ADR ("File Transfer Aborted"),
|
||
ADR (Class), 0, MB_OK + MB_ICONEXCLAMATION);
|
||
ELSE
|
||
WinMessageBox (HWND_DESKTOP, hwnd,
|
||
ADR ("File Transfer Completed"),
|
||
ADR (Class), 0, MB_OK + MB_ICONASTERISK);
|
||
END;
|
||
DosSleep (2000);
|
||
VioAssociate (0, hvps);
|
||
WinDestroyWindow(ChildFrameWindow);
|
||
Enable (IDM_CONNECT);
|
||
Enable (IDM_SEND);
|
||
Enable (IDM_REC);
|
||
Enable (IDM_DIR);
|
||
Enable (IDM_OPTIONS);
|
||
Enable (IDM_COLORS);
|
||
ELSE
|
||
DoPADMsg (mp1, mp2);
|
||
END;
|
||
RETURN 0;
|
||
| WM_DL:
|
||
DoDLMsg (mp1, mp2);
|
||
RETURN 0;
|
||
| WM_SIZE:
|
||
WinSetWindowPos (ChildFrameWindow, 0,
|
||
Pos.cx DIV 4, Pos.cy DIV 4,
|
||
Pos.cx DIV 2, Pos.cy DIV 2 - 3,
|
||
SWP_MOVE + SWP_SIZE);
|
||
RETURN WinDefAVioWindowProc (hwnd, msg, mp1, mp2);
|
||
ELSE
|
||
RETURN WinDefWindowProc (hwnd, msg, mp1, mp2);
|
||
END;
|
||
END ChildWindowProc;
|
||
|
||
|
||
BEGIN (* Module Initialization *)
|
||
WITH Settings[ID_COM1 - COM_OFF] DO
|
||
baudrate := ID_B1200;
|
||
parity := ID_EVEN;
|
||
databits := ID_DATA7;
|
||
stopbits := ID_STOP1;
|
||
END;
|
||
|
||
WITH Settings[ID_COM2 - COM_OFF] DO
|
||
baudrate := ID_B19K2;
|
||
parity := ID_EVEN;
|
||
databits := ID_DATA7;
|
||
stopbits := ID_STOP1;
|
||
END;
|
||
PrevComPort := NONE;
|
||
comport := ID_COM1;
|
||
TermMode := FALSE; (* Not Initially in Terminal Emulation Mode *)
|
||
END Shell.
|
||
|
||
[LISTING 10 - PART II]
|
||
|
||
IMPLEMENTATION MODULE Term; (* TVI950 Terminal Emulation for Kermit *)
|
||
|
||
FROM Drives IMPORT
|
||
SetDrive;
|
||
|
||
FROM Directories IMPORT
|
||
FileAttributes, AttributeSet, DirectoryEntry, FindFirst, FindNext;
|
||
|
||
FROM SYSTEM IMPORT
|
||
ADR;
|
||
|
||
FROM DosCalls IMPORT
|
||
DosChDir, DosSleep;
|
||
|
||
FROM Screen IMPORT
|
||
ClrScr, ClrEol, GotoXY, GetXY,
|
||
Right, Left, Up, Down, WriteAtt, WriteString, WriteLn, Write,
|
||
attribute, NORMAL, HIGHLIGHT, REVERSE;
|
||
|
||
FROM PMWIN IMPORT
|
||
MPARAM, WinPostMsg;
|
||
|
||
FROM Shell IMPORT
|
||
comport, FrameWindow;
|
||
|
||
FROM KH IMPORT
|
||
COM_OFF;
|
||
|
||
FROM CommPort IMPORT
|
||
CommStatus, GetChar, SendChar;
|
||
|
||
FROM Strings IMPORT
|
||
Length, Concat;
|
||
|
||
IMPORT ASCII;
|
||
|
||
|
||
CONST
|
||
(* Key codes: Note: F1 -- F12 are actually Shift-F1 -- Shift-F12 *)
|
||
F1 = 124C;
|
||
F2 = 125C;
|
||
F3 = 126C;
|
||
F4 = 127C;
|
||
F5 = 130C;
|
||
F6 = 131C;
|
||
F7 = 132C;
|
||
F8 = 133C;
|
||
F9 = 134C;
|
||
F10 = 135C;
|
||
F11 = 207C;
|
||
F12 = 210C;
|
||
AF1 = 213C; (* Alt-F1 *)
|
||
AF2 = 214C; (* Alt-F2 *)
|
||
INS = 122C;
|
||
DEL = 123C;
|
||
HOME = 107C;
|
||
PGDN = 121C; (* synonym for PF10 *)
|
||
PGUP = 111C; (* synonym for PF11 *)
|
||
ENDD = 117C; (* synonym for PF12 *)
|
||
UPARROW = 110C;
|
||
DOWNARROW = 120C;
|
||
LEFTARROW = 113C;
|
||
RIGHTARROW = 115C;
|
||
CtrlX = 30C;
|
||
CtrlCaret = 36C;
|
||
CtrlZ = 32C;
|
||
CtrlL = 14C;
|
||
CtrlH = 10C;
|
||
CtrlK = 13C;
|
||
CtrlJ = 12C;
|
||
CtrlV = 26C;
|
||
ESC = 33C;
|
||
BUFSIZE = 4096; (* character buffer used by term thread *)
|
||
|
||
|
||
VAR
|
||
commStat : CommStatus;
|
||
echo : (Off, Local, On);
|
||
newline: BOOLEAN; (* translate <cr> to <cr><lf> *)
|
||
Insert : BOOLEAN;
|
||
MP1, MP2 : MPARAM;
|
||
|
||
|
||
PROCEDURE Dir (path : ARRAY OF CHAR);
|
||
(* Change drive and/or directory; display a directory (in wide format) *)
|
||
|
||
VAR
|
||
gotFN : BOOLEAN;
|
||
filename : ARRAY [0..20] OF CHAR;
|
||
attr : AttributeSet;
|
||
ent : DirectoryEntry;
|
||
i, j, k : INTEGER;
|
||
|
||
BEGIN
|
||
filename := ""; (* in case no directory change *)
|
||
i := Length (path);
|
||
IF (i > 2) AND (path[1] = ':') THEN (* drive specifier *)
|
||
DEC (i, 2);
|
||
SetDrive (ORD (CAP (path[0])) - ORD ('A'));
|
||
FOR j := 0 TO i DO (* strip off the drive specifier *)
|
||
path[j] := path[j + 2];
|
||
END;
|
||
END;
|
||
IF i # 0 THEN
|
||
gotFN := FALSE;
|
||
WHILE (i >= 0) AND (path[i] # '\') DO
|
||
IF path[i] = '.' THEN
|
||
gotFN := TRUE;
|
||
END;
|
||
DEC (i);
|
||
END;
|
||
IF gotFN THEN
|
||
j := i + 1;
|
||
k := 0;
|
||
WHILE path[j] # 0C DO
|
||
filename[k] := path[j];
|
||
INC (k); INC (j);
|
||
END;
|
||
filename[k] := 0C;
|
||
IF (i = -1) OR ((i = 0) AND (path[0] = '\')) THEN
|
||
INC (i);
|
||
END;
|
||
path[i] := 0C;
|
||
END;
|
||
END;
|
||
IF Length (path) # 0 THEN
|
||
DosChDir (ADR (path), 0);
|
||
END;
|
||
IF Length (filename) = 0 THEN
|
||
filename := "*.*";
|
||
END;
|
||
attr := AttributeSet {ReadOnly, Directory, Archive};
|
||
i := 1; (* keep track of position on line *)
|
||
|
||
ClrScr;
|
||
gotFN := FindFirst (filename, attr, ent);
|
||
WHILE gotFN DO
|
||
WriteString (ent.name);
|
||
j := Length (ent.name);
|
||
WHILE j < 12 DO (* 12 is maximum length for "filename.typ" *)
|
||
Write (' ');
|
||
INC (j);
|
||
END;
|
||
INC (i); (* next position on this line *)
|
||
IF i > 5 THEN
|
||
i := 1; (* start again on new line *)
|
||
WriteLn;
|
||
ELSE
|
||
WriteString (" | ");
|
||
END;
|
||
gotFN := FindNext (ent);
|
||
END;
|
||
WriteLn;
|
||
END Dir;
|
||
|
||
|
||
PROCEDURE InitTerm;
|
||
(* Clear Screen, Home Cursor, Get Ready For Terminal Emulation *)
|
||
BEGIN
|
||
ClrScr;
|
||
Insert := FALSE;
|
||
attribute := NORMAL;
|
||
END InitTerm;
|
||
|
||
|
||
PROCEDURE PutKbdChar (ch1, ch2 : CHAR);
|
||
(* Process a character received from the keyboard *)
|
||
BEGIN
|
||
IF ch1 = ASCII.enq THEN (* Control-E *)
|
||
echo := On;
|
||
ELSIF ch1 = ASCII.ff THEN (* Control-L *)
|
||
echo := Local;
|
||
ELSIF ch1 = ASCII.dc4 THEN (* Control-T *)
|
||
echo := Off;
|
||
ELSIF ch1 = ASCII.so THEN (* Control-N *)
|
||
newline := TRUE;
|
||
ELSIF ch1 = ASCII.si THEN (* Control-O *)
|
||
newline := FALSE;
|
||
ELSIF (ch1 = ASCII.can) OR (ch1 = ESC) THEN
|
||
attribute := NORMAL;
|
||
WinPostMsg (FrameWindow, WM_TERMQUIT, MPARAM (0), MPARAM (0));
|
||
ELSIF ch1 = 0C THEN
|
||
Function (ch2);
|
||
ELSE
|
||
commStat := SendChar (comport - COM_OFF, ch1, FALSE);
|
||
IF (echo = On) OR (echo = Local) THEN
|
||
WriteAtt (ch1);
|
||
END;
|
||
END;
|
||
END PutKbdChar;
|
||
|
||
|
||
PROCEDURE Function (ch : CHAR);
|
||
(* handles the function keys -- including PF1 - PF12, etc. *)
|
||
BEGIN
|
||
CASE ch OF
|
||
F1 : commStat := SendChar (comport - COM_OFF, ASCII.soh, FALSE);
|
||
commStat := SendChar (comport - COM_OFF, '@', FALSE);
|
||
commStat := SendChar (comport - COM_OFF, ASCII.cr, FALSE);
|
||
| F2 : commStat := SendChar (comport - COM_OFF, ASCII.soh, FALSE);
|
||
commStat := SendChar (comport - COM_OFF, 'A', FALSE);
|
||
commStat := SendChar (comport - COM_OFF, ASCII.cr, FALSE);
|
||
| F3 : commStat := SendChar (comport - COM_OFF, ASCII.soh, FALSE);
|
||
commStat := SendChar (comport - COM_OFF, 'B', FALSE);
|
||
commStat := SendChar (comport - COM_OFF, ASCII.cr, FALSE);
|
||
| F4 : commStat := SendChar (comport - COM_OFF, ASCII.soh, FALSE);
|
||
commStat := SendChar (comport - COM_OFF, 'C', FALSE);
|
||
commStat := SendChar (comport - COM_OFF, ASCII.cr, FALSE);
|
||
| F5 : commStat := SendChar (comport - COM_OFF, ASCII.soh, FALSE);
|
||
commStat := SendChar (comport - COM_OFF, 'D', FALSE);
|
||
commStat := SendChar (comport - COM_OFF, ASCII.cr, FALSE);
|
||
| F6 : commStat := SendChar (comport - COM_OFF, ASCII.soh, FALSE);
|
||
commStat := SendChar (comport - COM_OFF, 'E', FALSE);
|
||
commStat := SendChar (comport - COM_OFF, ASCII.cr, FALSE);
|
||
| F7 : commStat := SendChar (comport - COM_OFF, ASCII.soh, FALSE);
|
||
commStat := SendChar (comport - COM_OFF, 'F', FALSE);
|
||
commStat := SendChar (comport - COM_OFF, ASCII.cr, FALSE);
|
||
| F8 : commStat := SendChar (comport - COM_OFF, ASCII.soh, FALSE);
|
||
commStat := SendChar (comport - COM_OFF, 'G', FALSE);
|
||
commStat := SendChar (comport - COM_OFF, ASCII.cr, FALSE);
|
||
| F9 : commStat := SendChar (comport - COM_OFF, ASCII.soh, FALSE);
|
||
commStat := SendChar (comport - COM_OFF, 'H', FALSE);
|
||
commStat := SendChar (comport - COM_OFF, ASCII.cr, FALSE);
|
||
| F10,
|
||
PGDN: commStat := SendChar (comport - COM_OFF, ASCII.soh, FALSE);
|
||
commStat := SendChar (comport - COM_OFF, 'I', FALSE);
|
||
commStat := SendChar (comport - COM_OFF, ASCII.cr, FALSE);
|
||
| F11,
|
||
AF1,
|
||
PGUP: commStat := SendChar (comport - COM_OFF, ASCII.soh, FALSE);
|
||
commStat := SendChar (comport - COM_OFF, 'J', FALSE);
|
||
commStat := SendChar (comport - COM_OFF, ASCII.cr, FALSE);
|
||
| F12,
|
||
AF2,
|
||
ENDD: commStat := SendChar (comport - COM_OFF, ESC, FALSE);
|
||
commStat := SendChar (comport - COM_OFF, 'Q', FALSE);
|
||
| INS : IF NOT Insert THEN
|
||
commStat := SendChar (comport - COM_OFF, ESC, FALSE);
|
||
commStat := SendChar (comport - COM_OFF, 'E', FALSE);
|
||
END;
|
||
| DEL : commStat := SendChar (comport - COM_OFF, ESC, FALSE);
|
||
commStat := SendChar (comport - COM_OFF, 'R', FALSE);
|
||
| HOME : commStat := SendChar (comport - COM_OFF, CtrlZ, FALSE);
|
||
| UPARROW : commStat := SendChar (comport - COM_OFF, CtrlK, FALSE);
|
||
| DOWNARROW : commStat := SendChar (comport - COM_OFF, CtrlV, FALSE);
|
||
| LEFTARROW : commStat := SendChar (comport - COM_OFF, CtrlH, FALSE);
|
||
| RIGHTARROW : commStat := SendChar (comport - COM_OFF, CtrlL, FALSE);
|
||
ELSE
|
||
(* do nothing *)
|
||
END;
|
||
END Function;
|
||
|
||
|
||
PROCEDURE TermThrProc;
|
||
(* Thread to get characters from port, put into buffer *)
|
||
|
||
VAR
|
||
ch : CHAR;
|
||
|
||
BEGIN
|
||
LOOP
|
||
IF GetChar (comport - COM_OFF, ch) = Success THEN
|
||
MP1.W1 := ORD (ch); MP1.W2 := 0;
|
||
MP2.L := 0;
|
||
WinPostMsg (FrameWindow, WM_TERM, MP1, MP2);
|
||
ELSE
|
||
DosSleep (0);
|
||
END
|
||
END;
|
||
END TermThrProc;
|
||
|
||
|
||
VAR
|
||
EscState, CurState1, CurState2 : BOOLEAN;
|
||
CurChar1 : CHAR;
|
||
|
||
PROCEDURE PutPortChar (ch : CHAR);
|
||
(* Process a character received from the port *)
|
||
BEGIN
|
||
IF EscState THEN
|
||
EscState := FALSE;
|
||
IF ch = '=' THEN
|
||
CurState1 := TRUE;
|
||
ELSE
|
||
Escape (ch);
|
||
END;
|
||
ELSIF CurState1 THEN
|
||
CurState1 := FALSE;
|
||
CurChar1 := ch;
|
||
CurState2 := TRUE;
|
||
ELSIF CurState2 THEN
|
||
CurState2 := FALSE;
|
||
Cursor (ch);
|
||
ELSE
|
||
CASE ch OF
|
||
CtrlCaret, CtrlZ : ClrScr;
|
||
| CtrlL : Right;
|
||
| CtrlH : Left;
|
||
| CtrlK : Up;
|
||
| CtrlJ : Down;
|
||
| ESC : EscState := TRUE;
|
||
ELSE
|
||
WriteAtt (ch);
|
||
IF newline AND (ch = ASCII.cr) THEN
|
||
WriteLn;
|
||
END;
|
||
END;
|
||
END;
|
||
IF echo = On THEN
|
||
commStat := SendChar (comport - COM_OFF, ch, FALSE);
|
||
END;
|
||
END PutPortChar;
|
||
|
||
|
||
PROCEDURE Escape (ch : CHAR);
|
||
(* handles escape sequences *)
|
||
BEGIN
|
||
CASE ch OF
|
||
'*' : ClrScr;
|
||
| 'T', 'R' : ClrEol;
|
||
| ')' : attribute := NORMAL;
|
||
| '(' : attribute := HIGHLIGHT;
|
||
| 'f' : InsertMsg;
|
||
| 'g' : InsertOn;
|
||
ELSE
|
||
(* ignore *)
|
||
END;
|
||
END Escape;
|
||
|
||
|
||
PROCEDURE Cursor (ch : CHAR);
|
||
(* handles cursor positioning *)
|
||
|
||
VAR
|
||
x, y : CARDINAL;
|
||
|
||
BEGIN
|
||
y := ORD (CurChar1) - 20H;
|
||
x := ORD (ch) - 20H;
|
||
GotoXY (x, y); (* adjust for HOME = (1, 1) *)
|
||
END Cursor;
|
||
|
||
|
||
VAR
|
||
cx, cy : CARDINAL;
|
||
|
||
PROCEDURE InsertMsg;
|
||
(* get ready insert mode -- place a message at the bottom of the screen *)
|
||
BEGIN
|
||
IF NOT Insert THEN
|
||
GetXY (cx, cy); (* record current position *)
|
||
GotoXY (1, 24);
|
||
ClrEol;
|
||
attribute := REVERSE;
|
||
ELSE (* exit Insert mode *)
|
||
GetXY (cx, cy);
|
||
GotoXY (1, 24);
|
||
ClrEol;
|
||
GotoXY (cx, cy);
|
||
Insert := FALSE;
|
||
END;
|
||
END InsertMsg;
|
||
|
||
|
||
PROCEDURE InsertOn;
|
||
(* enter insert mode -- after INSERT MODE message is printed *)
|
||
BEGIN
|
||
attribute := NORMAL;
|
||
GotoXY (cx, cy);
|
||
Insert := TRUE;
|
||
END InsertOn;
|
||
|
||
|
||
BEGIN (* module initialization *)
|
||
echo := Off;
|
||
newline := FALSE;
|
||
Insert := FALSE;
|
||
EscState := FALSE;
|
||
CurState1 := FALSE;
|
||
CurState2 := FALSE;
|
||
END Term.
|
||
|
||
[LISTING ELEVEN]
|
||
|
||
IMPLEMENTATION MODULE Screen;
|
||
(* module to perform "low level" screen functions (via AVIO) *)
|
||
|
||
IMPORT ASCII;
|
||
|
||
FROM SYSTEM IMPORT
|
||
ADR;
|
||
|
||
FROM Strings IMPORT
|
||
Length;
|
||
|
||
FROM Conversions IMPORT
|
||
IntToString;
|
||
|
||
FROM KH IMPORT
|
||
IDM_GREEN;
|
||
|
||
FROM Vio IMPORT
|
||
VioSetCurPos, VioGetCurPos, VioScrollUp,
|
||
VioWrtNCell, VioWrtTTY, VioCell;
|
||
|
||
|
||
CONST
|
||
GREY = 07H;
|
||
WHITE = 0FH;
|
||
REV_GY = 70H;
|
||
GREEN = 02H;
|
||
LITE_GRN = 0AH;
|
||
REV_GRN = 20H;
|
||
AMBER = 06H;
|
||
LITE_AMB = 0EH;
|
||
REV_AMB = 60H;
|
||
RED = 0CH;
|
||
CY_BK = 0B0H;
|
||
CY_BL = 0B9H;
|
||
REV_RD = 0CFH;
|
||
REV_BL = 9FH;
|
||
MAGENTA = 05H;
|
||
|
||
|
||
VAR
|
||
(* From Definition Module
|
||
NORMAL : CARDINAL;
|
||
HIGHLIGHT : CARDINAL;
|
||
REVERSE : CARDINAL;
|
||
attribute : CARDINAL;
|
||
hvps : HVPS;
|
||
*)
|
||
x, y : CARDINAL;
|
||
bCell : VioCell;
|
||
|
||
|
||
PROCEDURE White;
|
||
(* Sets up colors: Monochrome White *)
|
||
BEGIN
|
||
NORMAL := GREY;
|
||
HIGHLIGHT := WHITE;
|
||
REVERSE := REV_GY;
|
||
attribute := NORMAL;
|
||
END White;
|
||
|
||
|
||
PROCEDURE Green;
|
||
(* Sets up colors: Monochrome Green *)
|
||
BEGIN
|
||
NORMAL := GREEN;
|
||
HIGHLIGHT := LITE_GRN;
|
||
REVERSE := REV_GRN;
|
||
attribute := NORMAL;
|
||
END Green;
|
||
|
||
|
||
PROCEDURE Amber;
|
||
(* Sets up colors: Monochrome Amber *)
|
||
BEGIN
|
||
NORMAL := AMBER;
|
||
HIGHLIGHT := LITE_AMB;
|
||
REVERSE := REV_AMB;
|
||
attribute := NORMAL;
|
||
END Amber;
|
||
|
||
|
||
PROCEDURE Color1;
|
||
(* Sets up colors: Blue, Red, Green *)
|
||
BEGIN
|
||
NORMAL := GREEN;
|
||
HIGHLIGHT := RED;
|
||
REVERSE := REV_BL;
|
||
attribute := NORMAL;
|
||
END Color1;
|
||
|
||
|
||
PROCEDURE Color2;
|
||
(* Sets up colors: Cyan Background; Black, Blue, White-on-Red *)
|
||
BEGIN
|
||
NORMAL := CY_BK;
|
||
HIGHLIGHT := CY_BL;
|
||
REVERSE := REV_RD;
|
||
attribute := NORMAL;
|
||
END Color2;
|
||
|
||
|
||
PROCEDURE HexToString (num : INTEGER;
|
||
size : CARDINAL;
|
||
VAR buf : ARRAY OF CHAR;
|
||
VAR I : CARDINAL;
|
||
VAR Done : BOOLEAN);
|
||
(* Local Procedure to convert a number to a string, represented in HEX *)
|
||
|
||
CONST
|
||
ZERO = 30H; (* ASCII code *)
|
||
A = 41H;
|
||
|
||
VAR
|
||
i : CARDINAL;
|
||
h : CARDINAL;
|
||
t : ARRAY [0..10] OF CHAR;
|
||
|
||
BEGIN
|
||
i := 0;
|
||
REPEAT
|
||
h := num MOD 16;
|
||
IF h <= 9 THEN
|
||
t[i] := CHR (h + ZERO);
|
||
ELSE
|
||
t[i] := CHR (h - 10 + A);
|
||
END;
|
||
INC (i);
|
||
num := num DIV 16;
|
||
UNTIL num = 0;
|
||
|
||
IF (size > HIGH (buf)) OR (i > HIGH (buf)) THEN
|
||
Done := FALSE;
|
||
RETURN;
|
||
ELSE
|
||
Done := TRUE;
|
||
END;
|
||
|
||
WHILE size > i DO
|
||
buf[I] := '0'; (* pad with zeros *)
|
||
DEC (size);
|
||
INC (I);
|
||
END;
|
||
|
||
WHILE i > 0 DO
|
||
DEC (i);
|
||
buf[I] := t[i];
|
||
INC (I);
|
||
END;
|
||
|
||
buf[I] := 0C;
|
||
END HexToString;
|
||
|
||
|
||
PROCEDURE ClrScr;
|
||
(* Clear the screen, and home the cursor *)
|
||
BEGIN
|
||
bCell.ch := ' '; (* space = blank screen *)
|
||
bCell.attr := CHR (NORMAL); (* Normal Video Attribute *)
|
||
VioScrollUp (0, 0, 24, 79, 25, bCell, hvps);
|
||
GotoXY (0, 0);
|
||
END ClrScr;
|
||
|
||
|
||
|
||
PROCEDURE ClrEol;
|
||
(* clear from the current cursor position to the end of the line *)
|
||
BEGIN
|
||
GetXY (x, y); (* current cursor position *)
|
||
bCell.ch := ' '; (* space = blank *)
|
||
bCell.attr := CHR (NORMAL); (* Normal Video Attribute *)
|
||
VioScrollUp (y, x, y, 79, 1, bCell, hvps);
|
||
END ClrEol;
|
||
|
||
|
||
PROCEDURE Right;
|
||
(* move cursor to the right *)
|
||
BEGIN
|
||
GetXY (x, y);
|
||
INC (x);
|
||
GotoXY (x, y);
|
||
END Right;
|
||
|
||
|
||
PROCEDURE Left;
|
||
(* move cursor to the left *)
|
||
BEGIN
|
||
GetXY (x, y);
|
||
DEC (x);
|
||
GotoXY (x, y);
|
||
END Left;
|
||
|
||
|
||
PROCEDURE Up;
|
||
(* move cursor up *)
|
||
BEGIN
|
||
GetXY (x, y);
|
||
DEC (y);
|
||
GotoXY (x, y);
|
||
END Up;
|
||
|
||
|
||
PROCEDURE Down;
|
||
(* move cursor down *)
|
||
BEGIN
|
||
GetXY (x, y);
|
||
INC (y);
|
||
GotoXY (x, y);
|
||
END Down;
|
||
|
||
|
||
PROCEDURE GotoXY (col, row : CARDINAL);
|
||
(* position cursor at column, row *)
|
||
BEGIN
|
||
IF (col <= 79) AND (row <= 24) THEN
|
||
VioSetCurPos (row, col, hvps);
|
||
END;
|
||
END GotoXY;
|
||
|
||
|
||
PROCEDURE GetXY (VAR col, row : CARDINAL);
|
||
(* determine current cursor position *)
|
||
BEGIN
|
||
VioGetCurPos (row, col, hvps);
|
||
END GetXY;
|
||
|
||
|
||
PROCEDURE Write (c : CHAR);
|
||
(* Write a Character *)
|
||
BEGIN
|
||
WriteAtt (c);
|
||
END Write;
|
||
|
||
|
||
PROCEDURE WriteString (str : ARRAY OF CHAR);
|
||
(* Write String *)
|
||
|
||
VAR
|
||
i : CARDINAL;
|
||
c : CHAR;
|
||
|
||
BEGIN
|
||
i := 0;
|
||
c := str[i];
|
||
WHILE c # 0C DO
|
||
Write (c);
|
||
INC (i);
|
||
c := str[i];
|
||
END;
|
||
END WriteString;
|
||
|
||
|
||
PROCEDURE WriteInt (n : INTEGER; s : CARDINAL);
|
||
(* Write Integer *)
|
||
|
||
VAR
|
||
i : CARDINAL;
|
||
b : BOOLEAN;
|
||
str : ARRAY [0..6] OF CHAR;
|
||
|
||
BEGIN
|
||
i := 0;
|
||
IntToString (n, s, str, i, b);
|
||
WriteString (str);
|
||
END WriteInt;
|
||
|
||
|
||
PROCEDURE WriteHex (n, s : CARDINAL);
|
||
(* Write a Hexadecimal Number *)
|
||
|
||
VAR
|
||
i : CARDINAL;
|
||
b : BOOLEAN;
|
||
str : ARRAY [0..6] OF CHAR;
|
||
|
||
BEGIN
|
||
i := 0;
|
||
HexToString (n, s, str, i, b);
|
||
WriteString (str);
|
||
END WriteHex;
|
||
|
||
|
||
PROCEDURE WriteLn;
|
||
(* Write <cr> <lf> *)
|
||
BEGIN
|
||
Write (ASCII.cr); Write (ASCII.lf);
|
||
END WriteLn;
|
||
|
||
|
||
PROCEDURE WriteAtt (c : CHAR);
|
||
(* write character and attribute at cursor position *)
|
||
|
||
VAR
|
||
s : ARRAY [0..1] OF CHAR;
|
||
|
||
BEGIN
|
||
GetXY (x, y);
|
||
IF (c = ASCII.ht) THEN
|
||
bCell.ch := ' ';
|
||
bCell.attr := CHR (attribute);
|
||
REPEAT
|
||
VioWrtNCell (bCell, 1, y, x, hvps);
|
||
Right;
|
||
UNTIL (x MOD 8) = 0;
|
||
ELSIF (c = ASCII.cr) OR (c = ASCII.lf)
|
||
OR (c = ASCII.bel) OR (c = ASCII.bs) THEN
|
||
s[0] := c; s[1] := 0C;
|
||
VioWrtTTY (ADR (s), 1, hvps);
|
||
IF c = ASCII.lf THEN
|
||
ClrEol;
|
||
END;
|
||
ELSE
|
||
bCell.ch := c;
|
||
bCell.attr := CHR (attribute);
|
||
VioWrtNCell (bCell, 1, y, x, hvps);
|
||
Right;
|
||
END;
|
||
END WriteAtt;
|
||
|
||
BEGIN (* module initialization *)
|
||
ColorSet := IDM_GREEN;
|
||
NORMAL := GREEN;
|
||
HIGHLIGHT := LITE_GRN;
|
||
REVERSE := REV_GRN;
|
||
attribute := NORMAL;
|
||
END Screen.
|
||
bCell.ch := ' '; (* space = blank *)
|
||
bCell.attr := CHR (NORMAL); (* Normal Video Attribute *)
|
||
VioScrollUp (y, x, y, 79, 1, bCell, hvps);
|
||
END ClrEol;
|
||
|
||
|
||
PROCEDURE Right;
|
||
(* move cursor to the right *)
|
||
BEGIN
|
||
GetXY (x, y);
|
||
INC (x);
|
||
GotoXY (x, y);
|
||
END Right;
|
||
|
||
|
||
PROCEDURE Left;
|
||
(* move cursor to the left *)
|
||
BEGIN
|
||
GetXY (x, y);
|
||
DEC (x);
|
||
GotoXY (x, y);
|
||
END Left;
|
||
|
||
|
||
PROCEDURE Up;
|
||
(* move cursor up *)
|
||
BEGIN
|
||
GetXY (x, y);
|
||
DEC (y);
|
||
GotoXY (x, y);
|
||
END Up;
|
||
|
||
|
||
PROCEDURE Down;
|
||
(* move cursor down *)
|
||
BEGIN
|
||
GetXY (x, y);
|
||
INC (y);
|
||
GotoXY (x, y);
|
||
END Down;
|
||
|
||
|
||
PROCEDURE GotoXY (col, row : CARDINAL);
|
||
(* position cursor at column, row *)
|
||
BEGIN
|
||
IF (col <= 79) AND (row <= 24) THEN
|
||
VioSetCurPos (row, col, hvps);
|
||
END;
|
||
END GotoXY;
|
||
|
||
|
||
PROCEDURE GetXY (VAR col, row : CARDINAL);
|
||
(* determine current cursor position *)
|
||
BEGIN
|
||
VioGetCurPos (row, col, hvps);
|
||
END GetXY;
|
||
|
||
|
||
PROCEDURE Write (c : CHAR);
|
||
(* Write a Character *)
|
||
BEGIN
|
||
WriteAtt (c);
|
||
END Write;
|
||
|
||
|
||
PROCEDURE WriteString (str : ARRAY OF CHAR);
|
||
(* Write String *)
|
||
|
||
VAR
|
||
i : CARDINAL;
|
||
c : CHAR;
|
||
|
||
BEGIN
|
||
i := 0;
|
||
c := str[i];
|
||
WHILE c # 0C DO
|
||
Write (c);
|
||
INC (i);
|
||
c := str[i];
|
||
END;
|
||
END WriteString;
|
||
|
||
|
||
PROCEDURE WriteInt (n : INTEGER; s : CARDINAL);
|
||
(* Write Integer *)
|
||
|
||
VAR
|
||
i : CARDINAL;
|
||
b : BOOLEAN;
|
||
str : ARRAY [0..6] OF CHAR;
|
||
|
||
BEGIN
|
||
i := 0;
|
||
IntToString (n, s, str, i, b);
|
||
WriteString (str);
|
||
END WriteInt;
|
||
|
||
|
||
PROCEDURE WriteHex (n, s : CARDINAL);
|
||
(* Write a Hexadecimal Number *)
|
||
|
||
VAR
|
||
i : CARDINAL;
|
||
b : BOOLEAN;
|
||
str : ARRAY [0..6] OF CHAR;
|
||
|
||
BEGIN
|
||
i := 0;
|
||
HexToString (n, s, str, i, b);
|
||
WriteString (str);
|
||
END WriteHex;
|
||
|
||
|
||
PROCEDURE WriteLn;
|
||
(* Write <cr> <lf> *)
|
||
BEGIN
|
||
Write (ASCII.cr); Write (ASCII.lf);
|
||
END WriteLn;
|
||
|
||
|
||
PROCEDURE WriteAtt (c : CHAR);
|
||
(* write character and attribute at cursor position *)
|
||
|
||
VAR
|
||
s : ARRAY [0..1] OF CHAR;
|
||
|
||
BEGIN
|
||
GetXY (x, y);
|
||
IF (c = ASCII.ht) THEN
|
||
bCell.ch := ' ';
|
||
bCell.attr := CHR (attribute);
|
||
REPEAT
|
||
VioWrtNCell (bCell, 1, y, x, hvps);
|
||
Right;
|
||
UNTIL (x MOD 8) = 0;
|
||
ELSIF (c = ASCII.cr) OR (c = ASCII.lf)
|
||
OR (c = ASCII.bel) OR (c = ASCII.bs) THEN
|
||
s[0] := c; s[1] := 0C;
|
||
VioWrtTTY (ADR (s), 1, hvps);
|
||
IF c = ASCII.lf THEN
|
||
ClrEol;
|
||
END;
|
||
ELSE
|
||
bCell.ch := c;
|
||
bCell.attr := CHR (attribute);
|
||
VioWrtNCell (bCell, 1, y, x, hvps);
|
||
Right;
|
||
END;
|
||
END WriteAtt;
|
||
|
||
BEGIN (* module initialization *)
|
||
ColorSet := IDM_GREEN;
|
||
NORMAL := GREEN;
|
||
HIGHLIGHT := LITE_GRN;
|
||
REVERSE := REV_GRN;
|
||
attribute := NORMAL;
|
||
END Screen.
|
||
|
||
[LISTING TWELVE]
|
||
|
||
(**************************************************************************)
|
||
(* *)
|
||
(* Copyright (c) 1988, 1989 *)
|
||
(* by Stony Brook Software *)
|
||
(* and *)
|
||
(* Copyright (c) 1990 *)
|
||
(* by Brian R. Anderson *)
|
||
(* All rights reserved. *)
|
||
(* *)
|
||
(**************************************************************************)
|
||
|
||
IMPLEMENTATION MODULE CommPort [7];
|
||
|
||
FROM SYSTEM IMPORT
|
||
ADR, BYTE, WORD, ADDRESS;
|
||
|
||
FROM Storage IMPORT
|
||
ALLOCATE, DEALLOCATE;
|
||
|
||
FROM DosCalls IMPORT
|
||
DosOpen, AttributeSet, DosDevIOCtl, DosClose, DosRead, DosWrite;
|
||
|
||
|
||
TYPE
|
||
CP = POINTER TO CHAR;
|
||
|
||
VAR
|
||
pn : CARDINAL;
|
||
Handle : ARRAY [0..3] OF CARDINAL;
|
||
BufIn : ARRAY [0..3] OF CP;
|
||
BufOut : ARRAY [0..3] OF CP;
|
||
BufStart : ARRAY [0..3] OF CP;
|
||
BufLimit : ARRAY [0..3] OF CP;
|
||
BufSize : ARRAY [0..3] OF CARDINAL;
|
||
Temp : ARRAY [1..1024] OF CHAR; (* size of OS/2's serial queue *)
|
||
|
||
|
||
PROCEDURE CheckPort (portnum : CARDINAL) : BOOLEAN;
|
||
(* Check for a valid port number and open the port if it not alredy open *)
|
||
|
||
CONST
|
||
PortName : ARRAY [0..3] OF ARRAY [0..4] OF CHAR =
|
||
[['COM1', 0C], ['COM2', 0C], ['COM3', 0C], ['COM4', 0C]];
|
||
|
||
VAR
|
||
Action : CARDINAL;
|
||
|
||
BEGIN
|
||
(* check the port number *)
|
||
IF portnum > 3 THEN
|
||
RETURN FALSE;
|
||
END;
|
||
|
||
(* attempt to open the port if it is not already open *)
|
||
IF Handle[portnum] = 0 THEN
|
||
IF DosOpen(ADR(PortName[portnum]), Handle[portnum], Action, 0,
|
||
AttributeSet{}, 1, 12H, 0) # 0 THEN
|
||
RETURN FALSE;
|
||
END;
|
||
END;
|
||
RETURN TRUE;
|
||
END CheckPort;
|
||
|
||
|
||
|
||
PROCEDURE InitPort (portnum : CARDINAL; speed : BaudRate; data : DataBits;
|
||
stop : StopBits; check : Parity) : CommStatus;
|
||
(* Initialize a port *)
|
||
|
||
CONST
|
||
Rate : ARRAY BaudRate OF CARDINAL =
|
||
[110, 150, 300, 600, 1200, 2400, 4800, 9600, 19200];
|
||
TransParity : ARRAY Parity OF BYTE = [2, 1, 0];
|
||
|
||
TYPE
|
||
LineChar = RECORD
|
||
bDataBits : BYTE;
|
||
bParity : BYTE;
|
||
bStopBits : BYTE;
|
||
END;
|
||
|
||
VAR
|
||
LC : LineChar;
|
||
|
||
BEGIN
|
||
(* Check the port number *)
|
||
IF NOT CheckPort(portnum) THEN
|
||
RETURN InvalidPort;
|
||
END;
|
||
|
||
(* Set the baud rate *)
|
||
IF DosDevIOCtl(0, ADR(Rate[speed]), 41H, 1, Handle[portnum]) # 0 THEN
|
||
RETURN InvalidParameter;
|
||
END;
|
||
|
||
(* set the characteristics *)
|
||
LC.bDataBits := BYTE(data);
|
||
IF stop = 1 THEN
|
||
DEC (stop); (* 0x00 = 1 stop bits; 0x02 = 2 stop bits *)
|
||
END;
|
||
LC.bStopBits := BYTE(stop);
|
||
LC.bParity := TransParity[check];
|
||
|
||
IF DosDevIOCtl(0, ADR(LC), 42H, 1, Handle[portnum]) # 0 THEN
|
||
RETURN InvalidParameter;
|
||
END;
|
||
|
||
RETURN Success;
|
||
END InitPort;
|
||
|
||
|
||
PROCEDURE StartReceiving (portnum, bufsize : CARDINAL) : CommStatus;
|
||
(* Start receiving characters on a port *)
|
||
BEGIN
|
||
IF NOT CheckPort(portnum) THEN
|
||
RETURN InvalidPort;
|
||
END;
|
||
IF BufStart[portnum] # NIL THEN
|
||
RETURN AlreadyReceiving;
|
||
END;
|
||
ALLOCATE (BufStart[portnum], bufsize);
|
||
BufIn[portnum] := BufStart[portnum];
|
||
BufOut[portnum] := BufStart[portnum];
|
||
BufLimit[portnum] := BufStart[portnum];
|
||
INC (BufLimit[portnum]:ADDRESS, bufsize - 1);
|
||
BufSize[portnum] := bufsize;
|
||
RETURN Success;
|
||
END StartReceiving;
|
||
|
||
|
||
PROCEDURE StopReceiving (portnum : CARDINAL) : CommStatus;
|
||
(* Stop receiving characters on a port *)
|
||
BEGIN
|
||
IF NOT CheckPort(portnum) THEN
|
||
RETURN InvalidPort;
|
||
END;
|
||
IF BufStart[portnum] # NIL THEN
|
||
DEALLOCATE (BufStart[portnum], BufSize[portnum]);
|
||
BufLimit[portnum] := NIL;
|
||
BufIn[portnum] := NIL;
|
||
BufOut[portnum] := NIL;
|
||
BufSize[portnum] := 0;
|
||
END;
|
||
DosClose(Handle[portnum]);
|
||
Handle[portnum] := 0;
|
||
RETURN Success;
|
||
END StopReceiving;
|
||
|
||
|
||
PROCEDURE GetChar (portnum : CARDINAL; VAR ch : CHAR) : CommStatus;
|
||
(* Get a character from the comm port *)
|
||
|
||
VAR
|
||
status : CARDINAL;
|
||
read : CARDINAL;
|
||
que : RECORD
|
||
ct : CARDINAL;
|
||
sz : CARDINAL;
|
||
END;
|
||
i : CARDINAL;
|
||
|
||
BEGIN
|
||
IF BufStart[portnum] = NIL THEN
|
||
RETURN NotReceiving;
|
||
END;
|
||
IF NOT CheckPort(portnum) THEN
|
||
RETURN InvalidPort;
|
||
END;
|
||
status := DosDevIOCtl (ADR (que), 0, 68H, 1, Handle[portnum]);
|
||
IF (status = 0) AND (que.ct # 0) THEN
|
||
status := DosRead (Handle[portnum], ADR (Temp), que.ct, read);
|
||
IF (status # 0) OR (read = 0) THEN
|
||
RETURN NotReceiving;
|
||
END;
|
||
FOR i := 1 TO read DO
|
||
BufIn[portnum]^ := Temp[i];
|
||
IF BufIn[portnum] = BufLimit[portnum] THEN
|
||
BufIn[portnum] := BufStart[portnum];
|
||
ELSE
|
||
INC (BufIn[portnum]:ADDRESS);
|
||
END;
|
||
IF BufIn[portnum] = BufOut[portnum] THEN
|
||
RETURN BufferOverflow;
|
||
END;
|
||
END;
|
||
END;
|
||
|
||
IF BufIn[portnum] = BufOut[portnum] THEN
|
||
RETURN NoCharacter;
|
||
END;
|
||
ch := BufOut[portnum]^;
|
||
IF BufOut[portnum] = BufLimit[portnum] THEN
|
||
BufOut[portnum] := BufStart[portnum];
|
||
ELSE
|
||
INC (BufOut[portnum]:ADDRESS);
|
||
END;
|
||
RETURN Success;
|
||
END GetChar;
|
||
|
||
|
||
PROCEDURE SendChar (portnum : CARDINAL; ch : CHAR;
|
||
modem : BOOLEAN) : CommStatus;
|
||
(* send a character to the comm port *)
|
||
|
||
VAR
|
||
wrote : CARDINAL;
|
||
status : CARDINAL;
|
||
commSt : CHAR;
|
||
|
||
BEGIN
|
||
IF NOT CheckPort(portnum) THEN
|
||
RETURN InvalidPort;
|
||
END;
|
||
status := DosDevIOCtl (ADR (commSt), 0, 64H, 1, Handle[portnum]);
|
||
IF (status # 0) OR (commSt # 0C) THEN
|
||
RETURN TimeOut;
|
||
ELSE
|
||
status := DosWrite(Handle[portnum], ADR(ch), 1, wrote);
|
||
IF (status # 0) OR (wrote # 1) THEN
|
||
RETURN TimeOut;
|
||
ELSE
|
||
RETURN Success;
|
||
END;
|
||
END;
|
||
END SendChar;
|
||
|
||
|
||
BEGIN (* module initialization *)
|
||
(* nothing open yet *)
|
||
FOR pn := 0 TO 3 DO
|
||
Handle[pn] := 0;
|
||
BufStart[pn] := NIL;
|
||
BufLimit[pn] := NIL;
|
||
BufIn[pn] := NIL;
|
||
BufOut[pn] := NIL;
|
||
BufSize[pn] := 0;
|
||
END;
|
||
END CommPort.
|
||
|
||
[LISTING THIRTEEN]
|
||
|
||
IMPLEMENTATION MODULE Files; (* File I/O for Kermit *)
|
||
|
||
FROM FileSystem IMPORT
|
||
File, Response, Delete, Lookup, Close, ReadNBytes, WriteNBytes;
|
||
|
||
FROM Strings IMPORT
|
||
Append;
|
||
|
||
FROM Conversions IMPORT
|
||
CardToString;
|
||
|
||
FROM SYSTEM IMPORT
|
||
ADR, SIZE;
|
||
|
||
|
||
TYPE
|
||
buffer = ARRAY [1..512] OF CHAR;
|
||
|
||
|
||
VAR
|
||
ext : CARDINAL; (* new file extensions to avoid name conflict *)
|
||
inBuf, outBuf : buffer;
|
||
inP, outP : CARDINAL; (* buffer pointers *)
|
||
read, written : CARDINAL; (* number of bytes read or written *)
|
||
(* by ReadNBytes or WriteNBytes *)
|
||
|
||
|
||
PROCEDURE Open (VAR f : File; name : ARRAY OF CHAR) : Status;
|
||
(* opens an existing file for reading, returns status *)
|
||
BEGIN
|
||
Lookup (f, name, FALSE);
|
||
IF f.res = done THEN
|
||
inP := 0; read := 0;
|
||
RETURN Done;
|
||
ELSE
|
||
RETURN Error;
|
||
END;
|
||
END Open;
|
||
|
||
|
||
PROCEDURE Create (VAR f : File; name : ARRAY OF CHAR) : Status;
|
||
(* creates a new file for writing, returns status *)
|
||
|
||
VAR
|
||
ch : CHAR;
|
||
str : ARRAY [0..3] OF CHAR;
|
||
i : CARDINAL;
|
||
b : BOOLEAN;
|
||
|
||
BEGIN
|
||
LOOP
|
||
Lookup (f, name, FALSE); (* check to see if file exists *)
|
||
IF f.res = done THEN
|
||
Close (f);
|
||
(* Filename Clash: Change file name *)
|
||
IF ext > 99 THEN (* out of new names... *)
|
||
RETURN Error;
|
||
END;
|
||
i := 0;
|
||
WHILE (name[i] # 0C) AND (name[i] # '.') DO
|
||
INC (i); (* scan for end of filename *)
|
||
END;
|
||
name[i] := '.'; name[i + 1] := 'K'; name[i + 2] := 0C;
|
||
i := 0;
|
||
CardToString (ext, 1, str, i, b);
|
||
Append (name, str); (* append new extension *)
|
||
INC (ext);
|
||
ELSE
|
||
EXIT;
|
||
END;
|
||
END;
|
||
Lookup (f, name, TRUE);
|
||
IF f.res = done THEN
|
||
outP := 0;
|
||
RETURN Done;
|
||
ELSE
|
||
RETURN Error;
|
||
END;
|
||
END Create;
|
||
|
||
|
||
PROCEDURE CloseFile (VAR f : File; Which : FileType) : Status;
|
||
(* closes a file after reading or writing *)
|
||
BEGIN
|
||
written := outP;
|
||
IF (Which = Output) AND (outP > 0) THEN
|
||
WriteNBytes (f, ADR (outBuf), outP);
|
||
written := f.count;
|
||
END;
|
||
Close (f);
|
||
IF (written = outP) AND (f.res = done) THEN
|
||
RETURN Done;
|
||
ELSE
|
||
RETURN Error;
|
||
END;
|
||
END CloseFile;
|
||
|
||
|
||
PROCEDURE Get (VAR f : File; VAR ch : CHAR) : Status;
|
||
(* Reads one character from the file, returns status *)
|
||
BEGIN
|
||
IF inP = read THEN
|
||
ReadNBytes (f, ADR (inBuf), SIZE (inBuf));
|
||
read := f.count;
|
||
inP := 0;
|
||
END;
|
||
IF read = 0 THEN
|
||
RETURN EOF;
|
||
ELSE
|
||
INC (inP);
|
||
ch := inBuf[inP];
|
||
RETURN Done;
|
||
END;
|
||
END Get;
|
||
|
||
|
||
PROCEDURE Put (ch : CHAR);
|
||
(* Writes one character to the file buffer *)
|
||
BEGIN
|
||
INC (outP);
|
||
outBuf[outP] := ch;
|
||
END Put;
|
||
|
||
|
||
PROCEDURE DoWrite (VAR f : File) : Status;
|
||
(* Writes buffer to disk only if nearly full *)
|
||
BEGIN
|
||
IF outP < 400 THEN (* still room in buffer *)
|
||
RETURN Done;
|
||
ELSE
|
||
WriteNBytes (f, ADR (outBuf), outP);
|
||
written := f.count;
|
||
IF (written = outP) AND (f.res = done) THEN
|
||
outP := 0;
|
||
RETURN Done;
|
||
ELSE
|
||
RETURN Error;
|
||
END;
|
||
END;
|
||
END DoWrite;
|
||
|
||
BEGIN (* module initialization *)
|
||
ext := 0;
|
||
END Files.
|
||
|
||
[LISTING FOURTEEN]
|
||
|
||
DEFINITION MODULE KH;
|
||
|
||
CONST
|
||
ID_OK = 25;
|
||
|
||
PARITY_OFF = 150;
|
||
ID_NONE = 152;
|
||
ID_ODD = 151;
|
||
ID_EVEN = 150;
|
||
|
||
STOP_OFF = 140;
|
||
ID_STOP2 = 142;
|
||
ID_STOP1 = 141;
|
||
|
||
DATA_OFF = 130;
|
||
ID_DATA8 = 138;
|
||
ID_DATA7 = 137;
|
||
|
||
BAUD_OFF = 120;
|
||
ID_B19K2 = 128;
|
||
ID_B9600 = 127;
|
||
ID_B4800 = 126;
|
||
ID_B2400 = 125;
|
||
ID_B1200 = 124;
|
||
ID_B600 = 123;
|
||
ID_B300 = 122;
|
||
ID_B150 = 121;
|
||
ID_B110 = 120;
|
||
|
||
COM_OFF = 100;
|
||
ID_COM2 = 101;
|
||
ID_COM1 = 100;
|
||
|
||
IDM_C2 = 24;
|
||
IDM_C1 = 23;
|
||
IDM_AMBER = 22;
|
||
IDM_GREEN = 21;
|
||
IDM_WHITE = 20;
|
||
IDM_COLORS = 19;
|
||
IDM_DIREND = 18;
|
||
ID_DIRPATH = 17;
|
||
ID_SENDFN = 16;
|
||
IDM_DIRPATH = 15;
|
||
IDM_SENDFN = 14;
|
||
IDM_TERMHELP = 13;
|
||
IDM_HELPMENU = 12;
|
||
IDM_ABOUT = 11;
|
||
IDM_PARITY = 10;
|
||
IDM_STOPBITS = 9;
|
||
IDM_DATABITS = 8;
|
||
IDM_BAUDRATE = 7;
|
||
IDM_COMPORT = 6;
|
||
IDM_QUIT = 5;
|
||
IDM_REC = 4;
|
||
IDM_SEND = 3;
|
||
IDM_CONNECT = 2;
|
||
IDM_DIR = 1;
|
||
IDM_OPTIONS = 52;
|
||
IDM_FILE = 51;
|
||
IDM_KERMIT = 50;
|
||
|
||
END KH.
|
||
|
||
[LISTING FIFTEEN]
|
||
|
||
IMPLEMENTATION MODULE KH;
|
||
END KH.
|
||
|
||
[LISTING SIXTEEN]
|
||
|
||
#define IDM_KERMIT 50
|
||
#define IDM_FILE 51
|
||
#define IDM_OPTIONS 52
|
||
#define IDM_HELP 0
|
||
#define IDM_DIR 1
|
||
#define IDM_CONNECT 2
|
||
#define IDM_SEND 3
|
||
#define IDM_REC 4
|
||
#define IDM_QUIT 5
|
||
#define IDM_COMPORT 6
|
||
#define IDM_BAUDRATE 7
|
||
#define IDM_DATABITS 8
|
||
#define IDM_STOPBITS 9
|
||
#define IDM_PARITY 10
|
||
#define IDM_ABOUT 11
|
||
#define IDM_HELPMENU 12
|
||
#define IDM_TERMHELP 13
|
||
#define IDM_SENDFN 14
|
||
#define IDM_DIRPATH 15
|
||
#define ID_SENDFN 16
|
||
#define ID_DIRPATH 17
|
||
#define IDM_DIREND 18
|
||
#define IDM_COLORS 19
|
||
#define IDM_WHITE 20
|
||
#define IDM_GREEN 21
|
||
#define IDM_AMBER 22
|
||
#define IDM_C1 23
|
||
#define IDM_C2 24
|
||
#define ID_OK 25
|
||
#define ID_COM1 100
|
||
#define ID_COM2 101
|
||
#define ID_B110 120
|
||
#define ID_B150 121
|
||
#define ID_B300 122
|
||
#define ID_B600 123
|
||
#define ID_B1200 124
|
||
#define ID_B2400 125
|
||
#define ID_B4800 126
|
||
#define ID_B9600 127
|
||
#define ID_B19K2 128
|
||
#define ID_DATA7 137
|
||
#define ID_DATA8 138
|
||
#define ID_STOP1 141
|
||
#define ID_STOP2 142
|
||
#define ID_EVEN 150
|
||
#define ID_ODD 151
|
||
#define ID_NONE 152
|
||
|
||
[LISTING SEVENTEEN]
|
||
|
||
IMPLEMENTATION MODULE DataLink; (* Sends and Receives Packets for PCKermit *)
|
||
|
||
FROM ElapsedTime IMPORT
|
||
StartTime, GetTime;
|
||
|
||
FROM Screen IMPORT
|
||
ClrScr, WriteString, WriteLn;
|
||
|
||
FROM PMWIN IMPORT
|
||
MPARAM, WinPostMsg;
|
||
|
||
FROM Shell IMPORT
|
||
ChildFrameWindow, comport;
|
||
|
||
FROM CommPort IMPORT
|
||
CommStatus, GetChar, SendChar;
|
||
|
||
FROM PAD IMPORT
|
||
PacketType, yourNPAD, yourPADC, yourEOL;
|
||
|
||
FROM KH IMPORT
|
||
COM_OFF;
|
||
|
||
FROM SYSTEM IMPORT
|
||
BYTE;
|
||
|
||
IMPORT ASCII;
|
||
|
||
|
||
CONST
|
||
MAXtime = 100; (* hundredths of a second -- i.e., one second *)
|
||
MAXsohtrys = 100;
|
||
DL_BadCS = 1;
|
||
DL_NoSOH = 2;
|
||
|
||
|
||
TYPE
|
||
SMALLSET = SET OF [0..7]; (* BYTE *)
|
||
|
||
VAR
|
||
ch : CHAR;
|
||
status : CommStatus;
|
||
MP1, MP2 : MPARAM;
|
||
|
||
|
||
PROCEDURE Delay (t : CARDINAL);
|
||
(* delay time in milliseconds *)
|
||
|
||
VAR
|
||
tmp : LONGINT;
|
||
|
||
BEGIN
|
||
tmp := t DIV 10;
|
||
StartTime;
|
||
WHILE GetTime() < tmp DO
|
||
END;
|
||
END Delay;
|
||
|
||
|
||
PROCEDURE ByteAnd (a, b : BYTE) : BYTE;
|
||
BEGIN
|
||
RETURN BYTE (SMALLSET (a) * SMALLSET (b));
|
||
END ByteAnd;
|
||
|
||
|
||
PROCEDURE Char (c : INTEGER) : CHAR;
|
||
(* converts a number 0-95 into a printable character *)
|
||
BEGIN
|
||
RETURN (CHR (CARDINAL (ABS (c) + 32)));
|
||
END Char;
|
||
|
||
|
||
PROCEDURE UnChar (c : CHAR) : INTEGER;
|
||
(* converts a character into its corresponding number *)
|
||
BEGIN
|
||
RETURN (ABS (INTEGER (ORD (c)) - 32));
|
||
END UnChar;
|
||
|
||
|
||
PROCEDURE FlushUART;
|
||
(* ensure no characters left in UART holding registers *)
|
||
BEGIN
|
||
Delay (500);
|
||
REPEAT
|
||
status := GetChar (comport - COM_OFF, ch);
|
||
UNTIL status = NoCharacter;
|
||
END FlushUART;
|
||
|
||
|
||
PROCEDURE SendPacket (s : PacketType);
|
||
(* Adds SOH and CheckSum to packet *)
|
||
|
||
VAR
|
||
i : CARDINAL;
|
||
checksum : INTEGER;
|
||
|
||
BEGIN
|
||
Delay (10); (* give host a chance to catch its breath *)
|
||
FOR i := 1 TO yourNPAD DO
|
||
status := SendChar (comport - COM_OFF, yourPADC, FALSE);
|
||
END;
|
||
status := SendChar (comport - COM_OFF, ASCII.soh, FALSE);
|
||
i := 1;
|
||
checksum := 0;
|
||
WHILE s[i] # 0C DO
|
||
INC (checksum, ORD (s[i]));
|
||
status := SendChar (comport - COM_OFF, s[i], FALSE);
|
||
INC (i);
|
||
END;
|
||
checksum := checksum + (INTEGER (BITSET (checksum) * {7, 6}) DIV 64);
|
||
checksum := INTEGER (BITSET (checksum) * {5, 4, 3, 2, 1, 0});
|
||
status := SendChar (comport - COM_OFF, Char (checksum), FALSE);
|
||
IF yourEOL # 0C THEN
|
||
status := SendChar (comport - COM_OFF, yourEOL, FALSE);
|
||
END;
|
||
END SendPacket;
|
||
|
||
|
||
PROCEDURE ReceivePacket (VAR r : PacketType) : BOOLEAN;
|
||
(* strips SOH and checksum -- returns status: TRUE = good packet *)
|
||
(* received; FALSE = timed out waiting for packet or checksum error *)
|
||
|
||
VAR
|
||
sohtrys : INTEGER;
|
||
i, len : INTEGER;
|
||
ch : CHAR;
|
||
checksum : INTEGER;
|
||
mycheck, yourcheck : CHAR;
|
||
|
||
BEGIN
|
||
sohtrys := MAXsohtrys;
|
||
REPEAT
|
||
StartTime;
|
||
REPEAT
|
||
status := GetChar (comport - COM_OFF, ch);
|
||
UNTIL (status = Success) OR (GetTime() > MAXtime);
|
||
ch := CHAR (ByteAnd (ch, 177C)); (* mask off MSB *)
|
||
(* skip over up to MAXsohtrys padding characters, *)
|
||
(* but allow only MAXsohtrys/10 timeouts *)
|
||
IF status = Success THEN
|
||
DEC (sohtrys);
|
||
ELSE
|
||
DEC (sohtrys, 10);
|
||
END;
|
||
UNTIL (ch = ASCII.soh) OR (sohtrys <= 0);
|
||
|
||
IF ch = ASCII.soh THEN
|
||
(* receive rest of packet *)
|
||
StartTime;
|
||
REPEAT
|
||
status := GetChar (comport - COM_OFF, ch);
|
||
UNTIL (status = Success) OR (GetTime() > MAXtime);
|
||
ch := CHAR (ByteAnd (ch, 177C));
|
||
len := UnChar (ch);
|
||
r[1] := ch;
|
||
checksum := ORD (ch);
|
||
i := 2; (* on to second character in packet -- after LEN *)
|
||
REPEAT
|
||
StartTime;
|
||
REPEAT
|
||
status := GetChar (comport - COM_OFF, ch);
|
||
UNTIL (status = Success) OR (GetTime() > MAXtime);
|
||
ch := CHAR (ByteAnd (ch, 177C));
|
||
r[i] := ch; INC (i);
|
||
INC (checksum, (ORD (ch)));
|
||
UNTIL (i > len);
|
||
(* get checksum character *)
|
||
StartTime;
|
||
REPEAT
|
||
status := GetChar (comport - COM_OFF, ch);
|
||
UNTIL (status = Success) OR (GetTime() > MAXtime);
|
||
ch := CHAR (ByteAnd (ch, 177C));
|
||
yourcheck := ch;
|
||
r[i] := 0C;
|
||
checksum := checksum +
|
||
(INTEGER (BITSET (checksum) * {7, 6}) DIV 64);
|
||
checksum := INTEGER (BITSET (checksum) * {5, 4, 3, 2, 1, 0});
|
||
mycheck := Char (checksum);
|
||
IF mycheck = yourcheck THEN (* checksum OK *)
|
||
RETURN TRUE;
|
||
ELSE (* ERROR!!! *)
|
||
MP1.W1 := DL_BadCS; MP1.W2 := 0;
|
||
MP2.L := 0;
|
||
WinPostMsg (ChildFrameWindow, WM_DL, MP1, MP2);
|
||
RETURN FALSE;
|
||
END;
|
||
ELSE
|
||
MP1.W1 := DL_NoSOH; MP1.W2 := 0;
|
||
MP2.L := 0;
|
||
WinPostMsg (ChildFrameWindow, WM_DL, MP1, MP2);
|
||
RETURN FALSE;
|
||
END;
|
||
END ReceivePacket;
|
||
|
||
|
||
PROCEDURE DoDLMsg (mp1, mp2 [VALUE] : MPARAM);
|
||
(* Process DataLink Messages *)
|
||
BEGIN
|
||
CASE CARDINAL (mp1.W1) OF
|
||
DL_BadCS:
|
||
WriteString ("Bad Checksum"); WriteLn;
|
||
| DL_NoSOH:
|
||
WriteString ("No SOH"); WriteLn;
|
||
ELSE
|
||
(* Do Nothing *)
|
||
END;
|
||
END DoDLMsg;
|
||
|
||
END DataLink.
|
||
|
||
[LISTING EIGHTEEN]
|
||
|
||
#include <os2.h>
|
||
#include "pckermit.h"
|
||
|
||
ICON IDM_KERMIT pckermit.ico
|
||
|
||
MENU IDM_KERMIT
|
||
BEGIN
|
||
SUBMENU "~File", IDM_FILE
|
||
BEGIN
|
||
MENUITEM "~Directory...", IDM_DIR
|
||
MENUITEM "~Connect\t^C", IDM_CONNECT
|
||
MENUITEM "~Send...\t^S", IDM_SEND
|
||
MENUITEM "~Receive...\t^R", IDM_REC
|
||
MENUITEM SEPARATOR
|
||
MENUITEM "E~xit\t^X", IDM_QUIT
|
||
MENUITEM "A~bout PCKermit...", IDM_ABOUT
|
||
END
|
||
|
||
SUBMENU "~Options", IDM_OPTIONS
|
||
BEGIN
|
||
MENUITEM "~COM port...", IDM_COMPORT
|
||
MENUITEM "~Baud rate...", IDM_BAUDRATE
|
||
MENUITEM "~Data bits...", IDM_DATABITS
|
||
MENUITEM "~Stop bits...", IDM_STOPBITS
|
||
MENUITEM "~Parity bits...", IDM_PARITY
|
||
END
|
||
|
||
SUBMENU "~Colors", IDM_COLORS
|
||
BEGIN
|
||
MENUITEM "~White Mono", IDM_WHITE
|
||
MENUITEM "~Green Mono", IDM_GREEN
|
||
MENUITEM "~Amber Mono", IDM_AMBER
|
||
MENUITEM "Full Color ~1", IDM_C1
|
||
MENUITEM "Full Color ~2", IDM_C2
|
||
END
|
||
|
||
MENUITEM "F1=Help", IDM_HELP, MIS_HELP | MIS_BUTTONSEPARATOR
|
||
END
|
||
|
||
ACCELTABLE IDM_KERMIT
|
||
BEGIN
|
||
"^C", IDM_CONNECT
|
||
"^S", IDM_SEND
|
||
"^R", IDM_REC
|
||
"^X", IDM_QUIT
|
||
END
|
||
|
||
DLGTEMPLATE IDM_COMPORT LOADONCALL MOVEABLE DISCARDABLE
|
||
BEGIN
|
||
DIALOG "", IDM_COMPORT, 129, 91, 143, 54, FS_NOBYTEALIGN | FS_DLGBORDER |
|
||
WS_VISIBLE | WS_CLIPSIBLINGS | WS_SAVEBITS
|
||
BEGIN
|
||
CONTROL "Select COM Port", IDM_COMPORT, 10, 9, 83, 38,
|
||
WC_STATIC, SS_GROUPBOX | WS_VISIBLE
|
||
CONTROL "COM1", ID_COM1, 30, 25, 43, 10, WC_BUTTON,
|
||
BS_AUTORADIOBUTTON | WS_GROUP | WS_TABSTOP | WS_VISIBLE
|
||
CONTROL "COM2", ID_COM2, 30, 15, 39, 10, WC_BUTTON,
|
||
BS_AUTORADIOBUTTON | WS_TABSTOP | WS_VISIBLE
|
||
CONTROL "OK", ID_OK, 101, 10, 38, 12, WC_BUTTON, BS_PUSHBUTTON |
|
||
BS_DEFAULT | WS_GROUP | WS_TABSTOP | WS_VISIBLE
|
||
END
|
||
END
|
||
|
||
DLGTEMPLATE IDM_BAUDRATE LOADONCALL MOVEABLE DISCARDABLE
|
||
BEGIN
|
||
DIALOG "", IDM_BAUDRATE, 131, 54, 142, 115, FS_NOBYTEALIGN |
|
||
FS_DLGBORDER | WS_VISIBLE | WS_CLIPSIBLINGS | WS_SAVEBITS
|
||
BEGIN
|
||
CONTROL "Select Baud Rate", IDM_BAUDRATE, 8, 6, 85, 107,
|
||
WC_STATIC, SS_GROUPBOX | WS_VISIBLE
|
||
CONTROL "110 Baud", ID_B110, 20, 90, 62, 10, WC_BUTTON,
|
||
BS_AUTORADIOBUTTON | WS_GROUP | WS_TABSTOP | WS_VISIBLE
|
||
CONTROL "150 Baud", ID_B150, 20, 80, 57, 10, WC_BUTTON,
|
||
BS_AUTORADIOBUTTON | WS_TABSTOP | WS_VISIBLE
|
||
CONTROL "300 Baud", ID_B300, 20, 70, 58, 10, WC_BUTTON,
|
||
BS_AUTORADIOBUTTON | WS_TABSTOP | WS_VISIBLE
|
||
CONTROL "600 Baud", ID_B600, 20, 60, 54, 10, WC_BUTTON,
|
||
BS_AUTORADIOBUTTON | WS_TABSTOP | WS_VISIBLE
|
||
CONTROL "1200 Baud", ID_B1200, 20, 50, 59, 10, WC_BUTTON,
|
||
BS_AUTORADIOBUTTON | WS_TABSTOP | WS_VISIBLE
|
||
CONTROL "2400 Baud", ID_B2400, 20, 40, 63, 10, WC_BUTTON,
|
||
BS_AUTORADIOBUTTON | WS_TABSTOP | WS_VISIBLE
|
||
CONTROL "4800 Baud", ID_B4800, 20, 30, 62, 10, WC_BUTTON,
|
||
BS_AUTORADIOBUTTON | WS_TABSTOP | WS_VISIBLE
|
||
CONTROL "9600 Baud", ID_B9600, 20, 20, 59, 10, WC_BUTTON,
|
||
BS_AUTORADIOBUTTON | WS_TABSTOP | WS_VISIBLE
|
||
CONTROL "19,200 Baud", ID_B19K2, 20, 10, 69, 10, WC_BUTTON,
|
||
BS_AUTORADIOBUTTON | WS_TABSTOP | WS_VISIBLE
|
||
CONTROL "OK", ID_OK, 100, 8, 38, 12, WC_BUTTON, BS_PUSHBUTTON |
|
||
BS_DEFAULT | WS_GROUP | WS_TABSTOP | WS_VISIBLE
|
||
END
|
||
END
|
||
|
||
DLGTEMPLATE IDM_DATABITS LOADONCALL MOVEABLE DISCARDABLE
|
||
BEGIN
|
||
DIALOG "", IDM_DATABITS, 137, 80, 140, 56, FS_NOBYTEALIGN |
|
||
FS_DLGBORDER | WS_VISIBLE | WS_SAVEBITS
|
||
BEGIN
|
||
CONTROL "Select Data Bits", IDM_DATABITS, 8, 11, 80, 36,
|
||
WC_STATIC, SS_GROUPBOX | WS_VISIBLE
|
||
CONTROL "7 Data Bits", ID_DATA7, 15, 25, 67, 10, WC_BUTTON,
|
||
BS_AUTORADIOBUTTON | WS_GROUP | WS_TABSTOP | WS_VISIBLE
|
||
CONTROL "8 Data Bits", ID_DATA8, 15, 15, 64, 10, WC_BUTTON,
|
||
BS_AUTORADIOBUTTON | WS_TABSTOP | WS_VISIBLE
|
||
CONTROL "OK", ID_OK, 96, 12, 38, 12, WC_BUTTON, BS_PUSHBUTTON |
|
||
BS_DEFAULT | WS_GROUP | WS_TABSTOP | WS_VISIBLE
|
||
END
|
||
END
|
||
|
||
DLGTEMPLATE IDM_STOPBITS LOADONCALL MOVEABLE DISCARDABLE
|
||
BEGIN
|
||
DIALOG "", IDM_STOPBITS, 139, 92, 140, 43, FS_NOBYTEALIGN |
|
||
FS_DLGBORDER | WS_VISIBLE | WS_SAVEBITS
|
||
BEGIN
|
||
CONTROL "Select Stop Bits", IDM_STOPBITS, 9, 6, 80, 32,
|
||
WC_STATIC, SS_GROUPBOX | WS_VISIBLE
|
||
CONTROL "1 Stop Bit", ID_STOP1, 20, 20, 57, 10, WC_BUTTON,
|
||
BS_AUTORADIOBUTTON | WS_GROUP | WS_TABSTOP | WS_VISIBLE
|
||
CONTROL "2 Stop Bits", ID_STOP2, 20, 10, 60, 10, WC_BUTTON,
|
||
BS_AUTORADIOBUTTON | WS_TABSTOP | WS_VISIBLE
|
||
CONTROL "OK", ID_OK, 96, 8, 38, 12, WC_BUTTON, BS_PUSHBUTTON |
|
||
BS_DEFAULT | WS_GROUP | WS_TABSTOP | WS_VISIBLE
|
||
END
|
||
END
|
||
|
||
DLGTEMPLATE IDM_PARITY LOADONCALL MOVEABLE DISCARDABLE
|
||
BEGIN
|
||
DIALOG "", IDM_PARITY, 138, 84, 134, 57, FS_NOBYTEALIGN | FS_DLGBORDER |
|
||
WS_VISIBLE | WS_SAVEBITS
|
||
BEGIN
|
||
CONTROL "Select Parity", IDM_PARITY, 12, 6, 64, 46, WC_STATIC,
|
||
SS_GROUPBOX | WS_VISIBLE
|
||
CONTROL "Even", ID_EVEN, 25, 30, 40, 10, WC_BUTTON,
|
||
BS_AUTORADIOBUTTON | WS_GROUP | WS_TABSTOP | WS_VISIBLE
|
||
CONTROL "Odd", ID_ODD, 25, 20, 38, 10, WC_BUTTON,
|
||
BS_AUTORADIOBUTTON | WS_TABSTOP | WS_VISIBLE
|
||
CONTROL "None", ID_NONE, 25, 10, 40, 10, WC_BUTTON,
|
||
BS_AUTORADIOBUTTON | WS_TABSTOP | WS_VISIBLE
|
||
CONTROL "OK", ID_OK, 88, 8, 38, 12, WC_BUTTON, BS_PUSHBUTTON |
|
||
BS_DEFAULT | WS_GROUP | WS_TABSTOP | WS_VISIBLE
|
||
END
|
||
END
|
||
|
||
|
||
DLGTEMPLATE IDM_ABOUT LOADONCALL MOVEABLE DISCARDABLE
|
||
BEGIN
|
||
DIALOG "", IDM_ABOUT, 93, 74, 229, 88, FS_NOBYTEALIGN | FS_DLGBORDER |
|
||
WS_VISIBLE | WS_SAVEBITS
|
||
BEGIN
|
||
ICON IDM_KERMIT -1, 12, 64, 22, 16
|
||
CONTROL "PCKermit for OS/2", 256, 67, 70, 82, 8, WC_STATIC,
|
||
SS_TEXT | DT_LEFT | DT_TOP | WS_GROUP | WS_VISIBLE
|
||
CONTROL "Copyright (c) 1990 by Brian R. Anderson", 257, 27, 30, 172, 8,
|
||
WC_STATIC, SS_TEXT | DT_LEFT | DT_TOP | WS_GROUP | WS_VISIBLE
|
||
CONTROL "Microcomputer to Mainframe Communications", 259, 13, 50, 199, 8,
|
||
WC_STATIC, SS_TEXT | DT_LEFT | DT_TOP | WS_GROUP | WS_VISIBLE
|
||
CONTROL " OK ", 258, 88, 10, 38, 12, WC_BUTTON, BS_PUSHBUTTON |
|
||
BS_DEFAULT | WS_TABSTOP | WS_VISIBLE
|
||
END
|
||
END
|
||
|
||
DLGTEMPLATE IDM_HELPMENU LOADONCALL MOVEABLE DISCARDABLE
|
||
BEGIN
|
||
DIALOG "", IDM_HELPMENU, 83, 45, 224, 125, FS_NOBYTEALIGN | FS_DLGBORDER |
|
||
WS_VISIBLE | WS_CLIPSIBLINGS | WS_SAVEBITS
|
||
BEGIN
|
||
ICON IDM_KERMIT -1, 14, 99, 21, 16
|
||
CONTROL "PCKermit Help Menu", 256, 64, 106, 91, 8, WC_STATIC,
|
||
SS_TEXT | DT_LEFT | DT_TOP | WS_GROUP | WS_VISIBLE
|
||
CONTROL "set communications Options .................. Alt, O",
|
||
258, 10, 80, 201, 8, WC_STATIC, SS_TEXT | DT_LEFT | DT_TOP |
|
||
WS_GROUP | WS_VISIBLE
|
||
CONTROL "Connect to Host ................................... Alt, F; C",
|
||
259, 10, 70, 204, 8, WC_STATIC, SS_TEXT | DT_LEFT | DT_TOP |
|
||
WS_GROUP | WS_VISIBLE
|
||
CONTROL "Directory .............................................. Alt, F; D",
|
||
260, 10, 60, 207, 8, WC_STATIC, SS_TEXT | DT_LEFT | DT_TOP |
|
||
WS_GROUP | WS_VISIBLE
|
||
CONTROL "Send a File .......................................... Alt, F; S",
|
||
261, 10, 50, 207, 8, WC_STATIC, SS_TEXT | DT_LEFT | DT_TOP |
|
||
WS_GROUP | WS_VISIBLE
|
||
CONTROL "Receive a File ...................................... Alt, F; R",
|
||
262, 10, 40, 209, 8, WC_STATIC, SS_TEXT | DT_LEFT | DT_TOP |
|
||
WS_GROUP | WS_VISIBLE
|
||
CONTROL "Exit ...................................................... Alt, F; X",
|
||
263, 10, 30, 205, 8, WC_STATIC, SS_TEXT | DT_LEFT | DT_TOP |
|
||
WS_GROUP | WS_VISIBLE
|
||
CONTROL "OK", 264, 83, 9, 38, 12, WC_BUTTON, BS_PUSHBUTTON |
|
||
WS_TABSTOP | WS_VISIBLE | BS_DEFAULT
|
||
END
|
||
END
|
||
|
||
DLGTEMPLATE IDM_TERMHELP LOADONCALL MOVEABLE DISCARDABLE
|
||
BEGIN
|
||
DIALOG "", IDM_TERMHELP, 81, 20, 238, 177, FS_NOBYTEALIGN |
|
||
FS_DLGBORDER | WS_VISIBLE | WS_CLIPSIBLINGS | WS_SAVEBITS
|
||
BEGIN
|
||
CONTROL "^E = Echo mode", 256, 10, 160, 72, 8, WC_STATIC,
|
||
SS_TEXT | DT_LEFT | DT_TOP | WS_GROUP | WS_VISIBLE
|
||
CONTROL "^L = Local echo mode", 257, 10, 150, 97, 8, WC_STATIC,
|
||
SS_TEXT | DT_LEFT | DT_TOP | WS_GROUP | WS_VISIBLE
|
||
CONTROL "^T = Terminal Mode (no echo)", 258, 10, 140, 131, 8, WC_STATIC,
|
||
SS_TEXT | DT_LEFT | DT_TOP | WS_GROUP | WS_VISIBLE
|
||
CONTROL "^N = Newline mode (<cr> --> <cr><lf>)", 259, 10, 130, 165, 8,
|
||
WC_STATIC, SS_TEXT | DT_LEFT | DT_TOP | WS_GROUP | WS_VISIBLE
|
||
CONTROL "^O = Newline mode OFF", 260, 10, 120, 109, 8, WC_STATIC,
|
||
SS_TEXT | DT_LEFT | DT_TOP | WS_GROUP | WS_VISIBLE
|
||
CONTROL "Televideo TVI950 / IBM 7171 Terminal Emulation", 261, 10, 100, 217, 8,
|
||
WC_STATIC, SS_TEXT | DT_LEFT | DT_TOP | WS_GROUP | WS_VISIBLE
|
||
CONTROL "Sh-F1 - Sh-F12 = PF1 - PF12", 262, 10, 90, 135, 8,
|
||
WC_STATIC, SS_TEXT | DT_LEFT | DT_TOP | WS_GROUP | WS_VISIBLE
|
||
CONTROL "Home = Clear", 263, 10, 80, 119, 8, WC_STATIC,
|
||
SS_TEXT | DT_LEFT | DT_TOP | WS_GROUP | WS_VISIBLE
|
||
CONTROL "PgDn = Page Down (as used in PROFS)",
|
||
264, 10, 70, 228, 8, WC_STATIC, SS_TEXT | DT_LEFT | DT_TOP |
|
||
WS_GROUP | WS_VISIBLE
|
||
CONTROL "PgUp = Page Up (as used in PROFS)",
|
||
265, 10, 60, 227, 8, WC_STATIC, SS_TEXT | DT_LEFT | DT_TOP |
|
||
WS_GROUP | WS_VISIBLE
|
||
CONTROL "Insert = Insert (Enter to Clear)", 266, 10, 40, 221, 8,
|
||
WC_STATIC, SS_TEXT | DT_LEFT | DT_TOP | WS_GROUP | WS_VISIBLE
|
||
CONTROL "Delete = Delete", 267, 10, 30, 199, 8,
|
||
WC_STATIC, SS_TEXT | DT_LEFT | DT_TOP | WS_GROUP | WS_VISIBLE
|
||
CONTROL "Control-G = Reset (rewrites the screen)",
|
||
268, 10, 20, 222, 8,
|
||
WC_STATIC, SS_TEXT | DT_LEFT | DT_TOP | WS_GROUP | WS_VISIBLE
|
||
CONTROL "Cursor Keys (i.e., Up, Down, Left, Right) all work.",
|
||
269, 10, 10, 220, 8, WC_STATIC, SS_TEXT | DT_LEFT | DT_TOP |
|
||
WS_GROUP | WS_VISIBLE
|
||
CONTROL "OK", 270, 193, 158, 38, 12, WC_BUTTON, BS_PUSHBUTTON |
|
||
BS_DEFAULT | WS_TABSTOP | WS_VISIBLE
|
||
CONTROL "End = End (as used in PROFS)", 271, 10, 50, 209, 8,
|
||
WC_STATIC, SS_TEXT | DT_LEFT | DT_TOP | WS_GROUP | WS_VISIBLE
|
||
END
|
||
END
|
||
|
||
|
||
DLGTEMPLATE IDM_SENDFN LOADONCALL MOVEABLE DISCARDABLE
|
||
BEGIN
|
||
DIALOG "", IDM_SENDFN, 113, 90, 202, 60, FS_NOBYTEALIGN | FS_DLGBORDER |
|
||
WS_VISIBLE | WS_SAVEBITS
|
||
BEGIN
|
||
CONTROL "Send File", 256, 4, 4, 195, 24, WC_STATIC, SS_GROUPBOX |
|
||
WS_GROUP | WS_VISIBLE
|
||
CONTROL "Enter filename:", 257, 13, 11, 69, 8, WC_STATIC, SS_TEXT |
|
||
DT_LEFT | DT_TOP | WS_GROUP | WS_VISIBLE
|
||
ICON IDM_KERMIT -1, 15, 38, 22, 16
|
||
CONTROL "PCKermit for OS/2", 259, 59, 45, 82, 8, WC_STATIC, SS_TEXT |
|
||
DT_LEFT | DT_TOP | WS_GROUP | WS_VISIBLE
|
||
CONTROL "OK", 260, 154, 36, 38, 12, WC_BUTTON, BS_PUSHBUTTON |
|
||
WS_TABSTOP | WS_VISIBLE | BS_DEFAULT
|
||
CONTROL "", ID_SENDFN, 89, 10, 98, 8, WC_ENTRYFIELD, ES_LEFT |
|
||
ES_MARGIN | WS_TABSTOP | WS_VISIBLE
|
||
END
|
||
END
|
||
|
||
DLGTEMPLATE IDM_DIRPATH LOADONCALL MOVEABLE DISCARDABLE
|
||
BEGIN
|
||
DIALOG "", IDM_DIRPATH, 83, 95, 242, 46, FS_NOBYTEALIGN | FS_DLGBORDER |
|
||
WS_VISIBLE | WS_SAVEBITS
|
||
BEGIN
|
||
CONTROL "Directory", 256, 7, 5, 227, 24, WC_STATIC, SS_GROUPBOX |
|
||
WS_GROUP | WS_VISIBLE
|
||
CONTROL "Path:", 257, 28, 11, 26, 8, WC_STATIC, SS_TEXT | DT_LEFT |
|
||
DT_TOP | WS_GROUP | WS_VISIBLE
|
||
CONTROL "OK", 258, 185, 31, 38, 12, WC_BUTTON, BS_PUSHBUTTON |
|
||
WS_TABSTOP | WS_VISIBLE | BS_DEFAULT
|
||
CONTROL "*.*", ID_DIRPATH, 57, 11, 166, 8, WC_ENTRYFIELD, ES_LEFT |
|
||
ES_AUTOSCROLL | ES_MARGIN | WS_TABSTOP | WS_VISIBLE
|
||
END
|
||
END
|
||
|
||
DLGTEMPLATE IDM_DIREND LOADONCALL MOVEABLE DISCARDABLE
|
||
BEGIN
|
||
DIALOG "", IDM_DIREND, 149, 18, 101, 27, FS_NOBYTEALIGN | FS_DLGBORDER |
|
||
WS_VISIBLE | WS_SAVEBITS
|
||
BEGIN
|
||
CONTROL "Cancel", 256, 30, 2, 38, 12, WC_BUTTON, BS_PUSHBUTTON |
|
||
BS_DEFAULT | WS_TABSTOP | WS_VISIBLE
|
||
CONTROL "Directory Complete", 257, 9, 16, 84, 8, WC_STATIC, SS_TEXT |
|
||
DT_LEFT | DT_TOP | WS_GROUP | WS_VISIBLE
|
||
END
|
||
END
|
||
|
||
[LISTING NINETEEN]
|
||
|
||
NAME PCKermit WINDOWAPI
|
||
DESCRIPTION 'PCKermit: (c) Brian R. Anderson, 1990'
|
||
HEAPSIZE 16384
|
||
STACKSIZE 8192
|
||
PROTMODE
|
||
EXETYPE OS2
|
||
CODE LOADONCALL EXECUTEREAD NOIOPL NONCONFORMING
|
||
DATA LOADONCALL READWRITE MULTIPLE NONSHARED NOIOPL
|
||
EXPORTS
|
||
WindowProc
|
||
ChildWindowProc
|
||
ComDlgProc
|
||
BaudDlgProc
|
||
DataDlgProc
|
||
StopDlgProc
|
||
ParityDlgProc
|
||
AboutDlgProc
|
||
SendFNDlgProc
|
||
PathDlgProc
|
||
DirEndDlgProc
|
||
HelpDlgProc
|
||
|
||
[FILE PCKERMIT]
|
||
|
||
KH.SYM: KH.DEF
|
||
M2 KH.DEF/OUT:KH.SYM
|
||
KH.OBJ: KH.MOD KH.SYM
|
||
M2 KH.MOD/OUT:KH.OBJ
|
||
SHELL.SYM: SHELL.DEF
|
||
M2 SHELL.DEF/OUT:SHELL.SYM
|
||
TERM.SYM: TERM.DEF
|
||
M2 TERM.DEF/OUT:TERM.SYM
|
||
PAD.SYM: PAD.DEF
|
||
M2 PAD.DEF/OUT:PAD.SYM
|
||
DATALINK.SYM: DATALINK.DEF PAD.SYM
|
||
M2 DATALINK.DEF/OUT:DATALINK.SYM
|
||
COMMPORT.SYM: COMMPORT.DEF
|
||
M2 COMMPORT.DEF/OUT:COMMPORT.SYM
|
||
FILES.SYM: FILES.DEF
|
||
M2 FILES.DEF/OUT:FILES.SYM
|
||
pckermit.OBJ: pckermit.MOD SHELL.SYM KH.SYM
|
||
M2 pckermit.MOD/OUT:pckermit.OBJ
|
||
SCREEN.SYM: SCREEN.DEF
|
||
M2 SCREEN.DEF/OUT:SCREEN.SYM
|
||
SCREEN.OBJ: SCREEN.MOD KH.SYM SCREEN.SYM
|
||
M2 SCREEN.MOD/OUT:SCREEN.OBJ
|
||
COMMPORT.OBJ: COMMPORT.MOD COMMPORT.SYM
|
||
M2 COMMPORT.MOD/OUT:COMMPORT.OBJ
|
||
FILES.OBJ: FILES.MOD FILES.SYM
|
||
M2 FILES.MOD/OUT:FILES.OBJ
|
||
SHELL.OBJ: SHELL.MOD COMMPORT.SYM KH.SYM SCREEN.SYM DATALINK.SYM PAD.SYM -
|
||
TERM.SYM SHELL.SYM
|
||
M2 SHELL.MOD/OUT:SHELL.OBJ
|
||
TERM.OBJ: TERM.MOD COMMPORT.SYM KH.SYM SHELL.SYM SCREEN.SYM TERM.SYM
|
||
M2 TERM.MOD/OUT:TERM.OBJ
|
||
PAD.OBJ: PAD.MOD DATALINK.SYM KH.SYM SHELL.SYM FILES.SYM SCREEN.SYM PAD.SYM
|
||
M2 PAD.MOD/OUT:PAD.OBJ
|
||
DATALINK.OBJ: DATALINK.MOD KH.SYM PAD.SYM COMMPORT.SYM SHELL.SYM SCREEN.SYM -
|
||
DATALINK.SYM
|
||
M2 DATALINK.MOD/OUT:DATALINK.OBJ
|
||
pckermit.res: pckermit.rc pckermit.h pckermit.ico
|
||
rc -r pckermit.rc
|
||
pckermit.EXE: KH.OBJ pckermit.OBJ SCREEN.OBJ COMMPORT.OBJ FILES.OBJ SHELL.OBJ -
|
||
TERM.OBJ PAD.OBJ DATALINK.OBJ
|
||
LINK @pckermit.LNK
|
||
rc pckermit.res
|
||
pckermit.exe: pckermit.res
|
||
rc pckermit.res
|
||
|
||
[ FILE PCKERMIT.LNK]
|
||
|
||
KH.OBJ+
|
||
pckermit.OBJ+
|
||
SCREEN.OBJ+
|
||
COMMPORT.OBJ+
|
||
FILES.OBJ+
|
||
SHELL.OBJ+
|
||
TERM.OBJ+
|
||
PAD.OBJ+
|
||
DATALINK.OBJ
|
||
pckermit
|
||
pckermit
|
||
PM+
|
||
OS2+
|
||
M2LIB+
|
||
DOSCALLS
|
||
pckermit.edf
|
||
|
||
[FILE PAD.MOD]
|
||
|
||
IMPLEMENTATION MODULE PAD; (* Packet Assembler/Disassembler for Kermit *)
|
||
|
||
FROM SYSTEM IMPORT
|
||
ADR;
|
||
|
||
FROM Storage IMPORT
|
||
ALLOCATE, DEALLOCATE;
|
||
|
||
FROM Screen IMPORT
|
||
ClrScr, WriteString, WriteInt, WriteHex, WriteLn;
|
||
|
||
FROM DosCalls IMPORT
|
||
ExitType, DosExit;
|
||
|
||
FROM Strings IMPORT
|
||
Length, Assign;
|
||
|
||
FROM FileSystem IMPORT
|
||
File;
|
||
|
||
FROM Directories IMPORT
|
||
FileAttributes, AttributeSet, DirectoryEntry, FindFirst, FindNext;
|
||
|
||
FROM Files IMPORT
|
||
Status, FileType, Open, Create, CloseFile, Get, Put, DoWrite;
|
||
|
||
FROM PMWIN IMPORT
|
||
MPARAM, WinPostMsg;
|
||
|
||
FROM Shell IMPORT
|
||
ChildFrameWindow, comport;
|
||
|
||
FROM KH IMPORT
|
||
COM_OFF;
|
||
|
||
FROM DataLink IMPORT
|
||
FlushUART, SendPacket, ReceivePacket;
|
||
|
||
FROM SYSTEM IMPORT
|
||
BYTE;
|
||
|
||
IMPORT ASCII;
|
||
|
||
|
||
CONST
|
||
myMAXL = 94;
|
||
myTIME = 10;
|
||
myNPAD = 0;
|
||
myPADC = 0C;
|
||
myEOL = 0C;
|
||
myQCTL = '#';
|
||
myQBIN = '&';
|
||
myCHKT = '1'; (* one character checksum *)
|
||
MAXtrys = 5;
|
||
(* From DEFINITION MODULE:
|
||
PAD_Quit = 0; *)
|
||
PAD_SendPacket = 1;
|
||
PAD_ResendPacket = 2;
|
||
PAD_NoSuchFile = 3;
|
||
PAD_ExcessiveErrors = 4;
|
||
PAD_ProbClSrcFile = 5;
|
||
PAD_ReceivedPacket = 6;
|
||
PAD_Filename = 7;
|
||
PAD_RequestRepeat = 8;
|
||
PAD_DuplicatePacket = 9;
|
||
PAD_UnableToOpen = 10;
|
||
PAD_ProbClDestFile = 11;
|
||
PAD_ErrWrtFile = 12;
|
||
PAD_Msg = 13;
|
||
|
||
|
||
TYPE
|
||
(* From Definition Module:
|
||
PacketType = ARRAY [1..100] OF CHAR;
|
||
*)
|
||
SMALLSET = SET OF [0..7]; (* a byte *)
|
||
|
||
|
||
VAR
|
||
yourMAXL : INTEGER; (* maximum packet length -- up to 94 *)
|
||
yourTIME : INTEGER; (* time out -- seconds *)
|
||
(* From Definition Module
|
||
yourNPAD : INTEGER; (* number of padding characters *)
|
||
yourPADC : CHAR; (* padding characters *)
|
||
yourEOL : CHAR; (* End Of Line -- terminator *)
|
||
*)
|
||
yourQCTL : CHAR; (* character for quoting controls '#' *)
|
||
yourQBIN : CHAR; (* character for quoting binary '&' *)
|
||
yourCHKT : CHAR; (* check type -- 1 = checksum, etc. *)
|
||
sF, rF : File; (* files being sent/received *)
|
||
InputFileOpen : BOOLEAN;
|
||
rFname : ARRAY [0..20] OF CHAR;
|
||
sP, rP : PacketType; (* packets sent/received *)
|
||
sSeq, rSeq : INTEGER; (* sequence numbers *)
|
||
PktNbr : INTEGER; (* actual packet number -- no repeats up to 32,000 *)
|
||
ErrorMsg : ARRAY [0..40] OF CHAR;
|
||
MP1, MP2 : MPARAM;
|
||
|
||
|
||
PROCEDURE PtrToStr (mp [VALUE] : MPARAM; VAR s : ARRAY OF CHAR);
|
||
(* Convert a pointer to a string into a string *)
|
||
|
||
TYPE
|
||
PC = POINTER TO CHAR;
|
||
|
||
VAR
|
||
p : PC;
|
||
i : CARDINAL;
|
||
c : CHAR;
|
||
|
||
BEGIN
|
||
i := 0;
|
||
REPEAT
|
||
p := PC (mp);
|
||
c := p^;
|
||
s[i] := c;
|
||
INC (i);
|
||
INC (mp.L);
|
||
UNTIL c = 0C;
|
||
END PtrToStr;
|
||
|
||
|
||
PROCEDURE DoPADMsg (mp1, mp2 [VALUE] : MPARAM);
|
||
(* Output messages for Packet Assembler/Disassembler *)
|
||
|
||
VAR
|
||
Message : ARRAY [0..40] OF CHAR;
|
||
|
||
BEGIN
|
||
CASE CARDINAL (mp1.W1) OF
|
||
PAD_SendPacket:
|
||
WriteString ("Sent Packet #");
|
||
WriteInt (mp2.W1, 5);
|
||
WriteString (" (ID: "); WriteHex (mp2.W2, 2);
|
||
WriteString ("h)");
|
||
| PAD_ResendPacket:
|
||
WriteString ("ERROR -- Resending:"); WriteLn;
|
||
WriteString (" Packet #");
|
||
WriteInt (mp2.W1, 5);
|
||
WriteString (" (ID: "); WriteHex (mp2.W2, 2);
|
||
WriteString ("h)");
|
||
| PAD_NoSuchFile:
|
||
WriteString ("No such file: ");
|
||
PtrToStr (mp2, Message); WriteString (Message);
|
||
| PAD_ExcessiveErrors:
|
||
WriteString ("Excessive errors ...");
|
||
| PAD_ProbClSrcFile:
|
||
WriteString ("Problem closing source file...");
|
||
| PAD_ReceivedPacket:
|
||
WriteString ("Received Packet #");
|
||
WriteInt (mp2.W1, 5);
|
||
WriteString (" (ID: "); WriteHex (mp2.W2, 2);
|
||
WriteString ("h)");
|
||
| PAD_Filename:
|
||
WriteString ("Filename = ");
|
||
PtrToStr (mp2, Message); WriteString (Message);
|
||
| PAD_RequestRepeat:
|
||
WriteString ("ERROR -- Requesting Repeat:"); WriteLn;
|
||
WriteString (" Packet #");
|
||
WriteInt (mp2.W1, 5);
|
||
WriteString (" (ID: "); WriteHex (mp2.W2, 2);
|
||
WriteString ("h)");
|
||
| PAD_DuplicatePacket:
|
||
WriteString ("Discarding Duplicate:"); WriteLn;
|
||
WriteString (" Packet #");
|
||
WriteString (" (ID: "); WriteHex (mp2.W2, 2);
|
||
WriteString ("h)");
|
||
| PAD_UnableToOpen:
|
||
WriteString ("Unable to open file: ");
|
||
PtrToStr (mp2, Message); WriteString (Message);
|
||
| PAD_ProbClDestFile:
|
||
WriteString ("Error closing file: ");
|
||
PtrToStr (mp2, Message); WriteString (Message);
|
||
| PAD_ErrWrtFile:
|
||
WriteString ("Error writing to file: ");
|
||
PtrToStr (mp2, Message); WriteString (Message);
|
||
| PAD_Msg:
|
||
PtrToStr (mp2, Message); WriteString (Message);
|
||
ELSE
|
||
(* Do Nothing *)
|
||
END;
|
||
WriteLn;
|
||
END DoPADMsg;
|
||
|
||
|
||
PROCEDURE CloseInput;
|
||
(* Close the input file, if it exists. Reset Input File Open flag *)
|
||
BEGIN
|
||
IF InputFileOpen THEN
|
||
IF CloseFile (sF, Input) = Done THEN
|
||
InputFileOpen := FALSE;
|
||
ELSE
|
||
MP1.W1 := PAD_ProbClSrcFile; MP1.W2 := 0;
|
||
MP2.L := LONGINT (ADR (sFname));
|
||
WinPostMsg (ChildFrameWindow, WM_PAD, MP1, MP2);
|
||
END;
|
||
END;
|
||
END CloseInput;
|
||
|
||
|
||
PROCEDURE NormalQuit;
|
||
(* Exit from Thread, Post message to Window *)
|
||
BEGIN
|
||
MP1.W1 := PAD_Quit; MP1.W2 := 0;
|
||
MP1.L := 0;
|
||
WinPostMsg (ChildFrameWindow, WM_PAD, MP1, MP2);
|
||
DosExit (EXIT_THREAD, 0);
|
||
END NormalQuit;
|
||
|
||
|
||
PROCEDURE ErrorQuit;
|
||
(* Exit from Thread, Post message to Window *)
|
||
BEGIN
|
||
MP1.W1 := PAD_Error; MP1.W2 := 0;
|
||
MP2.L := 0;
|
||
WinPostMsg (ChildFrameWindow, WM_PAD, MP1, MP2);
|
||
DosExit (EXIT_THREAD, 0);
|
||
END ErrorQuit;
|
||
|
||
|
||
PROCEDURE ByteXor (a, b : BYTE) : BYTE;
|
||
BEGIN
|
||
RETURN BYTE (SMALLSET (a) / SMALLSET (b));
|
||
END ByteXor;
|
||
|
||
|
||
PROCEDURE Char (c : INTEGER) : CHAR;
|
||
(* converts a number 0-94 into a printable character *)
|
||
BEGIN
|
||
RETURN (CHR (CARDINAL (ABS (c) + 32)));
|
||
END Char;
|
||
|
||
|
||
PROCEDURE UnChar (c : CHAR) : INTEGER;
|
||
(* converts a character into its corresponding number *)
|
||
BEGIN
|
||
RETURN (ABS (INTEGER (ORD (c)) - 32));
|
||
END UnChar;
|
||
|
||
|
||
PROCEDURE TellError (Seq : INTEGER);
|
||
(* Send error packet *)
|
||
BEGIN
|
||
sP[1] := Char (15);
|
||
sP[2] := Char (Seq);
|
||
sP[3] := 'E'; (* E-type packet *)
|
||
sP[4] := 'R'; (* error message starts *)
|
||
sP[5] := 'e';
|
||
sP[6] := 'm';
|
||
sP[7] := 'o';
|
||
sP[8] := 't';
|
||
sP[9] := 'e';
|
||
sP[10] := ' ';
|
||
sP[11] := 'A';
|
||
sP[12] := 'b';
|
||
sP[13] := 'o';
|
||
sP[14] := 'r';
|
||
sP[15] := 't';
|
||
sP[16] := 0C;
|
||
SendPacket (sP);
|
||
END TellError;
|
||
|
||
|
||
PROCEDURE ShowError (p : PacketType);
|
||
(* Output contents of error packet to the screen *)
|
||
|
||
VAR
|
||
i : INTEGER;
|
||
|
||
BEGIN
|
||
FOR i := 4 TO UnChar (p[1]) DO
|
||
ErrorMsg[i - 4] := p[i];
|
||
END;
|
||
ErrorMsg[i - 4] := 0C;
|
||
MP1.W1 := PAD_Msg; MP1.W2 := 0;
|
||
MP2.L := LONGINT (ADR (ErrorMsg));
|
||
WinPostMsg (ChildFrameWindow, WM_PAD, MP1, MP2);
|
||
END ShowError;
|
||
|
||
|
||
PROCEDURE youInit (type : CHAR);
|
||
(* I initialization YOU for Send and Receive *)
|
||
BEGIN
|
||
sP[1] := Char (11); (* Length *)
|
||
sP[2] := Char (0); (* Sequence *)
|
||
sP[3] := type;
|
||
sP[4] := Char (myMAXL);
|
||
sP[5] := Char (myTIME);
|
||
sP[6] := Char (myNPAD);
|
||
sP[7] := CHAR (ByteXor (myPADC, 100C));
|
||
sP[8] := Char (ORD (myEOL));
|
||
sP[9] := myQCTL;
|
||
sP[10] := myQBIN;
|
||
sP[11] := myCHKT;
|
||
sP[12] := 0C; (* terminator *)
|
||
SendPacket (sP);
|
||
END youInit;
|
||
|
||
|
||
PROCEDURE myInit;
|
||
(* YOU initialize ME for Send and Receive *)
|
||
|
||
VAR
|
||
len : INTEGER;
|
||
|
||
BEGIN
|
||
len := UnChar (rP[1]);
|
||
IF len >= 4 THEN
|
||
yourMAXL := UnChar (rP[4]);
|
||
ELSE
|
||
yourMAXL := 94;
|
||
END;
|
||
IF len >= 5 THEN
|
||
yourTIME := UnChar (rP[5]);
|
||
ELSE
|
||
yourTIME := 10;
|
||
END;
|
||
IF len >= 6 THEN
|
||
yourNPAD := UnChar (rP[6]);
|
||
ELSE
|
||
yourNPAD := 0;
|
||
END;
|
||
IF len >= 7 THEN
|
||
yourPADC := CHAR (ByteXor (rP[7], 100C));
|
||
ELSE
|
||
yourPADC := 0C;
|
||
END;
|
||
IF len >= 8 THEN
|
||
yourEOL := CHR (UnChar (rP[8]));
|
||
ELSE
|
||
yourEOL := 0C;
|
||
END;
|
||
IF len >= 9 THEN
|
||
yourQCTL := rP[9];
|
||
ELSE
|
||
yourQCTL := 0C;
|
||
END;
|
||
IF len >= 10 THEN
|
||
yourQBIN := rP[10];
|
||
ELSE
|
||
yourQBIN := 0C;
|
||
END;
|
||
IF len >= 11 THEN
|
||
yourCHKT := rP[11];
|
||
IF yourCHKT # myCHKT THEN
|
||
yourCHKT := '1';
|
||
END;
|
||
ELSE
|
||
yourCHKT := '1';
|
||
END;
|
||
END myInit;
|
||
|
||
|
||
PROCEDURE SendInit;
|
||
BEGIN
|
||
youInit ('S');
|
||
END SendInit;
|
||
|
||
|
||
PROCEDURE SendFileName;
|
||
|
||
VAR
|
||
i, j : INTEGER;
|
||
|
||
BEGIN
|
||
(* send file name *)
|
||
i := 4; j := 0;
|
||
WHILE sFname[j] # 0C DO
|
||
sP[i] := sFname[j];
|
||
INC (i); INC (j);
|
||
END;
|
||
sP[1] := Char (j + 3);
|
||
sP[2] := Char (sSeq);
|
||
sP[3] := 'F'; (* filename packet *)
|
||
sP[i] := 0C;
|
||
SendPacket (sP);
|
||
END SendFileName;
|
||
|
||
|
||
PROCEDURE SendEOF;
|
||
BEGIN
|
||
sP[1] := Char (3);
|
||
sP[2] := Char (sSeq);
|
||
sP[3] := 'Z'; (* end of file *)
|
||
sP[4] := 0C;
|
||
SendPacket (sP);
|
||
END SendEOF;
|
||
|
||
|
||
PROCEDURE SendEOT;
|
||
BEGIN
|
||
sP[1] := Char (3);
|
||
sP[2] := Char (sSeq);
|
||
sP[3] := 'B'; (* break -- end of transmit *)
|
||
sP[4] := 0C;
|
||
SendPacket (sP);
|
||
END SendEOT;
|
||
|
||
|
||
PROCEDURE GetAck() : BOOLEAN;
|
||
(* Look for acknowledgement -- retry on timeouts or NAKs *)
|
||
|
||
VAR
|
||
Type : CHAR;
|
||
Seq : INTEGER;
|
||
retrys : INTEGER;
|
||
AckOK : BOOLEAN;
|
||
|
||
BEGIN
|
||
MP1.W1 := PAD_SendPacket; MP1.W2 := 0;
|
||
MP2.W1 := PktNbr; MP2.W2 := sSeq;
|
||
WinPostMsg (ChildFrameWindow, WM_PAD, MP1, MP2);
|
||
|
||
retrys := MAXtrys;
|
||
LOOP
|
||
IF Aborted THEN
|
||
TellError (sSeq);
|
||
CloseInput;
|
||
ErrorQuit;
|
||
END;
|
||
IF ReceivePacket (rP) THEN
|
||
Seq := UnChar (rP[2]);
|
||
Type := rP[3];
|
||
IF (Seq = sSeq) AND (Type = 'Y') THEN
|
||
AckOK := TRUE;
|
||
ELSIF (Seq = (sSeq + 1) MOD 64) AND (Type = 'N') THEN
|
||
AckOK := TRUE; (* NAK for (n + 1) taken as ACK for n *)
|
||
ELSIF Type = 'E' THEN
|
||
ShowError (rP);
|
||
AckOK := FALSE;
|
||
retrys := 0;
|
||
ELSE
|
||
AckOK := FALSE;
|
||
END;
|
||
ELSE
|
||
AckOK := FALSE;
|
||
END;
|
||
IF AckOK OR (retrys = 0) THEN
|
||
EXIT;
|
||
ELSE
|
||
MP1.W1 := PAD_ResendPacket; MP1.W2 := 0;
|
||
MP2.W1 := PktNbr; MP2.W2 := sSeq;
|
||
WinPostMsg (ChildFrameWindow, WM_PAD, MP1, MP2);
|
||
|
||
DEC (retrys);
|
||
FlushUART;
|
||
SendPacket (sP);
|
||
END;
|
||
END;
|
||
|
||
IF AckOK THEN
|
||
INC (PktNbr);
|
||
sSeq := (sSeq + 1) MOD 64;
|
||
RETURN TRUE;
|
||
ELSE
|
||
RETURN FALSE;
|
||
END;
|
||
END GetAck;
|
||
|
||
|
||
PROCEDURE GetInitAck() : BOOLEAN;
|
||
(* configuration for remote station *)
|
||
BEGIN
|
||
IF GetAck() THEN
|
||
myInit;
|
||
RETURN TRUE;
|
||
ELSE
|
||
RETURN FALSE;
|
||
END;
|
||
END GetInitAck;
|
||
|
||
|
||
PROCEDURE Send;
|
||
(* Send one or more files: sFname may be ambiguous *)
|
||
|
||
TYPE
|
||
LP = POINTER TO LIST; (* list of filenames *)
|
||
LIST = RECORD
|
||
fn : ARRAY [0..20] OF CHAR;
|
||
next : LP;
|
||
END;
|
||
|
||
VAR
|
||
gotFN : BOOLEAN;
|
||
attr : AttributeSet;
|
||
ent : DirectoryEntry;
|
||
front, back, t : LP; (* add at back of queue, remove from front *)
|
||
|
||
BEGIN
|
||
Aborted := FALSE;
|
||
InputFileOpen := FALSE;
|
||
|
||
front := NIL; back := NIL;
|
||
attr := AttributeSet {}; (* normal files only *)
|
||
IF Length (sFname) = 0 THEN
|
||
MP1.W1 := PAD_Msg; MP1.W2 := 0;
|
||
MP2.L := LONGINT (ADR ("No file specified..."));
|
||
WinPostMsg (ChildFrameWindow, WM_PAD, MP1, MP2);
|
||
ErrorQuit;
|
||
ELSE
|
||
gotFN := FindFirst (sFname, attr, ent);
|
||
WHILE gotFN DO (* build up a list of file names *)
|
||
ALLOCATE (t, SIZE (LIST));
|
||
Assign (ent.name, t^.fn);
|
||
t^.next := NIL;
|
||
IF front = NIL THEN
|
||
front := t; (* start from empty queue *)
|
||
ELSE
|
||
back^.next := t; (* and to back of queue *)
|
||
END;
|
||
back := t;
|
||
gotFN := FindNext (ent);
|
||
END;
|
||
END;
|
||
|
||
IF front = NIL THEN
|
||
MP1.W1 := PAD_NoSuchFile; MP1.W2 := 0;
|
||
MP2.L := LONGINT (ADR (sFname));
|
||
WinPostMsg (ChildFrameWindow, WM_PAD, MP1, MP2);
|
||
ErrorQuit;
|
||
ELSE
|
||
sSeq := 0; PktNbr := 0;
|
||
FlushUART;
|
||
SendInit; (* my configuration information *)
|
||
IF NOT GetInitAck() THEN (* get your configuration information *)
|
||
MP1.W1 := PAD_ExcessiveErrors; MP1.W2 := 0;
|
||
MP2.L := 0;
|
||
WinPostMsg (ChildFrameWindow, WM_PAD, MP1, MP2);
|
||
ErrorQuit;
|
||
END;
|
||
|
||
WHILE front # NIL DO (* send the files *)
|
||
Assign (front^.fn, sFname);
|
||
PktNbr := 1;
|
||
Send1;
|
||
t := front;
|
||
front := front^.next;
|
||
DEALLOCATE (t, SIZE (LIST));
|
||
END;
|
||
END;
|
||
|
||
SendEOT;
|
||
IF NOT GetAck() THEN
|
||
MP1.W1 := PAD_ExcessiveErrors; MP1.W2 := 0;
|
||
MP2.L := 0;
|
||
WinPostMsg (ChildFrameWindow, WM_PAD, MP1, MP2);
|
||
CloseInput;
|
||
ErrorQuit;
|
||
END;
|
||
NormalQuit;
|
||
END Send;
|
||
|
||
|
||
PROCEDURE Send1;
|
||
(* Send one file: sFname *)
|
||
|
||
VAR
|
||
ch : CHAR;
|
||
i : INTEGER;
|
||
|
||
BEGIN
|
||
IF Open (sF, sFname) = Done THEN
|
||
InputFileOpen := TRUE;
|
||
ELSE;
|
||
MP1.W1 := PAD_NoSuchFile; MP1.W2 := 0;
|
||
MP2.L := LONGINT (ADR (sFname));
|
||
WinPostMsg (ChildFrameWindow, WM_PAD, MP1, MP2);
|
||
ErrorQuit;
|
||
END;
|
||
|
||
MP1.W1 := PAD_Filename; MP1.W2 := 0;
|
||
MP2.L := LONGINT (ADR (sFname));
|
||
WinPostMsg (ChildFrameWindow, WM_PAD, MP1, MP2);
|
||
MP1.W1 := PAD_Msg; MP1.W2 := 0;
|
||
MP2.L := LONGINT (ADR ("(<ESC> to abort file transfer.)"));
|
||
WinPostMsg (ChildFrameWindow, WM_PAD, MP1, MP2);
|
||
|
||
SendFileName;
|
||
IF NOT GetAck() THEN
|
||
MP1.W1 := PAD_ExcessiveErrors; MP1.W2 := 0;
|
||
MP2.L := 0;
|
||
WinPostMsg (ChildFrameWindow, WM_PAD, MP1, MP2);
|
||
CloseInput;
|
||
ErrorQuit;
|
||
END;
|
||
|
||
(* send file *)
|
||
i := 4;
|
||
LOOP
|
||
IF Get (sF, ch) = EOF THEN (* send current packet & terminate *)
|
||
sP[1] := Char (i - 1);
|
||
sP[2] := Char (sSeq);
|
||
sP[3] := 'D'; (* data packet *)
|
||
sP[i] := 0C; (* indicate end of packet *)
|
||
SendPacket (sP);
|
||
IF NOT GetAck() THEN
|
||
MP1.W1 := PAD_ExcessiveErrors; MP1.W2 := 0;
|
||
MP2.L := 0;
|
||
WinPostMsg (ChildFrameWindow, WM_PAD, MP1, MP2);
|
||
CloseInput;
|
||
ErrorQuit;
|
||
END;
|
||
SendEOF;
|
||
IF NOT GetAck() THEN
|
||
MP1.W1 := PAD_ExcessiveErrors; MP1.W2 := 0;
|
||
MP2.L := 0;
|
||
WinPostMsg (ChildFrameWindow, WM_PAD, MP1, MP2);
|
||
CloseInput;
|
||
ErrorQuit;
|
||
END;
|
||
EXIT;
|
||
END;
|
||
|
||
IF i >= (yourMAXL - 4) THEN (* send current packet *)
|
||
sP[1] := Char (i - 1);
|
||
sP[2] := Char (sSeq);
|
||
sP[3] := 'D';
|
||
sP[i] := 0C;
|
||
SendPacket (sP);
|
||
IF NOT GetAck() THEN
|
||
MP1.W1 := PAD_ExcessiveErrors; MP1.W2 := 0;
|
||
MP2.L := 0;
|
||
WinPostMsg (ChildFrameWindow, WM_PAD, MP1, MP2);
|
||
CloseInput;
|
||
ErrorQuit;
|
||
END;
|
||
i := 4;
|
||
END;
|
||
|
||
(* add character to current packet -- update count *)
|
||
IF ch > 177C THEN (* must be quoted (QBIN) and altered *)
|
||
(* toggle bit 7 to turn it off *)
|
||
ch := CHAR (ByteXor (ch, 200C));
|
||
sP[i] := myQBIN; INC (i);
|
||
END;
|
||
IF (ch < 40C) OR (ch = 177C) THEN (* quote (QCTL) and alter *)
|
||
(* toggle bit 6 to turn it on *)
|
||
ch := CHAR (ByteXor (ch, 100C));
|
||
sP[i] := myQCTL; INC (i);
|
||
END;
|
||
IF (ch = myQCTL) OR (ch = myQBIN) THEN (* must send it quoted *)
|
||
sP[i] := myQCTL; INC (i);
|
||
END;
|
||
sP[i] := ch; INC (i);
|
||
END; (* loop *)
|
||
|
||
CloseInput;
|
||
END Send1;
|
||
|
||
|
||
PROCEDURE ReceiveInit() : BOOLEAN;
|
||
(* receive my initialization information from you *)
|
||
|
||
VAR
|
||
RecOK : BOOLEAN;
|
||
trys : INTEGER;
|
||
|
||
BEGIN
|
||
trys := 1;
|
||
LOOP
|
||
IF Aborted THEN
|
||
TellError (rSeq);
|
||
ErrorQuit;
|
||
END;
|
||
RecOK := ReceivePacket (rP) AND (rP[3] = 'S');
|
||
IF RecOK OR (trys = MAXtrys) THEN
|
||
EXIT;
|
||
ELSE
|
||
INC (trys);
|
||
SendNak;
|
||
END;
|
||
END;
|
||
|
||
IF RecOK THEN
|
||
myInit;
|
||
RETURN TRUE;
|
||
ELSE
|
||
RETURN FALSE;
|
||
END;
|
||
END ReceiveInit;
|
||
|
||
|
||
PROCEDURE SendInitAck;
|
||
(* acknowledge your initialization of ME and send mine for YOU *)
|
||
BEGIN
|
||
MP1.W1 := PAD_ReceivedPacket; MP1.W2 := 0;
|
||
MP2.W1 := PktNbr; MP2.W2 := rSeq;
|
||
WinPostMsg (ChildFrameWindow, WM_PAD, MP1, MP2);
|
||
INC (PktNbr);
|
||
rSeq := (rSeq + 1) MOD 64;
|
||
youInit ('Y');
|
||
END SendInitAck;
|
||
|
||
|
||
PROCEDURE ValidFileChar (VAR ch : CHAR) : BOOLEAN;
|
||
(* checks if character is one of 'A'..'Z', '0'..'9', makes upper case *)
|
||
BEGIN
|
||
ch := CAP (ch);
|
||
RETURN ((ch >= 'A') AND (ch <= 'Z')) OR ((ch >= '0') AND (ch <= '9'));
|
||
END ValidFileChar;
|
||
|
||
|
||
TYPE
|
||
HeaderType = (name, eot, fail);
|
||
|
||
PROCEDURE ReceiveHeader() : HeaderType;
|
||
(* receive the filename -- alter for local conditions, if necessary *)
|
||
|
||
VAR
|
||
i, j, k : INTEGER;
|
||
RecOK : BOOLEAN;
|
||
trys : INTEGER;
|
||
|
||
BEGIN
|
||
trys := 1;
|
||
LOOP
|
||
IF Aborted THEN
|
||
TellError (rSeq);
|
||
ErrorQuit;
|
||
END;
|
||
RecOK := ReceivePacket (rP) AND ((rP[3] = 'F') OR (rP[3] = 'B'));
|
||
IF trys = MAXtrys THEN
|
||
RETURN fail;
|
||
ELSIF RecOK AND (rP[3] = 'F') THEN
|
||
i := 4; (* data starts here *)
|
||
j := 0; (* beginning of filename string *)
|
||
WHILE (ValidFileChar (rP[i])) AND (j < 8) DO
|
||
rFname[j] := rP[i];
|
||
INC (i); INC (j);
|
||
END;
|
||
REPEAT
|
||
INC (i);
|
||
UNTIL (ValidFileChar (rP[i])) OR (rP[i] = 0C);
|
||
rFname[j] := '.'; INC (j);
|
||
k := 0;
|
||
WHILE (ValidFileChar (rP[i])) AND (k < 3) DO
|
||
rFname[j + k] := rP[i];
|
||
INC (i); INC (k);
|
||
END;
|
||
rFname[j + k] := 0C;
|
||
MP1.W1 := PAD_Filename; MP1.W2 := 0;
|
||
MP2.L := LONGINT (ADR (rFname));
|
||
WinPostMsg (ChildFrameWindow, WM_PAD, MP1, MP2);
|
||
RETURN name;
|
||
ELSIF RecOK AND (rP[3] = 'B') THEN
|
||
RETURN eot;
|
||
ELSE
|
||
INC (trys);
|
||
SendNak;
|
||
END;
|
||
END;
|
||
END ReceiveHeader;
|
||
|
||
|
||
PROCEDURE SendNak;
|
||
BEGIN
|
||
MP1.W1 := PAD_RequestRepeat; MP1.W2 := 0;
|
||
MP2.W1 := PktNbr; MP2.W2 := rSeq;
|
||
WinPostMsg (ChildFrameWindow, WM_PAD, MP1, MP2);
|
||
FlushUART;
|
||
sP[1] := Char (3); (* LEN *)
|
||
sP[2] := Char (rSeq);
|
||
sP[3] := 'N'; (* negative acknowledgement *)
|
||
sP[4] := 0C;
|
||
SendPacket (sP);
|
||
END SendNak;
|
||
|
||
|
||
PROCEDURE SendAck (Seq : INTEGER);
|
||
BEGIN
|
||
IF Seq # rSeq THEN
|
||
MP1.W1 := PAD_DuplicatePacket; MP1.W2 := 0;
|
||
MP2.W1 := 0; MP2.W2 := rSeq;
|
||
WinPostMsg (ChildFrameWindow, WM_PAD, MP1, MP2);
|
||
ELSE
|
||
MP1.W1 := PAD_ReceivedPacket; MP1.W2 := 0;
|
||
MP2.W1 := PktNbr; MP2.W2 := rSeq;
|
||
WinPostMsg (ChildFrameWindow, WM_PAD, MP1, MP2);
|
||
rSeq := (rSeq + 1) MOD 64;
|
||
INC (PktNbr);
|
||
END;
|
||
|
||
sP[1] := Char (3);
|
||
sP[2] := Char (Seq);
|
||
sP[3] := 'Y'; (* acknowledgement *)
|
||
sP[4] := 0C;
|
||
SendPacket (sP);
|
||
END SendAck;
|
||
|
||
|
||
PROCEDURE Receive;
|
||
(* Receives a file (or files) *)
|
||
|
||
VAR
|
||
ch, Type : CHAR;
|
||
Seq : INTEGER;
|
||
i : INTEGER;
|
||
EOF, EOT, QBIN : BOOLEAN;
|
||
trys : INTEGER;
|
||
|
||
BEGIN
|
||
Aborted := FALSE;
|
||
|
||
MP1.W1 := PAD_Msg; MP1.W2 := 0;
|
||
MP2.L := LONGINT (ADR ("Ready to receive file(s)..."));
|
||
WinPostMsg (ChildFrameWindow, WM_PAD, MP1, MP2);
|
||
MP1.W1 := PAD_Msg; MP1.W2 := 0;
|
||
MP2.L := LONGINT (ADR ("(<ESC> to abort file transfer.)"));
|
||
WinPostMsg (ChildFrameWindow, WM_PAD, MP1, MP2);
|
||
|
||
FlushUART;
|
||
rSeq := 0; PktNbr := 0;
|
||
IF NOT ReceiveInit() THEN (* your configuration information *)
|
||
MP1.W1 := PAD_ExcessiveErrors; MP1.W2 := 0;
|
||
MP2.L := 0;
|
||
WinPostMsg (ChildFrameWindow, WM_PAD, MP1, MP2);
|
||
ErrorQuit;
|
||
END;
|
||
SendInitAck; (* send my configuration information *)
|
||
EOT := FALSE;
|
||
WHILE NOT EOT DO
|
||
CASE ReceiveHeader() OF
|
||
eot : EOT := TRUE; EOF := TRUE;
|
||
| name : IF Create (rF, rFname) # Done THEN
|
||
MP1.W1 := PAD_UnableToOpen; MP1.W2 := 0;
|
||
MP2.L := LONGINT (ADR (rFname));
|
||
WinPostMsg (ChildFrameWindow, WM_PAD, MP1, MP2);
|
||
ErrorQuit;
|
||
ELSE
|
||
PktNbr := 1;
|
||
EOF := FALSE;
|
||
END;
|
||
| fail : MP1.W1 := PAD_ExcessiveErrors; MP1.W2 := 0;
|
||
MP2.L := 0;
|
||
WinPostMsg (ChildFrameWindow, WM_PAD, MP1, MP2);
|
||
ErrorQuit;
|
||
END;
|
||
SendAck (rSeq); (* acknowledge for name or eot *)
|
||
trys := 1; (* initialize *)
|
||
WHILE NOT EOF DO
|
||
IF Aborted THEN
|
||
TellError (rSeq);
|
||
ErrorQuit;
|
||
END;
|
||
IF ReceivePacket (rP) THEN
|
||
Seq := UnChar (rP[2]);
|
||
Type := rP[3];
|
||
IF Type = 'Z' THEN
|
||
EOF := TRUE;
|
||
IF CloseFile (rF, Output) = Done THEN
|
||
(* normal file termination *)
|
||
ELSE
|
||
MP1.W1 := PAD_ProbClDestFile; MP1.W2 := 0;
|
||
MP2.L := LONGINT (ADR (rFname));
|
||
WinPostMsg (ChildFrameWindow, WM_PAD, MP1, MP2);
|
||
ErrorQuit;
|
||
END;
|
||
trys := 1; (* good packet -- reset *)
|
||
SendAck (rSeq);
|
||
ELSIF Type = 'E' THEN
|
||
ShowError (rP);
|
||
ErrorQuit;
|
||
ELSIF (Type = 'D') AND ((Seq + 1) MOD 64 = rSeq) THEN
|
||
(* discard duplicate packet, and Ack anyway *)
|
||
trys := 1;
|
||
SendAck (Seq);
|
||
ELSIF (Type = 'D') AND (Seq = rSeq) THEN
|
||
(* put packet into file buffer *)
|
||
i := 4; (* first data in packet *)
|
||
WHILE rP[i] # 0C DO
|
||
ch := rP[i]; INC (i);
|
||
IF ch = yourQBIN THEN
|
||
ch := rP[i]; INC (i);
|
||
QBIN := TRUE;
|
||
ELSE
|
||
QBIN := FALSE;
|
||
END;
|
||
IF ch = yourQCTL THEN
|
||
ch := rP[i]; INC (i);
|
||
IF (ch # yourQCTL) AND (ch # yourQBIN) THEN
|
||
ch := CHAR (ByteXor (ch, 100C));
|
||
END;
|
||
END;
|
||
IF QBIN THEN
|
||
ch := CHAR (ByteXor (ch, 200C));
|
||
END;
|
||
Put (ch);
|
||
END;
|
||
|
||
(* write file buffer to disk *)
|
||
IF DoWrite (rF) # Done THEN
|
||
MP1.W1 := PAD_ErrWrtFile; MP1.W2 := 0;
|
||
MP2.L := LONGINT (ADR (rFname));
|
||
WinPostMsg (ChildFrameWindow, WM_PAD, MP1, MP2);
|
||
ErrorQuit;
|
||
END;
|
||
trys := 1;
|
||
SendAck (rSeq);
|
||
ELSE
|
||
INC (trys);
|
||
IF trys = MAXtrys THEN
|
||
MP1.W1 := PAD_ExcessiveErrors; MP1.W2 := 0;
|
||
MP2.L := 0;
|
||
WinPostMsg (ChildFrameWindow, WM_PAD, MP1, MP2);
|
||
ErrorQuit;
|
||
ELSE
|
||
SendNak;
|
||
END;
|
||
END;
|
||
ELSE
|
||
INC (trys);
|
||
IF trys = MAXtrys THEN
|
||
MP1.W1 := PAD_ExcessiveErrors; MP1.W2 := 0;
|
||
MP2.L := 0;
|
||
WinPostMsg (ChildFrameWindow, WM_PAD, MP1, MP2);
|
||
ErrorQuit;
|
||
ELSE
|
||
SendNak;
|
||
END;
|
||
END;
|
||
END;
|
||
END;
|
||
NormalQuit;
|
||
END Receive;
|
||
|
||
|
||
BEGIN (* module initialization *)
|
||
yourEOL := ASCII.cr;
|
||
yourNPAD := 0;
|
||
yourPADC := 0C;
|
||
END PAD.
|
||
|