rlm@68: (ns com.aurellem.vbm rlm@68: (:import java.io.File) rlm@68: (:import org.apache.commons.io.FileUtils)) rlm@68: rlm@68: (defn vbm-bytes [#^File vbm] rlm@68: (let [bytes (FileUtils/readFileToByteArray vbm) rlm@68: ints (int-array (count bytes))] rlm@68: (areduce bytes idx _ nil rlm@68: (aset ints idx rlm@68: (bit-and 0xFF (aget bytes idx)))) rlm@68: ints)) rlm@68: rlm@68: (def button-mask rlm@68: {;; main buttons rlm@68: :a 0x0001 rlm@68: :b 0x0002 rlm@68: rlm@68: ;; directional pad rlm@68: :r 0x0010 rlm@68: :l 0x0020 rlm@68: :u 0x0040 rlm@68: :d 0x0080 rlm@68: rlm@68: ;; meta buttons rlm@68: :select 0x0004 rlm@68: :start 0x0008 rlm@68: rlm@68: ;; hard reset -- not really a button rlm@68: :reset 0x0800}) rlm@68: rlm@68: (defn button-code [buttons] rlm@68: (reduce bit-or 0x0000 (map button-mask buttons))) rlm@68: rlm@68: (defn buttons [mask] rlm@68: (loop [buttons [] rlm@68: masks (seq button-mask)] rlm@68: (if (empty? masks) buttons rlm@68: (let [[button value] (first masks)] rlm@68: (if (not= 0x0000 (bit-and value mask)) rlm@68: (recur (conj buttons button) (rest masks)) rlm@68: (recur buttons (rest masks))))))) rlm@68: rlm@68: (def vbm-header-length 255) rlm@68: rlm@68: (defn repair-vbm rlm@70: "Two 0's must be inserted after every reset." rlm@68: [vbm-seq] rlm@68: (loop [fixed [] rlm@70: pending vbm-seq] rlm@68: (if (empty? pending) fixed rlm@68: (let [mask (first pending)] rlm@68: (if (not= 0x0000 (bit-and mask (button-mask :reset))) rlm@68: (recur (conj fixed mask 0x0000 0x0000) (next pending)) rlm@68: (recur (conj fixed mask) (next pending))))))) rlm@68: rlm@68: (defn vbm-masks [#^File vbm] rlm@68: (repair-vbm rlm@68: (map (fn [[a b]] rlm@68: (+ (bit-shift-left a 8) b)) rlm@68: (partition rlm@68: 2 (drop vbm-header-length (vbm-bytes vbm)))))) rlm@68: rlm@68: (defn vbm-buttons [#^File vbm] rlm@68: (map buttons (vbm-masks vbm))) rlm@68: rlm@68: rlm@68: rlm@68: rlm@68: rlm@68: