Jump to page content

Checking whether a printer is online

The hard way.

Long before we had bidirectional parallel communication and modern printer drivers, and when we did all of our printing in plain text on 9-pin dot matrix printers, checking to see if a printer was switched on and set as online within your code was not so easy. You had to do something like this code fragment from LSAIT Hangman:

2430DEFFNck:LOCALa,t,q:a=1
2440PROCm("Testing for printer..."):OSCLI("FX21,3"):t=ADVAL(-4)
2450OSCLI("FX3,10"):VDU127,127,127:OSCLI("FX3,0"):q=INKEY25:IFADVAL(-4)<t a=0
2460IFa=0PROCm("Oops-printer not ready."):t=INKEY(150)
2470=a

The specifics:

OSCLI("FX21,3"):t=ADVAL(-4)

Flush the printer output buffer, and read the buffer’s capacity. ADVAL() is designed to read values from the analogue-to-digital converter but with negative arguments will read operating system buffer space.

OSCLI("FX3,10")

Switch the machine to printer output only. Not really sure what this actually does, other than that it works! Neither the Model B nor the B+ manuals are clear. (Forget what I said previously about 2 and 10: the API changed.)

VDU127,127,127

Write three backspace characters; these will only be sent to the printer as that is presently the single active output device.

OSCLI("FX3,0"):q=INKEY25:IFADVAL(-4)<t a=0
Set output back to screen only, pause, and re-read the printer buffer capacity. If the capacity has dropped, at least one of those three backspaces is still sat in the buffer, going nowhere. Were the printer online, it would have silently eaten them and the buffer would have returned to empty, so the determined capacity would not appear to have changed. If the capacity has dropped, the printer ain’t ready.

The original code that I “borrowed” for this task omitted the pause and I was puzzled to find it to be rather erratic, until I realised that I needed to pause the program to let the OS deal with the request for printed output.

OSCLI and the Acorn MOS system calls

Under Acorn MOS, OSCLI does indeed stand for Operating System Command Line Interpreter, which is a system call that executes a single command string. Earlier versions of Acorn MOS had no shell, and expected that OS commands would be passed in by the active language or application using the OSCLI system call. Languages and applications that provide a command prompt, for example BBC BASIC and the Acornsoft View word processor, pass any command beginning with “*” directly to the OS:

*FX 3, 10
*CONFIGURE TUBE
*HELP BASIC

In BBC BASIC, a * indicates that the remainder of the line is an OS command. A BASIC command OSCLI() exists to invoke OS commands where you want some of the command line to be formed from variables or function output, e.g. OSCLI("FX3, " + outMode%). The following instructions are equivalent:

  10 *FX 3, 10
  10 OSCLI("FX 3, 10")
  10 OsCli=&FFF7         :REM change case to avoid conflict with OSCLI()
  20 ...
1000 DIM command 8       :REM closest BBC BASIC has to pointers
1010 $command="FX 3, 10" :REM $ operator includes &0D terminator
1020 X%=command MOD 256  :REM X and Y point to address of command line
1030 Y%=command DIV 256
1060 CALL OsCli          :REM call the OS to execute the command

A operating system command of the form FX a[, x[, y]] allows the OSBYTE system call to be made directly from the command line; the three parameters a, x and y are passed into the accumulator and X and Y registers on entry. OSBYTE provides a wide range of services selected using the accumulator, all of which require only one or two bytes of parameters held in X and Y. The following command to direct text output to the printer only:

  10 *FX 3, 10

is equivalent to the following direct operating system call:

  10 OSBYTE=&FFF4
  20 ...
1000 A%=3  :REM Select output dest
1020 X%=10 :REM Printer only
1030 Y%=0
1040 CALL OSBYTE

The assembly version is as follows:

  10 OSBYTE=&FFF4
  20 ...
2000 DIM P% 10 :REM allocate 10 bytes from the heap for the machine code
2010 [
2020  LDA #3  \ Select output dest
2030  LDX #10 \ Printer only
2040  LDY #0
2050  JSR OSBYTE
2060 ]
2070 CALL P%

In the interests of saving space from avoiding unnecessary line numbers, I wanted to cram as much onto each line (without exceeding the screen width) as possible, so I used OSCLI to invoke an OS command and then put more code after it on the same line. Madness.