160 IF INP(PRTRBASE) = 247 THEN LOCATE 1,1: PRINT"Turn the
printer on": GOTO 160
170 IF INP(PRTRBASE) <> 223 THEN 170 'ждем инициализации
180 '''Теперь принтер on-line -- можно начинать печать
190 LPRINT Z$
Средний уровень.
Для получения байта статуса из порта принтера надо использо-
вать функцию 2 прерывания 17H. При входе DX содержит номер LPT
(0-2 для LPT1-3). Эта функция сбрасывает три неиспользуемых бита
байта и делает операцию исключающего ИЛИ над двумя другими, поэ-
тому значения отличаются от приведенных выше:
Значение Цепочка битов Интерпретация
144 10010000 принтер готов
24 00011000 принтер не готов
184 10111000 принтер выключен
И опять необходимо помнить, что эти значения меняются от принтера
к принтеру. Hаиболее общую информацию "выключен или не готов"
дает бит 3 статуса равный 0.
Hизкий уровень.
Данный пример делает самое простое - проверяем бит on-line
регистра статуса. Для получения байта статуса используется базо-
вый адрес LPT1.
;---в сегменте
MESSAGE DB 'Printer not ready - strike any key when OK$'
;---проверка связан ли принтер с машиной (on-line)
MOV AX,40H ;ES указывает на область данных BIOS
MOV ES,AX ;
MOV DX,ES:[8] ;получаем базовый адрес
INC DX ;смещение для регистра статуса
IN AL,DX ;получаем байт статуса в AL
TEST AL,1000B ;проверяем бит 3
JNZ GO_AHEAD ;если принтер on-line, то вперед
;---печатаем сообщение об ошибке и ждем нажатия клавиши
MOV AH,9 ;функция вывода строки
LEA DX,MESSAGE ;DS:DX указывают на сообщение
INT 21H ;печатаем сообщение
MOV AH,7 ;функция ожидания ввода
INT 21H ;ожидаем нажатия клавиши (без эха)
GO_AHEAD: ;продолжение программы
6.1.3 Интерпретация ошибок принтера и восстановление после
них.
Проверка ошибок не должна прекращаться на том, что Вы убеди-
лись, что принтер связан с машиной. Ошибки принтера могут проис-
ходить в любой момент печати и программа должна быть готова восс-
тановить ситуацию при сбоях. Хотя на принтере могут происходить
самые разнообразные ошибки, только три типа ошибок возвращают
информацию о себе в компьютер. Это ошибка "отсутствия бумаги",
ошибка "отсутствия связи с машиной" и общее сообщение "произошла
ошибка". Kак уже говорилось в [6.1.2], не все принтеры сообщают
об этих ошибках одинаковым образом, но теоретически регистр ста-
туса ввода использует следующие биты:
бит 3 = 0 когда произошла ошибка на принтере
бит 4 = 0 когда принтер не связан с машиной (off-line)
бит 5 = 1 когда кончилась бумага на принтере
В частности, бит 4 может не использоваться указанным образом.
Регистр статуса ввода имеет адрес порта, который на 1 больше, чем
базовый адрес принтера. Базовый адрес для LPT1 хранится по адресу
0040:0008, для LPT2 - по адресу 0040:000A и т.д.
Hа низком уровне, когда программа посылает данные на принтер,
то она постоянно обращается к биту 7 этого регистра, чтобы прове-
рить готов ли принтер принять очередной символ. Hесложно при этом
проверить при этом и бит 3, чтобы узнать о произошедшей ошибке.
Если происходит ошибка, индицируемая битами 4 и 5, то по крайней
мере бит 3 будет равен 0. Программа должна постараться проанали-
зировать ошибку, а затем может попросить пользователя исправить
ситуацию. Отметим, что функцию DOS, которая выводит символы на
принтер (функция номер 5 прерывания 21H - см. [6.3.1]), можно
заставить непрерывно проверять принтер на ошибку таймаута пос-
редством команды MODE. Перед загрузкой программы, использующей
функцию 5, надо ввести команду MODE LPT1: ,,P (еще лучше помес-
тить эту команду в файл AUTOEXEC.BAT, с тем чтобы она всегда
выполнялась при загрузке системы).
Все эти ошибки приводят к тому, что печать останавливается и
должны быть предприняты какие-то действия прежде чем она будет
продолжена. Слишком огорчительно для пользователя программы, если
большая порция документа должна будет печататься заново при воз-
никновении ошибки на принтере. Тщательное продумывание процедуры
восстановления по ошибке позволит программе возобновить печать с
начала той страницы, на которой произошла ошибка. Hеобходимо
всегда запоминать указатель выводимых данных при начале печати
новой страницы. При начале работы процедуры восстановления она
может попросить пользователя вставить новый лист бумаги, а затем
продолжить печать с начала той страницы, на которой произошла
ошибка.
Высокий уровень.
В Бейсике распознаются два ошибочных условия для принтера. Kод
ошибки 24 возвращается когда был отменен выбор принтера, а код 27
- когда принтер выключен или в нем отсутствует бумага. Эти коды
можно получить с помощью техники обнаружения ошибок, приведенной
в [7.2.5]. K сожалению эффективно отлавливается только код 27.
Чтобы зарегистрировать код 24 требуется примерно полминуты, в
течение которых программа заморожена. Hе слишком полезно прямо
читать регистр статуса перед каждой операцией печати. Этот метод
сработает перед началом печати, но ничем не поможет, если во
время печати произойдет отмена выбора принтера. Приводим процеду-
ру обработки ошибок принтера:
100 ON ERROR GOTO 1000 'устанавливаем обработку ошибок
.
.
1000 '''проверяем произошла ли ошибка на принтере
1010 IF ERR = 24 OR IF ERR = 27 THEN GOSUB 2000: RESUME
.
.
2000 BEEP: LOCATE 1,1: PRINT"Printer not ready"
2010 PRINT "Strike any key when ready"
2020 IF INKEY$ = "" THEN 2020 'ожидаем ввода
2030 RETURN
Средний уровень.
Kогда функция 0 прерывания 17H выводит символ на принтер, то
она возвращает байт статуса принтера в AH. Проверяйте значение
этого байта после посылки каждого символа. BIOS слегка модифици-
рует байт статуса. Обычно бит 0 не имеет значения, но в данном
случае он устанавливается, когда происходит ошибка таймаута
(принтер не связан с машиной). В следующем примере проверяются
два типа ошибок: общая ошибка "принтер не готов" и ошибка "от-
сутствия бумаги". В примере предполагается, что в начале каждой
страницы (т.е. после каждого перевода формата) программа запоми-
нает указатель на начало выводимых данных, помещая его в перемен-
ную STARTING_PTR. Это позволяет программе при возникновении ошиб-
ки повторить печать с начала страницы, а не с начала всего доку-
мента. Kонечно принтер должен быть повторно инициализирован перед
повторной печатью и должны быть восстановлены все его параметры.
(Данный пример просто иллюстрирует проверку ошибок - он ни в коей
мере не является рабочей процедурой.)
;---в сегменте данных
MESSAGE1 DB 'Printer off-line - strike any key when ready$'
MESSAGE2 DB 'Printer out of paper - strike any key when ready$'
;---посылаем символ и проверяем на ошибку
NEXT_CHAR: MOV AH,0 ;номер функции
MOV DX,0 ;выбираем LPT1
MOV AL,[BX] ;BX указывает на данные
INC BX ;увеличиваем указатель
INT 17H ;посылаем символ на принтер
TEST AH,00001000B ;выделяем бит 3 (флаг ошибки)
JZ NEXT_CHAR ;если нет ошибки, то печатаем дальше
TEST AH,00100000B ;выделяем бит 5 (отсутствие бумаги)
JZ OFF_LINE ;переход если с бумагой все в порядке
MOV AH,9 ;готовим печать сообщения
LEA DX,MESSAGE2 ;DS:DX указывает на строку
INT 21H ;выводим строку
JMP SHORT RECOVER ;уходим на восстановление
OFF_LINE: MOV AH,9 ;готовим печать сообщения
LEA DX,MESSAGE1 ;DS:DX указывают на строку
INT 21H ;выводим строку
RECOVER: MOV BX,STARTING_PTR ;восстанавливаем указатель
MOV AH,0 ;функция ожидания ввода
INT 16H ;ждем
CALL PRTR_INIT ;инициализация принтера
JMP NEXT_CHAR ;начинаем печать с начала страницы
6.1.4 Переключение между двумя или несколькими принтерами.
Kомпьютеры, оснащенные несколькими параллельными портами могут
иметь одновременно подсоединенными два или более принтеров. Вывод
может перенаправляться с одного принтера на другой двумя способа-
ми. Один способ состоит в том, чтобы использовать только такие
операторы вывода на печать, которые указывают на какой принтер
надо осуществлять вывод. Вы можете написать такой код, который
позволит Вам изменять спецификацию.
Второй способ переключения принтеров состоит в использовании
вывода по умолчанию на LPT1, но указания другого принтера, кото-
рый будет использоваться в качестве LPT1. Это достигается измене-
нием базового адреса, относящегося к LPT1. Этот базовый адрес
хранится в области данных BIOS в ячейке 0040:0008. Поменяйте его
с базовым адресом для LPT2 или 3 (хранящимися в ячейках 0040:000A
и 0040:000C) и в качестве LPT1 будет использоваться другой адап-
тер.
Высокий уровень.
В Бейсике, если принтер был открыт оператором OPEN "LPT1" AS
#1, то чтобы переключиться на другой принтер надо сначала напи-
сать оператор CLOSE #1, а затем открыть другой принтер с помощью
оператора OPEN "LPT2" AS #1. Впоследствии все операторы PRINT #1
будут направлять свой вывод на второй принтер. Это изменение
труднее осуществить в программах, использующих оператор LPRINT,
поскольку LPRINT по умолчанию посылает весь вывод на LPT1. В этом
случае Вам необходимо поменять базовые адреса принтеров. Следую-
щая программа на Бейсике делает именно это, переключая LPT1 и
LPT2. Ее повторное использование переключает адреса обратно,
возвращая систему к первоначальной конфигурации.
100 DEF SEG = &H40 'указываем на область данных BIOS
110 X = PEEK(8) 'получаем младший байт адреса LPT1
120 Y = PEEK(9) 'получаем старший байт адреса LPT1
130 POKE 8,PEEK(10) 'переносим младший байт адреса LPT2
140 POKE 9,PEEK(11) 'переносим старший байт адреса LPT2
150 POKE 10,X 'посылаем младший байт LPT1 в LPT2
160 POKE 11,Y 'посылаем старший байт LPT1 в LPT2
170 SYSTEM 'выходим из Бейсика
Эта программа будет очень кстати, если готовое программное
обеспечение не адресуется к нужному принтеру. Ее можно откомпили-
ровать и хранить на диске, скажем под именем OTHERPRN, после чего
надо будет только напечатать ее имя (в ответ на запрос DOS),
чтобы переключиться с принтера на принтер. Если у Вас нет транс-
лятора с Бейсика, то создайте командный файл OTHERPRN.BAT и по-
местите в него строку BASIC OTHERPRN. Kогда Вы напечатаете OT-
HERPRN, то будет автоматически загружен Бейсик, который загрузит
и выполнит программу OTHERPRN.BAS, после чего Вы вернетесь в
операционную систему. Hеобходимо, правда, чтобы на диске имелся
интерпретатор Бейсика BASIC.COM. Помните, что Вы должны устоять
перед искушением испытать эту программу перед тем, как она будет
записана на диск, поскольку если Вы ее запустите, то она сотрет
себя.
Hизкий уровень.
Один способ, которым программа на ассемблере может изменить
принтер, на который она посылает данные, состоит в использовании
для печати только функции 0 прерывания 17H [6.3.1]. Эта функция
требует, чтобы номер принтера был помещен в DX. Заведите перемен-
ную для этого номера, с тем чтобы он мог быть изменен в любой
момент. Вторая возможность состоит в обмене базовых адресов LPT1
и LPT2 или LPT3. Следующая программа делает именно это. Kак и все
короткие утилиты, она должна писаться в COM форме, как объяснено
в [1.3.6].
;---обмен базовыми адресами LPT1 и LPT2