;;;-*- Mode:LISP; Package:TIGER; Base:10; READTABLE:CL -*- ;;; Copyright Lisp Machine, Inc. 1985 ;;; See filename "COPYRIGHT.TEXT" for ;;; licensing and release information. ;;; minimal support for LMI Laser I. one could do a lot better than this. ;;; 2/19/85 09:35:20 -George Carrette ;;; Note: We are in Common-Lisp mode and are using rational numbers and floor/ceiling ;;; arithmetic. ;;; How: ;;; * support font shifts in text mode. ;;; * support :BITBLT message in graphics mode. Use 2^8 element table to ;;; do byte-reverse. Use copy-array-portion into byte-hacking 1-D workspace ;;; then microcompiled utility functions. (def-tiger-props :laser1 tiger-stream-flavor laser1-stream TIGER-SERIAL-HANDSHAKE-TYPE :software tiger-font-type vanilla-font font-directory nil default-x-scale 1 default-y-scale 1 ) (defvar laser1-simulation-table (make-array 256)) (defvar *laser1-orientation* :PORTRAIT "Determine orientation of LASER1 printer, should be :LANDSCAPE or :PORTRAIT") (define-site-variable *laser1-orientation* :laser1-orientation "Determine orientation of LASER1 printer, should be :LANDSCAPE or :PORTRAIT") (stuff-array laser1-simulation-table nil (t (#\Center-Dot #\Space)) (t #\Integral) (:discard (#\Null #o400)) ((ascii-code #\line) #\Line) ((list (ascii-code #\space) (ascii-code #\space) (ascii-code #\space) (ascii-code #\space) (ascii-code #\space) (ascii-code #\space) (ascii-code #\space) (ascii-code #\space)) #\Tab) ((ascii-code #\form) #\Form) ((list (ascii-code #\return) (ascii-code #\line)) #\Return)) (defflavor laser1-stream ((raster-character-buffer (make-array (round (* 300 8.5) 7) ;; big enough for maximum resolution ;; and 8.5 inch width paper. :element-type 'string-char)) (buffer-bit-index 0) (number-of-bytes-sent-in-graphics-page 0) (horizontal-pixel-margin 0) (horizontal-decipoint-margin 0) (y-pixel-position 0) (rotation nil) (p/d-numerator 0) (p/d-denominator 0)) (basic-printer-stream-mixin) (:default-init-plist :name :laser1 :lines-per-page 59 :character-simulation-table laser1-simulation-table :dots-per-line 1)) (defmethod (laser1-stream :setup-normal) () (escape-sequence #\E) (cond ((eq *laser1-orientation* :LANDSCAPE) (escape-format "&l1O") (setq lines-per-page 44)) (t (escape-format "&l0O") (setq lines-per-page 59)))) (defvar *laser1-pixels-per-inch* 100 "this can be 75, 100, 150, or 300, dots per inch") (defmethod (laser1-stream :set-up-for-graphics) (r) ;; set up for 100 dots per inch. 850 dots across. ;; support 75, 100, 150 and 300. (setq number-of-bytes-sent-in-graphics-page 0) (setq p/d-numerator (numerator (/ *laser1-pixels-per-inch* 720))) (setq p/d-denominator (denominator (/ *laser1-pixels-per-inch* 720))) (escape-format "*t~DR" *laser1-pixels-per-inch*) (escape-format "&a-2R") ;; should hack portrait/landscape with rotation. (setq y-pixel-position 0) (setq rotation r) (setq horizontal-pixel-margin -1)) (defmethod (laser1-stream :position-horizontal) (pixels) (multiple-value-bind (exact leftover) (floor pixels p/d-numerator) (setq horizontal-decipoint-margin (* exact p/d-denominator)) (setq buffer-bit-index leftover) (laser1-horizontal-position-escapes destination horizontal-decipoint-margin) (setq horizontal-pixel-margin pixels) (fill raster-character-buffer 0))) (defun laser1-horizontal-position-escapes (destination decipoints) (escape-format "&a~DH" decipoints) (escape-format "*r~DA" 1)) (defmethod (laser1-stream :bitblt) (width height array x y &aux left-bit right-bit) (if ( width height) (bitblt-to-stream-simple-case width height array x y self) (do ((j (1- width) (1- j))) ((minusp j)) (cond ((null (setq left-bit (column-bit-search array y (+ x j) height)))) ('else (send self :position-horizontal (- left-bit y)) (setq right-bit (column-reverse-bit-search array y (+ x j) height)) (do ((k left-bit (1+ k))) ((> k right-bit)) (send self :print-bit-graphics (aref array k (+ x j)))))) (send self :new-graphics-line)))) (defun column-bit-search (array1 y1 x1 count1) (do ((j1 0 (1+ j1))) ((= j1 count1) nil) (or (zerop (aref array1 (+ y1 j1) x1)) (return (+ y1 j1))))) (defun column-reverse-bit-search (array y x count) (do ((position (+ y (1- count)) (1- position))) ((< position y) nil) (or (zerop (aref array position x)) (return position)))) ;; if an art-1b array is displaced to an art-8b array then the bits ;; go into the bytes in what is called "little indian" order. That is, ;; VAX = DEC = Little Indian, 370 = IBM = Big Indian. ;; Our LAMBDA is a little Indian also. 68000 is Big. etc. ;; The Laser1 wants its bytes of pixels in Big indian order. ;; Therefore we cant just do a displaced array, instead you can see the ;; use of floor with a modulus of 8 to get the correct ordering for the Laser1. (defmethod (laser1-stream :print-bit-graphics) (char) ;; we intend that CHAR is actually a bit. put it into the ;; raster-character-buffer and frob the buffer-bit-index. (when (not (zerop char)) (multiple-value-bind (bytepos bitpos) (floor buffer-bit-index 8) (setf (ldb (byte 1 (- 7 bitpos)) (si:aref raster-character-buffer bytepos)) 1))) (incf buffer-bit-index)) ;; manual claims 59k. We forgot to keep track of bytes used by setup and positioning commands ;; so 57k is comfortable margin. fix in the future. (defvar *laser1-graphics-byte-storage-limit* 57000 "experimentally determined") (defmethod (laser1-stream :new-graphics-line) () (when (minusp horizontal-pixel-margin) (send self :position-horizontal 0) (send self :print-bit-graphics 0)) (let ((bytes (ceiling buffer-bit-index 8))) (incf number-of-bytes-sent-in-graphics-page bytes) (when (> number-of-bytes-sent-in-graphics-page *laser1-graphics-byte-storage-limit*) (send destination :tyo (ascii-code #\form)) (send self :set-up-for-graphics rotation) (Laser1-horizontal-position-escapes destination horizontal-decipoint-margin)) (escape-format "*b~DW" bytes) (send destination :string-out raster-character-buffer 0 bytes) (escape-format "*rB")) (incf y-pixel-position) (setq horizontal-pixel-margin -1)) (compile-flavor-methods laser1-stream) ;; Q? why isnt there a way to read the status code through the serial port? ;; how about a decoder for the error message codes.