Un-commit in Git

I just accidentally made a commit in git that I didn’t want – I’d made several changes at once and wanted to commit them separately. Instead I did one big commit so I wanted to get back to a state where I had the uncommitted changes. The methods of undoing a commit (git reset and git revert) dont cut it here, as they just take you back to the previous commit, and lose the changes you made. Here’s what I came up with:

git show > ~/uncommit.patch # Take the commit I just made and store the differences in a patch
git reset --hard HEAD^ # Reset to the previous commit
patch -p1 < ~/uncommit.patch # Re-apply the changes

If you've got some changes that aren't committed yet that you still want to keep, you'll want to do make a second patch from the output of git diff before resetting.

Boogie Board Rip on Linux

I’m fed up of making notes on scrappy bits of paper that I lose, so with some money I got for Christmas I got myself a Boogie Board Rip. I’m not going to do a full-blown review here, but essentially it’s an etch-a-sketch on top of a portable graphics tablet. The graphics tablet bit is battery powered, and converts what you draw to PDF. The PDFs can be accessed by plugging the board into a PC via a Micro USB cable. Some people complain that it’s not very good for drawing, but I only wanted it for writing and it’s great for that.

After using the board for a couple of days I found this piece of software and this blog post. It turns out that as well as appearing as a USB storage device when plugged in, it also appears as a human interface device and spits out a stream of binary (32 bytes of it to be exact) for each event that occurs on the device (button presses, movement of the stylus, etc). With a bit of help from the aforementioned blog post I’ve managed to decode the binary and write a short Ruby script that reports what’s happened each time you do something.

The script as it stands at time of posting is shown below. The latest version is available on github.

begin
    lsusb = `lsusb`
    if lsusb.split("\n").select{|l| l.include? "2047:ffe7"}.count == 0
        raise "Boogie Board Rip not currently connected"
    end

    begin
        dmesg = `dmesg`
        bbdev = dmesg.split("\n").select{|l| l.match "2047:FFE7.*hidraw[0-9]"}.pop.match("(hidraw[0-9]+)").to_s
        raise RuntimeError if bbdev.empty? 
    rescue NoMethodError, RuntimeError
        raise "Boogie Board Rip detected, but device's path could not be determined"
    end

    events = []
    threads = []

    thread = Thread.new do
        board = File.new("/dev/"+bbdev, 'r')
        while true do
            data = board.sysread(32)
            event = Array.new()
            data.bytes { |b| event << b }
            events << event
        end
    end
    threads << thread

    thread = Thread.new do
        previous = Array.new(32, 0)
        current = []
        while true do
            current = events.shift
            next if current.nil?

            if current[10] != previous[10]
                state = current[10]
                pstate = previous[10]
                lock = 32
                erase = 4
                wake = 2
                if (pstate == pstate | lock) && (state != state | lock)
                    puts "Board unlocked"
                elsif (pstate != pstate | lock) && (state == state | lock)
                    puts "Board locked"
                end
                if (pstate == pstate | erase) && (state != state | erase)
                    puts "Erase released"
                elsif (pstate != pstate | erase) && (state == state | erase)
                    puts "Erase Pressed"
                end
                if (pstate == pstate | wake) && (state != state | wake)
                    puts "Wake released"
                elsif (pstate != pstate | wake) && (state == state | wake)
                    puts "Wake Pressed"
                end
            end
            if current[3] != previous[3]
                state = current[3]
                pstate = previous[3]
                detected = 32
                contact = 1
                if (pstate == pstate | detected) && (state != state | detected)
                    puts "Pen Lost"
                elsif (pstate != pstate | detected) && (state == state | detected)
                    puts "Pen Detected"
                end
                if (pstate == pstate | contact) && (state != state | contact)
                    puts "Pen contact lost"
                elsif (pstate != pstate | contact) && (state == state | contact)
                    puts "Pen contact detected"
                end
            end
            cury = current[4]+(current[5]*256)
            curx = current[6]+(current[7]*256)
            prey = previous[4]+(previous[5]*256)
            prex = previous[6]+(previous[7]*256)
            if cury != prey || curx != prex
                puts "Pen moved from ("+prex.to_s+","+prey.to_s+") to ("+curx.to_s+","+cury.to_s+")"
            end    
            previous = current
        end
    end
    threads << thread

    threads.each{ |thread| thread.join}
    
rescue RuntimeError => error
    puts error
end

It’s very rudimentary at the moment, and needs to be run as root so the device can be accessed, but hopefully with a bit more hacking I’ll be able to get something graphical up and running. It also strikes me that you should be able to use the Boogie Board like a Wacom tablet if someone would be good enough to write a device driver. It’s a bit beyond me but the information’s pretty much all there in the script!