Im Magazin „The Computer Journal" wurde in der Ausgabe Nummer 15 vom November 1984 der folgende Artikel abgedruckt.
Der zweite Artikel einer Serie über die Programmierung des Hayes Micromodem II für die 6502 (Apple II+)

Controlling the Hayes Micromodem II
From Assembly Language

by Jan Eugenides

Last month I presented you with the first part of this program, which consisted of routines to dial the phone, gather incoming data, display it on the screen, store it in memory, and send data from the keyboard (with upper and lower case conversion). I also explained the workings of the command handler. This time, I'll show you the disk access routines, develop a way to save the buffer to disk, and show how to upload files directly from the disk. I'll add the input and print routines and a configuration program, and voila!, a working terminal program for the Apple II.
If you missed last month's article, or if you hate typing, I can supply you with the complete source code, the configuration program, and a binary file of the program itself on disk for $10.00 (plus $1.50 postage). Just send a check to me at 11601 N.W 18th St., Pembroke Pines, FL 33026.
Examine Listing 3. These are the lines I left out of Listing 1 last time. You can type them in as they appear, and they will fit into the proper spaces. Just watch the line numbers carefully.

The Equates

In lines 1180-1450 you'll find the equates, the various addresses the program uses or calls. You will remember from last time that CR1, CR2, CHAR, and OUTA are part of the Micromodem firmware. In addition, there are a few routines from the Apple monitor, and a couple of zero-page pointers and flags. Rather than go into each one separately, I will explain the function of each of them along with their associated routines.

Initialization

Lines 1500-1904 are the initialization part of the program. First, a zero goes in the capture flag, which means the program starts up with capture "on." Next, the monitor HOME routine is called to clear the screen, and then the window top edge is set to line four by simply storing a four in location $22. This will prevent the title lines from scrolling off the screen. Next, the capture buffer top address is set to $800, which is also the bottom address. In other words, the buffer is empty.
Lines 1650-1690 are necessary because DOS 3.3 does not allow direct file commands. Unless there is an Applesoft program running, you cannot OPEN, READ, or WRITE to a text file. So, our program adjusts the values of a few locations to fool DOS into thinking an Applesoft program is running, and allows us to issue normal DOS file commands from within our binary program. You'll see how this is used a little later.
Then, in lines 1710-1760, the ONERR flag is set up, and the address of our file closing routine is placed in the DOS error handler locations, $9D5A and $9D5B. This way, when DOS encounters an error, instead of a horrible crash it jumps to our routine, which closes any open files and continues with the program. This will come in handy in the uploading routine.
Finally, the titles are printed on the screen, and the main program loop is entered. (The main loop was presented last time.)

Saving The Buffer

When you press "ESC S" the command handler passes control to the SAVEBUF routine in lines 4060-4660, after first signaling the host to stop sending data (X-off).
In order to save the buffer to disk, you need to know three things:
  1. The start of the buffer.
  2. The end of the buffer.
  3. The filename to save it under.
The start of the buffer is always $800, so in lines 4110-4130 the pointer LNGTH is set to $800. Next, in lines 4170-4250, a filename is requested from the attending human, and stored in a safe place pointed to by IPTR. More about this in the discussion of the input routine a bit later. Once that's done, you need to OPEN the file. Here's where the direct DOS commands come in. Because DOS thinks an Applesoft program is running, all that you have to do now is issue a normal DOS command, by outputting a CTRL-D ($84) followed by the command. DOS only looks for commands at the beginning of a line, so you must precede the CTRL-D with a CR ($8D). Thus in lines 4270-4480, the program first OPENs the file, and then issues the WRITE command. Notice how a short loop is used to output the filename which is stored at IPTR.
Now, DOS is set up to WRITE to a text file, and all you have to do is spit out the buffer through COUT. This occurs in lines 4520-4610. As each byte is output, LNGTH is incremented and compared against PTR. When the two are the same, the end of the buffer has been reached. Then in lines 4360-4640, a final CR is output. Line 4660 CLOSES the file and returns to the main loop.
To save memory to disk as a text file:
  1. Put $40 at $AAB6 and $76
  2. Put $06 at $33 (PROMPT)
This allows direct file commands. Then, output the data byte by through COUT

Cataloging The Disk

Knowing what you do about issuing DOS commands, this should be easy. Just output CR CTRL-D CATALOG CR. This happens in lines 4700-4750.

Reviewing The Buffer

