I am working on a complicated macro and have run into a roadblock.
(defmacro for-each-hashtable-band (body vars on &optional counter name)
`(block o
(with-hash-table-iterator (next-entry ,on)
(destructuring-bind
,(apply #'append vars)
(let ((current-band (list ,#(mapcar #'not (apply #'append vars)))))
(for (i 1 ,(length (apply #'append vars)) 2)
(multiple-value-bind
(succ k v) (next-entry)
(if succ
(progn
(setf (nth i current-band) k)
(setf (nth (+ 1 i) current-band) v))
(return-from o nil))))
current-band)
,#body))))
im getting "Evaluation aborted on #<UNDEFINED-FUNCTION NEXT-ENTRY {100229C693}>"
i dont understand why next-entry appears to be invisible to the macro i have created.
I've tried stripping down this to a small replicable example but i couldnt find a minimal scenario without the macro i created where next-entry would be invisible besides this scenario no matter what I tried, i've always managed to find a way to call next-entry in my other examples so im stumped as to why i cannot get it working here
I've tested the for macro ive created and it seems to generally work in most cases but for some reason it cannot see this next-entry variable. How do i make it visible?
In your code there are multiple places where the macro generates bindings in a way that is subject to variable capture (pdf).
(defmacro for-each-hashtable-band (body vars on &optional counter name)
`(block o ;; VARIABLE CAPTURE
(with-hash-table-iterator (next-entry ,on) ;; VARIABLE CAPTURE
(destructuring-bind ,(apply #'append vars)
(let ((current-band ;;; VARIABLE CAPTURE
(list ,#(mapcar #'not (apply #'append vars)))))
(for
(i ;;; VARIABLE CAPTURE
1 ,(length (apply #'append vars)) 2)
(multiple-value-bind (succ k v) ;;; VARIABLE CAPTURE
,(next-entry) ;;; WRONG EVALUATION TIME
(if succ
(progn
(setf (nth i current-band) k)
(setf (nth (+ 1 i) current-band) v))
(return-from o nil))))
current-band)
,#body))))
A simplified example of such a capture is:
`(let ((x 0)) ,#body)
Here above, the x variable is introduced, but if the code is expanded in a context where xis already bound, then body will not be able to reference that former x binding and will always see x bound to zero (you generally don't want this behavior).
Write a function instead
Instead of writing a big macro for this, let's first try understanding what you want to achieve and write instead a higher-order function, ie. a function that calls user-provided functions.
If I understand correctly, your function iterates over a hash-table by bands of entries. I assume vars holds a list of (key value) pairs of symbols, for example ((k1 v1) (k2 v2)). Then, body works on all the key/value pairs in the band.
In the following code, the function map-each-hashtable-band accepts a function, a hash-table, and instead of vars it accepts a size, the width of the band (the number of pairs).
Notice how in your code, you only have one loop, which builds a band using the hash-table iterator. But then, since the macro is named for-each-hashtable-band, I assume you also want to loop over all the bands. The macro with-hash-table-iterator provides an iterator but does not loop itself. That's why here I have two loops.
(defun map-each-hashtable-band (function hash-table band-size)
(with-hash-table-iterator (next-entry hash-table)
(loop :named outer-loop :do
(loop
:with key and value and next-p
:repeat band-size
:do (multiple-value-setq (next-p key value) (next-entry))
:while next-p
:collect key into current-band
:collect value into current-band
:finally (progn
(when current-band
(apply function current-band))
(unless next-p
(return-from outer-loop)))))))
For example:
(map-each-hashtable-band (lambda (&rest band) (print `(:band ,band)))
(alexandria:plist-hash-table
'(:a 0 :b 1 :c 2 :d 3 :e 4 :f 5 :g 6))
2)
NB. Iterating over a hash-table happens in an arbitrary order, there is no guarantee that you'll see the entries in any particular kind of order, this is implementation-dependant.
With my current version of SBCL this prints the following:
(:BAND (:A 0 :B 1))
(:BAND (:C 2 :D 3))
(:BAND (:E 4 :F 5))
(:BAND (:G 6))
Wrap the function in a macro
The previous function might not be exactly the behavior you want, so you need to adapt to your needs, but once it does what you want, you can wrap a macro around it.
(defmacro for-each-hashtable-band (vars hash-table &body body)
`(map-each-hashtable-band (lambda ,(apply #'append vars) ,#body)
,hash-table
,(length vars)))
For example:
(let ((test (alexandria:plist-hash-table '(:a 0 :b 1 :c 2 :d 3 :e 4 :f 5))))
(for-each-hashtable-band ((k1 v1) (k2 v2)) test
(format t "~a -> ~a && ~a -> ~a ~%" k1 v1 k2 v2)))
This prints:
A -> 0 && B -> 1
C -> 2 && D -> 3
E -> 4 && F -> 5
Macro-only solution, for completeness
If you want to have only one, single macro, you can start by inlining the body of the above function in the macro, you don't need to use apply anymore, but instead you need to establish bindings around the body, using destructuring-bind as you did. A first draft would be to simply as follows, but notice that this is not a proper solution:
(defmacro for-each-hashtable-band (vars hash-table &body body)
(let ((band-size (length vars)))
`(with-hash-table-iterator (next-entry ,hash-table)
(loop :named outer-loop :do
(loop
:with key and value and next-p
:repeat ,band-size
:do (multiple-value-setq (next-p key value) (next-entry))
:while next-p
:collect key into current-band
:collect value into current-band
:finally (progn
(when current-band
(destructuring-bind ,(apply #'append vars) current-band
,#body))
(unless next-p
(return-from outer-loop))))))))
In order to be free of variable capture problems with macros, each temporary variable you introduce must be named after a symbol that cannot exist in any context you expand your code. So instead we first unquote all the variables, making the macro definition fail to compile:
(defmacro for-each-hashtable-band (vars hash-table &body body)
(let ((band-size (length vars)))
`(with-hash-table-iterator (,next-entry ,hash-table)
(loop :named ,outer-loop :do
(loop
:with ,key and ,value and ,next-p
:repeat ,band-size
:do (multiple-value-setq (,next-p ,key ,value) (,next-entry))
:while ,next-p
:collect ,key into ,current-band
:collect ,value into ,current-band
:finally (progn
(when ,current-band
(destructuring-bind ,(apply #'append vars) ,current-band
,#body))
(unless ,next-p
(return-from ,outer-loop))))))))
When compiling the macro, the macro is supposed to inject symbols into the code, but here we have a compilation error that says undefined variables:
;; undefined variables: CURRENT-BAND KEY NEXT-ENTRY NEXT-P OUTER-LOOP VALUE
So now, those variables should be fresh symbols:
(defmacro for-each-hashtable-band (vars hash-table &body body)
(let ((band-size (length vars)))
(let ((current-band (gensym))
(key (gensym))
(next-entry (gensym))
(next-p (gensym))
(outer-loop (gensym))
(value (gensym)))
`(with-hash-table-iterator (,next-entry ,hash-table)
(loop :named ,outer-loop :do
(loop
:with ,key and ,value and ,next-p
:repeat ,band-size
:do (multiple-value-setq (,next-p ,key ,value) (,next-entry))
:while ,next-p
:collect ,key into ,current-band
:collect ,value into ,current-band
:finally (progn
(when ,current-band
(destructuring-bind ,(apply #'append vars) ,current-band
,#body))
(unless ,next-p
(return-from ,outer-loop)))))))))
This above is a bit verbose, but you could simplify that.
Here is what the previous for-each-hashtable-band example expands into with this new macro:
(with-hash-table-iterator (#:g1576 test)
(loop :named #:g1578
:do (loop :with #:g1575
and #:g1579
and #:g1577
:repeat 2
:do (multiple-value-setq (#:g1577 #:g1575 #:g1579) (#:g1576))
:while #:g1577
:collect #:g1575 into #:g1574
:collect #:g1579 into #:g1574
:finally (progn
(when #:g1574
(destructuring-bind
(k1 v1 k2 v2)
#:g1574
(format t "~a -> ~a && ~a -> ~a ~%" k1 v1 k2
v2)))
(unless #:g1577 (return-from #:g1578))))))
Each time you expand it, the #:gXXXX variables are different, and cannot possibly shadow existing bindings, so for example, the body can use variables named like current-band or value without breaking the expanded code.
Hi I'm adapting the following UCI lisp code to common lisp.
This is the original function:
(DE MATCH-ARGS (PAT-ARGS CONST BINDING-FORM)
(LOOP ((INITIAL PAT-ARG NIL CONST-VAL NIL)
(WHILE (SETQ PAT-ARG (POP PAT-ARGS)))
(DO (SETQ CONST-VAL (FILLER:ROLE (ROLE:PAIR PAT-ARG) CONST)))
(WHILE (SETQ BINDING-FORM
(MATCH (FILLER:PAIR PAT-ARG)
CONST-VAL
BINDING-FORM)))
(RESULT BINDING-FORM]
Here's my current adaptation of it:
(defun match-args (pat-args const binding-form)
(loop (initial pat-arg nil const-val nil)
(while (setq pat-arg (pop pat-args)))
do (setq const-val (filler/role (role/pair pat-arg) const))
(while (setq binding-form
(match (filler/pair pat-arg)
const-val
binding-form)))
(result binding-form)))
Here's the error that it shows:
*** - LOOP: illegal syntax near (INITIAL PAT-ARG NIL CONST-VAL NIL) in
(LOOP (INITIAL PAT-ARG NIL CONST-VAL NIL) (WHILE (SETQ PAT-ARG (POP PAT-ARGS))) DO
(SETQ CONST-VAL (FILLER/ROLE (ROLE/PAIR PAT-ARG) CONST))
(WHILE (SETQ BINDING-FORM (MATCH (FILLER/PAIR PAT-ARG) CONST-VAL BINDING-FORM)))
(RESULT BINDING-FORM))
Please help. Match, filler/role, filler/pair and role/pair are all custom functions.
i would say it'd look something like this:
(defun match-args (pat-args const binding-form)
(loop for pat-arg in pat-args
for const-val = (filler/role (role/pair pat-arg) const)
do (setq binding-form
(match (filler/pair pat-arg)
const-val
binding-form))
while binding-form
collect binding-form))
it would be better if you could show the source of those functions (or at least their protocol), and input parameters example.
I'm trying to get a binary search tree's struct print function as below to print out a node (with its children, recursively) in an xml-ish style. The idea being that adding appropriate indentation should make it easier to see the structure of the BST.
What I have currently is:
(defstruct
(node (:print-function
(lambda (n s d)
(format s "#<~A ~A ~A>" (node-elt n) (node-l n) (node-r n)))))
elt (l nil) (r nil))
This prints out a BST as, for example:
#<5 #<4 #<2 #<1 NIL NIL> #<3 NIL NIL>> NIL> #<8 #<6 NIL #<7 NIL NIL>> #<9 NIL NIL>>>
But I'd like something from which it is easier to visualise the tree structure.
I have something like this in mind:
#<5
#<4
#<2
#<1 NIL NIL>
#<3 NIL NIL>> NIL>
#<8
#<6 NIL
#<7 NIL NIL>>
#<9 NIL NIL>>>
Assuming my goal is a good one, the indentation depth of each line must depend on the depth of the recursion. I'm not sure how to do that within the format form above.
Actually, maybe this isn't a very good way to display it after all.
If not, what is a good way to print out a (small, of course) binary search tree in the REPL, such that one can easily see its structure? (as a tool to help with algorithm development).
Thanks.
You can use logical blocks.
(defstruct
(node
(:constructor bst (elt &optional l r))
(:print-function
(lambda (n s d)
(declare (ignore d))
(format s
"(~s ~#<~s ~_~s ~_~s)~:>"
'bst
(node-elt n) (node-l n) (node-r n)))))
elt (l nil) (r nil))
When you call PPRINT-LOGICAL-BLOCK, the stream being used becomes a pretty-printing stream during the extent of the block (if it is not already one). Functions that start with pprint- like pprint-newline or pprint-indent respect indentation levels, logical blocks, etc. Usual functions like terpri or fresh-line do not.
The above format defines a logical block after bst, and prints conditional newlines between each element. The added value of this particular printer is that it prints the form readably.
Input
Thanks to the :constructor option, we can write a BST as follows:
(bst t
(bst 1 (bst :x) (bst :y))
(bst 2 (bst :a) (bst :b)))
Printed result
When evaluated, the resulting tree is printed in a way that can be read back to produce an equivalent tree.
(BST T
(BST 1 (BST :X NIL NIL) (BST :Y NIL NIL))
(BST 2 (BST :A NIL NIL) (BST :B NIL NIL)))
Alternative printer
You could also define a printer that just prints the form using an intermediate list. This is simpler to write and relies on existing pretty print functions.
(defstruct
(node
(:constructor bst (elt &optional l r))
(:print-function
(lambda (n s d)
(declare (ignore d))
(princ (list 'bst
(node-elt n)
(node-l n)
(node-r n))
s))))
elt (l nil) (r nil))
Output for modified printer
(BST T (BST 1 (BST X NIL NIL) (BST Y NIL NIL))
(BST 2 (BST A NIL NIL) (BST B NIL NIL)))
I'm baffled. I'm playing around with the tic-tac-toe game found in Ch 10 of COMMON LISP:
A Gentle Introduction to Symbolic Computation https://www.cs.cmu.edu/~dst/LispBook/book.pdf . I worked everything up in the IDE, saved it and then compiled+loaded it. I ran several games with no problem. So, I copied the known-working file and started tweaking. Again, no problems -- everything was working fine. Now, however, when I run (play-one-game) I get the following error:
Error: Attempt to take the value of the unbound variable '*OPPONENT**'
I get the error in both the original and the copy. I closed the AllegroCL and restarted my computer, but the problem persisted after reboot. I then updated the program and ran ./update.sh in it's app directory.
Finally, I decided to then copy the example right from the PDF in a brand-new file in a different directory, and I get the same problem. I don't know what changed, but it's got me plussed to say the least.
(defun make-board ()
(list 'board 0 0 0 0 0 0 0 0 0))
(defun convert-to-letter (v)
(cond ((equal v 1) "O")
((equal v 10) "X")
(t " ")))
(defun print-row (x y z)
(format t "~& ~A | ~A | ~A"
(convert-to-letter x)
(convert-to-letter y)
(convert-to-letter z)))
(defun print-board (board)
(format t "~%")
(print-row
(nth 1 board) (nth 2 board) (nth 3 board))
(format t "~& -----------")
(print-row
(nth 4 board) (nth 5 board) (nth 6 board))
(format t "~& -----------")
(print-row
(nth 7 board) (nth 8 board) (nth 9 board))
(format t "~%~%"))
(defun make-move (player pos board)
(setf (nth pos board) player)
board)
(setf *triplets*
'((1 2 3) (4 5 6) (7 8 9) ;Horizontal triplets.
(1 4 7) (2 5 8) (3 6 9) ;Vertical triplets.
(1 5 9) (3 5 7))) ;Diagonal triplets.
(defun sum-triplet (board triplet)
(+ (nth (first triplet) board)
(nth (second triplet) board)
(nth (third triplet) board)))
(defun compute-sums (board)
(mapcar #'(lambda (triplet)
(sum-triplet board triplet))
*triplets*))
(defun winner-p (board)
(let ((sums (compute-sums board)))
(or (member (* 3 *computer*) sums)
(member (* 3 *opponent*) sums))))
(defun play-one-game ()
(if (y-or-n-p "Would you like to go first? ")
(opponent-move (make-board))
(computer-move (make-board))))
(defun opponent-move (board)
(let* ((pos (read-a-legal-move board))
(new-board (make-move
*opponent*
pos
board)))
(print-board new-board)
(cond ((winner-p new-board)
(format t "~&You win!"))
((board-full-p new-board)
(format t "~&Tie game."))
(t (computer-move new-board)))))
(defun read-a-legal-move (board)
(format t "~&Your move: ")
(let ((pos (read)))
(cond ((not (and (integerp pos)
(<= 1 pos 9)))
(format t "~&Invalid input.")
(read-a-legal-move board))
((not (zerop (nth pos board)))
(format t
"~&That space is already occupied.")
(read-a-legal-move board))
(t pos))))
(defun board-full-p (board)
(not (member 0 board)))
(defun computer-move (board)
(let* ((best-move (choose-best-move board))
(pos (first best-move))
(strategy (second best-move))
(new-board (make-move
*computer* pos board)))
(format t "~&My move: ~S" pos)
(format t "~&My strategy: ~A~%" strategy)
(print-board new-board)
(cond ((winner-p new-board)
(format t "~&I win!"))
((board-full-p new-board)
(format t "~&Tie game."))
(t (opponent-move new-board)))))
(defun random-move-strategy (board)
(list (pick-random-empty-position board)
"random move"))
(defun pick-random-empty-position (board)
(let ((pos (+ 1 (random 9))))
(if (zerop (nth pos board))
pos
(pick-random-empty-position board))))
(defun make-three-in-a-row (board)
(let ((pos (win-or-block board
(* 2 *computer*))))
(and pos (list pos "make three in a row"))))
(defun block-opponent-win (board)
(let ((pos (win-or-block board
(* 2 *opponent*))))
(and pos (list pos "block opponent"))))
(defun win-or-block (board target-sum)
(let ((triplet (find-if
#'(lambda (trip)
(equal (sum-triplet board
trip)
target-sum))
*triplets*)))
(when triplet
(find-empty-position board triplet))))
(defun find-empty-position (board squares)
(find-if #'(lambda (pos)
(zerop (nth pos board)))
squares))
(defun choose-best-move (board) ;Second version.
(or (make-three-in-a-row board)
(block-opponent-win board)
(random-move-strategy board)))
If you're following the instructions it the book, it tells you to invoke
(setf *computer* 10)
(setf *opponent* 1)
Apparently you didn't include that in your code listing.
In general -- if you get an error that something is unbound, the obvious thing to do is to look for the code that should be binding it to a value.
Is there a library for serial port communication in Common Lisp on Windows?
Here are a few functions that implement serial communication using SBCL foreign function POSIX calls. Its not as nice as a full library but I solved my problem of talking to the device according to this protocol
https://valelab.ucsf.edu/svn/micromanager2/branches/micromanager1.3/DeviceAdapters/ZeissCAN/ZeissCAN.cpp
package.lisp:
(defpackage :serial
(:shadowing-import-from :cl close open ftruncate truncate time
read write)
(:use :cl :sb-posix)
(:export #:open-serial
#:close-serial
#:fd-type
#:serial-recv-length
#:read-response
#:write-zeiss
#:talk-zeiss))
(defpackage :focus
(:use :cl :serial)
(:export #:get-position
#:set-position
#:connect
#:disconnect))
serial.lisp:
(in-package :serial)
(defconstant FIONREAD #x541B)
(defconstant IXANY #o4000)
(defconstant CRTSCTS #o20000000000)
(deftype fd-type ()
`(unsigned-byte 31))
(defun open-serial (tty)
(declare (string tty)
(values stream fd-type &optional))
(let* ((fd (sb-posix:open
tty (logior O-RDWR
O-NOCTTY #+nil (this terminal can't control this program)
O-NDELAY #+nil (we don't wait until dcd is space)
)))
(term (tcgetattr fd))
(baud-rate B9600))
(fcntl fd F-SETFL (logior O-RDWR O-NOCTTY)) #+nil (reset file status flags, clearing e.g. O-NDELAY)
(cfsetispeed baud-rate term)
(cfsetospeed baud-rate term)
(macrolet ((set-flag (flag &key (on ()) (off ()))
`(setf ,flag (logior ,#on (logand ,flag ,#off)))))
(setf
(aref (termios-cc term) VMIN) 1 #+nil (wake up after 32 chars are read)
(aref (termios-cc term) VTIME) 5 #+nil (wake up when no char arrived for .1 s))
;; check and strip parity, handshake off
(set-flag (termios-iflag term)
:on ()
:off (IXON IXOFF IXANY
IGNBRK BRKINT PARMRK ISTRIP
INLCR IGNCR ICRNL
))
;; process output
(set-flag (termios-oflag term)
:off (OPOST))
;; canonical input but no echo
(set-flag (termios-lflag term)
:on ()
:off (ICANON ECHO ECHONL IEXTEN ISIG))
;; enable receiver, local mode, 8N1 (no parity)
(set-flag (termios-cflag term)
:on (CLOCAL CREAD
CS8 CRTSCTS)
:off (CSTOPB CSIZE PARENB)))
(tcflush fd TCIFLUSH) #+nil (throw away any input data)
(tcsetattr fd TCSANOW term) #+nil (set terminal port attributes)
(values
(sb-sys:make-fd-stream fd :input t :output t
:buffering :full)
fd)))
(defun close-serial (fd)
(declare (fd-type fd)
(values null &optional))
(fcntl fd F-SETFL 0) #+nil (reset file status flags, clearing e.g. O-NONBLOCK)
(sb-posix:close fd) #+nil (this will set DTR low)
nil)
(defun serial-recv-length (fd)
(declare (fd-type fd)
(values (signed-byte 32) &optional))
(sb-alien:with-alien ((bytes sb-alien:int))
(ioctl fd FIONREAD (sb-alien:addr bytes))
bytes))
(defun read-response (tty-fd tty-stream)
(declare (fd-type tty-fd)
(stream tty-stream)
(values string &optional))
(declare (fd-type tty-fd)
(stream tty-stream)
(values string &optional))
(let ((n (serial-recv-length tty-fd)))
(if (eq 0 n)
""
(let ((ret (make-string n)))
(dotimes (i n)
(setf (char ret i) (read-char tty-stream)))
ret))))
(defun write-zeiss (tty-stream command)
(declare (stream tty-stream)
(string command))
(format tty-stream "~a~a" command #\Return)
(finish-output tty-stream))
(defun talk-zeiss (tty-fd tty-stream command)
(declare (fd-type tty-fd)
(stream tty-stream)
(string command)
(values string &optional))
(write-zeiss tty-stream command)
;; I measured that the position is fully transmitted after 30 ms.
(let ((n (do ((i 0 (1+ i))
(n 0 (serial-recv-length tty-fd)))
((or (< 0 n) (<= 30 i)) n)
(sleep .03d0))))
(if (eq 0 n)
""
(read-response tty-fd tty-stream))))
focus.lisp:
(in-package :focus)
(defvar *stream* nil)
(defvar *fd* nil)
(defun run-shell (command)
(with-output-to-string (stream)
(sb-ext:run-program "/bin/bash" (list "-c" command)
:input nil
:output stream)))
(defun find-zeiss-usb-adapter ()
(let ((port (run-shell "dmesg|grep pl2303|grep ttyUSB|tail -n1|sed s+.*ttyUSB+/dev/ttyUSB+g|tr -d '\\n'")))
(if (string-equal "" port)
(error "dmesg output doesn't contain ttyUSB assignment. This can happen when the system ran a long time. You could reattach the USB adapter that is connected to the microscope.")
port)))
#+nil
(find-zeiss-usb-adapter)
(defun connect (&optional (devicename (find-zeiss-usb-adapter)))
(multiple-value-bind (s fd)
(open-serial devicename)
(defparameter *stream* s)
(defparameter *fd* fd)))
#+nil
(connect)
(defun disconnect ()
(close-serial *fd*)
(setf *stream* nil))
#+nil
(disconnect)
#+nil
(serial-recv-length *fd*)
#+nil ;; do cat /dev/ttyUSB1 in some terminal, or use read-response below
(progn
(format *stream* "HPTv0~a" #\Return)
(finish-output *stream*))
#+nil
(progn
(format *stream* "FPZp~a" #\Return)
(finish-output *stream*))
#+nil
(read-response *fd* *stream*)
#+nil
(response->pos-um (read-response *fd* *stream*))
#+nil
(close-serial *fd2*)
#+nil
(time
(response->pos-um (talk-zeiss *fd2* *s2* "FPZp")))
#+nil ;; measure the time it takes until the full response has arrived
(progn
(format *s2* "FPZp~a" #\Return)
(finish-output *s2*)
(dotimes (i 10)
(sleep .01d0)
(format t "~a~%" (list i (serial-recv-length *fd2*))))
(read-response *fd2* *s2*))
(defconstant +step-size+ .025s0 "Distance of one z step in micrometer.")
(defun response->pos-um (answer)
(declare (string answer)
(values single-float &optional))
(if (equal "PF" (subseq answer 0 2))
(let* ((uval (the fixnum (read-from-string
(format nil "#x~a" (subseq answer 2)))))
(val (if (eq 0 (logand uval #x800000))
uval ;; positive
(- uval #xffffff 1))))
(* +step-size+ val))
(error "unexpected answer on serial port.")))
;; some tricks with two's complement here! be sure to generate a
;; 24bit signed number consecutive application of pos-um->request and
;; response->pos-um should be the identity (if you don't consider the
;; prefix "PF" that response->pos-um expects)
(defun pos-um->request (pos-um)
(declare (single-float pos-um)
(values string &optional))
(format nil "~6,'0X"
(let ((val (round pos-um +step-size+)))
(if (< val 0)
(+ #xffffff val 1)
val))))
(defun get-position ()
(declare (values single-float &optional))
(response->pos-um (talk-zeiss *fd* *stream* "FPZp")))
(defun set-position (position-um)
"Decreasing the position moves away from sample."
(declare (single-float position-um))
(write-zeiss *stream*
(format nil "FPZT~a" (pos-um->request position-um))))
#+nil
(format nil "FPZT~a" (pos-um->request -8.0d0))
#+nil
(defparameter current-pos (get-position *fd* *stream*))
#+nil
(format t "pos: ~a~%" (get-position *fd2* *s2*))
# +nil
(time (format t "response ~a~%"
(set-position *s2* (+ current-pos 0.7d0))))
#+nil
(progn
(set-position *s2* (+ current-pos 135d0))
(dotimes (i 20)
(format t "pos ~a~%" (list i (get-position *fd2* *s2*)))))
#+nil
(loop for i below 100 do
(sleep .1)
(format t "~a~%" (response->pos-um (talk-zeiss "FPZp"))))
I don't know if there's a free one available, but LispWorks has one - SERIAL-PORT.
Failing that, you might have to write your own. You could try simply writing the FFI wrappers for the Windows calls (GetCommState, WaitCommEvent, etc.) as a start. It's most certainly doable.
This isn't really a lisp question, but I'll attempt to answer it anyway. Short answer: no. Long answer: possibly. It depends on how the FFI works and what environment you're using(raw windows, cygwin, mingw) If you are using raw windows, the chances is very slim. Actually, either way I'd bet the chances are slim. Lisp is a fairly high-level language, and isn't designed for stuff such as this.