;;; ;;; han14xs.lisp ;;; ;;; experiments to figure out how to control a han14xs (buslink) mp3 player ;;; (cl:defpackage :han14xs (:use :common-lisp #| :sb-alien |# :sb-usb)) (cl:in-package :han14xs) ;; Utility function (defun hexdump (array index base &optional (n #x80) &aux (textbuf (make-string 18))) (unless (zerop (logand base 15)) (format t "~(~8,'0X:~)" base)) (setf (aref textbuf 0) #\|) (dotimes (i (logand base 15)) (format t " ") (setf (aref textbuf i) #\Space) (setf (aref textbuf (1+ i)) #\|)) (setf (aref textbuf 17) #\|) (dotimes (j n) (when (zerop (logand 15 (+ base j))) (format t "~(~8,'0X:~)" (+ base j))) (format t " ~(~2,'0X~)" (aref array (+ index j))) (setf (aref textbuf (1+ (logand 15 (+ base j)))) (if (and (< (aref array (+ index j)) #x80) (graphic-char-p (code-char (aref array (+ index j))))) (code-char (aref array (+ index j))) #\.)) (when (= 15 (logand 15 (+ base j))) (format t " ~A~%" textbuf) (setf (aref textbuf 0) #\|))) (unless (zerop (logand 15 (+ base n))) (setf (aref textbuf (1+ (logand 15 (+ base n)))) #\|) (dotimes (i (- 16 (logand 15 (+ base n)))) (format t " ") (setf (aref textbuf (+ 2 i (logand 15 (+ base n)))) #\Space)) (format t " ~A~%" textbuf))) ;;; DOS file date/time encoding. (defun file-encode-date (time) "Convert the universal-time TIME to a DOS file date as an unsigned-byte 16." (multiple-value-bind (f1 f2 f3 day month year) (decode-universal-time time) (declare (ignore f1 f2 f3)) (dpb (- year 1980) (byte 7 9) (dpb month (byte 4 5) day)))) (defun file-decode-date (date) "Convert the DOS file date (unsigned-byte 16) DATE to a string." (let ((year (+ 1980 (ldb (byte 7 9) date))) (month (ldb (byte 4 5) date)) (day (ldb (byte 5 0) date))) (format nil "~4,'0D-~A-~2,'0D" year (elt '(nil "Jan" "Feb" "Mar" "Apr" "May" "Jun" "Jul" "Aug" "Sep" "Oct" "Nov" "Dec") month) day))) (defun file-encode-time (time) "Convert the universal-time TIME to a DOS file time as an unsigned-byte 16." (multiple-value-bind (seconds minutes hours) (decode-universal-time time) (dpb hours (byte 5 11) (dpb minutes (byte 6 5) (ldb (byte 5 1) seconds))))) (defun file-decode-time (time) "Convert the (unsigned-byte 16) DOS file time TIME to a string." (let ((hours (ldb (byte 5 11) time)) (minutes (ldb (byte 6 5) time)) (seconds (ash (ldb (byte 5 0) time) 1))) (format nil "~2,'0D:~2,'0D:~2,'0D" hours minutes seconds))) ;; Actual device handling (defun han14xs-start-command-frame (dev) (let ((result (make-array 1 :element-type '(unsigned-byte 8) :fill-pointer t))) (usb-control dev #xc0 #x0a #x0000 #x0000 result) (assert (= (aref result 0) #x40)))) (defun han14xs-start-upload-frame (dev) (let ((result (make-array 1 :element-type '(unsigned-byte 8) :fill-pointer t))) (usb-control dev #xc0 #x0b #x0000 #x0000 result) (assert (= (aref result 0) #x80)))) (defun han14xs-start-result-frame (dev) (let ((result (make-array 1 :element-type '(unsigned-byte 8) :fill-pointer t))) (usb-control dev #xc0 #x0c #x0000 #x0000 result) (assert (= (aref result 0) #x40)))) (defun han14xs-stop-frame (dev) (let ((result (make-array 1 :element-type '(unsigned-byte 8) :fill-pointer t))) (usb-control dev #xc0 #x0a #x0000 #xffff result) (assert (= (aref result 0) #x40)))) (defun han14xs-send-command (dev &rest bytes) (let ((command (make-array (logand #x-40 (+ #x3f 5 (length bytes))) :element-type '(unsigned-byte 8) :initial-element 0 :fill-pointer t))) (setf (aref command 0) #x23 (aref command 2) (+ 2 (length bytes)) (aref command 3) (char-code #\:) (aref command (+ 4 (length bytes))) (char-code #\.)) (loop for index from 4 for byte in bytes do (setf (aref command index) byte)) ;; FIXME: Should really send in #x40-byte chunks. (usb-bulk dev 2 command))) (defun han14xs-recv-result (dev) (let ((result (make-array #x40 :element-type '(unsigned-byte 8) :fill-pointer t))) (usb-bulk dev #x83 result) result)) (defmacro with-restart-on-timeout (&body body) `(handler-bind ((usb-timeout #'(lambda (c) (declare (ignore c)) (invoke-restart 'retry)))) ,@body)) (defun han14xs-read-bulk-data (dev length) (let* ((padded-length (logand #x-40 (+ #x3f length))) (blocks (ash padded-length -6)) (result (make-array padded-length :element-type '(unsigned-byte 8) :fill-pointer t))) (han14xs-start-result-frame dev) (with-restart-on-timeout (loop for i from 0 below blocks do (setf (fill-pointer result) (ash (1+ i) 6)) (usb-bulk dev #x83 result (ash i 6)))) (han14xs-stop-frame dev) (setf (fill-pointer result) length) result)) (defun han14xs-read-reply-data (dev) (let ((result (make-array #x40 :element-type '(unsigned-byte 8) :fill-pointer t))) ;; Load the first result block. (with-restart-on-timeout (usb-bulk dev #x83 result)) ;; Validate the first part of the wrapper. (assert (= #x23 (aref result 0))) (assert (zerop (aref result 1))) (assert (= #x3a (aref result 3))) ;; Find the reply length, number of additional blocks ;; required, and validate the length. (let* ((length (aref result 2)) (extra-blocks (floor (+ length 3) #x40))) (assert (>= length 2)) ;; Load additional result blocks if required. (unless (zerop extra-blocks) ;; Allocate more space for the result. (let ((new-result (make-array (* #x40 (1+ extra-blocks)) :element-type '(unsigned-byte 8) :fill-pointer #x40))) (replace new-result result) (setf result new-result)) ;; Load the remaining data in #x40 byte blocks. (with-restart-on-timeout (loop for i from 1 to extra-blocks do (incf (fill-pointer result) #x40) (usb-bulk dev #x83 result (* i #x40))))) ;; Validate the result end marker. (assert (= #x2e (aref result (+ 2 length)))) ;; Pick out the actual result data. (subseq result 4 (+ length 2))))) (defun han14xs-transact (dev &rest command) (han14xs-start-command-frame dev) (apply #'han14xs-send-command dev command) (han14xs-stop-frame dev) (han14xs-start-result-frame dev) (prog1 (han14xs-read-reply-data dev) (han14xs-stop-frame dev))) (defun han14xs-bulk-transact (dev result-length &rest command) (han14xs-start-command-frame dev) (apply #'han14xs-send-command dev command) (han14xs-stop-frame dev) (han14xs-start-result-frame dev) (prog1 (han14xs-read-bulk-data dev result-length) (han14xs-stop-frame dev))) (defun han14xs-read-directory (dev card) (let* ((card-byte (ecase card (:internal #x4d) (:external #x53))) (result-1 (han14xs-transact dev card-byte #x47))) (assert (= 4 (length result-1))) (let* ((length (dpb (aref result-1 2) (byte 8 8) (aref result-1 3))) (result-2 (han14xs-bulk-transact dev length #x46)) (card-size-blocks (dpb (aref result-2 0) (byte 8 8) (aref result-2 1))) (card-remaining-blocks (dpb (aref result-2 4) (byte 8 8) (aref result-2 5)))) (format t "~A card (~A/~A blocks free, ~A/~A kbytes free):~%" card card-remaining-blocks card-size-blocks (* #x40 card-remaining-blocks) (* #x40 card-size-blocks)) ;; FIXME: Convert to more useful form? (hexdump result-2 8 0 (- length 8))))) (defun han14xs-format-card (dev card) (let* ((card-byte (ecase card (:internal #x4d) (:external #x53))) (result-1 (han14xs-transact dev card-byte #x46))) (assert (= 2 (length result-1))) (assert (= card-byte (aref result-1 0))) (assert (= #x46 (aref result-1 1))) (let ((result-2 (han14xs-transact dev #x46))) (assert (= 1 (length result-2))) (assert (zerop (aref result-2 0)))))) (defun han14xs-delete-file (dev short-name) "Delete a file from the player. SHORT-NAME is a DOS 8.3 filename." ;; Internal memory only? (let* ((command-bytes (concatenate 'list '(#x4d #x45) (map 'list #'char-code short-name))) (result-1 (apply #'han14xs-transact dev command-bytes)) (result-2 (han14xs-transact dev #x46))) ;; FIXME: Probably should validate result-1 somehow. (declare (ignore result-1)) (assert (= 1 (length result-2))) (assert (zerop (aref result-2 0))))) (defun han14xs-upload-file (dev card filespec &key (shortname "TESTFI~1.MP3") progress-report) (with-open-file (infile filespec :direction :input :element-type '(unsigned-byte 8)) (let* ((longname (file-namestring (pathname filespec))) ;; FIXME: Real shortname? (shortname shortname) (file-time (file-write-date filespec)) (dos-file-time (file-encode-time file-time)) (dos-file-date (file-encode-date file-time)) (encoded-time (list (ldb (byte 8 0) dos-file-time) (ldb (byte 8 8) dos-file-time))) (encoded-date (list (ldb (byte 8 0) dos-file-date) (ldb (byte 8 8) dos-file-date))) (encoded-shortname (loop for char across shortname collect (char-code char))) (shortname-length (length shortname)) (encoded-shortname-length (list (ldb (byte 8 8) shortname-length) (ldb (byte 8 0) shortname-length))) (encoded-longname (sb-ext:string-to-octets longname :external-format :ucs2le)) (longname-length (* 2 (length longname))) (encoded-longname-length (list (ldb (byte 8 8) longname-length) (ldb (byte 8 0) longname-length))) (card-byte (ecase card (:internal #x4d) (:external #x53))) (file-length (file-length infile)) (encoded-file-length (list (ldb (byte 8 24) file-length) (ldb (byte 8 16) file-length) (ldb (byte 8 8) file-length) (ldb (byte 8 0) file-length))) (command-bytes (concatenate 'list (list card-byte) '(#x90 #x17 #x02 #x20) ;; Magic? encoded-date encoded-time encoded-file-length '(#x00) ;; Padding? encoded-shortname-length encoded-shortname encoded-longname-length encoded-longname)) (result-1 (apply #'han14xs-transact dev command-bytes))) ;; FIXME: Do some validation on result-1. (declare (ignore result-1)) (let* ((upload-data (make-array #x40 :element-type '(unsigned-byte 8) :fill-pointer t)) (padded-length (logand #x-8000 (+ #x7fff file-length))) (blocks (ash padded-length -6))) (han14xs-start-upload-frame dev) ;; Upload the file data. (with-restart-on-timeout (loop for i from 0 below blocks for index = (read-sequence upload-data infile) when (< index #x40) do (fill upload-data 0 :start index) end ;; FIXME: Real progress report interface would be nice. when (and progress-report (zerop (logand i #x1f))) do (swank::background-message "~D/~D blocks transferred (~D%)" (1+ i) blocks (truncate (* 100 (/ blocks (1+ i))))) end do (usb-bulk dev 2 upload-data))) (han14xs-stop-frame dev))))) (defun read-usb-devices () "Returns the contents of /proc/bus/usb/devices as a string." (with-open-file (devlist "/proc/bus/usb/devices") ;; This "file" violates the usual contract of select(2). ;; Anally. With a spiked dildo. An input-ready condition on ;; the file indicates that a device has been connected or ;; disconnected, not that there happens to be more data to ;; read. No select(2) means no serve-event. No serve-event ;; means that we can't use the standard Lisp file I/O, and ;; have to do our own buffering... And, while we're at it, we ;; won't bother doing our own error handling. (let* ((buffers (loop for buf = (make-array #x200 :element-type '(unsigned-byte 8) :fill-pointer t) for (len error) = (multiple-value-list (sb-unix:unix-read (sb-sys:fd-stream-fd devlist) (sb-sys:vector-sap (sb-kernel:%array-data-vector buf)) #x200)) until (or (null len) (zerop len)) do (setf (fill-pointer buf) len) collect buf)) (combined-buffer (apply #'concatenate '(vector (unsigned-byte 8)) buffers)) (file-contents (sb-ext:octets-to-string combined-buffer))) file-contents))) (defun open-usb-device (bus device) (let ((device-file (format nil "/proc/bus/usb/~3,'0D/~3,'0D" bus device))) (open device-file :direction :io :if-exists :overwrite))) #| (let ((directory *dir*)) (loop with lfn for entry from 8 below (length directory) by #x20 when (= #x0f (aref directory (+ entry #x0b))) do (let* ((length-bits (ldb (byte 5 0) (aref directory entry))) (base (* 26 (1- length-bits)))) (when (logbitp 6 (aref directory entry)) (setf lfn (make-array (* length-bits 26) :element-type '(unsigned-byte 8) :fill-pointer t))) (setf (subseq lfn base (+ base 10)) (subseq directory (+ entry 1)) (subseq lfn (+ base 10) (+ base 22)) (subseq directory (+ entry #x0e)) (subseq lfn (+ base 22) (+ base 26)) (subseq directory (+ entry #x1c)))) else collect (let* ((8-length (or (position #x20 directory :start entry :end (+ entry 8)) 8)) (3-length (or (position #x20 directory :start (+ entry 8) :end (+ entry 11)) 3)) (8-part (subseq directory entry (+ entry 8-length))) (3-part (subseq directory (+ entry 8) (+ entry 8 3-length))) (filename (sb-ext:octets-to-string (concatenate '(vector (unsigned-byte 8)) 8-part '(#.(char-code #\.)) 3-part))) (encoded-date (dpb (aref directory (+ entry #x19)) (byte 8 8) (aref directory (+ entry #x18)))) (encoded-time (dpb (aref directory (+ entry #x16)) (byte 8 8) (aref directory (+ entry #x17)))) (decoded-date (file-decode-date encoded-date)) (decoded-time (file-decode-time encoded-time)) (file-length (dpb (dpb (aref directory (+ entry #x1f)) (byte 8 8) (aref directory (+ entry #x1e))) (byte 16 16) (dpb (aref directory (+ entry #x1d)) (byte 8 8) (aref directory (+ entry #x1c)))))) ;; Crop LFN to length. (loop for index from 0 below (length lfn) by 2 when (and (zerop (aref lfn index)) (zerop (aref lfn (1+ index)))) do (setf (fill-pointer lfn) index) (loop-finish)) (list filename (sb-ext:octets-to-string lfn :external-format :ucs2le) file-length decoded-date decoded-time)) and do (setf lfn nil))) |# #| (with-open-file (dev "/proc/bus/usb/001/022" :direction :io :if-exists :overwrite) ;(usb-disconnect dev) ;; "no data available"? (usb-claim-interface dev 0) ;; FIXME: Should probably check connectinfo here. #+(or) (let ((descriptor (make-array #x12 :element-type '(unsigned-byte 8) :fill-pointer t))) (usb-control dev #x80 #x06 #x0001 #x0000 descriptor) descriptor) (format t "Sending identify request:~%") (han14xs-start-command-frame dev) (han14xs-send-command dev #x90 #x53) ;; What does this command mean? (han14xs-stop-frame dev) (han14xs-start-result-frame dev) (handler-bind ((usb-timeout #'(lambda (c) (declare (ignore c)) (invoke-restart 'retry)))) (hexdump (han14xs-recv-result dev) 0 0 #x40) (hexdump (han14xs-recv-result dev) 0 0 #x40) (hexdump (han14xs-recv-result dev) 0 0 #x40)) (han14xs-stop-frame dev) #;| (format t "Sending mystery request:~%") (han14xs-start-command-frame dev) (han14xs-send-command dev #x4d #x47) ;; What does this command mean? (han14xs-stop-frame dev) (han14xs-start-result-frame dev) (handler-bind ((usb-timeout #'(lambda (c) (declare (ignore c)) (invoke-restart 'retry)))) (hexdump (han14xs-recv-result dev) 0 0 #x40)) (han14xs-stop-frame dev) (format t "Sending internal directory request:~%") (han14xs-start-command-frame dev) (han14xs-send-command dev #x46) ;; What does this command mean? (han14xs-stop-frame dev) (han14xs-start-result-frame dev) (handler-bind ((usb-timeout #'(lambda (c) (declare (ignore c)) (invoke-restart 'retry)))) (hexdump (han14xs-recv-result dev) 0 0 #x40) (hexdump (han14xs-recv-result dev) 0 0 #x40) (hexdump (han14xs-recv-result dev) 0 0 #x40) (hexdump (han14xs-recv-result dev) 0 0 #x40) (hexdump (han14xs-recv-result dev) 0 0 #x40) (hexdump (han14xs-recv-result dev) 0 0 #x40) (hexdump (han14xs-recv-result dev) 0 0 #x40) (hexdump (han14xs-recv-result dev) 0 0 #x40) (hexdump (han14xs-recv-result dev) 0 0 #x40) (hexdump (han14xs-recv-result dev) 0 0 #x40) (hexdump (han14xs-recv-result dev) 0 0 #x40) (hexdump (han14xs-recv-result dev) 0 0 #x40) (hexdump (han14xs-recv-result dev) 0 0 #x40)) (han14xs-stop-frame dev) (format t "Sending mystery request:~%") (han14xs-start-command-frame dev) (han14xs-send-command dev #x53 #x47) ;; What does this command mean? (han14xs-stop-frame dev) (han14xs-start-result-frame dev) (handler-bind ((usb-timeout #'(lambda (c) (declare (ignore c)) (invoke-restart 'retry)))) (hexdump (han14xs-recv-result dev) 0 0 #x40)) (han14xs-stop-frame dev) (format t "Sending external directory request:~%") (han14xs-start-command-frame dev) (han14xs-send-command dev #x46) ;; What does this command mean? (han14xs-stop-frame dev) (han14xs-start-result-frame dev) (handler-bind ((usb-timeout #'(lambda (c) (declare (ignore c)) (invoke-restart 'retry)))) (hexdump (han14xs-recv-result dev) 0 0 #x40) (hexdump (han14xs-recv-result dev) 0 0 #x40)) (han14xs-stop-frame dev) |;# (format t "Sending internal directory request:~%") (let (result-1) (han14xs-start-command-frame dev) (han14xs-send-command dev #x4d #x47) ;; Prep for internal directory (han14xs-stop-frame dev) (han14xs-start-result-frame dev) (handler-bind ((usb-timeout #'(lambda (c) (declare (ignore c)) (invoke-restart 'retry)))) (setf result-1 (han14xs-recv-result dev))) (han14xs-stop-frame dev) (han14xs-start-command-frame dev) (han14xs-send-command dev #x46) ;; Signal ready for data (han14xs-stop-frame dev) (let* ((dir-length (dpb (aref result-1 6) (byte 8 8) (aref result-1 7))) (directory-data (han14xs-read-bulk-data dev dir-length))) (hexdump directory-data 0 0 (length directory-data)))) (format t "Sending external directory request:~%") (let (result-1) (han14xs-start-command-frame dev) (han14xs-send-command dev #x53 #x47) ;; Prep for external directory (han14xs-stop-frame dev) (han14xs-start-result-frame dev) (handler-bind ((usb-timeout #'(lambda (c) (declare (ignore c)) (invoke-restart 'retry)))) (setf result-1 (han14xs-recv-result dev))) (han14xs-stop-frame dev) (han14xs-start-command-frame dev) (han14xs-send-command dev #x46) ;; Signal ready for data (han14xs-stop-frame dev) (let* ((dir-length (dpb (aref result-1 6) (byte 8 8) (aref result-1 7))) (directory-data (han14xs-read-bulk-data dev dir-length))) (hexdump directory-data 0 0 (length directory-data)))) ) |# ;; Sending identify request: ;; 00000000: 23 00 8a 3a 90 53 00 00 00 09 00 30 32 33 34 35 |#..:.S.....02345| ;; ^^ reply length (including 3a and 2e bytes) ;; 00000010: 36 37 38 2e 41 42 43 00 00 00 00 00 00 00 00 00 |678.ABC.........| ;; 00000020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| ;; 00000030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| ;; 00000000: 00 00 00 00 00 00 00 00 00 00 00 00 00 32 2e 32 |.............2.2| ;; 00000010: 2e 30 2e 30 2e 31 20 20 32 30 30 32 30 39 30 30 |.0.0.1 20020900| ;; 00000020: 48 61 6e 2d 31 34 78 73 6d 20 20 20 20 41 4d 41 |Han-14xsm AMA| ;; 00000030: 43 2e 20 43 6f 2e 20 20 20 20 20 20 20 20 20 20 |C. Co. | ;; 00000000: 20 00 00 00 00 00 00 00 00 00 00 00 2e 56 00 00 | ............V..| ;; 00000010: 8d e3 00 06 f6 90 00 00 39 92 00 5a 00 36 60 05 |........9..Z.6`.| ;; 00000020: 01 00 04 00 8f e3 00 1d 96 9f b2 00 39 92 00 00 |............9...| ;; 00000030: 8d e3 00 89 1d 01 8d e3 00 1d 89 d4 d7 00 39 92 |..............9.| ;; Select internal card: ;; 00000000: 23 00 06 3a 4d 47 03 08 2e 00 00 00 00 00 00 00 |#..:MG..........| ;; ^^ reply length (including 3a and 2e bytes) ;; ^^ ^^ command bytes (as originally sent) ;; ^^ ^^ directory data length ;; 00000010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| ;; 00000020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| ;; 00000030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| ;; Sending directory request: ;; 00000000: 07 d0 00 00 00 c1 80 00 |........| ;; "isbw_special002_060327.mp3" ? ;; 00000000: 42 30 00 32 00 5f 00 30 |B0.2._.0| ;; 00000010: 00 36 00 0f 00 9d 30 00 33 00 32 00 37 00 2e 00 |.6....0.3.2.7...| ;; 00000020: 6d 00 00 00 70 00 33 00 01 69 00 73 00 62 00 77 |m...p.3..i.s.b.w| ;; 00000030: 00 5f 00 0f 00 9d 73 00 70 00 65 00 63 00 69 00 |._....s.p.e.c.i.| ;; 00000000: 61 00 00 00 6c 00 30 00 |a...l.0.| ;; "IS1C54~1MP3" Is this a FAT-style directory entry? Yes. ; Filename: "IS1C54~1" ; Ext: "MP3" ; Attrib: #x20 (Archive) ; Reserved: #x03 #xe7 #xd1 #x02 #x00 #x8e #xc9 #x8e #xe3 #x00 ; Time: #xa77b ; Date: #x365a ; Cluster: 3 ; Size: #x2d571e (2971422 bytes) ;; 00000000: 49 53 31 43 35 34 7e 31 |IS1C54~1| ;; 00000010: 4d 50 33 20 03 e7 d1 02 00 8e c9 8e e3 00 7b a7 |MP3 ..........{.| ;; 00000020: 5a 36 03 00 1e 57 2d 00 |Z6...W-.| ;; "isbw_special003_060328.mp3" ? ;; 00000020: 42 30 00 33 00 5f 00 30 |B0.3._.0| ;; 00000030: 00 36 00 0f 00 e3 30 00 33 00 32 00 38 00 2e 00 |.6....0.3.2.8...| ;; 00000000: 6d 00 00 00 70 00 33 00 01 69 00 73 00 62 00 77 |m...p.3..i.s.b.w| ;; 00000010: 00 5f 00 0f 00 e3 73 00 70 00 65 00 63 00 69 00 |._....s.p.e.c.i.| ;; 00000020: 61 00 00 00 6c 00 30 00 49 53 35 44 45 33 7e 31 |a...l.0.IS5DE3~1| ;; 00000030: 4d 50 33 20 02 00 8e c9 8e 8e c9 8e e3 00 56 a8 |MP3 ..........V.| ;; 00000000: 5a 36 b9 00 6f d4 49 00 |Z6..o.I.| ;; 00000000: 42 30 00 34 00 5f 00 30 |B0.4._.0| ;; 00000010: 00 36 00 0f 00 21 30 00 33 00 32 00 39 00 2e 00 |.6...!0.3.2.9...| ;; 00000020: 6d 00 00 00 70 00 33 00 01 69 00 73 00 62 00 77 |m...p.3..i.s.b.w| ;; 00000030: 00 5f 00 0f 00 21 73 00 70 00 65 00 63 00 69 00 |._...!s.p.e.c.i.| ;; 00000000: 61 00 00 00 6c 00 30 00 49 53 37 32 41 41 7e 31 |a...l.0.IS72AA~1| ;; 00000010: 4d 50 33 20 c9 8e 8e c9 8e 8e c9 8e e3 00 73 a8 |MP3 ..........s.| ;; 00000020: 5a 36 e1 01 2c 41 4d 00 42 30 00 35 00 5f 00 30 |Z6..,AM.B0.5._.0| ;; 00000030: 00 36 00 0f 00 6c 30 00 33 00 33 00 30 00 2e 00 |.6...l0.3.3.0...| ;; 00000000: 6d 00 00 00 70 00 33 00 01 69 00 73 00 62 00 77 |m...p.3..i.s.b.w| ;; 00000010: 00 5f 00 0f 00 6c 73 00 70 00 65 00 63 00 69 00 |._...ls.p.e.c.i.| ;; 00000020: 61 00 00 00 6c 00 30 00 49 53 42 57 5f 53 7e 31 |a...l.0.ISBW_S~1| ;; 00000030: 4d 50 33 20 c9 8e 8e c9 8e 8e c9 8e e3 00 ba a6 |MP3 ............| ;; 00000000: 5a 36 17 03 6a e5 4b 00 42 30 00 36 00 5f 00 30 |Z6..j.K.B0.6._.0| ;; 00000010: 00 36 00 0f 00 6c 30 00 33 00 33 00 31 00 2e 00 |.6...l0.3.3.1...| ;; 00000020: 6d 00 00 00 70 00 33 00 01 69 00 73 00 62 00 77 |m...p.3..i.s.b.w| ;; 00000030: 00 5f 00 0f 00 6c 73 00 70 00 65 00 63 00 69 00 |._...ls.p.e.c.i.| ;; 00000000: 61 00 00 00 6c 00 30 00 49 53 42 57 5f 53 7e 31 |a...l.0.ISBW_S~1| ;; 00000010: 4d 50 33 20 c9 8e 8e c9 8e 8e c9 8e e3 00 f7 a6 |MP3 ............| ;; 00000020: 5a 36 47 04 d7 32 9e 00 42 30 00 36 00 30 00 34 |Z6G..2..B0.6.0.4| ;; 00000030: 00 30 00 0f 00 c8 35 00 2e 00 6d 00 70 00 33 00 |.0....5...m.p.3.| ;; 00000000: 00 00 00 00 ff ff ff ff 01 69 00 73 00 62 00 77 |.........i.s.b.w| ;; 00000010: 00 5f 00 0f 00 c8 73 00 68 00 6f 00 77 00 30 00 |._....s.h.o.w.0.| ;; 00000020: 33 00 00 00 30 00 5f 00 49 53 34 41 38 41 7e 31 |3...0._.IS4A8A~1| ;; 00000030: 4d 50 33 20 c9 8e 8e c9 8e 8e c9 8e e3 00 47 a8 |MP3 ..........G.| ;; 00000000: 5a 36 c0 06 0b 4b 60 01 42 30 00 36 00 30 00 34 |Z6...K`.B0.6.0.4| ;; 00000010: 00 31 00 0f 00 6c 30 00 2e 00 6d 00 70 00 33 00 |.1...l0...m.p.3.| ;; 00000020: 00 00 00 00 ff ff ff ff 01 69 00 73 00 62 00 77 |.........i.s.b.w| ;; 00000030: 00 5f 00 0f 00 6c 73 00 68 00 6f 00 77 00 30 00 |._...ls.h.o.w.0.| ;; 00000000: 33 00 00 00 31 00 5f 00 49 53 42 57 5f 53 7e 31 |3...1._.ISBW_S~1| ;; 00000010: 4d 50 33 20 c9 8e 8e c9 8e 8e c9 8e e3 00 dc a6 |MP3 ............| ;; 00000020: 5a 36 42 0c b5 aa 3b 01 42 30 00 36 00 30 00 34 |Z6B...;.B0.6.0.4| ;; 00000030: 00 31 00 0f 00 f8 36 00 2e 00 6d 00 70 00 33 00 |.1....6...m.p.3.| ;; 00000000: 00 00 00 00 ff ff ff ff 01 69 00 73 00 62 00 77 |.........i.s.b.w| ;; 00000010: 00 5f 00 0f 00 f8 73 00 68 00 6f 00 77 00 30 00 |._....s.h.o.w.0.| ;; 00000020: 33 00 00 00 32 00 5f 00 49 53 30 39 45 33 7e 31 |3...2._.IS09E3~1| ;; 00000030: 4d 50 33 20 c9 8e 8e c9 8e 8e c9 8e e3 00 7a a7 |MP3 ..........z.| ;; 00000000: 5a 36 31 11 13 db bf 02 2e 40 0a 24 02 63 06 0d |Z61......@.$.c..| ;; 00000010: e0 00 50 40 c6 00 00 07 30 08 00 0a 00 14 59 04 |..P@....0.....Y.| ;; 00000020: 40 88 10 00 a6 20 c0 31 0b 54 82 48 04 18 81 21 |@.... .1.T.H...!| ;; 00000030: 03 ac 00 80 11 0c 0b 10 82 21 00 88 41 22 01 00 |.........!..A"..| ;; Select external card: ;; 00000000: 23 00 06 3a 53 47 00 68 2e 00 00 00 00 00 00 00 |#..:SG.h........| ;; 00000010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| ;; 00000020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| ;; 00000030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| ;; Sending directory request: ;; 00000000: 07 d0 00 00 06 d8 40 00 42 30 00 36 00 30 00 34 |......@.B0.6.0.4| ;; 00000010: 00 32 00 0f 00 6c 33 00 2e 00 6d 00 70 00 33 00 |.2...l3...m.p.3.| ;; 00000020: 00 00 00 00 ff ff ff ff 01 69 00 73 00 62 00 77 |.........i.s.b.w| ;; 00000030: 00 5f 00 0f 00 6c 73 00 68 00 6f 00 77 00 30 00 |._...ls.h.o.w.0.| ;; 00000000: 33 00 00 00 33 00 5f 00 49 53 42 57 5f 53 7e 31 |3...3._.ISBW_S~1| ;; 00000010: 4d 50 33 20 03 e7 d1 02 00 8e c9 8e e3 00 f1 a6 |MP3 ............| ;; 00000020: 5a 36 02 00 74 de f4 00 2e 30 00 33 00 5f 00 30 |Z6..t....0.3._.0| ;; 00000030: 00 36 00 0f 00 e3 30 00 33 00 32 00 38 00 2e 00 |.6....0.3.2.8...| #| (defparameter *dev* (open "/proc/bus/usb/002/001" :direction :io :if-exists :overwrite)) (usb-claim-interface *dev* 0) (han14xs-read-directory *dev* :internal) |# ;;; EOF