B6800 KERMIT DOCUMENTATION ----- ------ ------------- 12/12/84 Randy McLaughlin Metro-II 360 Colborne St Paul, MN 55102 (612)227-9261 Accompanying this document are several files which may be of assistance to anyone attempting to implement Kermit on Burroughs Large System com- puters. We implemented Kermit on a B6800 for communications with Kermit on an Altos 586 running under Xenix. Because this implementation depends upon NDL support, users of Bx900 and A-series machines will not be able to implement Kermit without writing similar NDLII code. Users of smaller Burroughs machines will also find that the NDL and the main program, which is written in ALGOL are also not applicable to their environment. In any case, I hope that the enclosed files are at least helpful as a model for other implementations. The following files are included: B68KERMIT.ALG This is the source of the B6800 ALGOL program. B68KERMIT.NDL NDL request sets to replace READTELETYPE and WRITETELETYPE and associated DEFINE's. B68KERMIT.DOC This file--documentation of the B6800 Kermit. Appendixes to this document provide the source for the following programs which we use on the Altos to simplify communication with B6800 Kermit. kersh XENIX shell for specifying files to be trans- ferred and for initiating Kermit on the B6800 for each transfer. crend.c A program used by KERSH to send a message to the B6800 terminated by a CR rather that a NEWLINE. waitkerm A program used by KERSH. Once Kermit has been RUN on the B6800, WAITKERM waits for the B6800 Kermit to signal that it is running. SOME HISTORY ---- ------- My original approach to implementing Kermit was to write a single ALGOL program which provided the entire Kermit service, from packetizing and depacketizing messages to specification of files to transfer. This program, once run, would stay in the mix until specifically told to terminate. It would then process any number of file transfers requested from the remote end. One big problem with the above aproach was that Kermit was too sluggish. A file transfer would frequently fail because of the delay imposed transferring the data from the DCP to the main system, waking the DCC, and then waking the Kermit application. Especially in a full mix, Kermit would simply take too long to acknowledge a packet. I thus resorted to moving the depacketing and acknowledgement functions to NDL. The path towards this solution was guided by earlier work I had done implementing a different, but somewhat similar protocol for file transfers to and from Apples. As Kermit, and the earlier Apple program we not MCS's, but were instead run under CANDE, and because the same line had to accomodate both the file transfer protocol and the generic TTY interface, I had to resort to some tricks to get the NDL to switch protocols. I also encountered problems which again were familiar from work on the Apple interface. One is that the file naming conventions on the B6800 do not correspond to either those on an Apple or a UNIX machine. Both Kermit and the Apple program assume that one intends to use the same name for the file on both ends of the transfer. I therefore wanted to provide facilities for specifying the file name for both ends of the link. Another more substantial problem is that the B6800 likes to work with fixed record length, whereas the other machines use a vari- able length format. When transfering from the B6800 to another computer simply stripping off trailing blanks and separating records with a CR and a LF. Coming the other way though, either a facility had to be provided to allow specification of record and block sizes, or some kind of assumption had to be made. Although additional code could have been added to allow specification of these parameters inside of a large continuous B6800 Kermit, human interaction with a program on the other machine would be cleaner and easier, and these attributes can be spec- ified at run time under CANDE without any additional code. Thus the decision was made to change the B6800 Kermit to exist only for the duration of a single file transfer, returning to CANDE between transfers. This also allowed any additional file manipulation to be done under CANDE without subjecting the user to manually terminating and reinitiating the transfer. This was also natural considering the frequency that only a single file needs to be transferred. The name of the file, its record and block size, and any other attributes are thus specified through the mechanism of file equation. Indeed, the direction of transfer is specified through use of the MYUSE file attribute. A shell was then written on the Altos to ask for the per- tenent attributes, format them into a CANDE RUN statement and pass it on to the B6800. This was much easier to write and to use than the older approach. THE NDL TO PROGRAM INTERFACE --- --- -- ------- --------- Because any program except an MCS has very little control over NDL and because of the requirement that generic TTY traffic not be affected in any way by the imposition of the Kermit protocol on top of the TTY protocol, no obvious means existed for the Kermit program to tell the NDL that it should now expect and acknowledge Kermit packets. However a slighly tricky means did exist for communicating this state change. This trick relies on two unlikely elements in the format of data to be transmitted which when occuring together signify the special state change signal. One is the specific request that no carriage control be done (ALGOL WRITE( [STOP], ...) ). In our shop, this is used only infrequently. The other key to a protocol signal is that the first character of the message begins with an EBCDIC character in the range 4"B0" to 4"BF". Since these do not translate to any ASCII char- acter, they resemble an invalid punch on a WFL deck--something you should never find in the first (or any other position) of a record. Most of the characters were already defined for Apple protocol state changes, but 4"BF" was not, and was chosen to represent a Kermit protocol selection. At this point the only Kermit protocol service available in NDL is to automatically receive and acknowledge data ("D") packets. To initiate Kermit auto receive in the NDL then, the Kermit program writes (with STOP) a message consisting of the 4"BF" character, the Pad Count (as found in an "S" packet), the Pad Character, the maximum packet length, the sequence number of the packet last recieved (which will be acked), and the type of packet involved. At this point only the sequence number (in the range 4"20" to 4"5F") is significant, the other values are ignored. The message must consist of exactly this number of characters to be seen as a request to initiate Kermit auto receive. The NDL will then verify proper formation of packets, sequence numbers, and checksums. If the packet is a "D" (data) packet, it is then either ACKed or NAKed depending on the results of the tests. If a packet other than a "D" packet is received, it is passed through the DCP to the program and NDL auto receive is terminated, returning the NDL to normal TTY handling. In order to distinguish data from packets received in auto receive mode from packets which are passed through unchecked and unprocessed, data from auto receive packets is marked by a leading 4"BF" character. Any messages read by the Kermit application which are not preceded by the 4"BF" mark must be verified programmatically for form and content and programmatically acknowledged. There are sit- uations where only the single 4"BF" character is returned to the appli- cation. In this case auto receive is still in force, no data is present and the message can be ignored. A break indication (bit 13 in the IO result word) indicates a timeout has occured, probably because Kermit at the other end has terminated without warning. Note that when NDL auto receive is initiated, it will issue an ACK for a packet of the sequence number specified in the characters following 4"BF". The sequence number is then incremented, and auto receive ini- tiated. Messages then read by the application which start with the 4"BF" auto receive mark need no acknowledgement from the application. Once a message is read which is not marked with 4"BF", it and subsequent messages must be acknowledged in the appropriate manner from the appli- cation unless auto receive is reinitiated. Auto receive can be re- initiated, if needed, the same way it is originally initiated. Remember that the first action of such an initiation is to send an ACK packet. THE NDL REQUEST SETS --- --- ------- ---- Included with this tape are replacement READTELETYPE and WRITETELETYPE NDL request sets. These work with unmodified SPEEDSENSE and CONTENTION controls. These request sets make heavy use of the DEFINE facility and a number of defines are also included at the beginning of the file. Those DEFINEs which precede the READTELETYPE request are common to both requests and should be placed in your NDL before the first declaration of a control or request. Because of the close relationship between the Kermit protocol and our local Apple file xfer protocol, I have not attempted to untangle them and have included all of these two request sets as currently implemented. This should probably have no effect on your operation, as the Apple code will only be entered if specifically requested by use of the WRITE([STOP]) construct and a leading 4"B0" to 4"BE" code, something not likely to accidently occur. If you desire cleaner code, or if you have local patches to incorporate, I leave the task of modifying (and more painfully, testing) the request sets to you. I have selected sequence ranges such that the supplied code can be dropped right in in some empty ranges in the 34PR1 SYMBOL/SOURCENDL. Be sure to patch out the original READTELETYPE and WRITETELETYPE requests. One other important patch which must be made is to change the declaration of all terminals using the new request sets to specify CODE = ASCII(BINARY). As this will vary depending upon the structure of your NDL, I have not attempted to include any lines of this patch in the provided file. THE KERMIT ALGOL PROGRAM --- ------ ----- ------- As described above, the B6800 Kermit application is written in ALGOL, handles one file transfer (in either direction) and relies upon file attribute equation for specification of what to transfer and the format of the file. The file to be transfered from or to has an internal name of FYLE and defaults to KIND=DISK and FRAMESIZE=8. If MYUSE is INPUT then FYLE will be the source of a file transfer from the B6800 to your other computer. If MYUSE is OUTPUT the file transfer will be from your other computer into FYLE. TITLE will have to be set to actual name of the B6800 file involved in the transfer. You may also want to set NEWFILE to an appropriate value. If MYUSE is INPUT, setting the DEPENDENTSPECS attribute is usually the only other attribute equation needed. It will then allow the system to set the record and block sizes as appropriate. Any other relevant attributes may also be equated as well. If MYUSE is OUTPUT, you will need to specify MAXRECSIZE and BLOCKSIZE. By default, these will be in character (byte) units, though the FRAMESIZE attribute may be used to override this default. You may let the system calculate a default AREASIZE or set this attribute specifically. Likewise with AREAS. Of course, you can set any other attributes as well. The Kermit protocol specifies that an "F" packet must sent from the sender to the receiver of a file before file transfer commences. This packet is conventionally used to provide the name of the file to trans- fer to at the receiving end. When the B6800 is the receiver, the content of this packet is ignored, relying instead upon file equation at run time. When the B6800 is the sender, though, the other computer will be expecting the "F" packet to contain a file name. Since the name used on the B6800 probably differs from the name to be used on the other computer, this name must also be specified at run time. The mechanism for specifying this is through a string parameter to the program. This parameter must also be provided when the B6800 serves as the receiver, but is ignored and may consist of an empty string. In addition, at the time the Kermit application is run, it may be placed into monitor mode by specifying a TASKVALUE of 1. This is done by the task equation VALUE=1 from CANDE. Since TASKVALUE defaults to zero, the TASKVALUE equation needs only to be made when monitor mode is to be requested. When in monitor mode, all traffic to the remote (datacom) file is sent in both character and hex representations to the printer. This can be quite useful in debugging situations and I would reccommend setting it the first few times you run Kermit, both to check what is going on and to provide a baseline example should you later encounter trouble or make modifications. To summarize the syntax for running the Kermit application from CANDE is as follows: To transfer a file to the B6800: --- RUN KERMIT(""); ------------------------> ! A --- VALUE=1; --! >---FILE FYLE(MYUSE=OUT,MAXRECSIZE=,BLOCKSIZE= --> >---TITLE=, ) ---! Where ::= size of a record in characters ::= size of a block in characters ::= a name for the file to be created ::= any other file attribute equations which should be used To transfer from the B6800: --- RUN KERMIT(");------------------> ! A --- VALUE=1;--! >----FILE FYLE(MYUSE=IN,DEPENDENTSPECS,TITLE= --> >---- --- ) -----! Where ::= the name of the file to trans- fer to ::= the name of the file on the B6800 from which to transfer data. ::= any other file attribute equations which apply For example: RUN KERMIT("");VALUE=1;FILE FYLE(MYUSE=OUT,MAXRECSIZE=90, BLOCKSIZE=1800,TITLE="A/NEW/FILE/IS/BORN") Will start Kermit receiving a file to be named A/NEW/FILE/IS/BORN under your usercode. Monitor mode is requested. RUN KERMIT("/usr/randy/junk.file");FILE FYLE(MYUSE=IN, DEPENDENTSPECS,TITLE="(BURRO)JUNK/FILE") Will start Kermit sending JUNK/FILE from the BURRO usercode to the other computer where it will create a file called /usr/randy/junk.file. Monitor mode is not requested. The Kermit application is designed for an environment where someone who wishes to initiate a file transfer to or from the B6800 is at a terminal connected to a micro or mini computer using the "connect" facility of Kermit, or some other terminal program to allow logging on to the B6800 and initiating Kermit on the B6800. Once initiated, Kermit will verify the file attributes specified and if no error is found, Kermit will open its remote file and send a DEL character to indicate that it is up and running. If an attribute error is found or if for some other reason Kermit finds that it cannot perform the requested transfer, Kermit will send a message describing the error followed by a NAK character. Using a terminal program (or Kermit "connect") the user would have to wait while the B6800 started its Kermit until seeing CANDE return the "?#" indication that it has opened a remote file, and then waiting briefly to see if any error messages are sent before terminating the terminal connection and initiating their local Kermit. I have included the source for a program which does that waiting. It sends the text of all messages received from the B6800 to default output (presumably the operator's terminal) until B6800 Kermit send either a DEL or a NAK, at which point the program terminates. The source for this program, waitkerm.c can be found in Appendix C. I have also included a XENIX shell which allows a user to initiate any number of Kermit transfers to/from the B6800. It forms the proper CANDE RUN statement, sends it to CANDE and then uses waitkerm to wait for B6800 Kermit to signal its presence. The shell will then fire off a local Kermit to communicate with B6800 Kermit. I would suggest that you use it, or a similar shell or program to similarly isolate the user from the complexities of the interface, or at least to reduce the volume of typing necessary to get things going. Because the B6800 expects lines entered from a terminal to terminate with a CR, rather than a newline, the ECHO command doesn't work. The source for a simple echo program which emits a CR rather than a NL is included in Appendix B. It produces a program called crend, which is used in many places in the inclulded shell. If B6800 Kermit encounters an error that it cannot resolve, it will send an "E" packet before terminating. The "E" packet will contain a description of the error encountered. Not all Kermits display the text contained in an "E" packet, but I would reccommend adding that capability so you can be aware of what happened if B6800 Kermit decides to abandon you. I have included only the source for the Kermit application. If you wish to use it as is, it requires only a simple ALGOL compile. No unusual task or file equations are needed at compile time. APPENDIX A. -------- - Kersh, a UNIX shell for initiating Kermit transfers to/from a B6800: tty=/dev/tty5 speed=1200 setmode $tty $speed & trap " " 2 trap " " 3 echo A program to dial the B6800 was initiated at this point echo Wait for the B6800 to respond, then log on, and then hit control-c kermit cle $tty 3 while test "$RESPONSE" != "q" do echo '(s)end, (r)eceive, (c)onnect or (q)uit?' read RESPONSE case $RESPONSE in Q) RESPONSE="q" ;; d|D) echo 'set debug on(+) or off(-)?' read DEBUG if test "$DEBUG" = on then DEBUG="+" fi ;; c|C) echo Connecting to remote system. echo Type control-c to return to local system. kermit cle $tty 3 ;; s|r|S|R) case $RESPONSE in s|S) echo Enter name of local file to send read LOCNAME echo Enter name of file to create remotely read RMTNAME echo What is the maximum record size? read MAXRSZ echo What is the block size to be? read BLKSZ echo Enter any other attributes for destination file read ATTB echo -n 'R KERMIT("");' >$tty if test "$DEBUG" = + then echo -n "VALUE=1;" > $tty fi echo -n 'FILE FYLE(MYUSE=OUT,MAXRECSIZE=' >$tty echo -n "$MAXRSZ, BLOCKSIZE= $BLKSZ" >$tty echo -n ',TITLE=' "$RMTNAME" > $tty if test "$ATTB" != "" then echo -n ", $ATTB" > $tty fi crend ')' > $tty ;; R|r) echo Enter name of remote file to copy read RMTNAME echo Enter name of file to create locally read LOCNAME echo Enter any other attributes for the remote file read ATTB echo -n "R KERMIT(\"$LOCNAME\");" > $tty if test "$DEBUG" = + then echo -n "VALUE=1;" > $tty fi echo -n 'FILE FYLE(MYUSE=IN,' > $tty echo -n 'DEPENDENTSPECS,TITLE=' > $tty echo -n "$RMTNAME" > $tty if test "$ATTB" != "" then echo -n ", $ATTB" > $tty fi crend ')' > $tty ;; *) ;; esac echo Waiting for kermit on the remote system. if waitkerm $tty then case $RESPONSE in r|R) kermit rldm $tty ;; s|S) kermit sld $tty $LOCNAME ;; esac crend > $tty crend ?END > $tty else echo fi ;; *) ;; esac done echo -n terminating crend > $tty echo -n '.' sleep 2 crend '?END' >$tty echo -n '.' sleep 2 crend SA REC >$tty echo -n '.' sleep 2 crend BYE >$tty echo -n '.' kill -9 `ps -a|grep tty5|grep setmode|awk '{print $1}'` stty 0 >$tty echo APPENDIX B. -------- -- crend-- an echo program which terminates a line with a CR instead of a NL: main (argc,argv) int argc; char *argv[]; { while (--argc>0) printf("%s%c",*++argv,(argc>1)?' ':'\r'); } APPENDIX C. -------- - waitkerm-- a program which waits for B6800 Kermit to start functioning: /* This program waits for the B6800 Kermit program to come up and signal that it is ready. It will normally return zero but will return a non- zero value if B6800 Kermit did not properly begin. The name of the line to the B6800 is specified in the command line following waitkerm. For example, to wait for kermit to come up on a B6800 connected thru a modem which is connected to the TTY5 port: waitkerm /dev/tty5 */ #include #include #include struct sgttyb termio; main(argc,argv) int argc; char **argv; { int cflag, fd; char c, getone(); int failure(), success(); signal(SIGHUP, failure); signal(SIGINT, success); setbuf(stdin,(char *)0); setbuf(stdout,(char *)0); setbuf(stderr,(char *)0); if ((fd = open (*++argv,2)) < 0) { printf("Can't open %s\n",*argv); exit(1); } ioctl(fd,TIOCGETP,&termio); /* get the terminal io structure */ termio.sg_flags &= ~(ECHO | CRMOD); /* turn off echo and crmod modes */ termio.sg_flags |= CBREAK; /* return each character as soon as typed */ ioctl(fd,TIOCSETP,&termio); while (c != '\177') { read(fd,&c,1); if (c == '\025') failure(); putchar(c); } exit(0); } success() { exit(0); } failure() { exit(1); }