Date: Mon, 24 Nov 86 17:18:42 est From: David Krowitz Here are the source files for a print-server for a Toshiba 1351 dot matrix printer running on an Apollo workstation with an RS232 interface. See the file PRF.TOSHIBA.HLP for the particular capabilities of this print-server (including multiple fonts, bitmap graphics, etc). Documentation and compiling instructions are in the normal .DOC and .BLD files. The bundled files start below the dashed line. -- David Krowitz ----------------------------------------------------------------------- # To unbundle, sh this file echo prf.toshiba.hlp 1>&2 cat >prf.toshiba.hlp <<'End of prf.toshiba.hlp' 9.04;prf (print_file), revision 9.04, 85/05/30 PRF (PRINT_FILE) -- Queue a file for printing. usage: PRF pathname... [-INTER] [-COP n] [-PR name] [-SITE entry_dir] [-USER name] [-SIG ALARM|OFF] [-BAN [ON|OFF]] [-CONFIG [pathname]|-NDB] [-TEXT|-PLOT|-TRANSPARENT] [-NPAG] [-MARGINS [ON|OFF]] [-TOP n] [-BOT n] [-RIGHT n] [-LEFT n] [-HEADERS [ON|OFF]] [-HEAD l-string/c-string/r-string] [-FOOT l-string/c-string/r-string] [-FTN [ON|OFF]] [-WRAP [ON|OFF]] [-PITCH n] [-POINT n] [-WEIGHT value] [-LQ [ON|OFF]] [-RES n] [-WHITE n] [-BW [ON|OFF]] [-MAGN {-1..16}] {CL} FORMAT PRF [pathname...] [options] PRF queues a file for printing. The file must be an ASCII stream (i.e., text) file, a graphics metafile (GMF), or a GPR bitmap object. After successfully queueing a file, PRF displays a message containing the full pathname of the file that you queued. You can execute PRF once for each file that you want to print (specifying all the necessary options every time), or you can enter PRF's interactive mode and hand files to the program continuously. See the examples below. Files queued by PRF are physically printed using PRSVR (PRINT_SERVER). When you invoke PRF, it first sets all options to their default states (as described below). Next, it looks for a PRF configuration file called ~USER_DATA/PRF.DB unless you have invoked PRF with the -NDB option (described below). If PRF locates a configuration file, it executes the options contained in the file to configure the current session. Finally, it proceeds to process any options on the command line or in the interactive session. A menu-based version of the PRF command is also available. Type HELP PRFD for more information. ARGUMENTS pathname (optional) Specify the file to be printed. Multiple pathnames and pathname wildcarding are permitted. Default if omitted: read standard input. OPTIONS The following options may appear on the Shell command line or in PRF interactive mode as noted below. In addition, you may place one or more options in a configuration file (see -CONFIG). In that case, create the file with one option per line without the prepended hyphens (-). See Example 3 below. If no options are specified, the file(s) are printed using ASCII carriage control, with pagination enabled, on the default printer (as established by PRSVR). ___ _________ _______ _____ __ ___ ____ _____ The following options apply to all file types. -INTER[ACTIVE] Enter interactive mode. -COP[IES] n Print multiple copies of the file, where 'n' is the requested number of copies. If -COP[IES] is specified, 'n' is required. If this option is omitted, one copy is printed by default. -PR[INTER] name Specify the printer 'name' for printing the file. This option is useful only if more than one printer is in use on the network, or if a printer has been assigned a nonstandard name with the "PRINTER_NAME" configuration directive in the PRSVR command. If you omit this option, PRF uses the default printer name, "P". Note that "P" is also the default printer name used by the PRINT_SERVER. -S[ITE] entry_dir Specify print queue (/SYS/PRINT) on alternate node by giving that node's entry directory name. This option allows you to maintain more than one printer queue directory. You may want to maintain separate queues for different organizations, or you may want two queues to provide redundancy in case of node failure. -USER[_NAME] name Specify user name that will appear on the banner page of the printed file. The alarm facility of PRF also uses this name to determine who should be notified when printing is complete (see -SIG below). This means that this name must be a valid login name (unless you don't care about sending an alarm). If this option is omitted, the current login name is used. -SIG[NAL] ALARM|OFF Request an alarm server signal when the file has finished printing. The default is OFF. -BAN[NER] [ON|OFF] Enable/disable banner page. The default is specified in the PRSVR configuration file. If neither ON nor OFF is specified, ON is assumed. -CONFIG[_FILE] [pathname] Specify a file containing further PRF options, one per line. Do not use prepended hyphens (-) with the option names in the configuration file. If 'pathname' is omitted, PRF will execute the configuration file ~USER_DATA/PRF.DB. -NDB Suppress processing of the configuration file. -TEXT Specify text mode for printing ASCII files. This is the default print mode. -PLOT Specify plot mode. Include this option to print bitmap files created by a graphics metafile (GMF) manager or GPR or the CPSCR (COPY_SCREEN) command. -TRANSPARENT Specify that when the file is printed, the records of the file are to be passed directly to the printer driver routine with no processing by the PRINT_SERVER. ___ _________ _______ _____ __ ____ _____ ____ The following options apply to text files only. -NPAG Disable the headers and margins generated by PRF. -MARGINS [ON|OFF] Enable/disable margins generated by PRF. The default is 'ON'. If neither ON nor OFF is specified, ON is assumed. -TOP n Specify page top margin, in inches. The default is a value specified in the PRSVR configuration file. -BOT[TOM] n Specify page bottom margin, in inches. The default is a value specified in the PRSVR configuration file. -RIGHT n Specify page right margin, in inches. The default is 0 inches. -LEFT n Specify page left margin, in inches. The default is 0 inches. -HEADERS [ON|OFF] Enable/disable page headers and footers generated by PRF. The default is specified in the PRSVR configuration file. If neither ON nor OFF is specified, ON is assumed. -HEAD[_STRING] l-string/c-string/r-string Specify contents of left, center, and right components of the page header generated by PRF. Components may be empty strings. The following special characters return the values indicated when they appear in the header strings. @ = escape character # = current page number with 1 leading and 1 trailing space % = current date ! = filename & = filename's last time,date modified * = insert a space in text string (literal spaces are not allowed) Example: -HEAD !/Page#/% will produce a header with the filename in the left component, the string "Page" followed by the current page number in the center component, and the current date in the right component. The default header is a string specified in the PRSVR configuration file. -FOOT[_STRING] l-string/c-string/r-string Specify contents of page footers. The format is the same as for -HEAD above. There is no default footer. -FTN [ON|OFF] Force use of FORTRAN carriage control. The -FTN option causes the PRINT_SERVER to use FORTRAN forms control even if the file does not have the FORTRAN carriage control flag. Use of this option will cause PRF to interpret the first character of each line as a FORTRAN carriage control character (and not print it). This can be unfortunate if the file has ASCII carriage control, so be careful. If neither ON nor OFF is specified, ON is assumed. The default state is OFF. -WRAP [ON|OFF] Enable/disable automatic line wrapping. When enabled, PRF will wrap any lines that exceed the right margin onto the next line. When disabled, PRF truncates lines that exceed the right margin. If neither ON nor OFF is specified, ON is assumed. ___ _________ _______ ___ ___ ___ ____ ________ __________ ________ ____ ___ The following options are for use with printers supporting variable font and _____ _____ pitch sizes. -PITCH n Set the pitch (characters/inch) at which you wish the document to be printed. The following pitch settings are available on the printers indicated. Printronix 10 Spinwriter 12 Imagen 8.5, 10, 12, 15, 17.1 GE 10, 12, 13.1, 16.7 Versatec 12 Toshiba 1351 5, 6, 10, 12, 16.7, 20 draft mode 5, 6, 10, 12 letter quality mode -POINT n Set the point size for the font to be used. This is a real number in units of a point which is 1/72 inch. -WEIGHT value Set the weight of the font to be used. This option is only valid for the GE printer type. Possible values are 'light', 'medium', and 'bold'. The default is 'medium'. If this option is used with the Toshiba 1351 printer, each character of the output will be printed once for the 'light' and 'medium' values and twice for the 'bold' value, resulting in a darker output when 'bold' is specified. -LQ [ON|OFF] Specify that the document is to be printed in 'letter quality' (ON) as opposed to 'draft' (OFF) mode. This option is only valid for the GE printer type. If neither ON nor OFF is specified, ON is assumed. The default state is OFF. If this option is given with the Toshiba 1351 printer, the printer will use its high-quality Elite font (font #1) when 'letter quality' (ON) is specified. The printer will use its default high-speed font (font #0) when 'draft mode' (OFF) is specified. ___ _________ _______ _____ __ ____ _____ The following options apply to plot files. -RES[OLUTION] n Specify resolution of output plot in dots per inch. If you specify a resolution not available on the particular printer, the file is printed at the closest available resolution. The default resolution is specified in the PRSVR configuration file. -WHITE[_SPACE] n Specify amount of white space (in inches) to appear between multiple plots in one file. The default is three inches. -BW[_REV] [ON|OFF] Enable/disable black and white reversal for bitmaps. If neither ON nor OFF is specified, ON is assumed. The default state is OFF. -MAGN[IFICATION] n Specify bitmap magnification value. 'n' is an integer in the range -1 to 16. -1 selects auto-scaling to magnify the bitmap to fill the available page space. 0 selects 'one-to-one' scaling between the display and the printer for GMF bitmaps. (For GPR bitmaps, this translates to magnification 1.) 1-16 selects magnification by that amount. Portions of the magnified bitmap that exceed the printer page boundaries are clipped. The default is 0. For the Toshiba 1351 printer, the default magnification (0) results in a one-to-two scaling between each pixel of the display and the printer for GMF bitmaps (same result as using a magnification value of 2). This will make the picture on the printer roughly the same size as the picture on the display. This command uses the command line parser, and so also accepts the standard command options listed in HELP CL. COMMANDS COMMANDS COMMANDS -INTER -INTER Once PRF has been invoked in interactive mode (see -INTER above), it accepts the following interactive commands at the "PRF> " prompt (in addition to the options already discussed). P[RINT] pathname P[RINT] pathname P[RINT] pathname Queue the specified file for printing. Q[UIT] Q[UIT] Q[UIT] Quit interactive mode and return to the Shell. SH[ELL] SH[ELL] SH[ELL] Create a shell command line. This command allows you to issue Shell commands without leaving PRF interactive mode. When you have finished entering Shell commands, type CTRL/Z. This will return you to PRF interactive mode. Your previous PRF option settings remain undisturbed by the intervening Shell commands. INIT[IALIZE] INIT[IALIZE] INIT[IALIZE] Reset PRF parameters to their default values. R[EAD] [printer] R[EAD] [printer] R[EAD] [printer] List entries in the queue for the specified printer at the current site (as specified by -S). If 'printer' is omitted, then the contents of the queue (determined by the current setting of -PR) are listed. WD [pathname] WD [pathname] WD [pathname] Execute the Shell command WD (WORKING_DIRECTORY) to set or display the working directory. GET option GET option GET option Display the value of the PRF option specified. Use this command to show the settings of the various PRF parameters. CAN[CEL] [queued_filename] CAN[CEL] [queued_filename] CAN[CEL] [queued_filename] Cancel printing of the specified file at the current site (as specified by -S). Note that you must specify the pathname which PRF assigns when the file is queued (which may differ from the name of your original file). Use the READ command to display the names of currently queued files. If the filename is omitted, the last file to be queued by this process is cancelled. This command is only effective for files which have not yet physically begun to print. EXAMPLES 1. $ prf mary -npag -ftn Queue "mary"; suppress "//NODE1/MY_DIR/MARY" queued for printing. pagination; force $ FORTRAN carriage 2. $ prf filex -s //tape "//NODE1/MY_DIR/TEST_FILE.PAS" queued for printing at site //TAPE. $ Queue "filex" to the printer queue on the node called //tape. 3. Configuration File: the following commands might appear in the default PRF configuration file ~USER_DATA/PRF.DB. PR ge SITE //rye FOOT %/my_file/& 4. Sample interactive session: $ PRF -INTER PRF> get pr pr = p PRF> -pr cx PRF> get pr pr = cx PRF> -pitch 20 PRF> print test_file.pas "//NODE1/MY_DIR/TEST_FILE.PAS" queued for printing. PRF> q $ 5. Running PRF from an icon: If you would like to run PRF interactively in a process devoted to it, you might place the following command in your ~USER_DATA/STARTUP_DM file: cp -i -c 'P' /com/prf -inter -n print_file This will create a PRF process and turn its window into an icon using the print icon character in (/SYS/DM/FONTS/ICONS). Issue the DM command ICON to change the icon window into its full-size format. RELATED TOPICS More information is available. Type: - HELP PRFD for information on the menu-based version of this command. - HELP PRINTER for general information about printers supported in a DOMAIN network. - HELP PRSVR for details about the Print Server. End of prf.toshiba.hlp echo toshiba.config 1>&2 cat >toshiba.config <<'End of toshiba.config' PAGE_WIDTH 132 PAGE_LENGTH 66 PAGENO_COLUMN 120 FILE_BANNERS OFF DEVICE user1 SIO_LINE 2 SPEED 9600 TOP_MARGIN 2 BOTTOM_MARGIN 2 FORM_FEEDS 0 PLOT_MODE ON RESOLUTION 180 End of toshiba.config echo user1.ins.pas 1>&2 cat >user1.ins.pas <<'End of user1.ins.pas' { PRSVR.INS.PAS, us/com/print, gtr, 05/09/83 Print server routines and associated data types which are exported for user supplied device drivers. Changes: 03/30/85 jjm updated for sr9 release 04/09/84 jjm update to sr8 05/09/83 gtr original coding -------------------------------------------------------------------------- | THE FOLLOWING PROGRAMS ARE THE SOLE PROPERTY OF APOLLO COMPUTER INC. | | AND CONTAIN ITS PROPRIETARY AND CONFIDENTIAL INFORMATION. | -------------------------------------------------------------------------- } CONST pr_$bufsize = 2048 ; TYPE pr_$buf_t = ARRAY [1..pr_$bufsize] OF char ; pr_$t = (pr_$user1, pr_$user2, pr_$user3, pr_$user4) ; pr_$set_op_t = ( pr_$font_weight, pr_$font_size, pr_$text_precision, pr_$data_format, pr_$pitch, pr_$y_dimension, pr_$x_dimension, pr_$rep_factor, pr_$config, pr_$copies, pr_$server_db ); pr_$inq_op_t = ( pr_$bpi, pr_$rep_ability, pr_$driver_db ); pr_$font_weight_t = ( pr_$light, pr_$medium, pr_$bold ); pr_$text_precision_t = ( pr_$draft, pr_$letter_quality ); pr_$data_format_t = ( pr_$text, pr_$plot, pr_$transparent ); prsvr_color_format_t = (none, {not a color printer} pixel, {color map format} scan_line_rgb,{3 plane formats} scan_line_ymc, plane_rgb, plane_ymc ); {this tells the server how to send bitmap data} pr_$interface_t = ( pr_$serial, pr_$parallel, pr_$external, pr_$versatec, pr_$multibus); {This data base is set up by PRSVR based on PRF options specified by the user and information the driver passes to PRSVR via the driver database (driver_db_t). To use this database, set up a record in your driver of type server_db_t. The setmode call will pass a pointer to this database as it exists in PRSVR.} server_db_t = RECORD copies : binteger; print_mode : pr_$data_format_t; cpi : real; {characters per inch} lpi : real; {lines per inch} weight : pr_$font_weight_t; lq : boolean; resolution : pinteger; {set the printer to print at this resolution} magnification : integer; {set the printer to magnify a bitmap by this amount} bitmap_size : RECORD x : integer; {the number of bits PRSVR will send} y : integer; planes : integer; {bits per pixel} END; color : boolean; {this file should be printed in color} bw_rev : boolean; {set if user requests it and the printer can do it } END; server_db_ptr_t = ^server_db_t; {this points you to the PRSVR server_db} {Use this database to pass PRSVR information about the driver and printers capabilities. PRSVR will issue a return_info call at startup, requesting this information. When the operation type of this call = pr_$driver_db , pass the PRSVR program the pointer to your driver database} driver_db_t = RECORD {information about the printer that the driver supplies} valid : boolean; { set this to true } copies : boolean; {does the printer do multiple copies} cpi : ARRAY [1..10] OF real; {an array of character spacings} lpi : ARRAY [1..10] OF real; resolution : ARRAY [1..4] OF pinteger; { the printer plots at these resolutions} res_min : pinteger; {a range of resolutions from minimum ...} res_max : pinteger; {... to maximum} magnification : ARRAY [1..16] OF binteger; color_format : prsvr_color_format_t; {tell prsvr how to send color images} bw_rev : boolean; {set if the printer can bw reverse image} END; driver_db_ptr_t = ^driver_db_t; {this tells PRSVR where to find your driver database} pr_$data_rec_t = packed RECORD font_weight : pr_$font_weight_t ; font_size : real ; text_precision : pr_$text_precision_t ; bpi : RECORD x : integer ; y : integer ; END; data_format: pr_$data_format_t; pitch : real ; x_dimension : pinteger ; y_dimension : pinteger ; rep_factor : pinteger; rep_ability : boolean; copies : pinteger; interface: pr_$interface_t; server_db_ptr : server_db_ptr_t; driver_db_ptr : driver_db_ptr_t; END ; %eject ; End of user1.ins.pas echo user1.toshiba.bld 1>&2 cat >user1.toshiba.bld <<'End of user1.toshiba.bld' #################################################################################### ### ### ### Command file for Compiling and Binding the Toshiba 1351 Print Server ### ### ### #################################################################################### von pas user1.toshiba.pas -cpu any -optall -opt bind -b prsvr.user1.toshiba /com/prsvr user1.toshiba.bin voff End of user1.toshiba.bld echo user1.toshiba.doc 1>&2 cat >user1.toshiba.doc <<'End of user1.toshiba.doc' ******************************************************************************* ***** ***** ***** USER1.TOSHIBA.DOC ***** ***** Version 6 ***** ***** ***** ***** Programming Notes for the Toshiba P1351 Print Server ***** ***** ***** ***** Copyright (c) 1986 ***** ***** David M. Krowitz ***** ***** Massachusetts Institute of Technology ***** ***** Department of Earth, Atmosheric, and Planetary Sciences ***** ******************************************************************************* The Toshiba P1351 printer ------------------------- The Toshiba P1351 printer is a high quality, high speed (192 characters per second) dot-matrix printer which retails for less than $2000. It offers three built-in fonts - one high speed and two near letter quality fonts - and two user definable fonts. The printer has a 24 pin print-head which gives excellent output. Even the high speed font provides better quality output than most other printers provide. The printer also has the capability to print full bitmap graphics printing at a density of 180 by 180 dots per inch - almost twice the resolution of the Apollo's display. In graphics mode, the Toshiba prints 24 scan lines of up to 2448 dots on each pass of the print-head across the paper, and it will print with the print-head moving in either direction which speeds the printing process. Interfacing the Printer with the Apollo --------------------------------------- We have interfaced our Toshiba P1351 printer to an Apollo DN320 using a 3-wire RS232-C null modem cable. The wiring of the cable is: pin 2 - pin 3, pin 3 - pin 2, and pin 7 - pin 7 (ie. cross the data receive and data transmit wires, and connect the signal ground wire). We are using the X-ON/X-OFF protocal to control the flow of data between the Apollo and the printer rather than using the DTR and CTS signals in the RS232-C cable. The SIO line characteristics necessary to run the printer using X-ON/X-OFF are set up in the routine USER1_INIT. It is also necessary to change some of the internal jumpers in the Toshiba printer in order to use the 3-wire cable. The jumpers that we change are located on the left-center area of the printed circuit board in the back of the printer. The printer's cover must be removed to reach this board. The dip switches for setting the printer's baud rate, even or odd parity, 7 or 8 bits per characters, number of stop bits, etc. are also located on this board, so it is necessary to get to this board even if you plan on using the DTR and CTS signals rather than X-ON/X-OFF. The printer is shipped with the jumpers in the following configuration: pin 2 - pin 15, pin 13 - pin 14, pin 11 - pin 12, pin 7 - pin 10, and pin 8 - pin 9. To turn off the use of DTR and CTS, we change pin 2 - pin 15 to be pin 1 - pin 2 and we also change pin 7 - pin 10 to be pin 6 - pin 7. A diagram of the jumper plug configuration has been enclosed showing the altered positions in dashed lines. Description of the Print Server Routines ---------------------------------------- The Toshiba print server program consists of six main subroutines (procedures) which are compiled and then bound to the standard print server program (/COM/PRSVR) supplied by Apollo. The subroutines are: USER1_INIT, USER1_WRITE, USER1_FLUSH, USER1_CLOSE, USER1_SET_MODE, and USER1_RETURN_INFO. Section 6.5 of The DOMAIN System Administrator's Guide gives a general description of the standard print server supplied by Apollo and the steps needed to generate a print server for a printer other than those supported by Apollo. The arguments to the user-supplied subroutines and the format of the data passed to the subroutines are defined in the Apollo supplied insert files /SYS/INS/PRSVR.INS.PAS or /SYS/INS/PRSVR.INS.C which, while defining the options and data types doesn't really tell you what these various options are supposed to do. To get that information, you either have to call Apollo or you just have to play with the print server for awhile and see how it responds to your poking and prying. Unfortunately for those of you who program in Fortran, there is no insert file for that language - you just have to learn Pascal. The USER1_INIT subroutine is called once by the print server when it starts up. The subroutine is given the line number of the SIO line to which the printer is connected and the baud rate of that SIO line. Both of these numbers are read from the printer configuration file (TOSHIBA.CONFIG) by the print server at startup time. The USER1_INIT subroutine opens the specified SIO line for stream output and then sets the necessary SIO line characteristics. These include the use of X-ON/X-OFF by both the Apollo node and the printer (input_sync and host_sync), turning off the echoing of characters which the printer may send to the host (something which is never really done except for X-ON and X-OFF), disabling the quit character on the SIO line (so if the printer accidentally glitches it can't kill the print server process), and the parity, number of bits per character, and number of stop bits of the characters being transmitted. After defining the SIO line for the printer, USER1_INIT also initializes several strings of control characters for the printer, and resets the graphics buffer counter. Finally, USER1_INIT sends the printer-init command to the Toshiba to make sure the printer is correctly initialized. Note that the printer-init command also sets the top-of-page to the current position of the paper, so the paper should be correctly position in the printer before starting the print server. The USER1_WRITE subroutine does most of the work of the print server. This subroutine is called from the print server to perform the actual output of the data to the Toshiba printer. The subroutine is given a buffer of up to 2048 characters and a buffer length. In practice, I have never seen the buffer length exceed 256 bytes. The USER1_WRITE subroutine checks the current printer output mode and then outputs the contents of the buffer according to the mode. The mode is set by the print server calling the USER1_SET_MODE subroutine prior to the first call to USER1_WRITE for the current output file. There are three possible output modes: 'text', 'transparent', and 'plot'. If the current output mode is 'text' (ie. a PRF command with no -PLOT or -TRANSPARENT switches), the print server keeps track of the current page and line counts and prints a page header and and page number at the top of each page. The print server calls USER1_WRITE one time for each buffer of text to be printed and simply inserts an extra call to USER1_WRITE at the top of each page to print the page header and page number. All that USER1_WRITE has to do in text mode is to dump the buffer to the printer. If the -WEIGHT option of the PRF command was 'light' or 'medium', USER1_WRITE just dumps the buffer straight to the printer. If the -WEIGHT option was 'bold', then USER1_WRITE prints each of the printable characters in the buffer twice (of course characters such as tabs, line feeds, and carriage returns which are in the buffer are only sent once to the printer). The default for the -WEIGHT option of the PRF command is 'medium'. Note that the documentation for the print server in the System Administrator's Guide does not guarantee that the buffer sent to USER1_WRITE will contain a complete output line or that it will contain only a single line of output to be printed. The code for printing each line with the 'bold' option is somewhat more complicated because of this. If the current output mode is 'transparent' (ie. a PRF -TRANSPARENT command), the print server sends the contents of the output file to the printer with no modifications. USER1_WRITE is called once for each buffer of output (same as with 'text' mode), but no page headers are inserted into the output stream. In this output mode USER1_WRITE does nothing except to dump the buffer to the Toshiba's output stream. If the current output mode is 'plot' (ie. a PRF -PLOT command), the print server checks that the output file is a GMF bitmap file, calls USER1_SET_MODE to set the size of the bitmap, and then calls USER1_WRITE once for each horizontal scan line in the bitmap. The print server will not attempt to print bitmap files unless the PLOT_MODE switch in the printer's configuration file (ie. TOSHIBA.CONFIG -- which is specified on the command line which started the print server) is set to ON. The print server will try to automatically scale the bitmap so that it is roughly the same size on the printed page as it is on the display screen of the Apollo. (I am assuming that the bitmap was created from a dump from the screen. Actually, the print server checks the bits-per-inch at which the bitmap was created and compares that against the bit-per-inch of the printer and then tries to scale the bitmap to the closest integer factor. The bits-per-inch of the printer is defined in the USER1_RETURN_INFO subroutine. You can define the bit-per-inch at which the bitmap is created through one of the GPR or GMR calls.) Since the Toshiba printer's resolution (180 bpi) is roughly twice that of the Apollo's display screen, the print server will replace each bit in the bitmap with a two dot by two dot block on the printer. This results in the print server calling USER1_WRITE twice as many times as the Y_BITMAP_SIZE with buffers containg twice as many bits as the X_BITMAP_SIZE. The -MAGNIFICATION option of the PRF command can be used to control the scaling of the bitmap by the print server. The default value (0) will cause the print server to try to scale the bitmap to the same size that it was on the screen (this results in a two to one scaling on the printer). In this case, the print server will simply tell the USER1_SET_MODE routine that the bitmap is twice the size of the bitmap on the screen and it will scale the bitmap before passing the data to the USER1_WRITE routine for printing. Since the Toshiba prints 24 horizontal scan line on each pass, the USER1_WRITE routine buffers up 24 complete scan lines, padding short lines with zeros, before dumping the buffer to the printer. Lines which are longer than the maximum printable by the Toshiba (2448 dots across the page) are truncated to the maximum length which can be printed. If the user has requested the bitmap to be inverted (ie. black and white reversed), then each byte of the scan line is inverted as it is buffered. The bits in each of the horizontal scan lines sent to USER1_WRITE by the print server are packed 8 bits to each byte, the high order bit of the byte being the leftmost bit on the scan line. Since the Toshiba printer (along with most other dot matrix printers) wants to print one complete vertical column of bits at a time, it is necessary to repack the bits in the scan lines which have been buffered before they can be sent to the printer. USER1_WRITE calls the WRITE_PLOT_BUFFER routine to repack the bits and output the repacked buffer to the printer. The Toshiba takes four 8-bit bytes for each column of 24 bits which it prints. Each byte contains 6 of the 24 bits in its low order. The highest order bit of the first byte is at the top of the column and the lowest order bit of the fourth byte is at the bottom of the column. See the enclosed pages from the Toshiba printer manual for a description of the bitmap graphics mode of the 1351 printer. The two high order bits of each byte are not printed, but we have found that certain sequences of bytes in the stream of bitmap data being sent to the printer will cause the printer to drop out of bitmap graphics mode. To avoid these sequences, we set the two non-printing high order bits of each byte to 1 before dumping the repacked bitmap buffer to the printer's output stream. The WRITE_PLOT_BUFFER subroutine also attempts to speed up the output process by stripping zero bytes off of the ending the buffer to avoid the expense of having to repack and transmit these bytes. (Note that a buffer of scan lines of 1024 bits requires 4098 bytes to be sent to the printer - which takes almost 4 seconds to do at 9600 baud.) Finally, the WRITE_PLOT_BUFFER subroutine checks the ratio of black pixels to the total number of pixels in the buffer. If it exceeds the duty cycle limit of the printer (currently set to 50% for any given 200 pixel wide segment), the buffer is printed in two passes across the page using a checkerboard pattern to avoid overheating the Toshiba's print-head. The Toshiba printer will actually shut itself off if it trys to print a bitmap with too many black pixels in it, so there is not much danger to the printer if this technique fails. We just try to avoid having the printer shut down in the middle of a plot. The USER1_SET_MODE subroutine is called by the printer server prior to the output of each file being printed to set the proper printer output mode and to such things as the bitmap size (for plot mode files). The print server may also call USER1_SET_MODE after the end of an output file to reset the printer mode or to change the printer mode to 'text' so it can output a top-of-page command (ie. a form feed) after finishing the printing of a bitmap. Note that we can not use the Toshiba's printer-init command to reset the printer's mode to the default text mode. This is because the printer-init command resets the printer's top-of-page to the current paper position, and the print server may call USER1_SET_MODE at any point on the page. The USER1_FLUSH subroutine is called once at the end of each file output by the print server and also in between changing printer output modes. This routine checks if the printer is 'plot' and also checks if there is a partially full buffer of bitmap data. If this is the case, USER1_FLUSH will call USER1_WRITE with a dummy output buffer to force the output of the final buffer of the bitmap data. USER1_FLUSH then resets all of the page, line, and buffer counters used during the output of the file. The USER1_CLOSE subroutine is only called when the print server is stopping permanently (as opposed to waiting between files). All that it does is to close the printer's output stream. Changes Since Version 1 ----------------------- Version 5 of the Toshiba USER1 routines is compatible with the AEGIS SR9.0 version of PRSVR. It should also be backwards compatible with the SR8.0 version of the print server. The buffer repacking algorithm for printing GMF bitmap files has been improved. The new algorithm is faster and it also correctly handles bitmaps which are wider than the page (the bitmap is truncated to the width of the page). The printing of GMF bitmap files is now done with unidirectional printing (left to right on all lines) in order to get vertical line segments to line up better. The Toshiba 1351 printer has no unidirectional/bidirectional printing control, but by sending a non-printing graphics sequence the printer's print-head is forced to return to the left margin of each line before beginning to print the next line of the bitmap. The duty cycle checking of the printer has been improved. Now each 200 pixel wide segment of the bitmap is checked independently. Previously, it was possible for a short segment of the bitmap to be completely black and the rest of the line to be blank. This would result in the printer shutting down during the printing of the black segment even though the duty cyle limit was set as low as 15%. Now, any particular segment of 200 (wide) by 24 (high) pixels can have a duty cycle (ratio of black pixels to the total number of pixels) as high as 50% without the printer shutting itself off. Lines which contain any segment which exceeds the 50% duty cycle limit will be printed in two passes in order to prevent the printer from overheating its print head. If the -LQ option of the PRF command (letter quality printing) is used the printer will now switch to printing with its built in font #1 (high quality Elite) from its default font (which is usually font #0 - the high speed font). If the -WEIGHT option of the PRF command is used with the 'bold' value, each printing character in the output will be printed twice in order to make the output darker. If the 'light' or 'medium' values are used with the -WEIGHT option then the characters are only printed once (as is normal). The default value of the weight option is 'medium'. The -PITCH option of the PRF command can now be used to select printing in 5, 6, 10, or 12 characters per inch for both the high speed font ('draft mode') and the high quality Elite font ('letter quality mode'). The high speed font is also available in a compressed font at 16.7 and 20 characters per inch. The high quality Elite font is not available at these high densities and will be printed at 10 or 12 characters per inch if the -LQ (letter quality) option is selected along with a -PITCH option of 16.7 or 20 characters per inch, respectively. The default character pitch is 10 characters per inch for both the high speed and the Elite fonts. The -MAGNIFICATION option of the PRF command can now be used to control the scaling of bitmaps printed on the Toshiba. The default magnification value (0) causes the print server to try to make the bitmap the same size on the printer as it was on the screen of the Apollo. Since the Toshiba's 180 dot per inch resolution is approximately twice that of the Apollo's screen the print server will double each pixel of the bitmap before printing it. Giving the PRF command a magnification value of 1 will cause the bitmap to be printed without any scaling on the printer, a value of 2 will cause the bitmap to be doubled in size (same as the default automatic scaling), a value of 3 will cause the bitmap to be tripled in size, etc. The USER1_INIT routine now reports any errors which it encounters while attempting to set up the SIO line for the printer. Seperate error messages are generated for each SIO line parameter to aid in locating any problems with the SIO line. Changes Since Version 5 ----------------------- The -BW_REV option of the PRF command can now be used to invert a GMF bitmap before it is printed. Areas of the bitmap which are normally white will be printed as black and vice versa. Files Needed to Build the Print Server -------------------------------------- The files which are provided for the Toshiba 1351 print server are: USER1.TOSHIBA.DOC - This file. USER1.TOSHIBA.DOC.INSTALL - Notes on how to install the print server. PRF.TOSHIBA.HLP - An edited version of the standard Apollo help file for the PRF command (/SYS/HELP/PRF.HLP) with notes included for the Toshiba printer. USER1.TOSHIBA.PAS - The Pascal sources for the print server. USER1.INS.PAS - An edited version of the standard Apollo insert file, /SYS/INS/PRSVR.INS.PAS, which is used by USER1.TOSHIBA.PAS to define the data types and structures used by the print server. USER1.TOSHIBA.BLD - A shell script file for compiling the USER1 routines (and their subroutines) and binding them with the Apollo supplied print server. TOSHIBA.CONFIG - The configuration file for the Toshiba printer to be given as an argument to the print server when it is started. PRSVR.USER1.TOSHIBA - A ready to run Toshiba print server. Just in case you don't have a Pascal compiler. This is the file which is produced by USER1.BLD. You will also need the following standard Apollo-supplied files: /SYS/INS/BASE.INS.PAS - These are all standard insert files which /SYS/INS/SIO.INS.PAS are used by USER1.TOSHIBA.PAS. /SYS/INS/STREAMS.INS.PAS /SYS/INS/PGM.INS.PAS /COM/PRSVR - The standard Apollo print server which must be bound with the Toshiba routines to produce a working print server. Used in USER1.BLD to produce PRSVR.USER1.TOSHIBA. Bugs, Questions, and Improvements --------------------------------- If you find a bugs in the print server, have questions on how to install or use it, or have a good idea for improving the program please feel free to contact me at the address below. David M. Krowitz MIT dept. of Earth, Atmospheric, and Planetary Sciences Room 54-527 Cambridge, MA 02139 (617) 253-6180 ARPA net mailing adress: DAVID@MIT-MC.ARPA or KROWITZ%MIT-MARIE@MIT-MC.ARPA End of user1.toshiba.doc echo user1.toshiba.doc.install 1>&2 cat >user1.toshiba.doc.install <<'End of user1.toshiba.doc.install' ******************************************************************************* ***** ***** ***** USER1.TOSHIBA.DOC.INSTALL ***** ***** Version 5 ***** ***** Installing the Toshiba P1351 Print Server ***** ***** ***** ***** Copyright (c) 1986 ***** ***** David M. Krowitz ***** ***** Massachusetts Institute of Technology ***** ***** Department of Earth, Atmosheric, and Planetary Sciences ***** ******************************************************************************* Read the general installation and documentation notes in USER1.TOSHIBA.DOC if you have not already done so. Then use the shell script file USER1.TOSHIBA.BLD to compile the Toshiba device-driver routines and to bind them to the standard Apollo printer server located in /COM/PRSVR. This will create the Toshiba 1351 version of the print server (PRSVR.USER1.TOSHIBA) in you working directory. Then edit the print server configuration file (TOSHIBA.CONFIG) and make sure it contains the proper SIO line number and baud rate for your installation. Next copy the new print server (PRSVR.USER1.TOSHIBA) and the print server configuration file (TOSHIBA.CONFIG) to the system directory from which you normally run the print server on your system. /COM or /SYS/NODE_DATA are two common directories which we use. You can then run the print server using the command: /COM/PRSVR.USER1.TOSHIBA /COM/TOSHIBA.CONFIG (assuming the files are stored in /COM). This will run the server in the current window. The server will be stopped when you log out. If you want to run the print server automatically when the system is brought up, add the following command line to your installation's startup file in /SYS/NODE_DATA: ### ### To startup user-defined print server for the Toshiba 1351 printer ### CPS /COM/PRSVR.USER1.TOSHIBA -N PRINT_SERVER /COM/TOSHIBA.CONFIG (again, assuming the files are kept in /COM). This will run the print server automatically when the node is brought up and will give it the process a server status so that you can logout and leave the print server running for other users on the network. Apollo's standard print server (and the Toshiba version) looks for files to be printed in the /SYS/PRINT directory of the node on which the print server is running. If you want files from other nodes on the network to be automatically printed on the Toshiba you should delete the /SYS/PRINT directories on those nodes and replace them with links to the /SYS/PRINT directory on the node running the print server. Otherwise, users can use the command: PRF -S //NODE_NAME to have the PRF command send the file to the node which has the printer attached to it. More information on the installation and use of print servers can be found in The Domain System Administrator's Guide, section 6.5 (Peripheral Servers). End of user1.toshiba.doc.install echo user1.toshiba.pas 1>&2 cat >user1.toshiba.pas <<'End of user1.toshiba.pas' {***************************************************************************** ***** ***** ***** USER1.TOSHIBA.PAS ***** ***** ***** ***** Serial Printer Driver for the Toshiba P1351 dot-matrix printer ***** ***** Version 6 ***** ***** David M. Krowitz February 10, 1986. ***** ***** ***** ***** Copyright (c) 1986 ***** ***** David M. Krowitz ***** ***** Massachusetts Institute of Technology ***** ***** Department of Earth, Atmosheric, and Planetary Sciences ***** ***************************************************************************** } MODULE USER1_TOSHIBA; %NOLIST; %INSERT '/sys/ins/base.ins.pas'; %INSERT '/sys/ins/sio.ins.pas'; %INSERT '/sys/ins/streams.ins.pas'; %INSERT '/sys/ins/pgm.ins.pas'; %INSERT 'user1.ins.pas'; %LIST; CONST {Definitions of standard ascii control characters} nul = chr(0); {null character} bs = chr(8); {backspace (control-H)} tab = chr(9); {tab (control-I)} lf = chr(10); {line feed (control-J)} vt = chr(11); {vertical tab (control-K)} ff = chr(12); {form feed (control-L)} cr = chr(13); {carriage return (control-M)} sub = chr(26); {sub (control-Z)} esc = chr(27); {escape} rs = chr(30); {rs} {Define maximum bitmap size which can be printed} max_bitmap_size = 2448; {maximum number of pixels across the page} max_buffer_size = 306; {maximum buffer size to hold bitmap (2448/8)} TYPE str1_t = packed array[1..1] of char; str2_t = packed array[1..2] of char; str3_t = packed array[1..3] of char; str4_t = packed array[1..4] of char; str5_t = packed array[1..5] of char; str6_t = packed array[1..6] of char; str7_t = packed array[1..7] of char; str8_t = packed array[1..8] of char; str9_t = packed array[1..9] of char; bitmap_buffer_t = packed array[1..24,1..max_buffer_size] of char; print_buffer_t = packed array[1..max_bitmap_size,1..4] of char; VAR {Definitions of control sequences for the Toshiba 1351 printer} init_printer: str3_t; {initialize printer characteristics} elongated_on: str2_t; {start printing elongated (double width) characters} elongated_off: str2_t; {start printing normal width characters} condense_on: str2_t; {start printing condensed width characters} condense_off: str2_t; {start printing normal width characters} pitch10: str4_t; {use 10 characters per inch when printing} pitch12: str4_t; {use 12 characters per inch when printing} font_0: str3_t; {select font 0 - resident high speed font} font_1: str3_t; {select font 1 - resident high quality Elite font} font_2: str3_t; {select font 2 - resident high quality Courier font} {*** Note: the Toshiba 1351 has no font 3 ***} font_4: str3_t; {select font 4 - non-resident high quality font} font_5: str3_t; {select font 5 - non-resident high quality font} image_data: str6_t; {start 24 pin by nnnn column bit map image transfer} text_vert_spacing: str3_t; {set vertical spacing to 2/15" for bit map graphics} plot_vert_spacing: str3_t; {set vertical spacing to 1/6" for default text size} crlf: str2_t; {carriage-return, line-feed sequence} column0: str6_t; {forces print head to column 0 for uni-directional printing} {Defintions of global variables} x_bitmap_size: pinteger; {x dimension of GMR bit map being printed} y_bitmap_size: pinteger; {y dimension of GMR bit map being printed} scale_factor: pinteger; {factor by which bitmap has been scaled up by top-level routines} bitmap_buffer: bitmap_buffer_t; {buffer of 24 lines of 2448 bits to hold data for one pass of the Toshiba printer's print-head} bcount: pinteger; {count of number of buffers of GMR data} invert_image: boolean; {TRUE if user requested black/white reversed for bitmap} plot_flag: boolean; {TRUE if we have been printing a bitmap} trans_flag: boolean; {TRUE if we have been printing in transparent mode} printer_mode: pr_$data_format_t; {printer mode: text, transparent, or plot} font_number: pinteger; {Number of font in use for TEXT mode printing} print_repeat: pinteger; {Number of times to print a line for bold (2), medium (1), or light (1) printing} server_ptr: server_db_ptr_t; {pointer to database set up by server} driver_ptr: driver_db_ptr_t; {pointer to database of Toshiba's abilities} stream_id: stream_$id_t; {stream id returned by STREAM_$OPEN} status: status_$t; {status returned by SIO and STREAM calls} seek_key: stream_$SK_t; {seek_key returned by STREAM calls} testmask: array[1..8] of integer; {Constants for testing bits in a byte} setmask: array[1..6] of integer; {Constants for setting bits in a byte} PROCEDURE USER1_INIT ( IN sio_line: integer; IN sio_speed: UNIV sio_$value_t ); VAR sioname: array[1..3] of str9_t; {names of SIO lines for STREAM_$OPEN call} i,j: pinteger; {counters} BEGIN {Open I/O stream and set SIO line characteristics} sioname[1] := '/dev/sio1'; sioname[2] := '/dev/sio2'; sioname[3] := '/dev/sio3'; stream_$open (sioname[sio_line],9,stream_$append,stream_$no_conc_write, stream_id,status); IF (status.fail = TRUE) THEN BEGIN WRITELN ('**** USER1_INIT: Error - could not open output stream: ', sioname[sio_line],' ****'); PGM_$EXIT; END; sio_$control (stream_id,sio_$speed,sio_speed,status); IF (status.fail = TRUE) THEN BEGIN WRITELN ('**** USER1_INIT: Error - could not set SIO_$SPEED: ', sioname[sio_line],' ****'); PGM_$EXIT; END; sio_$control (stream_id,sio_$no_nl,false,status); IF (status.fail = TRUE) THEN BEGIN WRITELN ('**** USER1_INIT: Error - could not set SIO_$NO_NL off: ', sioname[sio_line],' ****'); PGM_$EXIT; END; sio_$control (stream_id,sio_$nlc_delay,0,status); IF (status.fail = TRUE) THEN BEGIN WRITELN ('**** USER1_INIT: Error - could not set SIO_$NLC_DELAY to 0: ', sioname[sio_line],' ****'); PGM_$EXIT; END; sio_$control (stream_id,sio_$input_sync,true,status); IF (status.fail = TRUE) THEN BEGIN WRITELN ('**** USER1_INIT: Error - could not set SIO_$INPUT_SYNC on: ', sioname[sio_line],' ****'); PGM_$EXIT; END; sio_$control (stream_id,sio_$host_sync,true,status); IF (status.fail = TRUE) THEN BEGIN WRITELN ('**** USER1_INIT: Error - could not set SIO_$HOST_SYNC on: ', sioname[sio_line],' ****'); PGM_$EXIT; END; sio_$control (stream_id,sio_$no_echo,true,status); IF (status.fail = TRUE) THEN BEGIN WRITELN ('**** USER1_INIT: Error - could not set SIO_$NO_ECHO on: ', sioname[sio_line],' ****'); PGM_$EXIT; END; sio_$control (stream_id,sio_$cts_enable,false,status); IF (status.fail = TRUE) THEN BEGIN WRITELN ('**** USER1_INIT: Error - could not set SIO_$CTS_ENABLE off: ', sioname[sio_line],' ****'); PGM_$EXIT; END; sio_$control (stream_id,sio_$quit_enable,false,status); IF (status.fail = TRUE) THEN BEGIN WRITELN ('**** USER1_INIT: Error - could not set SIO_$QUIT_ENABLE off: ', sioname[sio_line],' ****'); PGM_$EXIT; END; sio_$control (stream_id,sio_$parity,sio_$even_parity,status); IF (status.fail = TRUE) THEN BEGIN WRITELN ('**** USER1_INIT: Error - could not set SIO_$PARITY even: ', sioname[sio_line],' ****'); PGM_$EXIT; END; sio_$control (stream_id,sio_$bits_per_char,sio_$8bpc,status); IF (status.fail = TRUE) THEN BEGIN WRITELN ('**** USER1_INIT: Error - could not set SIO_$BPC to 8 bits/char: ', sioname[sio_line],' ****'); PGM_$EXIT; END; sio_$control (stream_id,sio_$stop_bits,sio_$stop_1,status); IF (status.fail = TRUE) THEN BEGIN WRITELN ('**** USER1_INIT: Error - could not set SIO_$STOP to 1 stop bit: ', sioname[sio_line],' ****'); PGM_$EXIT; END; {Initialize strings of control characters for printer} init_printer[1] := esc; init_printer[2] := sub; init_printer[3] := 'I'; elongated_on[1] := esc; elongated_on[2] := '!'; elongated_off[1] := esc; elongated_off[2] := '"'; condense_on[1] := esc; condense_on[2] := '['; condense_off[1] := esc; condense_off[2] := ']'; pitch10[1] := esc; {Set horizontal spacing to 12/120" (10 char/inch)} pitch10[2] := 'E'; pitch10[3] := '1'; pitch10[4] := '2'; pitch12[1] := esc; {Set horizontal spacing to 10/120" (12 char/inch)} pitch12[2] := 'E'; pitch12[3] := '1'; pitch12[4] := '0'; font_0[1] := esc; font_0[2] := '*'; font_0[3] := '0'; font_1[1] := esc; font_1[2] := '*'; font_1[3] := '1'; font_2[1] := esc; font_2[2] := '*'; font_2[3] := '2'; font_4[1] := esc; font_4[2] := '*'; font_4[3] := '4'; font_5[1] := esc; font_5[2] := '*'; font_5[3] := '5'; image_data[1] := esc; image_data[2] := ';'; image_data[3] := '0'; image_data[4] := '0'; image_data[5] := '0'; image_data[6] := '0'; plot_vert_spacing[1] := esc; plot_vert_spacing[2] := rs; plot_vert_spacing[3] := chr(8); text_vert_spacing[1] := esc; text_vert_spacing[2] := rs; text_vert_spacing[3] := chr(9); crlf[1] := cr; crlf[2] := lf; column0[1] := esc; {To force print head to left margin: Go into graphics} column0[2] := '='; { character print mode, print a blank character, exit} column0[3] := chr(16#E0); { graphics mode, and do a carriage return. Printing a} column0[4] := esc; { space character will not force the print head to the} column0[5] := '?'; { left margin. It only updates the 'print position',} column0[6] := cr; { ie. it only updates the buffer position} {Initialize the graphics output variables} bcount := 0; {No scan lines of graphics output waiting to be printed} scale_factor := 1; {Doesn't seem to be used in SR9.0 so must init ourselves for SR8 compatibility} invert_image := FALSE; {Do normal bitmap printing (not b/w reversed)} plot_flag := FALSE; {Not printing a bitmap right now} trans_flag := FALSE; {Not printing in transparent mode, either} {Initialize bit testing and bit setting masks} testmask[1] := 16#80; testmask[2] := 16#40; testmask[3] := 16#20; testmask[4] := 16#10; testmask[5] := 16#08; testmask[6] := 16#04; testmask[7] := 16#02; testmask[8] := 16#01; setmask[1] := 16#20; setmask[2] := 16#10; setmask[3] := 16#08; setmask[4] := 16#04; setmask[5] := 16#02; setmask[6] := 16#01; {Initialize the printer settings} stream_$put_chr (stream_id,addr(init_printer),3,seek_key,status); printer_mode := pr_$text; END; {End of USER1_INIT} PROCEDURE USER1_WRITE ( IN buffer: UNIV pr_$buf_t; IN buffer_length: pinteger ); PROCEDURE USER1_WRITE_TEXT ( IN buffer: UNIV pr_$buf_t; IN buffer_length: pinteger ); VAR output_buffer: pr_$buf_t; output_length: pinteger; i,j,k: pinteger; BEGIN IF (print_repeat = 1) THEN BEGIN {If printing weight is 'light' or 'medium' print buffer once.} stream_$put_chr (stream_id,addr(buffer),buffer_length, seek_key,status); END ELSE BEGIN {If printing weight is 'bold' print buffer twice.} output_length := 0; FOR i := 1 TO buffer_length DO BEGIN IF (buffer[i] IN [lf,vt,ff,cr,bs,tab]) THEN BEGIN IF (output_length <> 0) THEN BEGIN FOR j := 1 TO (print_repeat-1) DO BEGIN stream_$put_chr (stream_id,addr(output_buffer), output_length,seek_key,status); FOR k := 1 TO output_length DO BEGIN stream_$put_chr (stream_id,addr(bs),1, seek_key,status); END; stream_$put_chr (stream_id,addr(output_buffer), output_length,seek_key,status); END; output_length := 0; END; stream_$put_chr (stream_id,addr(buffer[i]),1, seek_key,status); END ELSE BEGIN output_length := output_length+1; output_buffer[output_length] := buffer[i]; END; END; IF (output_length <> 0) THEN BEGIN FOR j := 1 TO (print_repeat-1) DO BEGIN stream_$put_chr (stream_id,addr(output_buffer), output_length,seek_key,status); FOR k := 1 TO output_length DO BEGIN stream_$put_chr (stream_id,addr(bs),1, seek_key,status); END; stream_$put_chr (stream_id,addr(output_buffer), output_length,seek_key,status); END; END; END; END; {End of USER1_WRITE_TEXT} PROCEDURE USER1_WRITE_TRANSPARENT ( IN buffer: UNIV pr_$buf_t; IN buffer_length: pinteger ); BEGIN stream_$put_chr (stream_id,addr(buffer),buffer_length, seek_key,status); END; {End of USER1_WRITE_TRANSPARENT} PROCEDURE WRITE_PLOT_BUFFER ( IN buffer: bitmap_buffer_t; IN bitmap_length: pinteger ); VAR print_buffer: print_buffer_t; {Toshiba output buffer} print_buffer2: print_buffer_t; {Secondary buffer for high duty cycle} buffer_length: pinteger; {length of non-zero data in input buffer} data_length: pinteger; {length of non-zero data in print_buffer} i,j,k: pinteger; {index counters} ii,jj,kk: pinteger; {buffer subscript variables} iii,jjj,kkk: pinteger; {more buffer subscript variables} numbits: array [1..((max_bitmap_size div 200)+1)] of linteger; {# of bits set in each 200 column wide segment of the output buffer for checking duty-cycle} totalbits: linteger; {total # of bits in buffer segment} bit_value: pinteger; {value of bit being repacked} temp1: pinteger; {holds bits being repacked} temp2: pinteger; {tests bytes to see if repacking needed} BEGIN {Find end of the non-zero data in the input buffer. Don't want to waste time by having to repack a lot of zero bytes at the end of a line.} buffer_length := (((bitmap_length-1) div 8) +1); k := 0; REPEAT FOR j := 1 TO 24 DO BEGIN IF buffer[j,buffer_length] <> chr(0) THEN k := 1; END; IF k = 0 THEN buffer_length := buffer_length-1; UNTIL (k <> 0) OR (buffer_length = 0); {If the print buffer is all zeroes, then just output a carriage-return line-feed sequence. Otherwise, repack and print the non-zero portion of the printer buffer.} IF buffer_length = 0 THEN BEGIN stream_$put_chr (stream_id,addr(crlf),2, seek_key,status); END ELSE BEGIN {Repack the bitmap from 24 horizontal rows of BUFFER_LENGTH*8 bits (8 bits per byte) into BUFFER_LENGTH*8 columns of 4 bytes each (6 bits per byte). Note that the two high order bits in each byte must be set to 1 even though they are not printed. For some unknown reason, the Toshiba printer will drop out of image-data mode when certain character sequences are in the image-data stream. Setting the two high order bits avoids these sequences.} FOR i := 1 TO ((max_bitmap_size div 200)+1) DO numbits[i] := 0; FOR i := 1 TO buffer_length DO BEGIN ii := (i-1)*8; FOR j := 0 TO 3 DO BEGIN jj := j*6; jjj := j+1; {Check if 6 byte high by 8 bit wide section of bitmap is all zeros. If so, then we don't need to repack the bits in this section, we just set the output buffer to the correct constants. If the area is all ones, we also do not have to repack the bitmap, we just set the output buffer to a different constant.} temp2 := 0; FOR k := 1 TO 6 DO BEGIN temp2 := temp2+ord(buffer[(jj+k),i]); END; IF (temp2 = 0) THEN BEGIN FOR iii := 1 TO 8 DO BEGIN {Section is all zeros - don't need to repack} print_buffer[ii+iii,jjj] := chr(16#C0); END; END ELSE IF (temp2 <> 6*16#FF) THEN BEGIN FOR iii := 1 TO 8 DO BEGIN {Section is non-zero - repack bits} temp1 := 16#C0; {Init the high order bits} kk := ((ii+iii) div 200)+1; FOR k := 1 TO 6 DO BEGIN {Repack six bits into byte} bit_value := (ord(buffer[(jj+k),i])&testmask[iii]); IF bit_value <> 0 THEN BEGIN temp1 := temp1!setmask[k]; numbits[kk] := numbits[kk]+1; {Update duty-cycle count} END; END; print_buffer[ii+iii,jjj] := chr(temp1); {Put byte in output buffer} END; END ELSE BEGIN FOR iii := 1 TO 8 DO BEGIN {Section is all ones - don't need to repack} kk := ((ii+iii) div 200)+1; numbits[kk] := numbits[kk]+6; print_buffer[ii+iii,jjj] := chr(16#FF); END; END; END; END; {Find end of the non-zero data in the printer output buffer. Don't want to waste time by having to transmit a lot of zeroes at the end of a line.} IF buffer_length*8 < bitmap_length THEN BEGIN data_length := buffer_length*8; END ELSE BEGIN data_length := bitmap_length; END; k := 0; REPEAT FOR j := 1 TO 4 DO BEGIN IF print_buffer[data_length,j] <> chr(16#C0) THEN k := 1; END; IF k = 0 THEN data_length := data_length-1; UNTIL (k <> 0) OR (data_length = 0); {Set up the bitmap image data transfer header and output buffer.} image_data[3] := chr(ord('0')+((data_length mod 10000) div 1000)); image_data[4] := chr(ord('0')+((data_length mod 1000) div 100)); image_data[5] := chr(ord('0')+((data_length mod 100) div 10)); image_data[6] := chr(ord('0')+((data_length mod 10) div 1)); {Check if printer's duty cycle is greater than 40% in any segment of 200 consecutive columns or more. If the duty cycle is greater than 40%, then output the buffer in two passes to avoid overheating the Toshiba's print-head. The printer will actually shut itself off if the duty cycle is too high. The checkerboard pattern used to print the buffer helps to lessen the steaking that occurs when a totally black buffer is printed.} totalbits := (200*24); k := 0; FOR i := 1 TO ((max_bitmap_size div 200)+1) DO BEGIN IF (numbits[i]/totalbits) > 0.40 THEN k := 1; END; IF k = 0 THEN BEGIN stream_$put_chr (stream_id,addr(image_data),6, seek_key,status); stream_$put_chr (stream_id,addr(print_buffer),data_length*4, seek_key,status); stream_$put_chr (stream_id,addr(crlf),2, seek_key,status); stream_$put_chr (stream_id,addr(column0),6, seek_key,status); END ELSE BEGIN FOR i := 1 TO data_length DO BEGIN IF ODD(i) THEN BEGIN print_buffer2[i,1] := chr(16#C0); print_buffer2[i,2] := print_buffer[i,2]; print_buffer2[i,3] := chr(16#C0); print_buffer2[i,4] := print_buffer[i,4]; print_buffer[i,2] := chr(16#C0); print_buffer[i,4] := chr(16#C0); END ELSE BEGIN print_buffer2[i,1] := print_buffer[i,1]; print_buffer2[i,2] := chr(16#C0); print_buffer2[i,3] := print_buffer[i,3]; print_buffer2[i,4] := chr(16#C0); print_buffer[i,1] := chr(16#C0); print_buffer[i,3] := chr(16#C0); END; END; stream_$put_chr (stream_id,addr(image_data),6, seek_key,status); stream_$put_chr (stream_id,addr(print_buffer),data_length*4, seek_key,status); stream_$put_chr (stream_id,addr(cr),1, seek_key,status); stream_$put_chr (stream_id,addr(column0),6, seek_key,status); stream_$put_chr (stream_id,addr(image_data),6, seek_key,status); stream_$put_chr (stream_id,addr(print_buffer2),data_length*4, seek_key,status); stream_$put_chr (stream_id,addr(crlf),2, seek_key,status); stream_$put_chr (stream_id,addr(column0),6, seek_key,status); END; END; END; {End of WRITE_PLOT_BUFFER} PROCEDURE USER1_WRITE_PLOT ( IN buffer: UNIV pr_$buf_t; IN buffer_length: pinteger ); VAR i: integer; {counter} j: integer; {size of bitmap buffer in bytes} k: integer; {size of bitmap in pixels across the page} BEGIN {Check that BUFFER_LENGTH does not exceed the maximum buffer size and that X_BITMAP_SIZE*SCALE_FACTOR does not exceed the maximum printable bitmap size.} IF buffer_length <= max_buffer_size THEN j := buffer_length ELSE j := max_buffer_size; IF x_bitmap_size*scale_factor <= max_bitmap_size THEN k := x_bitmap_size*scale_factor ELSE k := max_bitmap_size; {Buffer up 24 lines by X_BITMAP_SIZE*SCALE_FACTOR columns of the bitmap and then dump them out to the printer. Pad short lines with zeros. Invert the buffer if the user requested black/white reversal for printing bitmap.} bcount := bcount+1; i:= 0; IF (invert_image = FALSE) THEN BEGIN WHILE i < j DO BEGIN i := i+1; bitmap_buffer[bcount,i] := buffer[i]; END; WHILE i < (((k-1) div 8)+1) DO BEGIN i := i+1; bitmap_buffer[bcount,i] := chr(0); END; END ELSE BEGIN WHILE i < j DO BEGIN i := i+1; bitmap_buffer[bcount,i] := chr(~ord(buffer[i])); END; WHILE i < (((k-1) div 8)+1) DO BEGIN i := i+1; bitmap_buffer[bcount,i] := chr(16#FF); END; END; IF bcount = 24 THEN BEGIN write_plot_buffer (bitmap_buffer,k); bcount := 0; END; END; {End of USER1_WRITE_PLOT} BEGIN {Beginning of actual USER1_WRITE code} {Determine printer mode and dispatch for output of buffer} CASE printer_mode OF pr_$text: user1_write_text (buffer,buffer_length); pr_$transparent: user1_write_transparent (buffer,buffer_length); pr_$plot: user1_write_plot (buffer,buffer_length) END; END; {End of USER1_WRITE} PROCEDURE USER1_SET_MODE ( IN mode: pr_$set_op_t; IN data: pr_$data_rec_t ); BEGIN CASE mode OF pr_$font_weight: IF (data.font_weight = pr_$bold) THEN print_repeat :=2 ELSE print_repeat := 1; pr_$font_size: ; pr_$text_precision: CASE data.text_precision OF pr_$draft: font_number := 0; pr_$letter_quality: font_number := 1; END; pr_$data_format: BEGIN printer_mode := data.data_format; CASE printer_mode OF pr_$text: BEGIN stream_$put_chr (stream_id,addr(elongated_off),2,seek_key,status); stream_$put_chr (stream_id,addr(condense_off),2,seek_key,status); stream_$put_chr (stream_id,addr(text_vert_spacing),3,seek_key,status); CASE font_number OF 0: stream_$put_chr (stream_id,addr(font_0),3,seek_key,status); 1: stream_$put_chr (stream_id,addr(font_1),3,seek_key,status); END; END; pr_$transparent: BEGIN stream_$put_chr (stream_id,addr(elongated_off),2,seek_key,status); stream_$put_chr (stream_id,addr(condense_off),2,seek_key,status); stream_$put_chr (stream_id,addr(font_0),3,seek_key,status); stream_$put_chr (stream_id,addr(text_vert_spacing),3,seek_key,status); trans_flag := TRUE; END; pr_$plot: BEGIN stream_$put_chr (stream_id,addr(plot_vert_spacing),3,seek_key,status); plot_flag := TRUE; END; END; END; pr_$pitch: CASE ROUND(data.pitch*10.0) OF 50: BEGIN stream_$put_chr (stream_id,addr(elongated_on),2,seek_key,status); stream_$put_chr (stream_id,addr(pitch10),4,seek_key,status); END; 60: BEGIN stream_$put_chr (stream_id,addr(elongated_on),2,seek_key,status); stream_$put_chr (stream_id,addr(pitch12),4,seek_key,status); END; 100: stream_$put_chr (stream_id,addr(pitch10),4,seek_key,status); 120: stream_$put_chr (stream_id,addr(pitch12),4,seek_key,status); 167: BEGIN stream_$put_chr (stream_id,addr(condense_on),2,seek_key,status); stream_$put_chr (stream_id,addr(pitch10),4,seek_key,status); END; 200: BEGIN stream_$put_chr (stream_id,addr(condense_on),2,seek_key,status); stream_$put_chr (stream_id,addr(pitch12),4,seek_key,status); END; END; pr_$x_dimension: x_bitmap_size := data.x_dimension; pr_$y_dimension: y_bitmap_size := data.y_dimension; pr_$rep_factor: scale_factor := data.rep_factor; pr_$config: ; pr_$copies: ; pr_$server_db: BEGIN server_ptr := data.server_db_ptr; printer_mode := server_ptr^.print_mode; IF server_ptr^.lq = FALSE THEN font_number := 0 ELSE font_number := 1; IF (server_ptr^.weight = pr_$bold) THEN print_repeat := 2 ELSE print_repeat := 1; IF server_ptr^.bw_rev = TRUE THEN invert_image := TRUE ELSE invert_image := FALSE; CASE printer_mode OF pr_$text: BEGIN stream_$put_chr (stream_id,addr(elongated_off),2,seek_key,status); stream_$put_chr (stream_id,addr(condense_off),2,seek_key,status); stream_$put_chr (stream_id,addr(text_vert_spacing),3,seek_key,status); CASE font_number OF 0: stream_$put_chr (stream_id,addr(font_0),3,seek_key,status); 1: stream_$put_chr (stream_id,addr(font_1),3,seek_key,status); END; CASE ROUND(server_ptr^.cpi*10.0) OF 50: BEGIN stream_$put_chr (stream_id,addr(elongated_on),2,seek_key,status); stream_$put_chr (stream_id,addr(pitch10),4,seek_key,status); END; 60: BEGIN stream_$put_chr (stream_id,addr(elongated_on),2,seek_key,status); stream_$put_chr (stream_id,addr(pitch12),4,seek_key,status); END; 100: stream_$put_chr (stream_id,addr(pitch10),4,seek_key,status); 120: stream_$put_chr (stream_id,addr(pitch12),4,seek_key,status); 167: BEGIN stream_$put_chr (stream_id,addr(condense_on),2,seek_key,status); stream_$put_chr (stream_id,addr(pitch10),4,seek_key,status); END; 200: BEGIN stream_$put_chr (stream_id,addr(condense_on),2,seek_key,status); stream_$put_chr (stream_id,addr(pitch12),4,seek_key,status); END; END; END; pr_$transparent: BEGIN stream_$put_chr (stream_id,addr(elongated_off),2,seek_key,status); stream_$put_chr (stream_id,addr(condense_off),2,seek_key,status); stream_$put_chr (stream_id,addr(font_0),3,seek_key,status); stream_$put_chr (stream_id,addr(text_vert_spacing),3,seek_key,status); trans_flag := TRUE; END; pr_$plot: BEGIN x_bitmap_size := server_ptr^.bitmap_size.x; y_bitmap_size := server_ptr^.bitmap_size.y; stream_$put_chr (stream_id,addr(plot_vert_spacing),3,seek_key,status); plot_flag := TRUE; END; END; END; END; END; {End of USER1_SET_MODE} PROCEDURE USER1_RETURN_INFO ( IN query: pr_$inq_op_t; OUT data: pr_$data_rec_t ); BEGIN CASE query OF pr_$bpi: BEGIN data.bpi.x := 180; data.bpi.y := 180; END; pr_$rep_ability: data.rep_ability := false; pr_$driver_db: BEGIN driver_ptr := data.driver_db_ptr; WITH driver_ptr^ DO BEGIN valid := TRUE; copies := FALSE; cpi[1] := 10.0; {Put the built-in font first so it will be default font} cpi[2] := 12.0; cpi[3] := 5.0; {Put the expanded fonts next} cpi[4] := 6.0; cpi[5] := 16.7; {Put the compressed fonts next} cpi[6] := 20.0; lpi[1] := 6.0; resolution[1] := 180; res_min := 180; res_max := 180; color_format := none; bw_rev := TRUE; END; END; END; END; {End of USER1_RETURN_INFO} PROCEDURE USER1_FLUSH; VAR temp: pr_$data_format_t; {printer mode: text, transparent, or plot} dummy: pr_$buf_t; {dummy buffer} BEGIN {If printer is in plot mode then make sure that the last buffer of bitmap data is filled out to 24 lines and printed. If the printer mode is TRANSPARENT or PLOT, then we need to eject the page from the printer. Under SR8, the PRSVR would change the printer mode to TEXT and issue a form feed after the end of a PLOT or TRANSPARENT mode output. Under SR9, we have to do the page ejection ourselves.} IF (bcount <> 0) THEN BEGIN temp := printer_mode; printer_mode := pr_$plot; REPEAT user1_write(dummy,0); UNTIL bcount = 0; printer_mode := temp; END; IF (plot_flag = TRUE) OR (trans_flag = TRUE) THEN BEGIN stream_$put_chr (stream_id,addr(ff),1,seek_key,status); END; plot_flag := FALSE; trans_flag := FALSE; END; {End of USER1_FLUSH} PROCEDURE USER1_CLOSE; BEGIN stream_$close (stream_id,status); END; {End of USER1_CLOSE} {***** End of module USER1_TOSHIBA *****} End of user1.toshiba.pas