When you're on-line, it is often useful to be able to see something that has already scrolled off the screen. A way is needed to display the contents of the buffer on the screen without disconnecting. Lines 4800-5060 accomplish this.
This routine works almost identically to the SAVEBUF routine, except that no file is open, and output goes to the screen. Also, for the sake of Apples without lower case, the characters are converted to upper case before display. The conversion to upper case can be defeated by the configuration program, for those of you with Apples which can display lower case. Notice that even if your Apple cannot DISPLAY lower case, you can still CAPTURE lower case material, and later load it into your word-processor, or print it on your printer. I haven't seen any other terminal program which does this! In line 4940 I have selected a delay to slow down the display of the buffer. Otherwise it scrolls by mighty fast. CTRL-S will of course stop the scrolling, but you may wish to change this delay setting to suit your taste.

Filling Up The Buffer

It is necessary for the user to know how much space is left in the buffer. As you saw last time, when the buffer fills up, the X-off is sent and a message is printed to the screen. You have the option at that point of saving the buffer, or clearing it. For some reason, the buffer always seems to fill up at the most inopportune times (Murphy's Law, right?). Rather than allow this to happen, you can monitor the buffer as it fills.
As each character is stored in the buffer, PTR is incremented. Therefore, PTR always points to the next available memory location. You can display this on the screen with a simple HEX to ASCII conversion. This is accomplished in lines 5100-5620.
There are lots of ways to convert HEX to ASCII, and there are certainly more elegant ways than the one I have used here. Unfortunately, the more elegant, the more difficult to understand, and this method works well. Let's examine it.
In line 5110 the high-order nibble is masked off (A nibble is 4 bits, one-half of a byte). You have to deal with each nibble separately, because each one becomes one ASCII character. In other words, $AF is only one byte in hex, but the letters AF require two bytes as ASCII.
If the nibble is between $00 and $09 then all that is necessary is to add $B0 to get the ASCII equivalent (Remember, we're dealing with "high" ASCII on the Apple, the eighth bit is set). If the nibble is between $0A and $0F, you must add $B7. Look it up on the ASCII chart I gave you last time, nd you'll see why. Between 9 and A ip ASCII there are seven other character, :, ;,> , =,< , and ?. The additional seven is necessary to skip over them.
Once the nibble is converted, it is stored directly in screen memory. This is the quickest way to put something on the screen! And you always know right where it will show up. $424-$427 corresponds to the upper right corner of the screen, where "BUFFER TOP=$" has previously been printed. Each nibble is converted and displayed and then the main loop is reentered. It takes a while to explain, but it all happens very fast.
To convert HEX to ASCII:
  1. Separate each nibble.
  2. If 0-9 add $B0
  3. If A-F add $B7

The Input Routine

This routine is used to get filenames, either to save or to upload. It uses the monitor GETLN routine, at $FD6F. This routine gets a line of input, and stores it at $200. It returns with the length of the string in the X register. In line 5910 the program checks for a null string, that is, one with length of zero. This would mean that only RETURN was pressed. If this is the case, lines 6010-6100 check to see if you're on-line (just like you did with the carrier detect routine last month). If you are, the main loop is reentered, if not, the program is terminated.
Assuming a filename has been entered, our routine takes the string from $200 and moves it to $9600 where it won't be bothered. Actually, in this case this is probably not necessary, but it's not a good practice to leave valuable information in the input buffer at $200, because it could easily be overwritten. The DOS buffer at $9600 won't be used, so that's a safe place. (Be careful, though, it might not be safe for other programs you may write.)

The Print Routine

This routine is a pretty standard way of printing embedded ASCII data. It allows you to put the ASCII right in the code, rather than having to structure it all in a table somewhere. Makes changes easier, too. It works like this:
In line 6408-6414 the address of the calling routine is retrieved from the stack, and stored in CTR. The next character is then loaded into the accumulator (it will be the first ASCII character). A loop is entered, and each character is output through COUT until a zero is reached. You MUST put a zero after the embedded ASCII data! Also, there cannot be more than 255 ASCII characters printed with any one call to this routine.
Once the end of the data is found, the Y register is then added to the address stored in CTR. This new address is then pushed back on the stack, and the RTS results in a return to the next instruction after the ASCII data! A little tricky, but nice.

Uploading From Disk

Most terminal programs I have seen upload text from memory. This is DUMB. First of all, you waste all that time reading the file in from the disk to memory, and secondly you limit the size of the file you can upload to the size of the available memory. Why not simply read in the file byte by byte, and upload it that way? Then, you can upload a file of any size that will fit on a floppy!
The upload routine is contained in lines 6560-7080, and begins in much the same way as the SAVEBUF routine. The same input routine is used, and the DOS commands OPEN and REA are issued in the same way. The actual reading of the file is done in lines 7120-7240.
The easiest way to read from an OPEN file is to call the monitor routine RDKEY at $FD0C. This routine gets one character from the currently selected input device, in this case the disk drive. Then, in line 7150, the character is stored in CHAR, which you will remember is the location the Micromodem uses for characters which are to be sent out through the modem. Next, to insure normal video, the character is ORed with $80 to set the high bit, and another monitor routine, STORADV is called. This routine displays the character on the screen, and advances the cursor position. Slick, eh? If the character is zero, the end of the file must have been reached, so the program jumps to the CLOSE routine. In practice, DOS usually issues an "END OF DATA" error before this happens, and jumps to the address we so cleverly set up way back in initialization. Since this is the address of the CLOSE routine, it has the same effect. Otherwise, OUTA is called to send the character. In line 7210-7220, a delay is introduced to slow things down to 300 baud. Without this delay, the routine runs too fast and characters will be lost.
Finally, in lines 6930-7080 the file is CLOSEd and the word "DONE" is put on the screen in inverse.
I should point out that if you are uploading a file which contains lower case, and your Apple cannot display lower case, what you see on the screen will be garbage. The file will be uploaded correctly, however. This is your chance to try out what you learned before about upper-lower case conversions, and modify the program to display only upper case when uploading. Consider it your homework assignment!
To upload a text file:
  1. Open the file for READing using normal DOS commands
  2. Call RDKEY ($FD0C) to get the characters
  3. On END OF DATA error, close file
That pretty much wraps up the blow-by-blow description. Now all you need to know is how to USE the program!

How To Use Big Buff

Big Buff is a breeze to use, but first you must configure it for the slot your modem is in, and for the type of machine you own. Type in and run the CONFIGURE program in Listing 4. This program will allow you to select the slot, and whether you have lower case display and/or keyboard. The file BIG.BUFF must be on the disk when you run the CONFIGURE program. A new file named BIG.BUFF.CONFIGURED will be produced. BRUN this file, or BLOAD it and, from the monitor, type 9100G.
You'll be asked for a phone number to dial. Just type it in and hit RETURN. The modem will pick up the phone and dial. If a carrier is detected, you'll see:
MICROMODEM II: CONN
on your screen. Log on to the host in the usual way (each host is different, so it's up to you to know the procedure.) Text will start being displayed on the screen, and you'll see the BUFFER TOP = $0800 display changing rapidly as data is stored in the buffer. You have seven commands available to you, as I discussed last month. They are:
ESC ZZero the buffer (clear it)
ESC XHang up the phone
ESC SSave the buffer to disk
ESC BToggle capture on or off
ESC UUpload a file from disk
ESC CCatalog the disk
ESC RReview the buffer (display on screen)
Try them out. They all work just like you would expect them to. I have noticed that occasionally, if you try to hang up the phone with ESC X during some log-off sequences (notably CompuServe), DOS picks up the incoming characters as a command, and issues a "SYNTAX ERROR." This is of course trapped by our program, and control passes to the CLOSE routine. No damage done, but you'll see an inverse "DONE" on the screen. Just press ESC X again, and this time it will work normally. You are given one last chance to save your buffer, RETURN alone exits the program.

Possible Uses

Big Buff is useful just as it is for day to day networking, chatting on CompuServe or whatever. Many bells and whistles could be added, and there is much room for customized applications. An easy mod would be to allow macros of some kind. All you would need would be a data table, and a routine to output the macros using OUTA. I am considering putting together a package for the E-COM system (Electronic Computer Originated Mail), combining the basic routines I have presented here with a specialized data base and word processsing program to make using the E-COM system easy for Apple users. If you haven't heard of E-COM, get in touch with the U.S Postal Service for more info. It's neat! Or, set up your own BBS (bulletin board system) (you'll have to add auto-answer capabilities), or develop a local network of Apple users. Whatever. Now you know how, right? As always, I welcome your questions and comments. If you come up with a good use for Big Buff, or any nifty modifications, let me know. Or just write to say "HI!"

Next Time

In the works is a serial/parallel interface which connects to the game port and allows you to run printers, modems, speech synthesizers, whatever, out of the game port! As of this writing, I've got it working with my Epson MX-80. Watch this magazine for it! In addition, I'll be showing you how to write a printer driver for the interface, and who knows what else will follow?!

Listing 3

To be combined with Listing 1 from last month (see article for details)
Lines from last month go here
Lines from last month go here...
Initialization goes here...

Listing 4

Die Quellen: Listing1, Listing2, Listing3 und Listing4.

Eingescanned von Werner Cirsovius
Dezember 2015
© The Computer Journal