home *** CD-ROM | disk | FTP | other *** search
Text File | 1987-10-27 | 8.7 KB | 246 lines | [TEXT/CCL ] |
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;;serial-streams.lisp
- ;;
- ;;copyright © 1987, Coral Software Corp.
- ;;
- ;The following knowledge is helpful in understanding the code:
- ;; Use of Macintosh Drivers and Serial Ports
- ;; Use of the Allegro CL low-level system interface
- ;; Use of Object Lisp
- ;; Use of Allegro CL stream implementation
- ;;
- ;;
- ;; If you just evaluate this file, it will create four streams, two input
- ;; and two output (one of each for each serial port). You can print and
- ;; read from these streams, just like any other streams. One caveat is that
- ;; you must ask them to STREAM-OPEN before you use them.
- ;;
- ;;
- ;
- ;; You could probably use this file to figure out how to implement other kinds
- ;; of streams, as well
- ;;
-
-
- (eval-when (eval compile)
- (require 'traps))
-
- ;Some Macintosh system constants {for referencing into parameter blocks}
- (defconstant $IOREFNUM 24)
- (defconstant $IOPERMSSN 27)
- (defconstant $IOFILENAME 18)
- (defconstant $IOBUFFER 32)
- (defconstant $IOREQCOUNT 36)
- (defconstant $CSCODE 26)
- (defconstant $CSPARAM 28)
-
- (proclaim '(object-variable driver-open driver-pb driver-open-p
- driver-unread-char driver-name))
-
-
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;;
- ;;the driver object
- ;;
- ;;drivers inherit from streams (because they are used for io).
- ;;
- ;;serial streams communicate through the Macintosh serial drivers
- ;;
-
- (defobject *driver* *stream*)
-
- (defobfun (exist *driver*) (init-list)
- (usual-exist init-list)
- (have 'driver-name (getf init-list :driver-name "Unspecified Driver"))
- (have 'driver-open-p nil)
- (have 'driver-pb
- (_NewPtr :errchk ;should this be errchk? {}
- :d0 (getf init-list :pb-size 80)
- :a0))
- (have 'driver-unread-char nil)
- (%put-word driver-pb 0 $ioRefNum) ;address, value, offset
- (%put-byte driver-pb 0 $ioPermssn) ;address, value, offset
- nil)
-
- (defobfun (driver-dispose *driver*) ()
- (if driver-open-p (stream-close)) ;maybe be a continuable error? {}
- (_DisposPtr :errchk :a0 driver-pb))
-
- (defobfun (stream-open *driver*) ()
- (unless driver-open-p
- (stream-close) ;close stream just in case? {}
- (with-pstrs ((np driver-name)) ;get name string in mac format
- (%put-ptr driver-pb np $ioFileName) ;address, value, offset
- (_Open :errchk :a0 driver-pb :d0)) ;open the driver
- (setq driver-open-p t))) ;set open-p to t
-
- (defobfun (stream-close *driver*) ()
- (when driver-open-p ;don't close if its already closed
- (_Close :errchk :a0 driver-pb :d0) ;close the driver
- (setq driver-open-p nil))) ;set open-p to nil
-
- (defobfun (stream-tyo *driver*) (char) ;function for writing to stream
- (%stack-block ((cp 1)) ;make room on stack for character
- (%put-byte cp char) ;put character there
- (%put-ptr driver-pb cp $ioBuffer) ;set up the parameter block
- (%put-long driver-pb 1 $ioReqCount) ;
- (_Write :errchk :a0 driver-pb :d0))) ;write the character
-
- (defobfun (stream-tyi *driver*) () ;function for reading from stream
- (when (not driver-open-p) ;error if driver not open
- (error "Driver: ~s is not open" (self)))
- (if driver-unread-char ;if a character has been 'unread'
- (prog1 driver-unread-char ; return it, and set unread-char
- (setq driver-unread-char nil)) ; to nil
- (%stack-block ((cp 2)) ;otherwise read in a character
- (%put-ptr driver-pb cp $ioBuffer)
- (%put-long driver-pb 1 $ioReqCount)
- (_Read :errchk :a0 driver-pb :d0)
- (%get-byte cp))))
-
- (defobfun (stream-untyi *driver*) (char) ;function 'unreads' a character
- (setq driver-unread-char char))
-
- (defobfun (driver-control *driver*) (code) ;{} find out what this does
- (if (not driver-open-p) (error "Driver: ~s is not open" (self)))
- (%put-word driver-pb code $csCode)
- (_Control :errchk :a0 driver-pb))
-
- (defobfun (driver-status *driver*) (code) ;{} find out what this does
- (if (not driver-open-p) (error "Driver: ~s is not open" (self)))
- (%put-word driver-pb code $csCode)
- (_Status :errchk :a0 driver-pb))
-
-
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;;
- ;;Serial Streams
- ;;
- ;;Serial Streams inherit from drivers.
- ;;
- ;;They provide a stream interface to some specific drivers on the Macintosh,
- ;; namely, the serial drivers.
- ;;
-
- (defobject *serial-stream* *driver*) ;define the new class
-
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;;
- ;;set-serial-port
- ;;
- ;; used to configure the serial port
- ;;
- ;; Takes keywords :BAUD
- ;; :STOP
- ;; :PARITY
- ;; :LENGTH
- ;;
- ;; Default values are: 9600 baud, 1 stop bit and parity 0.
- ;;
- ;; This function does fancy argument checking. It checks all args before
- ;; erroring on any single one of them.
- ;;
-
- (defobfun (set-serial-port *serial-stream*)
- (&key (baud 9600) (stop 1) (parity 0)
- (length nil length-supplied?))
- (if (not driver-open-p) (stream-open)) ;open if not already
- (let ((bad-args nil)
- (config (if length-supplied?
- (case (floor length)
- (5 0)
- (7 1024)
- (6 2048)
- (8 3072))
- 3072))
- (%baud (floor baud))
- (%stop (* 1.5 (floor (coerce stop 'number))))
- (%parity (floor parity)))
- ;Check arguments one at a time.
- (unless config (push `(length ,length) bad-args))
- (unless (<= 112 %baud 57600) (push `(baud ,baud) bad-args))
- (unless (<= 1 %stop 3) (push `(stop ,stop) bad-args))
- (unless (<= 0 %parity 2) (push `(parity ,parity) bad-args))
- (when bad-args
- (error "Invalid argument~p to set-serial-port. ~:{~a: ~s~:[~;, ~]~}"
- (length bad-args)
- (maplist #'(lambda (bad-arg-list)
- `(,@(car bad-arg-list)
- ,(> (length bad-arg-list) 1)))
- bad-args)))
- (%put-word driver-pb
- (+ config
- (- (round (/ 114750 %baud)) 2)
- (ash (truncate %stop) 14)
- (ash (if (eq %parity 2)
- 3 %parity)
- 12))
- $csParam)
- (driver-control 8))
- (self))
-
- ;;;;;;;;;;;;;;;
- ;;
- ;;set-hand-shake
- ;;
- ;; A hairy function to set the handshaking. It takes a list of numbers, but
- ;; should probably be converted to keywords.
- ;;
- ;; The list of numbers are as follows:
- ;;
- ;; (fXon fCTS xOn xOff errs evts fInX)
- ;;
- ;; If fXon is nonzero Xon/Xoff output flow control is enabled
- ;; If fInX is nonzero Xon/Xoff input flow control is enabled
- ;; XOn and XOff specify the characters used for Xon/Xoff
- ;; If fCTS is nonzero, CTS hardware handshake is enabled
- ;; errs indicates which errors cause input requests to be aborted
- ;; it should be the sum of the following:
- ;; 16 for parity errors
- ;; 32 for hardware overrun errors
- ;; 64 for framing errors
- ;; evts indicates whether changes in the CTS or break status will cause
- ;; device driver events to be posted; it should be the sum of the
- ;; following
- ;; 32 if CTS change should generate events
- ;; 128 if break status change should generate events
- ;; Note that these driver events are unsupported and degrade performance.
- ;;
- (defobfun (set-hand-shake *serial-stream*)
- (num-list &aux (param-ptr (%inc-ptr driver-pb $csParam)))
- (if (not driver-open-p) (stream-open))
- (dotimes (i 7)
- (%put-byte param-ptr (pop num-list) i))
- (driver-control 10))
-
- (defobfun (stream-tyi *serial-stream*) ()
- (if (not driver-open-p) (stream-open))
- (loop (if (stream-listen) (return))) ;so it won't hang
- (usual-stream-tyi))
-
- (defobfun (stream-eofp *serial-stream*) ()
- nil) ;always more
-
- (defobfun (stream-listen *serial-stream*) ()
- (if (not driver-open-p) (stream-open))
- (or driver-unread-char
- (progn
- (driver-status 2)
- (neq 0 (%get-long driver-pb $csParam)))))
-
- ;;;;;;;;;;;;;;;;;;;
- ;;
- ;; define some globals and bind them to serial streams
- ;;
- ;; printer port is b
- ;; modem port is a
- (defvar *serial-a-in* (oneof *serial-stream* :driver-name ".AIn"))
- (defvar *serial-a-out* (oneof *serial-stream* :driver-name ".AOut"))
- (defvar *serial-b-in* (oneof *serial-stream* :driver-name ".BIn"))
- (defvar *serial-b-out* (oneof *serial-stream* :driver-name ".BOut"))
-
-
- (provide 'serial-streams)
- (pushnew :serial-streams *features*)