TDOS3.WS4 --------- - "S-100 Computers & TurboDOS" Michael Winter "FOGHORN", Vol.VIII, No.3, December 1988, p.13 (Retyped by Emmanuel ROCHE.) Introduction ------------ I am the system manager and programmer for a business that repairs electric tools, and sells and repairs electric motors and pumps. We generate 20,000 sales invoices, 10,000 repair tags, 3,600 checks, and 5,000 purchase orders each year. We also process 6,000 payable invoices, and payroll for up to 20 employees paid on a weekly basis. We maintain a 40,000 record parts inventory database. All systems are integrated into general ledger, and a complete financial statement is generated by 9 a.m. on the first of every month, summarizing the just completed month. It is all done with dBASE II ver. 2.43 operating on an S-100 Bus 17-user system running a TurboDOS ver. 1.43 operating system. There are 5 system printers. Printing is automatically routed to the printer having the correct form loaded -- invoice, job tag, check, bookkeeping reports, and all other reports/plain paper forms. All printing is automatically spooled and despooled, so there are never any conflicts. The software is designed so that all users can be simultaneously generating any particular form, i.e., an invoice, and, if they all send it to the printer at the same moment, TurboDOS will despool each invoice, one at a time. The system accommodates both open account invoicing and point-of-sale invoicing. TurboDOS runs on the Zilog Z-80 and Intel 8086 families of processors. It is distinguished by its networking capability, and its ability to run virtually any CP/M program without modification. Our business has relied on it continually for the last 4 years, and we have never been "down" on a business day for more than an hour or two. A separate microcomputer supports each user's video console, and an additional microcomputer manages the disks and the bus. Growth forced hardware upgrade ------------------------------ Up until October 1987, we operated an 8-user NorthStar Horizon (S-100 Bus) system running an earlier version of TurboDOS. Although it had given us good service, we had outgrown it. The 8-bit 4-MHz 64-K RAM slave boards, combined with an 8-bit 64-K RAM master, just was not fast enough. All the slots on the bus were filled, and we had maxed out at 8 users. We implemented a massive hardware upgrade, purchasing a new chassis, S-100 Bus boards, hard disk controller, floppy drives, and a tape drive. We retained our existing hard disks, printers, and CRTs. Since the floppies and tapes used on the NorthStar system were completely incompatible with the floppies and tapes for the new system (ROCHE> NorthStar used "hard-sectored" floppies, because this simplified the disk controller. Unfortunately, "soft-sector" floppies became the standard...), all of the DBF and CMD files had to be ported to the new system by cabling slave serial ports together, and making the transfer with the MEX communications software. Two sets of slaves were used, and the transfer was completed overnight. No serious problems were encountered. Our system now includes the following hardware: a CPZ-186 single-board central processor (the master), manufactured by Intercontinental Micro System Corp. (I.C.M.) with a megabyte of memory managed by an Intel 80186 8-MHz processor, a floppy disk controller for up to 4 floppy drives, 2 serial ports, and 2 parallel I/O channels. The parallel channels are connected thru a SCSI port to an ICM Omti Disk Controller, which manages 2 Maxtor XT2085 85-megabyte hard disks and a half- height TEAC streaming tape drive. There are 4 Advanced Digital Corporation (ADC) multi-slave boards, each board supporting 3 users, each user with 128-K bank-switched RAM, an 8-MHz Z-80 CPU, and 2 serial ports: one used for the console, and another available for a printer, modem, or other RS-232C device. There is one ICM CPS-BMX board which is similar to the multi-slave, except that it is a 6-MHz single-user board, utilizing direct memory addressing and, in addition to the 2 serial ports, it has a parallel port which is connected to a battery-powered real-time clock board. Each time the system boots up, it goes out to this clock, and brings in the correct system time, even if the power has been off. We never have to key in the correct time, except in Spring and Fall, when the clock must be reset when Daylight Savings Time begins and ends. The final board plugged in our S-100 Bus is an ICM Q6A board, which is similar to the multi-slave, except that there are 4 6-MHz Z-80 CPUs on it, supporting 4 users, each with 128-K of bank-switched RAM. All the hardware is mounted in a single "box" about the size of an egg crate. This is an Integrand 3015T chassis which includes a 15-slot bus, 4 cooling fans, and the power supply. We have 2 8" double-sided, double-density floppy drives, mounted in a separate cabinet. TurboDOS formats 8" floppies to 1024-K. We use floppies only to back up the day's work at day's end. The system boots directly from hard disk. Surprisingly, the 6-MHz ICM CPS-BMX slave completes typical tasks that we run on the system up to 30 percent faster than any of the AD 8-MHz slaves. Technical people have tried to explain this to me, referring to the direct memory addressing feature of the CPS-BMX, and mentioning that the implementation of the AD multi-slave results in bus wait states. The logical setup ----------------- I read an article in the "FOGHORN" expressing interest in systems with CP/M compatibility and a multi-user capability. S-100 Bus systems operating TurboDOS are the logical step. The performance is excellent. The price is reasonable -- we have approximately $26,000 in the equipment and purchased software, including 14 consoles, an external 500 VA uninterruptible power supply, 6 printers, 2 hard disks, the S-100 Bus boards, the chassis, 2 floppy drives, modem, external IBM PC, and cabling. The system is flexible and expandable. We are using fewer than half the slots in the chassis, and could easily double our number of users by purchasing additional boards. Beyond that, TurboDOS supports multiple box networks, up to 65,534 nodes. Each master, slave, or LAN board occupies 1 node. Boxes with both 8-bit and 16-bit slaves on the same bus are feasible, too. The IBM PC is interfaced to the system for the singular purpose of importing data files from 5-1/4" MS-DOS floppies, which our suppliers periodically provide to maintain current parts/motor pricing information. One slave on the S-100 Bus runs MEX to operate a serial port which is cabled (with a "Null-Modem Cable") to the IBM PC serial port. We run CROSSTALK XVI on the IBM PC, and are able to quickly import data files off of the submitted floppies. That same slave has its other serial port cabled to the RS-232C interface on the uninterruptible power supply, which periodically reports technical information such as load, accumulated operating hours, projected back-up time remaining, operating temperature, number of previous outages, battery voltage, AC volts in, and AC volts out. This slave has no console cabled to it. System software enables any user, at any console, to ATTACH to its remote console driver, and operate it, as if cabled to it. All of the system users use it with enthusiasm, but are uninterested in operating systems or applications programming, so all needed operations are directly accessible from our dBASE II main menu. All of our staff, including the non-keyboard oriented people, have been able to assimilate at least enough know-how to do routine things on the system, such as looking up parts pricing, or punching in/out on our payroll time clock. TurboDOS also provides DO file operations, which is similar to CP/M SUBMIT operations. Although dBASE II runs on TurboDOS without modification, if you wish to change printers or auto-trigger despooling from within CMD files (on the fly), PEEK and POKE routines are needed. TurboDOS responds to virtually all C-function calls just as CP/M would, and adds additional T-function calls for managing network activities, that are easily implemented in POKE routines. All of the Z-80 slaves on our system use 128-K bank-switched memory. This means that your application program may utilize almost all of 64-K memory, because the operating system is in the other bank. Although TurboDOS supports file locking and record locking, these T-functions are not automatically implemented by dBASE II, as they did not exist in the CP/M world. (ROCHE> ??? They were available in MP/M-II... And network system calls in CP/NET!) Permissive multi-user file sharing is offered, which permits all users to read in any file at any time, but, as soon as any user writes to a file by changing or extending it, he has achieved an explicit lock. Should any other user try writing to that file, before the first user has closed it, the second user will crash to the dBASE dot prompt after receiving the oblique error message "Disk is Full". To avoid this problem, I write pseudo-file locking routines into any dBASE program where conflicts can be anticipated. The primary hard disk is partitioned into 2 logical drives: A and B. Drive B has only one track assigned to it, for the sole purpose of maintaining a 64- entry directory. All pseudo-file locks are then, actually, 0-K files on this directory. This makes wild-card file searches extremely fast, when an application checks for a file lock. For example, if the file to be locked is PARTS.DBF, and user F is the requester, the application will first check to see if there is a file named B:PARTS.LK0 ? If user A already has locked that file, there will be B:PARTS.LKA. The small file locking procedure then identifies that the final character of the name is A, and reports to the user trying to perfect his file lock that terminal A has the file, and suggests a later attempt. Any user is still permitted reading access for look-ups and reports; he just cannot write to the file. If user F's application found no files B:PARTS.LK?, then B:PARTS.LKF would be immediately created, and User F would then proceed with his change. If user F is posting a multiple transaction then, of course, the application must achieve file locks on all of the files before starting any posting. Care in implementing this scheme must be taken, to avoid the "Fatal Embrace", about which much has already been written. Essentially, if 4 file locks are needed, and the routine successfully locks the first 3, and finds it cannot perfect the 4th, then it must display its error message, and immediately release the first 3 which have already been created. You may be wondering why I just did not write the PEEK/POKE routine necessary to latch the TurboDOS T-functions needed to implement actual operating system file and record locking. Like CP/M, at the operating system level, TurboDOS uses File Control Blocks (FCB) for any function that references a file. Simply put, the ASCII file name is poked into memory first, and then that memory address is loaded into a register, the function number (open file, close file, make file, lock file, etc.) to be implemented is loaded into another register, and then a call is issued. dBASE, of course, does this every time with the USE "filespec" command. However, I have found no way to predictably determine where, in memory, dBASE will have the particular FCB in question. I was able to see the general area in memory where all of the up to 16 FCBs are maintained by dBASE, but found no way in an application program to quickly determine which of the 16 represents the FCB that I need at that moment. I would be pleased to hear from anyone out there, who has nailed this down. The other multi-user work-around that a programmer must face for a system like ours, copes with several users needing to generate, for example, a sale invoice at the same time. All invoices are retained in a master (core) file called INVOICE.DBF. If there was only this one file then, obviously, only one user could be creating (adding) an invoice at any time, and this limitation would severely inhibit productivity. Therefore, we have sets of daily files for each possible user -- AINVOICE.DBF, AJOB.DBF, ACHECKS.DBF for user A, -- BINVOICE.DBF, BJOB.DBF, BCHECKS.DBF for user B, etc. At the close of business, each day, the night program is run. Among the responsibilities of this program is appending to the core files all the records from the daily files, and then emptying the daily files. It then dumps routine reports into the spooler, to be printed the following day, such as the daily aged receivable and payable reports, the final sales report from the previous day, and other daily transaction reports. The second part of the night time procedure checks the date, and performs additional reporting activity for end of month, end of quarter, and end of year. The date is also tested during this part of the night procedure, to determine if it is a week-end. The second week-end of the month, housekeeping procedures (drop off the records closed out in excess of specified time period, and then re-index as appropriate) are run on the sales invoice and job tag files. The third week-end of the month, receivable and payable housekeeping occurs. On the fourth week-end of the month, core files such as the phone book and parts database are packed and re-indexed. These procedures sometimes take 12-18 hours and, if they were run during the business day, performance would be degraded somewhat but, more importantly, key files would not be available for needed look-ups. Finally, the last part of the night time procedure copies all data files and indexes from our primary hard disk to our backup hard disk. With the second hard disk functioning as a dynamic back up in this way, should we have a catastrophic failure on the primary hard disk, during the business day, we could immediately begin functioning on the back up hard disk, having lost only the transactions posted since 8 a.m. that morning, all of which can be quickly re-entered from control hard-copies routinely accumulated in trays on various desks. We also maintain routine daily off-site backup by copying all the data and index files off of the backup hard disk to tape, every morning. The employee responsible for this process arrives at 6 a.m. and runs a streaming tape that is completed in 3 hours. About 300 files, totaling 45 megabytes, are copied onto the tape. The tape program is run on a slave, and does not require system dedication, but does degrade responses to user requests for file accesses about 10-20 percent while running. Hard disk file organization is very similar to CP/M systems. Directory libraries are organized into user areas 0 to 31. Maximum file size is 134 megabytes. Disk drives up to a gigabyte are supported without partitioning. Drives, printers, and print queues are identified in each slave's operating systems by assignment tables, each table up to 16 entries long. For example, an individual slave could access 16 different logical drives, and 16 different network printers located anywhere on the network. All of our system printers are on slave serial ports, operated remotely across the network. We found that system performance was enhanced by not connecting printers to the serial ports on the master, allowing the master to focus 100% of its time functioning as a file server, and bus master. WordStar 3.0 is used to write all the dBASE CMD files. We are not running any spreadsheet software. TurboDOS comes with a well-organized manual (2-1/2" thick, usually presented in a 3" ring binder) that is logically divided into 5 sections -- User's Guide, Z-80 Programmer's Guide, Z-80 Implementer's Guide, 8086 Programmer's Guide, and 8086 Implementer's Guide. The documentation is very complete. I think Gene Davis, at Productive Data Systems, Inc., 303 North Indian Avenue, Palm Springs, CA 92262, is the best source of supply and support for S-100 Bus hardware and TurboDOS. Here are names and addresses of the manufacturers of the S-100 Bus hardware described above: - Integrand Research Corp. 8620 Roosevelt Avenue Visalia CA 93291 - Advanced Digital Corporation 5432 Production Drive Huntington Beach CA 92649 - Intercontinental Micro Systems Corp. (I.C.M.) 4020 Leaverton Court Anaheim CA 92807-1692 - The TEAC streaming tape drive accepts cassette-style tapes, and works fine, but I have no manual, and can supply no address for the manufacturer. - TurboDOS is a registered trademark of Software 2000, Inc., dBASE II is a registered trademark of Ashton-Tate. MEX is a trademark of NightOwl Software, Inc. IBM PC and MS-DOS are registered trademarks of International Business Machines. CP/M is a trademark of Digital Research. CROSSTALK XVI is a trademark of Microstuff, Inc. I hope that this overview of our S-100 Bus system running TurboDOS 1.43 excites some interest out there. I am really enthused because it offers us a truly integrated business solution, at a reasonable cost, using many of the system and programming techniques learned on an Osborne 1. - "dBASE II Machine Language Interface for TurboDOS Printer/Queue changes" Michael Winter "FOGHORN", Vol.VIII, No.3, December 1988, p.48 (Retyped by Emmanuel ROCHE.) The following routines are essential for switching printers on the fly, and signaling end of print (tripping the spooler) from within dBASE II ver. 2.43 running on a TurboDOS operating system ver. 1.43. They are stored in high memory, assuming that the slave hardware provides 128K bank-switched memory, and that dBASE has available almost all of 64K for its own use. I have shown the decimal derivation of each set of instructions just before the actual POKE command. They would not be included in the program itself, but are here to demonstrate the procedure that you would follow to write a POKE sequence to accomplish any other special function, not otherwise directly supported by dBASE. The POKE commands would be first implemented at the beginning of the Main Menu program. Signal end of print (Trip Spooler), TurboDOS T-function 28. Called by any CMD file requiring spooler trip. Mnemonics Hex Decimal Comments --------- --- ------- -------- LD C,1C 0E,1C 14,28 T-func.28 JP 0050 C3,50,0 195,80,0 TDOS Thus, POKE 62030,14,28,195,80,0 SET CALL TO 62030 Change Queue/Printer Assignment, TurboDOS T-function 27 (62123 -> 62133). Insert instructions at 62126 = METHOD, 62128 = QUEUE/PRINTER. Called by PRINTER.CMD. Mnemonics Hex Decimal Comments --------- --- ------- -------- LD C,1B 0E,1B 14,27 T-func.27 LD E,method 1E,methodH 30,method Print mode: 0=direct, 1=spooled, 2=console, -1=leave unchanged. LD D,prnt/q 16,prnt/qH 22,prnt/q 1=A, 2=B, ..., 16=P, Q0=leave unchanged, P0=output discarded. LD B,drive 6,driveH 6,drive 0=A, 1=B, ..., 15=P, -1=leave unchanged. JP 0050 C3,50,0 195,80,0 TDOS Thus, POKE 62123,14,27,30,0,22,0,6,255,195,80,0 PRINTER.CMD is implemented by any other dBASE command file, when it determines that a printer, other than the current printer, is needed. Data file area may be primary or secondary, depending on considerations of the calling file. If a file is open, it must be reopened and repointed as necessary -- those responsibilities must be handled by the calling file. The calling file passes its newly-selected printer in memvar NEWPR (i.e., NEWPR='1', the character is the printer name). Ever present memory variable TERMR identifies all available system printers as follows: $(TERMR,1,1) Current printer $(TERMR,2,1) Report printer $(TERMR,3,1) Invoice printer $(TERMR,4,1) Job tag printer $(TERMR,5,1) Bookkeeping report printer $(TERMR,6,1) Check printer An example from REPORTMN.CMD (report printer will be needed): IF $(TERMR,1,1)#$(TERMR,2,1) STORE $(TERMR,2,1) TO NEWPR DO PRINTER ENDIF $(TERMR,1,1) TERMR is initialized at sign-on in the beginning of MENU.CMD from the PRTR field of SYSPAR.DBF. All files assume that all printers are spooled and available system wide, except printer "4" is defined throughout this software as being LOCAL and NON- SPOOLED. All command files include a CALL to automatically Signal End of Print when a report or form is complete, if the current designated printer is *NOT* "4". To implement single-form printing (i.e., point of sale invoicing) effectively, all procedures that route print output to a special form printer, such as an invoice, job tag, or check, must assume that a form has just been torn off and, therefore, the form is already lined up and ready to go (no Form-Feed wanted). Output for a special form always ends with an eject. All other printers (plain paper) assume eject required before print output begins. Sounds simple, but there is a hitch. If you use dBASE's report command to generate a printout, then have TurboDOS switch printers to a special form printer, and then output printing @ 0,0, dBASE assumes a Form Feed is required, and automatically issues an eject (Form Feed) command to the printer. The following poke sequence sets printer 0, direct (TurboDOS traps print output, and discards it), so that the eject command can be issued to re- initialize dBASE, and avoid that extra eject upon any subsequent SET FORMAT TO PRINT command. * PRINTER.CMD SET CALL TO 62123 POKE 62126,0,22,0 CALL SET PRINT ON EJECT SET PRINT OFF * Note: Our system assumes TurboDOS operation, * allowing up to 16 printers/queues per processor. * '1'=A '2'=B ... '0'=J 'A'=K ... 'F'=P * (pseudo Hex). The @ sequence converts that * convention to decimal for the poke sequence. IF VAL(NEWPR)=0 STORE @(NEWPR,'0ABCDEF') TO METHOD IF METHOD=1 STORE 10 TO NEWPRD ELSE STORE 10+METHOD TO NEWPRD ENDIF METHOD ELSE STORE VAL(NEWPR) TO NEWPRD ENDIF VAL(NEWPR) IF NEWPRD#4 STORE 1 TO METHOD ELSE STORE 0 TO METHOD ENDIF POKE 62126,METHOD,22,NEWPRD CALL IF NEWPR#'4' USE PRINTER IF ##0 LOCATE FOR NEWPR=WHPRINT ENDIF ##0 ELSE USE TERMPRNT IF ##0 LOCATE FOR TERM=WHPRINT ENDIF ##0 ENDIF NEWPRD#4 IF EOF .OR. #=0 ACCEPT 'Can't identify printer. Get ; System Manager.' TO DUMWAIT ELSE STORE TRIM(HOW80) TO TERM80 STORE TRIM(HOW96) TO TERM96 STORE TRIM(HOW136) TO TERM136 STORE TRIM(HOWLONG) TO TERMLONG STORE TRIM(HOWSTAN) TO TERMSTAN ENDIF EOF USE * Reset the default call, for signaling end of print condition. SET CALL TO 62030 * Make $(TERMR,1,1) equal to the current printer. STORE NEWPR+$(TERMR,2,LEN(TERMR)-1) TO ; TERMR RELEASE METHOD,NEWPRD,NEWPR RETURN * EOF PRINTER.CMD PRINTER.DBF contains the CONTROL SEQUENCES for PITCH CHANGES, etc. for all system-wide printers -- one record for each printer. TERMPRNT.DBF contains the CONTROL SEQUENCES for the LOCAL PRINTERS, one record for each dedicated printer (identified by memvar TERM). Ever present memory variables, TERM80, TERM96, TERM136, TERMLONG, and TERMSTAN permit dBASE II to change print pitches while outputting any form or report, without executing any additional look-ups. One other note about implementing machine language commands in the dBASE II environment. I had the idea that, at a Main Menu sign-on, I would initialize all of my machine language routines in an area of memory not otherwise used by dBASE, and then simply adjust the ad hoc call address during the various procedures that would need these routines, without having to repoke the whole routine each time it was needed. My manual shows that, with the exception of the SORT command, dBASE never invades memory above A400 (41984 decimal). Although none of my dBASE program ever uses the SORT command, I found that the area between 45000 and 46000 was intermittently overwritten. That's why these procedures were put in the 62000 area. EOF