Author: mcermak Date: Mon Aug 20 16:05:17 2007 New Revision: 2
Modified: nxtlisp/remote-commands.lisp Log: set-sensor-state and sensor remote commands done but not tested yet
Modified: nxtlisp/remote-commands.lisp ============================================================================== --- nxtlisp/remote-commands.lisp (original) +++ nxtlisp/remote-commands.lisp Mon Aug 20 16:05:17 2007 @@ -57,10 +57,10 @@ ;; change-nxt-id (a wrapper around set-brick-name-command) ;; set-sensor-state (uses set-input-mode direct command and ;; reset-input-scaled-value if clear flag is set) -;; sensor - done just partly, consult next steps with Dr.K +;; sensor (type and mode are possible &optional arguments, maybe not the +;; best solution)
- ;; differences between RCX and NXT: ;; play-system-sound-file plays a sound file in NXT's memory, possibly in a loop ;; start-nxt-program takes and string as an program name; rcx requires a number @@ -74,6 +74,53 @@ (EXPORT '(var set-var message send-message sensor effector set-effector-state read-rcx-executable))
+(defvar *last-sensor-type* nil + "If sensor is called with no modifier arguments, *last-sensor-type* is checked +to obtain sensor type. It also maintains backward compatibility with RCXLisp.") + +(defvar *last-sensor-mode* nil + "If sensor is called with no modifier arguments, *last-sensor-mode* is checked +to obtain sensor mode. It also maintains backward compatibility with RCXLisp.") + +(defun update-last-sensor-type (port sensor-type) + "Updates the *last-sensor-type* variable according to last call of set-sensor-state." + (if (or (eql *last-sensor-type* nil) ; port has not been used yet (not in list) + (not (let ((used nil)) ; there's gotta be a better way... + (dolist (i *last-sensor-type*) + (if (eql (car i) port) + (setf used t))) + used))) + (push (list port sensor-type) *last-sensor-type*) + (loop for element in *last-sensor-type* ; port has been used, update + when (eql (car element) port) + return (setf (cdr element) sensor-type)))) + +(defun update-last-sensor-mode (port sensor-mode) + "Updates the *last-sensor-mode* variable according to last call of set-sensor-state." + (if (or (eql *last-sensor-mode* nil) ; port has not been used yet (not in list) + (not (let ((used nil)) + (dolist (i *last-sensor-mode*) + (if (eql (car i) port) + (setf used t))) + used))) + (push (list port sensor-mode) *last-sensor-mode*) + (loop for element in *last-sensor-mode* ; port has been used, update + when (eql (car element) port) + return (setf (cdr element) sensor-mode)))) + +(defun extract-type (port) + "Returns the last set type of sensor on port." + (loop for element in *last-sensor-type* + when (eql (car element) port) + return (cdr element))) + +(defun extract-mode (port) + "Returns the last set mode of sensor on port." + (loop for element in *last-sensor-mode* + when (eql (car element) port) + return (cdr element))) + + (defun play-tone (frequency duration &optional (stream *standard-nxt-io*)) "Plays a tone on the NXT. Frequency is in Hz (200-14000), duration in ms." (direct-play-tone frequency duration :stream stream)) @@ -147,12 +194,45 @@ (:slope-mask #x1F) (:mode-mask #xE0)))) ; has the same value as :angle-steps in docs (?) (set-input-mode port sensor-type sensor-mode :stream stream) - (if clear (reset-input-scaled-value port)))) ; if the clear flag is set, reset the counter + (if clear (reset-input-scaled-value port)) ; if the clear flag is set, reset the counter + ;; see the manual or documentation in the source code for description + (update-last-sensor-type port sensor-type) + (update-last-sensor-mode port sensor-mode))) +
-(defun sensor (port &optional (stream *standard-nxt-io*)) +;; TODO: should the type/mode handling be this way? rethink +(defun sensor (port &optional (type :raw type-supplied-p) + (mode :raw mode-supplied-p) (stream *standard-nxt-io*)) "Retrieves values from the sensor plugged in <port> port." - ;; TODO: handle the return value (consult with Dr. K) - (get-input-values port)) + (let ((raw-packet (get-input-values port)) + ;; if type or mode was not supplied, use values set + ;; in last call to set-sensor-state + (sensor-type (if type-supplied-p + type + (extract-type port))) + (sensor-mode (if mode-supplied-p + mode + (extract-mode port)))) + ;; let's decode the packet according to type/mode + (if (not (aref raw-packet 1)) + (warn "sensor: Packet marked as not valid.")) + ;; sensor-type has higher priority to sensor-mode + (case sensor-type + (:angle (extract-number (aref raw-packet 9) + (aref raw-packet 10) + :sword)) + ((or :light-active + :light-inactive) (extract-number (aref raw-packet 7) + (aref raw-packet 8) + :uword)) + (t (case sensor-mode + ((or :boolean :transition-cnt :period-counter + :celsius :fahrenheit) (extract-number (aref raw-packet 9) + (aref raw-packet 10) + :sword)) + (t (extract-number (aref raw-packet 5) + (aref raw-packet 6) + :uword)))))))
(defun effector (effector feature &optional (stream *standard-nxt-io*)) "Returns the current value of <feature> for <effector>." @@ -163,3 +243,10 @@ (defun set-effector-state (effector feature value &optional (stream *standard-nxt-io*)) "TODO: document")
+(defun extract-number (byte-1 byte-2 mode) + "Return a number constructed from 2 bytes, either a signed word or unsigned word." + (case mode + (:uword (+ byte-1 (* byte-2 256))) + (:sword (if (< byte-2 127) ; possitive? + (+ byte-1 (* byte-2 256)) + (1+ (lognot (+ byte-1 (* byte-2 256)))))))) \ No newline at end of file