home *** CD-ROM | disk | FTP | other *** search
-
- PROGRAM modem;
- {Written by Jack M. Wierda Chicago Illinois
- This program is in the public domain.
-
- LANGUAGE: UCSD Pascal
- FILES: MODEM3.PAS -- main program
- MDM3-Z80IO.Z80 -- serial line interface for Z80
- MDM3-8080IO.Z80 -- serial line interface for Intel 8080
-
- This program is basically a re-write in PASCAL of Ward Christensen's
- Modem Program which was distributed in CP/M User's Group Volume 25. Identical
- and compatible options are provided to allow this program to work directly
- with Ward's program running under CP/M. One difference is that when sending
- files the PASCAL or CP/M transfer mode must be selected. The PASCAL mode
- transfers files between two systems running PASCAL, while the CP/M mode is
- used when the receiving system is running CP/M. Basically the CP/M mode
- provides the linefeeds required to make a PASCAL file compatible with CP/M.
- When CP/M files are received they contain linefeeds, these can be deleted
- using the editor to make the file compatible with PASCAL. CP/M files may also
- contain tabs which the PASCAL editor does not expand.
- External assembly language routines are used to read the status, and read
- or write the keyboard and modem ports. These routines are available as
- separate files for the 8080 and Z80 processors. The port and flag definitions,
- and the timing constant for the one second delay should be changed as required
- for your particular hardware.
- The program has been tested with text files only, and may not work
- correctly for code or other types of files.
- The PDP-10 mode transfers PASCAL files to a DEC SYSTEM-10 computer.}
-
- CONST
- nul = 0;
- soh = 1;
- ctrlc = 3;
- eot = 4;
- errormax = 5;
- retrymax = 5;
- ctrle = 5;
- ack = 6;
- tab = 9;
- lf = 10;
- cr = 13;
- ctrlq = 17;
- ctrls = 19;
- nak = 21;
- ctrlz = 26;
- space = 32;
- delete = 127;
- lastbyte = 127;
- timeout = 256;
- loopspersec = 1800 {1800 LOOPS PER SECOND AT 4MHZ};
- kbsp = 0 {KEYBOARD STATUS PORT};
- kbdrf = 128 {KEYBOARD DATA READY FLAG};
- kbdp = 1 {KEYBOARD DATA PORT};
- kbmask = 127 {KEYBOARD DATA MASK};
- dchdp = 128 {D. C. HAYES DATA PORT};
- dchmask = 255 {D. C. HAYES DATA MASK};
- dchsp = 129 {D. C. HAYES STATUS PORT};
- {STATUS PORT BIT ASSIGNMENTS}
- rrf = 1 {RECEIVE REGISTER FULL};
- tre = 2 {TRANSMIT REGISTER EMPTY};
- perr = 4 {PARITY ERROR};
- ferr = 8 {FRAMING ERROR};
- oerr = 16 {OVERFLOW ERROR};
- cd = 64 {CARRIER DETECT};
- nri = 128 {NO RINGING INDICATOR};
- dchcp1 = 129 {D. C. HAYES CONTROL PORT 1};
- {CONTROL PORT 1 BIT ASSIGNMENTS}
- epe = 1 {EVEN PARITY ENABLE};
- ls1 = 2 {LENGTH SELECT 1};
- ls2 = 4 {LENGTH SELECT 2};
- sbs = 8 {STOP BIT SELECT};
- pi = 16 {PARITY INHIBIT};
- dchcp2 = 130 {D. C. HAYES CONTROL PORT 2};
- {CONTROL PORT 2 BIT ASSIGNMENTS}
- brs = 1 {BIT RATE SELECT};
- txe = 2 {TRANSMIT ENABLE};
- ms = 4 {MODE SELECT};
- es = 8 {ECHO SUPPRESS};
- st = 16 {SELF TEST};
- rid = 32 {RING INDICATOR DISABLE};
- oh = 128 {OFF HOOK};
-
- VAR file1 : text;
- option, hangup, return, mode, baudrate, display, filemode : char;
- sector : ARRAY[0..lastbyte] OF integer;
- dchcw2 : integer;
- ovrn1, ovrn2, showrecv, showtrans : boolean;
-
- FUNCTION stat(port,exr,mask:integer): boolean;
- external;
-
- FUNCTION input(port,mask:integer): integer;
- external;
-
- PROCEDURE output(port,data:integer);
- external;
-
- PROCEDURE sendline(sldata:integer);
- BEGIN
- REPEAT
- UNTIL stat(dchsp,tre,tre);
- output(dchdp,sldata);
- IF showtrans
- THEN
- IF (sldata = cr) OR ((sldata >= space) AND (sldata <= delete))
- THEN
- write(chr(sldata))
- END;
-
- FUNCTION readline(seconds:integer): integer;
-
- VAR j : integer;
- BEGIN
- j := loopspersec * seconds;
- REPEAT
- j := j-1
- UNTIL (stat(dchsp,rrf,rrf)) OR (j = 0);
- IF j = 0
- THEN
- readline := timeout
- ELSE
- BEGIN
- j := input(dchdp,dchmask);
- IF showrecv
- THEN
- IF (j = cr) OR ((j >= space) AND (j <= delete))
- THEN
- write(chr(j));
- readline := j
- END
- END;
-
- PROCEDURE sendstr(str:string);
-
- VAR j: integer;
- BEGIN
- FOR j := 1 TO length(str) DO
- sendline(ord(str[j]))
- END;
-
- FUNCTION uppercase(ch : char) : char;
- BEGIN
- IF ch IN ['a'..'z']
- THEN
- uppercase := chr(ord(ch)-space)
- ELSE
- uppercase := ch
- END;
-
- PROCEDURE purgeline;
-
- VAR j : integer;
- BEGIN
- REPEAT
- j := input(dchdp,dchmask) {PURGE THE RECEIVE REGISTER};
- UNTIL NOT stat(dchsp,rrf,rrf)
- END;
-
- PROCEDURE dchinitialize;
- BEGIN
- writeln('Waiting for carrier');
- REPEAT
- BEGIN
- IF option IN ['R','S']
- THEN
- BEGIN
- output(dchcp1,pi+ls2+ls1);
- output(dchcp2,oh+rid+txe+dchcw2)
- END;
- IF option IN ['C','P','T']
- THEN
- BEGIN
- output(dchcp1,ls2+epe);
- output(dchcp2,oh+rid+txe+dchcw2)
- END
- END
- UNTIL (stat(dchsp,cd,cd)) OR (input(kbdp,kbmask) = ctrle);
- purgeline;
- writeln('Carrier detected')
- END;
-
- PROCEDURE makesector;
-
- VAR j : integer;
- ch : char;
- BEGIN
- j := 0;
- IF ovrn1
- THEN
- BEGIN
- sector[j] := cr;
- j := j+1
- END;
- IF ovrn2
- THEN
- BEGIN
- sector[j] := lf;
- j := j+1
- END;
- ovrn1 := false;
- ovrn2 := false;
- WHILE (NOT eof(file1)) AND (j <= lastbyte) DO
- BEGIN
- WHILE (NOT eoln(file1)) AND (j <= lastbyte) DO
- BEGIN
- read(file1,ch);
- IF ord(ch) <> lf
- THEN
- BEGIN
- sector[j] := ord(ch);
- j := j+1
- END
- END;
- IF eoln(file1)
- THEN
- BEGIN
- readln(file1);
- IF filemode IN ['P']
- THEN
- IF j <= lastbyte
- THEN
- BEGIN
- sector[j] := cr;
- j := j+1
- END
- ELSE
- ovrn1 := true
- ELSE
- BEGIN
- IF j <= (lastbyte-1)
- THEN
- BEGIN
- sector[j] := cr;
- sector[j+1] := lf;
- j := j+2
- END
- ELSE
- IF j = lastbyte
- THEN
- BEGIN
- sector[j] := cr;
- j := j+1;
- ovrn1 := true
- END
- ELSE
- IF j > lastbyte
- THEN
- BEGIN
- ovrn1 := true;
- ovrn2 := true
- END
- END
- END
- END;
- CASE filemode OF
- 'P' : IF j <= lastbyte
- THEN
- FOR j := j TO lastbyte DO
- sector[j] := space;
- 'C' : IF j <= lastbyte
- THEN
- FOR j := j TO lastbyte DO
- sector[j] := ctrlz
- END
- END;
-
- PROCEDURE termcomp;
-
- VAR kbdata, dchdata : integer;
- crflag : boolean;
- BEGIN
- crflag := false;
- dchinitialize;
- WHILE stat(dchsp,cd,cd) AND (kbdata <> ctrle) DO
- BEGIN
- IF stat(kbsp,kbdrf,kbdrf)
- THEN
- BEGIN
- kbdata := input(kbdp,kbmask);
- IF option IN ['C']
- THEN
- write(chr(kbdata));
- output(dchdp,kbdata)
- END;
- IF stat(dchsp,rrf,rrf)
- THEN
- BEGIN
- dchdata := input(dchdp,dchmask);
- IF option IN ['C']
- THEN
- output(dchdp,dchdata);
- IF dchdata = cr
- THEN
- crflag := true;
- IF (dchdata = lf) AND crflag
- THEN
- crflag := false
- ELSE
- write(chr(dchdata))
- END
- END
- END;
-
- PROCEDURE pdp10;
-
- VAR wait10 : boolean;
- dchdata : integer;
- ch : char;
- filename, pdp10file : string;
- BEGIN
- showrecv := false;
- showtrans := true;
- wait10 := false;
- write('Filename.Ext ? ');
- readln(filename);
- reset(file1,filename);
- IF option IN ['P']
- THEN
- BEGIN
- write('PDP-10 Filename.Ext ? ');
- readln(pdp10file);
- dchinitialize;
- sendline(cr);
- sendstr('R PIP');
- sendline(cr);
- REPEAT
- UNTIL readline(5) IN [ord('*'),timeout];
- sendstr(pdp10file);
- sendstr('=TTY:');
- sendline(cr)
- END
- ELSE
- BEGIN
- write('UNIX Filename.Ext ? ');
- readln(pdp10file);
- dchinitialize;
- sendline(cr);
- sendstr('cat > ');
- sendstr(pdp10file);
- sendline(cr)
- END;
- WHILE (NOT eof(file1)) AND (stat(dchsp,cd,cd)) DO
- BEGIN
- WHILE NOT eoln(file1) DO
- BEGIN
- IF NOT wait10
- THEN
- BEGIN
- read(file1,ch);
- sendline(ord(ch))
- END;
- IF stat(dchsp,rrf,rrf)
- THEN
- BEGIN
- dchdata := input(dchdp,dchmask);
- IF dchdata = ctrls
- THEN
- wait10 := true;
- IF dchdata = ctrlq
- THEN
- wait10 := false
- END
- END;
- readln(file1);
- sendline(cr)
- END;
- close(file1);
- REPEAT
- UNTIL readline(1)=timeout;
- IF option IN ['P']
- THEN
- BEGIN
- sendline(ctrlz);
- sendline(ctrlc);
- END
- ELSE
- BEGIN
- sendline(eot)
- END;
- termcomp
- END;
-
- PROCEDURE sendfile;
-
- VAR j, k, sectornum, counter, checksum : integer;
- filename : string;
- BEGIN
- write('Filename.Ext ? ');
- readln(filename);
- reset(file1,filename);
- sectornum := 1;
- dchinitialize;
- ovrn1 := false;
- ovrn2 := false;
- REPEAT
- counter := 0;
- makesector;
- REPEAT
- writeln;
- writeln('Sending sector ', sectornum);
- sendline(soh);
- sendline(sectornum);
- sendline(-sectornum-1);
- checksum := 0;
- FOR j := 0 TO lastbyte DO
- BEGIN
- sendline(sector[j]);
- checksum := (checksum + sector[j]) MOD 256
- END;
- sendline(checksum);
- purgeline;
- counter := counter + 1;
- UNTIL (readline(10) = ack) OR (counter = retrymax);
- sectornum := sectornum + 1
- UNTIL (eof(file1)) OR (counter = retrymax);
- IF counter = retrymax
- THEN
- BEGIN
- writeln;
- writeln('No ACK on sector')
- END
- ELSE
- BEGIN
- counter := 0;
- REPEAT
- sendline(eot);
- counter := counter + 1
- UNTIL (readline(10) = ack) OR (counter = retrymax);
- IF counter = retrymax
- THEN
- BEGIN
- writeln;
- writeln('No ACK on EOT')
- END
- ELSE
- BEGIN
- writeln;
- writeln('Transfer complete')
- END
- END;
- close(file1)
- END;
-
- PROCEDURE readfile;
-
- VAR j, firstchar, sectornum,sectorcurrent, sectorcomp, errors,
- checksum : integer;
- errorflag : boolean;
- filename : string;
- BEGIN
- write('Filename.Ext ? ');
- readln(filename);
- rewrite(file1,filename);
- sectornum := 0;
- errors := 0;
- dchinitialize;
- sendline(nak);
- sendline(nak);
- REPEAT
- errorflag := false;
- REPEAT
- firstchar := readline(20)
- UNTIL firstchar IN [soh,eot,timeout];
- IF firstchar = timeout
- THEN
- BEGIN
- writeln;
- writeln('SOH error');
- END;
- IF firstchar = soh
- THEN
- BEGIN
- sectorcurrent := readline(1);
- sectorcomp := readline(1);
- IF (sectorcurrent+sectorcomp)=255
- THEN
- BEGIN
- IF (sectorcurrent=sectornum+1)
- THEN
- BEGIN
- checksum := 0;
- FOR j := 0 TO lastbyte DO
- BEGIN
- sector[j] := readline(1);
- checksum := (checksum+sector[j]) MOD 256
- END;
- IF checksum=readline(1)
- THEN
- BEGIN
- FOR j := 0 TO lastbyte DO
- write(file1,chr(sector[j]));
- errors := 0;
- sectornum := sectorcurrent;
- IF display <> 'R'
- THEN
- BEGIN
- writeln;
- writeln('Received sector ',sectorcurrent)
- END;
- sendline(ack)
- END
- ELSE
- BEGIN
- writeln;
- writeln('Checksum error');
- errorflag := true
- END
- END
- ELSE
- IF (sectorcurrent=sectornum)
- THEN
- BEGIN
- REPEAT
- UNTIL readline(1)=timeout;
- writeln;
- writeln('Received duplicate sector ', sectorcurrent);
- sendline(ack)
- END
- ELSE
- BEGIN
- writeln;
- writeln('Synchronization error');
- errorflag := true
- END
- END
- ELSE
- BEGIN
- writeln;
- writeln('Sector number error');
- errorflag := true
- END
- END;
- IF (errorflag=true)
- THEN
- BEGIN
- errors := errors+1;
- REPEAT
- UNTIL readline(1)=timeout;
- sendline(nak)
- END;
- UNTIL (firstchar IN [eot,timeout]) OR (errors = errormax);
- IF (firstchar = eot) AND (errors < errormax)
- THEN
- BEGIN
- sendline(ack);
- close(file1,lock);
- writeln;
- writeln('Transfer complete')
- END
- ELSE
- BEGIN
- close(file1);
- writeln;
- writeln('Aborting')
- END
- END;
- BEGIN
- writeln('Modem, 7-July-79');
- REPEAT
- REPEAT
- write('Option : C(omputer), P(DP-10), R(eceive), S(end), T(erminal)');
- write(', U(nix) ? ');
- read(option);
- option := uppercase(option);
- writeln
- UNTIL option IN ['C','P','R','S','T','U'];
- REPEAT
- write('Mode : A(nswer), O(riginate) ? ');
- read(mode);
- mode := uppercase(mode);
- writeln
- UNTIL mode IN ['A','O'];
- IF mode IN ['O']
- THEN
- dchcw2 := ms
- ELSE
- dchcw2 := 0;
- REPEAT
- write('Baud rate : 1(00), 3(00) ? ');
- read(baudrate);
- writeln
- UNTIL baudrate IN ['1','3'];
- IF baudrate='3'
- THEN
- dchcw2 := dchcw2+brs;
- IF option IN ['R','S']
- THEN
- BEGIN
- REPEAT
- write('Display : N(o), R(eceived), T(ransmitted) data ? ');
- read(display);
- display := uppercase(display);
- writeln
- UNTIL display IN ['N','R','T'];
- IF option = 'S'
- THEN
- BEGIN
- REPEAT
- write('File mode : C(pm), P(ascal) ? ');
- read(filemode);
- filemode := uppercase(filemode);
- writeln
- UNTIL filemode IN ['C','P']
- END;
- CASE display OF
- 'N': BEGIN
- showrecv := false;
- showtrans := false
- END;
- 'R': BEGIN
- showrecv := true;
- showtrans := false
- END;
- 'T': BEGIN
- showrecv := false;
- showtrans := true
- END
- END
- END;
- CASE option OF
- 'C': termcomp;
- 'P': pdp10;
- 'R': readfile;
- 'S': sendfile;
- 'T': termcomp;
- 'U': pdp10
- END;
- REPEAT
- writeln;
- write('Hangup : Y(es), N(o) ? ');
- read(hangup);
- hangup := uppercase(hangup);
- writeln
- UNTIL hangup IN ['Y','N'];
- IF hangup IN ['Y']
- THEN
- output(dchcp2,0);
- REPEAT
- writeln;
- write('Return to system : Y(es), N(o) ? ');
- read(return);
- return := uppercase(return);
- writeln
- UNTIL return IN ['Y','N'];
- UNTIL return IN ['Y']
- END
- .