This is the file containing the INFO-ized version of PCNET;INTRO >. See REM, or say :INFO NET PCNET PRO LOW QUICK  File: INTRO, Node: Top, Up: (MC:PCNET;PROTO INFO)Proto <> Introduction to PCNet, now treeified starting 1983.Feb.23 by John Gilmore, 29 September 1981 File MC:PCNET;INTRO > before treeification * Menu: * Random warnings:: Added 1982.Sept to the original 1981 online document, includes list of files that ought to be included in the document but aren't yet. Some of these are elsewhere in the main PCNET INFO tree, while others aren't linked at all (some are offline due to TCP switchover at the present). * COPyright notice:: from original 1981 document * General introductory stuff:: from original 1981 document * COMmunication-protocol introduction:: Very toplevel layers of software... Overall topology and organization of network:: (not yet included...) Offline processing such as headers of electronic mail:: (not yet included) Layers of communication protocol while in packet mode, top to bottom... Application programs:: (not yet included in this document) * Node-control:: pseudo application program * PREAD&PWRITE:: Interface between service levels and application prog. Service levels... * Lower&middle:: assures error-free data on multiple logical streams * Hardware interface:: standard interface to UART&modem&telephone Also not yet included in this document: establishing and breaking connections (HELLO and BYE). * Examples:: (Completely obsolete, uses old pre-1981 protocol) * Old protocol:: Differences between old (pre-1981) and new protocol  File: INTRO, Node: Random warnings, Up:Top added 1982.Sept to the original 1981 online document [DRAFT VERSION -- Several parts not yet included here. See later for a list of these missing parts.] ** WARNING -- A new draft is now written, which includes many of the missing parts. It is not yet online here. It is better than this draft, so please don't make listings of this draft because it is already obsolete. -- There are still several changes/improvements we want to make in this document, thus the current draft probably won't be put online here at all, rather a later draft, one that we're satisfied with, will be put online here after it's ready. Meanwhile, please just be patient. If you want to volunteer to be a proofreader, contact REM@MIT-MC and also G.Harris@SU-SCORE, and we might send a draft for review. ** [DRAFT VERSION - The following parts haven't yet been included here: Mail/FTP protocol, both at the level of opcodes&messages between application programs, and the header that begins each message -- Fylstra.TSCA@SRU-UNIX is working on this. Meanwhile consult PCNET;SERPRO TTY for header format and see REM;APPPRG > for server-level protocol, both now in new draft. Change to method by which application programs are started up, by ASCII name instead of 6-bit number -- REM;APPPRG > inc'l in new draft. Latest change to format of validating block -- included in new draft. Examples of protocol updated to new protocol -- PCNET;EXAMPL WRU Rewording of part about application programs (called "server processes" in this current draft) -- REM looked at this and decided there was no easy way to reword it. See REM;APPPRG > for current terminology. Listing of test nodes is now in PCNET;TEST NODES. Listing of software available and how to get it -- PCNET;SOURCE INDEX]  File: INTRO, Node: Copyright notice, Up:Top Copyright (c) by John C. Gilmore. Permission granted to reproduce for the purpose of making PCNet freely available to the public. For other purposes, explicit written permission must be obtained first. This copyright notice must be included in all copies.  File: INTRO, Node: General Introductory stuff, Up:Top PCNet stands for Personal Computer Network. It is a way for two personal computers to communicate with each other. When hundreds or thousands of people are communicating with each other via their personal computers, a network is formed. The PCNet Project started in 1977 when (who?) saw that the technology to allow personal computers to talk existed but was not being used. The existing and planned projects at that time had all been designed for particular computers or particular operating systems. It was not possible for an Apple to talk to a Pet, or a TRS-80 to talk to a CP/M system. This is still largely true today. These people formed the PCNet Committee as a volunteer, non-profit organization. They wanted to define and implement a protocol (a well-defined method for communicating) that would work with almost any type of equipment, from the smallest to the largest. They didn't want the project to be sponsored or funded by a partisan organization, so that these goals would be preserved. And they wanted their products to be in the public domain, freely available to everyone, to encourage their use and permit even the smallest users to communicate with everyone else. This is still true now, although the informal "PCNet Committee" became a formal Project under the sponsorship of People's Computer Company, the non-profit publishers of Dr. Dobb's Journal. There are many problems inherent in building a network out of a large, unorganized set of small, personally-controlled computers connected to the normal telephone network. Part of the problems have to do with the reliability of the communications lines and of the computers and their storage media. Other problems arise from the lack of centralized control over the network. We have done our best to solve these problems using what we know now. In a few years, when use of networks like PCNet is widespread, we will know much more about the process of making a network where once there was Chaos. Note that the lack of centralized control is by no means totally a liability. It enables new users to join the network simply by calling other network users. It also creates a network that cannot "go down" due to central difficulties, cannot be damaged by any local action, cannot be traced, cannot be stopped -- without stopping, damaging, or tracing the entire world telephone network. This is important to many of us who believe that centralized government control is not always a good thing. (Note, however, that since large parts of the world phone network are now being traced by "intelligence" agency computers -- in particular, by the NSA -- this advantage has practically disappeared. Perhaps illicit packet radio can save us from Uncle Sam's snooping ears.) The PCNet protocol solves the reliability problems inherent in using the normal phone network by using an error-checking and retransmission scheme. The first versions of PCNet to be released will implement the basic protocol and two applications -- mail transfer and file transfer. An application is a program that accomplishes useful work, "applying" the power of the cr to satisfy some want or need. Applications are distinct from the PCNet protocol, which exists only to satisfy technical constraints and not to provide a service that people desire. Other applications can and will be written for use with the PCNet protocol -- for example, two-player game programs. These applications can be written by anyone; they call on the protocol as required, but do not themselves get involved in the messy details. Full source will be provided for all PCNet code; and after the first release, new updates can of course be distributed over the network. The mail transfer application will accomplish the moving of short messages (a few thousand characters, typically) thru the network. Messages can be typed in and edited on the sender's home computer, and delivered immediately by telephone to the receivers' home computers, or can be delivered late at night to take advantage of the 60% discount rate; or they can be delivered to other PCNet nodes (other peoples' computers that use PCNet protocols) and be forwarded to their true destinations. In large metropolitan areas, many such forwarding centers will probably exist to move mail for free despite "message unit" or "zoned" call billing. These forwarders can also provide long-distance forwarding service to subscribers -- for example, a New York computer club could call a San Francisco computer club each night with high-speed equipment, forwarding all messages from its members to destinations in the West. Anyone who found that their average long-distance mail-forwarding bill was more expensive than their share of the cost of such a shared system could join. Furthermore, as local and transcontinental packet radio links become operational, non-commercial PCNet mail can be forwarded thru them without cost. The file transfer application will move data files from one computer to another. The files can contain any data -- text, programs, machine code, graphics images -- anything that a computer can represent. This application does not support forwarding and only acts point-to-point -- you must call the node that contains the file you want. (You can send files as messages, too; but this is only practical for small files.) When a node's computer is not in use for anything else, PCNet can be running, waiting for the phone to ring. When it does, the appropriate application(s) will be run and mail or files can be received without a human having to be there. The messages will be stored on disk or other media and will await the owner next time she returns. In this way PCNet mail is like Post Office mail, but it also has the advantages of instant or overnight delivery, and the ability to send to multiple people with a single command.  File: INTRO, Node: Communication-protocol introduction, Up:Top PCNet Communication Protocols This section describes the protocols used to communicate between applications. An application can send a block of information to another application, or can receive such a block. Because more than one application might be running at once, and because a single application might want to send several different types of data (and have the recipient be able to distinguish them), PCNet provides multiple "streams" of data to and from an application. With each block of data the application sends, it also indicates which "stream" the data is to travel along. The receiving application is told which stream each block of data was received on. PCNet also provides the ability to transmit an "end" marker in a stream. This tells the receiver that whatever was being transmitted is complete. For example, this marker shows the end of a message in the mail application. Further data coming along that stream could be commands, or other messages. Having this "end" marker independent of the data being sent means that all possible bytes can be transmitted and received in messages, without reserving one for "end of message" or requiring more elaborate schemes.  File: INTRO, Node: Node-control, Up: Top Calls PWRITE&PREAD to send&receive data, just like application programs, except it uses stream 0 instead of nonzero stream numbers. * CONtrol messages:: Opens&closes applications, changes parameters  File: INTRO, Node: CONtrol messages, Up:Top Opens&closes applications, changes parameters Control Messages ---------------- PREAD and PWRITE are the only primitives needed to communicate with another application, but we still haven't mentioned how an application starts. One of the applications will be started by some means external to PCNet, such as a user running the mail application with a console command because s/he wants to send a message. PCNet provides facilities for that application to connect itself, over some communications link, to the second PCNet node, and to tell the second node which application(s) it should run. The details of how an application makes a physical (eg telephone or packet radio) connection to another computer are beyond the scope of this document. A PCALL procedure takes whatever arguments are required to specify hardware and addressing parameters (line speed, modem type, telephone number, logon sequence, radio frequency, compass direction of receiver, etc.) and returns an indication of whether the connection was successfully initiated. Once PCALL indicates that a connection has been made, it remains to select the application to run on the called computer. This is done with a control message. Control messages are just like normal directing blocks, except that they are sent on "stream 0" -- the control stream. Their End-of-Data bit is always set, because each control message is complete in itself. (At some future point, it might be possible to send "continued" control messages with the End-of-Data bit set only in the last one.) Each control message has a one-byte operation code followed by variable-length arguments. The operation codes come in four variations. Each code refers to some particular option or application or action, and the four variations are "Please do xxxxx", "Please don't xxxxx", "I will xxxxx", and "I won't xxxxx". For example, the operation code for "hang up" can be sent as "Please do hang up". If the other node has further applications that it wants to run, it will send "I won't hang up". If it has nothing better to do, it will send "I will hang up" -- and then hang up its phone. The variations (also called "flavors" a la Raskin-Flakkers) are encoded into the top 2 bits of the operation code. They go like this: 00-- ---- I won't 01-- ---- I will 10-- ---- Please don't 11-- ---- Please do This encoding has the advantage (which is actually the purpose of this whole Please-do, I-will scheme) that if a PCNet node receives a control message that it doesn't understand, it can just invert the top 2 bits and send the message back. This turns Please Do into I Won't, I Will into Please Don't, etc., which is usually the right thing to do. This means that a newer PCNet node can safely talk to an older node -- if the new one requests something that the old one was never designed to do, it will automatically reject the request. The variable-length arguments in each control message vary depending on the operation code. The codes, and their arguments, are: *** *** THIS TABLE IS COMPLETELY OBSOLETE, SINCE THE BEGINNING OF 1982 *** *** I WISH DAVID HARRIS WOULD UPLOAD THE NEW DRAFT OF THIS DOCUMENT!!! Code Won't Don't Will Do Meaning and arguments --00 0000 00 40 80 C0 Unassigned --00 0001 01 41 81 C1 Hang up. --00 0010 02 42 82 C2 Echo. --00 0011 03 43 83 C3 Accept mail --00 0100 04 44 84 C4 Return mail --00 0101 05 45 84 C5 Accept file --00 0110 06 46 86 C6 Return file --00 0111 07 47 87 C7 Node ID; argument is ID --00 1000 08 48 88 C8 Return DIALOG file (*) (*) Specific to the DIALOG/PET implementation of PCNet; do not use. *** END OF OBSOLETE PART *** NOW THOSE INDIVIDUAL CODES FOR SENDING AND RECEIVING MAIL ARE INSIDE THE MAIL1 APPLICATION PROGRAM. THE CONTROL MESSAGE MERELY ACTIVATES THE APPLICATION PROGRAM AND ASSIGNS (OPENS) LOGICAL STREAMS TO IT. *** Where arguments are not defined in the table, received arguments should be ignored.  File: INTRO, Node: PREAD&PWRITE, Up: Top [This text is from PCNET;INTRO > written by John Gilmore.] Interface between service levels and application program To send a block of data, an application calls on PCNET-WRITE, which from here on will be abbreviated to PWRITE. The actual details of how the call is made are totally dependent on the language and operating system involved; from a high-level language like C or Pascal, PWRITE would probably be a procedure call; from BASIC or assembler language, a lower-level interface would be used, like USR() or JSR. In some systems, PWRITE could be invoked by doing output to the usual output device, with PRINT statements. PWRITE takes three arguments and produces one result. The arguments are the data to be sent, the stream number on which to send it, and whether to send an "end" marker after the data. PWRITE calls on lower levels of the protocol to format and error-check the transmission, and returns to the application once the data has been transmitted and acknowledged (the other application has received it correctly and told us so). The result of PWRITE indicates what happened. If everything went smoothly, it reports whether the other application sent any data to us along with the acknowledgement. (If it did, we can read the data with PCNET-READ.) If there were problems with the phone line, but they were circumvented by retransmitting the data, the application never hears about it, but just gets the indication that the data was (eventually) properly received. If there was a permanent problem, however, the error is indicated in PWRITE's result. Such things as the remote end hanging up the phone are reported in this way. An application can receive data from the other application by calling PCNET-READ, hereafter abbreviated to PREAD. If data is already waiting from the last PWRITE transaction, it just returns that data. If not, it sends a short acknowledgement to the other application to see if it has anything to transmit. It then returns the new data, or reports that there is no data to be read. PREAD takes no arguments, and returns four results. The first result indicates what happened -- there is data, there is no data, or there is an error. The other results are the received data, its stream number, and whether an "end marker" was found after the data. When one application does a PREAD and then the other does a PWRITE, the effect of the PCNet protocol is to move the arguments of the PWRITE over as the results of the PREAD. If the second application does a PREAD instead of a PWRITE, the first PREAD will return an indication that no data was received. If both applications had done PWRITEs, the first PWRITE would return an indication that there is data waiting to be read. (Note that a PREAD or PWRITE doesn't usually return to the caller until it has transmitted and then received. This means that when one application is in control, the other one is inside a PREAD or PWRITE call awaiting a response from the first application. That's why in the above description, the first PREAD/PWRITE got the indications, instead of the second one -- the first one returned after the second one transmitted to it, but the second one is still waiting for a response before it can return. This doesn't have to be true when running with more complicated software or protocol variations, but for PCNet Simple protocol it's true.) One restriction in PREAD and PWRITE was made to make them easier and cheaper to write. If an application does a PWRITE and the result indicates that data was received along with the acknowledgement, it must PREAD that data before it can do another PWRITE. (The second PWRITE will return an error if this is violated.) This is because PWRITE only has one place to put data received with acknowledgements. If this area was full and PWRITE sent some data, and the other application sent us more data along with its acknowledgement of our data, either its old data or its new data would have to be thrown away. Rather than make that decision, PWRITE forces the application to read the data and either use it or throw it away -- but the application gets to choose.  File: INTRO, Node: Lower&middle, Up: Top * Menu: Middle layer of protocol * Directing:: (7) Multiplexes several logical streams Lower layer, divided into micro-layers, from nearest the middle layer... * 2I:val seq intro Intro to next two layers lumped together * Sequencing:: (6) * Validating:: (5) ... downward ... * 3I:tr fr hdx intro Intro to next three layers lumped together * Translating:: (3,4) * Packet-framing:: (2) * Half-duplex:: (1) ... to nearest the modem.  File: INTRO, Node: Directing, Up:Top [This text is from PCNET;INTRO > written by John Gilmore] The Directing Layer ------------------- The directing layer handles PREADs and PWRITEs from the applications. It takes the arguments of a PWRITE and packs them into a "directing block", which it then sends to the directing layer in the other PCNet node. Here's what a directing block looks like: |-1 byte-| +--------+ The flags look like this: | flags | X--- ---- End-of-Data flag from PWRITE call +--------+ -1-- ---- This bit is reserved and must be 1. | data | --XX XXXX Stream number from PWRITE call | from | | PWRITE | Data may be 0-128 bytes unless a larger size is +--------+ negotiated between the PCNet nodes. As you can see, except for one reserved bit, this is just the information that the application passed to PWRITE. For a PWRITE, the directing layer creates this block and passes it on to the validating layer, which takes care of transmitting it error-free to the other PCNet node. For a PREAD, the directing layer calls the validating layer, and if any data has been received, it decodes the End-Of-Data bit and the stream number, and returns the block to the application. In a system with multiple applications running at the same time, the directing layer would have to look at the stream number in each incoming block and give it to the proper application, so the two (or more) applications would not receive blocks meant for each other. In simple PCNet nodes, only one application can be running at once, so it just gets all the blocks that arrive.  File: INTRO, Node: val seq intro, Up: Validating&sequencing layers The Validating Layer [sic, really two different layers] -------------------- The purpose of the validating layer [sic] is to provide error-free transmission of data. It does this by breaking data into blocks; detecting errors in blocks; and retransmitting blocks that were not received error-free. [ERRATA - The data is already broken into blocks before these layers receive it, and no additional or different blocking is done by these layers.] The validating layer [sic] is called by the directing layer when PWRITE wants to send some data, or PREAD wants to receive some (and there's none in the buffer). It returns with an indication of whether new data has been received error-free, and whether a timeout or serious error (such as loss of carrier on the phone line) occured. In PCNet Simple, the validating layer is called when we are in control of the phone line (it has been "turned around" to us). It transmits, turns the line around to the other system, then receives and awaits turnaround to us. It does not return until the block we sent has been acknowledged and we once again have control of the line. (This prevents data from arriving as we are bashing the disk from inside an application, for example.) If our block was not acknowledged, we ignore any data received from the other node (because we have no place to keep it), retransmit our block, and go 'round once again. In FDX (full-duplex) or with an acknowledgement window greater than 1 (I'll explain this terminology later), the Validating Layer returns as soon as the Directing Layer's data has been queued for sending. This allows the Directing Layer (and thus, applications that call it) to give the Validating Layer several blocks of data to transmit while awaiting the acknowledgement of the first block. Since at the moment a maximum of four blocks can be outstanding (queued for transmission but not yet acknowledged) at once, if the Validating Layer already has four blocks queued, it waits until one has been acknowledged before returning to the Directing Layer, so that no additional outgoing data can possibly be queued until there is room for it in the queue. If any data is waiting in the receive queue, a PWRITE will get a data-available status passed up to it, while a PREAD will get the first such block. (Note that if the Directing Layer gives it an empty block to send, it is not even queued. The Validating Layer takes care of inserting empty blocks where required in FDX, even though the Directing Layer has an HDX mentality.) Data coming into the Validating Layer is already broken into blocks (in the current design), so it need not worry about achieving that goal. Errors are detected by appending a checksum to each transmitted block, and checking it upon reception. Retransmissions are explained below. [In the section on sequencing]  File: INTRO, Node: Sequencing, Up: Validating&sequencing layers Validating Layer Sequence Numbers --------------------------------- Sequence numbers in the validating blocks are used to ensure that all blocks have been received correctly. Their use corresponds roughly to the "acknowledgements" used in some other protocols. Two 3-bit fields in each block's header are used for this purpose. In Simple (HDX, 1 block transmitted per turnaround) mode, only one such field is really needed, but two are used to retain compatability with Extended Simple and Advanced nodes, which will appear rapidly after a few Simple nodes appear. The algorithm used by the Simple nodes is much easier to understand and implement than the one used by the more advanced nodes. The Advanced algorithm uses three variables to keep track of acknowledgements. WEGIVE contains the number of the next block to be transmitted. As blocks are passed from the directing layer to the validating layer, the current value of WEGIVE is placed in them, and then WEGIVE is incremented. When a block is received from the other node, WEGIVE is checked to see if our last transmission has been acknowledged. WEWANT contains the number of the next block that we want to receive. In Simple mode, this is always the number of the block after the last one we correctly received. When a block is received correctly, its number is compared to WEWANT to see if it was (1) the previous block, retransmitted; (2) the block that we want, or (3) some other block -- a violation of protocol. WEWANT is copied into all transmitted blocks, to let the other node know which block we are awaiting. SHEWANTS corresponds to WEWANT, but from the other node. It contains the number of the next block that the other node wants to receive from us, as best we know it. It is set from each correctly received block's Want field. It is compared to WEGIVE to see if she has correctly received the block we just sent to her -- i.e. if she has acknowledged the block. ----------------------------- The receive side of the validating layer is always looking for a particular block from the other side. Each block is identified by a sequence number, called "Give", which runs from 0 to 7 and back to 0. (It's Give because it's the number of a block given to the receiver.) The Give that the receive validating layer (RVL) wants to see is remembered in the variable WEWANT. Each block that the RVL sees, that has already passed the other tests (checksum, etc.) is tested to see if it is the block the RVL wants to see (its Give = WEWANT). If not, the RVL ignores the block. If it matches, tho, the RVL passes the block to the Directing Layer and remembers to look for the next block (next Give) next time. The Transmit side of the Validating Layer (TVL) puts the RVL's WEWANT value into each block it transmits. This tells the other node which block the RVL is waiting for. Corrspondingly, the RVL gets this field (called "Want") out of each block it receives, and leaves it around for the TVL in the variable SHEWANTS. ----------------------------- The TVL is always transmitting a particular block to the other side. It remembers the block's Give in a variable called WEGIVE. Every time the TVL gets a chance to transmit a block, it compares SHEWANTS with WEGIVE. If they're equal, she wants the block we're sending, so TVL sends it. If on the other hand, SHEWANTS = 1+WEGIVE, then she has already received this block from us, and we should send her a newer one. The TVL returns to the Directing Layer, passing it whatever data we might have received, and asking for some data to transmit. If on the third hand, SHEWANTS has some other value, there is an error in somebody's PCNet program, and the TVL throws up its hands and complains. Here's an example: . . . . . . Give 3, Want 3 ----> OK OK <---- Give 3, Want 4 Give 4, Want 4 ----> OK Checksum error <--garble-- Give 4, Want 5 (retran) Give 4, Want 4 ----> Give <> Wewant OK <---- Give 4, Want 5 (retran) Give 5, Want 5 --garble--> Invalid length Give <> Wewant <---- Give 4, Want 5 (retran) (retran) Give 5, Want 5 --garble--> Checksum error Give <> Wewant <---- Give 4, Want 5 (retran) (retran) Give 5, Want 5 ----> OK OK <---- Give 5, Want 6 . . . . . . Notice that anytime an error occurs in one direction, and no error occurs in the other direction, a "Give <> Wewant" error occurs, because the node that received the error retransmitted its previous block, because it never received the acknowledgement that the other side had seen it. Note also that one node's Give and Want are always the same, and the other's were always off by 1. This is always true in HDX 1-of-8 (half-duplex, when only one packet is sent per turnaround), and can be used to simplify the programming. Since the Originate node (the one that dialed the phone call, if phones are being used) transmits the first block, it will send a block with the Give same as the Want -- both zeros. The Answer node will send Give+1=Want blocks -- starting with give 0, want 1. Simple mode Originate nodes must check that blocks they receive have this offset, because of a glitch that could occur on the very first block. If the first block does not get thru error-free, the Answer node must send a block with Give 0 (since this is its first block) and Want 0 (since it is awaiting block 0 from the originate node). If the Originate node accepted that block, it would have to send a block with Give 0 (since its previous message was not acknowledged), Want 1 (since it accepted block 0 already). This would result in Originate sending the "unequal" numbers and Answer having the "equal"s. Since we always want the Originate node to send the "equal" numbers, the Originate node must reject the Answer node's Give 0 Want 0 block (i.e., pretend to have received it in error) and retransmit its previous block, which also had Give 0, Want 0. Once the Originate Give 0 Want 0 block gets thru, Answer will send a Give 0 Want 1 block, and things will be properly synchronized. ------------------------- Given that we have assured that Originate always transmits "equal" blocks, and Answer always sends "unequal"s, each node only needs one variable to keep track of its acknowldgements. That number corresponds to WEGIVE. When a block is received, its Want and its Give are compared. If they are not in the proper relationship (either equal, or Give + 1 = Want), the block is invalid. Next, its Want is compared to WEGIVE. (Its Give is ignored, except for the comparison to its Want.) If its Want is the same as WEGIVE, our block has been received and acknowledged, and we can return the current block to the Directing Layer and send a new block next time. If its Want is 1 less than WEGIVE, our block has not been received, and we must retransmit it. If no correct block is received before it's our turn to transmit, we must also retransmit our block, since it has not been acknowledged. This exhausts the cases possible in HDX 1-of-8 protocol. The first-block problem is taken care of by starting up the Answer node with a Give 0, Want 0 block in its retransmission buffer. Of course, all blocks that its software builds will have Give+1=Want -- but this block was never built by its software, and is only used if the first block received is in error. (The software is already set up to retransmit its block if it receives a block in error; all that needs to be done is to put this dummy message in the retransmission buffer before starting, and the rest works.)  File: INTRO, Node: Validating, Up: Validating&sequencing layers Validating Blocks look like this: |-1 byte-| +--------+ The Flags byte looks like this: | direct-| 0--- ---- Originate node sent this block | ing | 1--- ---- Answer node sent this block | block | -0-- ---- Reserved, must be zero +--------+ --XX X--- Give sequence number | flags | ---- -XXX Want acknowledgement number +--------+ | check- | +--------+ | sum | +--------+ | [pad] | +--------+ When a Validating Block is received (returned from the Translation and Framing layer), its length, flags, and data are checksummed, and the result is compared to the supplied checksums. If they are different, the block is ignored. The length is a 2-byte binary value which counts the number of data bytes in the block, not including the header and checksums. ____________Checksummed______________ / \ +++++++++++++++++-------+-------+-------+-------+-------+ | ... data ... | flags | len H | len L | cks 1 | cks 2 | +++++++++++++++++-------+-------+-------+-------+-------+ \Not transmitted/ The receiver checksums the data bytes, flags, and physical length (the two bytes of lengths are generated locally, everything else was in the block as received), and compares them to the checksum (also in the block as received). If the checksum is the same, the data is valid; if not, either some data was corrupted or some was inserted or deleted (i.e. the length was corrupted). In one case this does not work. The Translating Layer (which we haven't gotten to yet) can only send even numbers of bytes when translating to and from Radix-41. If we try to send an odd-length Validating Block, it will stick an extra byte of zeros on the end of the block and transmit it that way. Since this is a "corruption" of the data, the received block will not pass the checksum test. We deal with this by cursing at the Translating Layer and putting a special kludge in the Validating Layer. If a block fails the checksum test, we look at its last byte. If that byte is zero, we remove it, and decrement the length of the block, then recompute the checksum. (Note that this changes the length bytes, and causes us to use different bytes as the "desired checksum".) If the new checksum matches, all is well; if not, a real error occurred. Note that this method uses the physical block length to imply the true length, then checks it; just as it uses the physical data to imply the true data, and then checks it. Validating Layer Checksums -------------------------- There are two checksum algorithms used by PCNet. The first is used when the Translating Layer is translating to and from Radix-41 (because it's simple and sufficient); the other is used when translating to and from Transparent Binary (for more muscle). The first algorithm consists of simply adding up the bytes of the block and ignoring any overflow out of the 8-bit sum. We add up the even-numbered bytes separately from the odd-numbered bytes. The two's complement of these two 8-bit sums form the 16 bits of checksum information. (The negated sum of the even bytes goes to the even checksum location; the negated sum of the odd bytes to the odd location. The checksums will be a different order depending on the evenness of the block length. To see if a blocks's checksum and data match, we simply add up all the bytes of the block, including the checksum bytes. (Again we keep separate even and odd sums and ignore overflows.) If the resulting sums are both zero, the block is correct. This simple method works because Radix-41 translation mixes up the bits of the block so much that a 1-bit transmission error would mess up a bunch of bits of the block, and get detected easily. The second algorithm is called CRC for Cyclic Redundancy Check. It is a method based on mathematical theories that I do not understand well, but it is much better at detecting errors than the simple addition checksum. There are many different CRC algorithms. The one used in PCNet is the same one that is used in "SDLC" or "X.25" protocols. It is a 16-bit CRC and uses the formula (X^16)+(X^12)+(X^5)+1. When computing this CRC checksum, the checksum is initialized to FFFF hex, then each byte of the length, block, and flags are passed thru the algorithm. The complement of the resulting checksum is transmitted. The receiver does the same, but also runs the received checksum bytes thru the algorithm. If the final checksum is F0B8 hex after the second checksum byte has been processed, the block is correct. Once the checksums have been validated, the block is assumed to be good (uncorrupted by phone noise -- that is, we received exactly what the sender sent). However, the block may get ignored for other reasons, such as: we've already received this block, or it fails some further checks because it was sent by buggy software. If the -X-- ---- bit in the packet is on, the packet is in error. This bit is reserved for extensions to the existing PCNet protocol -- if it is set, anything in the packet could have a different meaning, and we must ignore it. If the X--- ---- bit indicates that we sent this block, we ignore it. Either the other system is echoing each character it receives (thinking, perhaps, that we are a FDX, non-local-copy terminal); or we have called a test node which is echoing at the Framing Layer -- waiting to see turnaround, and then sending everything it receives.  File: INTRO, Node: tr fr hdx intro, Up:Translating&framing&halfduplex layers The Translating and Framing Layer [sic, really three layers] --------------------------------- This layer determines where blocks start and end in the data passing over the phone line. It also allows all 8-bit combinations to be used in blocks, even though the node might not be able to read all possible 8-bit bytes from the phone line. It further determines which node is allowed to transmit, when Half Duplex is in use. The T/FL (Translating/Framing Layer) transmits and receives 7-bit or 8-bit characters over the phone line, and uses and returns binary data blocks to the higher layers. In the "Radix-41" translation method, 7 bits of data are used, with "mark" parity, one start bit, and one stop bit. (Systems that can't transmit "mark" parity can still be used, but will not recover as well from framing errors. Received parity is not checked.) In the "Binary" translation method, 8 bits of data, one start bit, and one stop bit are used. Four possible T/FLs exist: HDX, R41 - Used in Simple mode HDX, Bin - Used in Enhanced Simple mode FDX, R41 (not likely to get any use) FDX, Bin - Used in Advanced mode  File: INTRO, Node: Translating, Up:Translating&framing&halfduplex layers Translation ----------- Any 8-bit bytes can be passed to the T/FL by the higher layers. T/FL uses some 8-bit values for special things like framing and turnaround ("@", "]", "[") and would get very confused if these were sent as part of a data block. Furthermore, many computers cannot use all 8 bits from a phone-line as data; their hardware takes one bit for parity, or their operating system translates lowercase to uppercase, or intervenes if particular control characters are received. The T/FL must therefore TRANSLATE data blocks to a form which can be sent and received without confusion. For computers which can send or receive all 8 bits of data over the phone, Binary translation is used. Here we only have to worry about the 8-bit values that T/FL uses for other things. Therefore we encode such values as 2-byte sequences instead. Here are all the 8-bit values that the T/FL has to deal with specially in Binary translation: Hex Octal ASCII Means ----- ------- ----------- ----------------------------------------- C0 300 @ +top Start/end of block; *turnaround ack DB 333 [ +top *The originate node has finished sending DD 335 ] +top *The answer node has finished sending 90 220 DLE+top The next character is encoded data 90 40 220 100 DLE+top @ The data character C0/240/@+top 90 5B 220 133 DLE+top [ *The data character DB/333/[+top from orig 90 5D 220 135 DLE+top ] *The data character DD/335/]+top from ans 90 10 220 020 DLE+top DLE The data character 82/202/DLE+top Note that the bracket RECEIVED by a particular node need not be translated when sent in a data block (we can assume it will NOT be echoed back; we don't use binary mode when talking to a computer that insists on echoing). For example, the Originate node may send ]+top with impunity. When running FDX, neither bracket need be translated. This leaves the only char needing translation as @+top (and DLE+top since it is needed to translate @+top). This convention makes it very simple to do binary mode translation; receiving code must look for @ and brackets with the top bit on (the top bit is ignored in R41); and if a DLE+top is seen, the next byte must have hex 80 (octal 200) OR-ed in to it. The next byte should be checked for validity at least to the extent that a DLE+top followed by another "flag" should cause a translation error and then correctly interpret the second flag (eg @+top). Any other bytes received are just passed thru as-is. For computers which cannot receive all 8-bit values, we use Radix-41 encoding. Each pair of data bytes is transmitted and received as three characters from a restricted subset of ASCII -- uppercase letters, numbers, and a few punctuation marks. These characters, plus "@[]" and CR, are the only ones used by PCNet in Radix-41, and they can be sent or received by virtually all computer systems. +-------+-------+-------+-------+-------+------- Data |Byte 0 |Byte 1 |Byte 2 |Byte 3 |Byte 4 | etc... +-------+-------+-------+-------+-------+------- | \_____ \_____________ | \ \ +-------+-------+-------+-------+-------+-------+-------+-------+ Encoded |Char 0 |Char 1 |Char 2 |Char 3 |Char 3 |Char 5 |Char 6 | etc... +-------+-------+-------+-------+-------+-------+-------+-------+ This translation is done by taking a pair of data bytes as a 16-bit unsigned integer, and dividing it by 41. The remainder is the "ones" digit of the base-41 representation of the 16-bit quantity. The quotient is again divided by 41, and the remainder and quotient are the "41s" and "1681s" digits. +-------+-------+ Data |Byte 0 |Byte 1 | +-------+-------+ | +---------------+ | 16-bit number | +---------------+ Divide by 41 Quotient Remainder +----------+ +-------+ | | | 1's | +----------+ +-------+ Divide by 41 | Quotient Remainder | +-------+ +-------+ | | 1681's| | 41's | | +-------+ +-------+ | | | | | | | ----------Table Look-Up-------- | | | +-------+ +-------+ +-------+ Encoded |Char 0 | |Char 1 | |Char 2 | +-------+ +-------+ +-------+ What we are really doing is finding the base-41 representation of the 16-bit number, just as you find a base-16 representation (hexadecimal) by successive divisions by 16. The "digits" of hexadecimal are "0123456789ABCDEF"; the "digits" of our base-41 representation are "0123456789:;<=>ABCDEFGHIJKLMNOPQRSTUVWXYZ" Thus the pair of bytes 00 00 hex would turn into 16-bit number 0000, base 41 number 0,0,0, and would be sent as Radix-41 "000". Or bytes 02 00 hex would be decimal 512, base 41 0,12,10, or Radix-41 "0<:". Since the largest 16-digit base 2 number is 65536, and the largest 3-digit base 41 number is 68921, all possible 2-byte values will fit into 3 base-41 digits. In fact, there are a few left over, which we might want to use as flags at some point. Each pair of bytes in the data block given to T/FL is translated and sent this way. The validating layer always gives T/FL an even number of bytes (adding a pad byte if necessary), so we don't have to worry about dangling bytes. When receiving a data block in Radix-41, each character is examined to see if it is one of the Radix-41 characters ("digits"). If not, it is ignored; this removes assorted control characters sent by some host systems. It also allows a node to send debugging messages using lowercase letters, space, control characters, and symbols other than ":;<=>". This can be invaluable when debugging PCNet software; you can call a node which pulls apart your packets and gives detailed messages when something is wrong, and these messages won't interfere with the protocol at all. (Numbers can be spelled out in lower case, such as "want number is four, received packet six, you blew it.") If a received character is a Radix-41 digit, it is saved until 3 such characters have been collected. Then each is translated to its corresponding numeric value, and the digits are multiplied by 41 and added to produce the original 16-bit number. (If an overflow occurs, a character was garbled or lost, and the data block is in error.) If an "@" or a bracket is received and some Radix-41 characters have been received since the last group of 3, the data block is in error; it has an invalid length. [Note, this is actually determined in a different way; The packet-framing layer just below this translating layer passes up a block of data that was received between atsigns. This layer then notices the block doesn't contain a multiple of three bytes, and thus rejects it.] If all data translated without errors, the block is passed to the Validating Layer; otherwise an empty block is passed. The Validating Layer will decide whether and what to retransmit and/or pass on to the upper layers.  File: INTRO, Node: Packet-framing, Up:Translating&framing&halfduplex layers Framing of Data Blocks ---------------------- "@"s are also sent before and after a data block, to encourage the receiver to be synchronized, and to indicate the end of the block. Each byte received (after turnaround has been sent and acknowledged with five "@"s) could be part of a data block. Such a block begins with the first non-"@" received, and ends with the following "@" or bracket. In Pcnet Simple, only one data block is sent before turnaround, but due to garbling it may appear that several data blocks have been received. Each must be translated, if possible, and then passed to the validating layer for checking. The first block that passes the checks should be used, and anything between that and turnaround ignored. The following illustrates some possible framing situations and how they are handled. (Note that "ABCDEFGHI" isn't a valid Radix-41 block, but you get the idea.) Transmitted @@@@@ @ABCDEFGHI@]]]]] Received @@@@@ Y @ABCDEFGHI@]]]]] Interpretation 1st block = Y invalid length 2nd block = ABCDEFGHI OK Transmitted @@@@@ @ABCDEFGHI@]]]]] Received @XXX@ @ABCDEFGHI@]]]]] Interpretation 1st block = XXX invalid length 2nd block = ABCDEFGHI OK Transmitted @@@@@ @ABCDEFGHI@]]]]] Received @@@@@ @ABCDEF@HI@]]]]] Interpretation 1st block = ABCDEF bad checksum 2nd block = HI bad length No valid block received, request retransmission. Transmitted @@@@@ @ABCDEFGHI@]]]]] Received @@@@@ @ABCDEFGHI@]XX]] Interpretation 1st block = ABCDEFGHI OK 2nd block = XX ignored; 1st was good In FDX, each block is preceded by "@" and followed by "@". No blocks are ignored due to already having received a good block, since there are no turnarounds to wait for. If three good blocks come in, and the receiver has space to keep them in, they can be accepted and acknowledged. If a bad block comes in, it will not be acknowledged, and the sending node will retransmit it when it notices the lack of acknowledgement.  File: INTRO, Node: half-duplex, Up:Translating&framing&halfduplex layers When running HDX, the T/FL must always be aware of which node is in control of the phone line. It cannot return any received data to the higher layers until the other node has "turned the phone line around" by sending brackets. It must follow each transmission with brackets to turn the line back to the other node. The Originate node always sends "]" brackets, and listens for "[" brackets. The answer node does the opposite. (I remember this by noting that the answers are outside the brackets, unlike typical questions.) They send different brackets because their transmissions might get echoed by the other node. Receiving its own turnaround brackets would confuse a node if it couldn't tell its brackets from the other node's. Sending a single bracket to indicate turnaround will cause problems if we get errors on the phone line, though. In particular, - a data character could get turned into a bracket - a bracket could get turned into a non-bracket - the receiving hardware could be out of synchronization with the data -- that is, looking for the beginnings of characters elsewhere than where we're transmitting them. We solve the first problem by looking for three brackets, close together, as the turnaround signal. If too many other characters are in between the brackets, they do not cause a turnaround. This is implemented with a counter that goes up by 3 for each received bracket and goes down by 1 for each non-bracket. If the counter goes below zero, it is reset to zero. If it ever goes above 7, we have turned around. This was derived by: M = 3 How many brackets we must see P = 2 How many extra characters in between are OK. (P+1)xM-P = 7 Value of counter that signals turnaround. **** Clarify this a lot!!!! ******* We solve the second problem by transmitting five brackets. Even if two of them get garbled, the above method will correctly turn the line around. We solve the third problem by transmitting an "@" before the five brackets. The "@" character, with mark parity, goes down the phone line as 7 bits of space and 3 bits of mark, in that order. The receiving hardware is looking for a place where "mark" turns to "space" to signal the start of a character. If the receiving hardware thinks it's in mid-character when it receives the first bit of the "@", it won't see the start-of-character transition until the "@" ends and the first bit of bracket comes thru. It will therefore receive the first bracket even if framing errors lose the "@". There are some other aspects of turnaround that increase its robustness. First, if Radix-41 translation is in use, a Carriage Return (ASCII CR) is sent after the last bracket; this allows nodes on large and/or stupid computers to act as limited PCNet nodes. Such systems cannot look for three brackets to turn them around, but are locked-in to using CR to end a series of input characters. Since we only send one CR, these systems will have the same kind of problems that were described for sending just one bracket; but the PCNet protocol is mainly designed for micros, and is not very concerned with the problems of IBM (and IBM-like) nodes. The CR is a concession that allows limited use of such machines with the protocol. Secondly, a node must transmit five "@"s as soon as it recognizes a line turnaround. If the node that sent the turnaround has not seen these "@"s within ***10*** seconds, it retransmits the turnaround, so that severe errors on the phone line will not bring things to a total standstill. (Current implementations just look for the first "@", is this a good idea? If so, let's standardize it.) Thirdly, if no character has been received for ***50*** seconds, we assume the other node has gone off into never-never land and we give up. It's not clear that this qualifies as "robustness", but it does keep the long-distance phone bills down. When running FDX, no brackets or turnarounds are used. Either node can transmit at any time -- but also must be prepared to receive at any time. In practice, occasional lapses in reception are tolerable; if any data is missed, (for example, while interrupts are disabled for some reason), the Validation Layer will see to retransmitting it. Of course, such retransmissions cost because they increase the length of the phone call. These "lapses" could occur if interrupts are disabled due to critically timed operations, in an interrupt-driven machine, or would occur anytime a non-interrupt-driven machine did not poll the received data before two characters came in, the second clobbering the first. An FDX node should send a character at least every 10 or 20 seconds, to avoid missing the 50-second "never-never land" timeout. An atsign or two will do.  File: INTRO, Node: Hardware interface, Up:Top [All the sections of text are from PCNET;INTRO > -- this part originally trnscribed by REM as MODEMI WRU, from a proposal by one of the tiger-team members at the first workshop session.] * Menu: * Title&intro:modemi intro * IN = Naming conventions:modemi naming * NOtation used in function definitions:modemi not * Very Grubby Low-Level Routines:modemi grubby * IH = High level intro:modemi high intro * Higher-level routines:modemi high  File: INTRO, Node: modemi intro, Up:Hardware interface Interfacing to Hardware ----------------------- To make software easier to document and to make it easier to patch together parts written by different people, we've defined a set of procedure calls for handling the telephone interface (modem and UART). Modems are notorious for being unable to tell the difference between (a) a dial tone (b) a dead line (c) somebody on the line (d) the remote phone ringing, (e) the remote phone being busy, or (f) the remote phone answering but not putting up modem carrier. The only signals these modems can reliably decode are (aa) before picking up phone, if this phone is ringing from an incoming call (bb) after picking up phone and dialing blind and waiting a few seconds, if carrier comes up from the remote modem, and (cc) during a call if remote carrier drops either because the phone has hung up or because the phone is still connected but the remote modem has been disabled (these two cases are indistinguishable). These two signals (aa is ring-detect, bb is carrier-detect, cc is just the opposite of bb) are sufficient for programming the PCNet protocol, but must be programmed separately for each combination of modem and language, whereas the other parts of software can be done once in each language without regard for differences in modem.  File: INTRO, Node: modemi naming, Up:Hardware interface We decided upon a systematic way to name the low-level routines and some of the intermediate-level routines for operating these modems. By sticking to these conventions it will be easier to exchange subroutines, to know exactly which subroutine is being discussed, and to switch to another modem without changing the rest of the software. Our convention uses a 5-letter name for each subroutine, the first three letters having the role of a verb and the last two letters being an abbreviation for some object (signal, data, mode) being operated upon. Verbs -- SET (boolean, TRUE means set, FALSE means not-set i.e. clear) IST (is it true?, returns boolean) DIL (dial) SND (send, assuming we've already checked for ready) RCV (receive, assuming we've already checked for ready) SDW (send after wait for ready) RCW (receive after wait for ready) Nouns -- RG (ring; boolean) CA (carrier; boolean) OH (off-hook; TRUE means line open, FALSE means we've hung up) SP (speed in chars per second; integer such as 10,11,30,45,60,120) AN (answer mode; TRUE means answer, FALSE means originate) BT (byte of UART/ACIA data; integer) TR (transmitter ready, preceding character finished; boolean) RR (receiver ready, new data has arrived; boolean) TN (telephone number; string of digits with possible pause-characters if needed; implemented as list, vector, array, pipe, etc.)  File: INTRO, Node: modemi not, Up:Hardware interface Below where actual subroutines are defined, each description begins with the name of the subroutine and its arguments and returned value(s). For example: SNDBT: BT --> status means that SNDBT is the subroutine; it takes one argument which is a BT (byte of data), and returns one value which is status info. RCVBT: --> BT, status means that RCVBT is the name, it takes no arguments, but it returns two values, one a BT and the other a status. Arguments and results may be passed with whatever convenion is appropriate for the implementation language.  File: INTRO, Node: modemi grubby, Up:Hardware interface * Menu: * Init modem&UART:initm * Set speed i.e. baud rate:setsp * RG - Is phone ringing?:istrg * Dial telephone:diltn * CA - check for modem carrier:istca * AN - set orig/ans mode:setan * OH - set off/on hook:setoh * CA - set carrier on/of:setca * TR - is transmit buffer empty?:isttr * Send byte of data:sndbt * RR - Is receive data available?:istrr * REceive byte of data:rcvbt * Pause for a few seconds:delay  File: INTRO, Node: initm, Up:Hardware interface INITM: Initialize modem after power-up or non-PCNET use. This routine does whatever system-specific stuff may be needed before the other routines will work correctly.  File: INTRO, Node: setsp, Up:Hardware interface SETSP: SP --> status Set speed of UART/ACIA. If you use Bell-103 modem protocol at all speeds, this won't affect the modem, but for nonstandard implementations at 1200 baud or faster this may also select the carrier frequencies of the modem.  File: INTRO, Node: istrg, Up:Hardware interface ISTRG: --> RG Is telephone ringing (from incoming call we haven't yet answered)?  File: INTRO, Node: diltn, Up:Hardware interface DILTN: TN --> status Dial a number blindly (assumes you have dial tone, but you can't check for that with most $400 modems currently available).  File: INTRO, Node: istca, Up:Hardware interface ISTCA: --> CA Test for remote carrier being heard and recognized here. What frequency carrier is recognized depends on originate/answer mode which must have been set earlier.  File: INTRO, Node: setan, Up:Hardware interface SETAN: AN --> status Set originate/answer mode of carriers in modem and anything else in modem/DAA that is needed to correspond.  File: INTRO, Node: setoh, Up:Hardware interface SETOH: OH --> status Set off/on hook. If OH is TRUE this answers the phone or picks up phone in preparation to dial. If OH is FALSE this hangs up.  File: INTRO, Node: setca, Up:Hardware interface SETCA: CA --> status If CA is true, turn on my carrier (frequency transmitted depends on originate/answer mode which must have been set earlier). If CA is false, turn off my carrier.  File: INTRO, Node: isttr, Up:Hardware interface ISTTR: --> TR Check to see if transmitter is ready so that we can send more data. TRUE means safe to send next byte, FALSE means still busy with the preceding byte.  File: INTRO, Node: sndbt, Up:Hardware interface SNDBT: BT --> status (ISTTR must return TRUE before it is safe to call this routine.) Send one 8-bit byte of data in 10-bit start+data+stop frame.  File: INTRO, Node: istrr, Up:Hardware interface ISTRR: --> RR Check to see if receiver is ready. TRUE means a byte of data has completely arrived and we'd better get it before another byte arrives. FALSE means no new data has arrived.  File: INTRO, Node: rcvbt, Up:Hardware interface RCVBT: --> BT, status (ISTRR must return TRUE before it is safe to call this routine.) Receive the 8-bit byte of data that has arrived and has been waiting for us to get it. Status indicates whether a valid byte was received, or framing and/or overrun errors occurred.  File: INTRO, Node: delay, Up:Hardware interface DELAY: time --> status Delay for a specified interval of realtime. Some modems (PMMI for example) permit use of the baudrate clock for program timing, but if this feature isn't available the DELAY may be implemented as a program loop since it won't be used except when the whole machine is waiting for it to be safe to proceed with the next step. DELAY is needed because some modems don't work unless you pause between certain operations, and for things like awaiting a dial tone. The meaning of its argument may be defined by each programmer since it isn't used by higher-level software.  File: INTRO, Node: modemi high intro, Up:Hardware interface These routines call the preceding as subroutines, and do not access the hardware directly themselves. They may therefore be written either in a high-level language or in machine language. These routines perform almost all the functions called directly by the higher-level protocols, thus provide an interface between the atomic hardware operations defined in the preceding section and the useful hardware-related functions required by the PCNet software. These routines, together with INITM and ISTRG, are the only routines ever needed to be called from high-level half-duplex software such as PCNet (checking ISTCA is implicit in the failure-return from various of these routines).  File: INTRO, Node: modemi high, Up:Hardware interface * Menu: * Originate a call:oricl * Answer a call:anscl * End a call:endcl * Send byte after waiting for ready:sdwbt * Receive byte after waiting for ready:rcwbt  File: INTRO, Node: oricl, Up:Hardware interface ORICL: SP, TN --> success? Initiate an outgoing (originate-mode) call. * Call SETSP and SETAN as needed to put modem in correct mode. * Call SETOH(TRUE). * DELAY about 3 seconds to give the local telephone exchange time to give you a dial tone. * Call DILTN(TN). * DELAY about 30 seconds to give the remote telephone exchange time to make the connection, the remote modem time to answer the phone and put up carrier, and the local carrier time to see the remote carrier and sense it long enough to decide it is really there. Periodically call ISTCA and continue as soon as it's true. If after 30 seconds you don't have carrier, something went wrong, you'll have to try again later or give up. You may want to keep testing for carrier for a while just in case it was really there and phone noise obliterated it. * Call SETCA(TRUE). * Possibly DELAY about a half-second to give your modem time to stabilize (some modems drop carrier if you have just turned it on and you immediately try to do something else with the modem, a design bug we have to live with presently).  File: INTRO, Node: anscl, Up:Hardware interface ANSCL: SP --> success? Answer an incoming call. Normally another routine will loop testing for ISTRG. After seeing ISTRG return TRUE, indicating at last that someone has dialed this number and our phone is ringing, this ANSWER-CALL routine is called. It does: * Call SETSP to set the modem speed. * Call SETOH(TRUE) to answer the call. * Call SETAN(TRUE). * Call SETCA(TRUE). * Loop waiting for ISTCA to return TRUE. If this doesn't happen in a reasonable time (say 15 seconds), something is wrong.  File: INTRO, Node: endcl, Up:Hardware interface ENDCL: --> success? Terminate the call that is in progress. * Call SETCA(FALSE) to turn off carrier. * Call SETOH(FALSE) to hang up. * Call other routines as needed to establish the correct inactive state.  File: INTRO, Node: sdwbt, Up:Hardware interface SDWBT: BT --> status This routine waits until the UART/ACIA is ready for the next outgoing character (by seeing ISTTR return TRUE), then calls SNDBT(BT). It also calls ISTCA and if it returns FALSE then this routine returns an error.  File: INTRO, Node: rcwbt, Up:Hardware interface RCWBT: time --> BT, status This routine loops, calling ISTRR repeatedly for a few seconds. At any point in this loop, if ISTRR returns TRUE, RCWBT immediately terminates the loop, calls RCVBT to get a BT, and returns it up the line. If ISTRR remains FALSE for the full time, this routine gives up and returns a timeout signal. It also calls ISTCA inside the loop, and if it returns FALSE then this routine returns an error.  File: INTRO, Node: Examples, Up:Top *** *** *** This section is completely obsolete, but is included in case somebody has an old version of the software and wants to know whether it is totally broken or merely performs an old obsolete protocol such as shown here *** Examples -------- (THESE ARE IN THE OLD PROTOCOL!!!) The format used to describe the blocks is that of the Apple debug trace. The fields shown are the originate/answer bit, Give, Want, Length, Stream number (with "Z" indicating End-of-Data"). If the block is a control message (stream 0 with end-of-data), the opcode byte is shown. The remainder of the block is shown in ASCII. Orig G0 W0 L7 S00Z 87 "FOO" @S10OQJ)1BIE463(@]]]]] Ans G0 W1 L2 S00Z 87 "FOO" @Y40OQJ)1BIE400(@[[[[[ Orig G1 W1 L4 S00Z C3 @7O(9WS9S7@]]]]] Ans G1 W2 L4 S00Z 83 @DR(P1J-KH@[[[[[ Orig G2 W2 L19 S02Z "MAIL: REM^M^J^M^JFOO TEST^M^J" @LW2KXAF5A(Z7XL9101G)0CQ972BAWB+QB801C*FC4(@]]]]] Ans G2 W3 L0F S03Z "GOOD: THANKS" @9E12+972BWY7AWB0+87IAZ+8D((@[[[[[  File: INTRO, Node: Old protocol, Up:Top Differences between old (pre-1981) and new protocol Note: The Appendix on the 1980 protocol should go here. I haven't retyped it yet. DO NOT DELETE MC:PCNET;GNU INTRO until I do. This means YOU, REM!!! "APPENDIX A" ON 1980 PROTOCOL IS NOW INSERTED HERE -- WARNING, NOBODY HAS READ IT TO SEE IF IT'S CORRECT -- REPORT ERRATA TO Robert Maas, 415-323-0720 Appendix A -- Older Versions of the Protocol Retyped by Robert Elton Maas Older versions of the PCNet protocol included a length byte in the Validating Block, and used different orderings of characters that represent the Radix-41 digits. ---------------- There were two reasons for the length-byte change. First, one byte of overhead per block was saved. Second, it permitted two nodes to negotiate lengths longer than 255 bytes while remaining compatible with the PCNET Simple protocol. Without the change, the maximum length that a Validating Block could accomodate was 253 bytes of data. With the change, up to 65534 bytes of data can be used. (This would allow values in the hundreds or low thousands, which we think would be reasonable.) (In the following, the "physical block" is the received block passed to the validating layer by the translating layer. The "physical length" is the length of this block; that is the number of bytes it contains.) The current (new) layout of a Validating Block is: /-Length of--\ /--- Physical block -----------------\ / phys.blk. \ / \ +-------+-------+-------+++++++++++++++++-------+-------+ | len H | len L | header| ... data ... | cks 1 | cks 2 | +-------+-------+-------+++++++++++++++++-------+-------+ \ / \---- checksum all of this -----------/ When transmitting, the physical length (length of data plus 1 for the header byte and 2 for the checksum bytes that will be added later) is temporarily put at the front of the block as two extra bytes. This augmented block (lenH, lenL, header, data) is then checksummed. The two length bytes are then thrown away from the beginning, and the two checksum bytes are appended at the end. What actually gets transmitted then are the header byte, the data, and the two checksum bytes. When receiving, the physical length is measured from the arrived data (whatever number of bytes were received, that's the physical length we use) and as before the physical length is temporarily put at the front of the block and used to compute the checksum. This time the computed checksum is compared with the two checksum bytes that were received, and if they agree we accept the block as good. When using Radix-41 (Simple Mode), there is one special case that must be handled. If the physical block to be transmitted has an odd length, an extra zero byte is added after the second checksum byte so that the block will then be of even length. (This is necessary because Radix-41 translation can't handle an odd byte; it handles only pairs of bytes.) On receipt of the block, the first attempt to validate the block won't succeed because the zero byte won't have been thrown away. Checksum will be computed on lenH and lenL which are one higher than they are supposed to be, and the first checksum byte transmitted will be received as a data byte to be included in the checksum, and the second checksum byte will be treated as the first checksum byte, and the zero byte will be treated as the second checksum byte. The computed checksum will surely not match the checksum and zero bytes so the block will be rejected. [Can anybody prove there dosn't exist a valid block which just happens to have a zero second-checksum and just happens to match another block one shorter?] The simplest solution is that after finding the computed checksum doesn't match the checksum as received, if the second checksum byte is zero then remove it and try again. Note that the physical length bytes stuck on at the start of the block will have to be adjusted before computing the checksum. If after this second attempt the checksum bytes still don't agree, then the block really is bad and should be rejected. By contrast, the old validating block looked like this: /--- Physical block, all of this transmitted--\ / \ +-------+-------+++++++++++++++++-------+-------+ | header| length| ... data ... | cks 1 | cks 2 | +-------+-------+++++++++++++++++-------+-------+ \ / \--------Checksum this--------/ The header byte occured at the start instead of at the end, then the single length-byte (maximum value 255). Everything (except of course the checksums) is checksummed. But the length byte was transmitted along with everything else instead of being dropped. The receiver had to compute the checksum only once, even in the case of an odd-length block with zero byte appended since the length byte is part of the data as received rather than being guessed two different ways depending on the zero byte. If the length was odd and the last byte was zero then the last byte was dropped. An extra validity check could then be performed, comparing the actual length (after dropping the zero byte if it was dropped) with the length byte and rejecting the block if they were different. However this extra check could be omitted since the preceding tests were sufficient to achieve the desired level of assurance that only good blocks were accepted. ---------------- The ordering of Radix-41 "digits" (ASCII characters used to represent numeric digits) was changed to make it easier to convert the "digits" to and from values 0 thru 40. The current ordering is: 0123456789:;<=>ABCDEFGHIJKLMNOPQRSTUVWXYZ which consists of two contiguous sets in ASCII, 0 thru >, and A thru Z. The old ordering was: (0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ*+-) Note that neither is a direct extension of IBM hexadecimal notation: 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ..... but the new method can be implemented as a single test for the two contiguous sections (0 thru >, and A thru Z) followed by a different offset in the two cases (hexadecimal 30 and 32 respectively), whereas the old method has to be implemented as a table-lookup to avoid a whole bunch of tests. ---------------- The arithmetic mapping that converts pairs of 8-bit values (2^16=65536 different possible 16-bit values, i.e. values 0 thru 65535) into triples of base-41 values (41^3=68921 possible values, i.e. values 0 thru 68920, except only 0 thru 65535 are actually used) when transmitting, and then converts them back again when receiving, is the same. However the sequence in which pairs of 8-bit values are assembled to make 16-bit values, and the sequence in which triples of base-41 values are transmitted after the arithmetic is done, have been reversed. The old method took the first byte of the pair as the low-order byte (times 1) and the second as the high-order byte (times 256), just like 8080 and 6502 opcodes take their 16-bit addresses. This is backwards from normal mathematical notation, sort of like "four and twenty blackbirds". The new method takes the first byte as the high-order byte and the second as the low-order byte, just like normal notation "twenty-four". The old method transmitted the low-order base-41 digit (1) first, then the middle (41) and lastly the high-order (1681). This was backwards, like "four and twenty and a hundred". The new method transmits the high-order digit (1681) first, then the middle (41), then the low-order (1) last, like "a hundred and twenty-four".  File: PCNET, Node: DUMMY, Up: DUMMY, Previous: DUMMY, Next: DUMMY This is a dummy node for copying when making new nodes.