Gaming, Software

DSx86

Every now and then I come across something that I can’t believe someone has taken the time to write.

In this case, it’s a DOS emulator for the Nintendo DS, the DSx86.

As if there weren’t enough options for extending the DS (homebrew, NES emulation), one man has taken it upon himself to write a DOS emulator for the DS. It will run most games that run on a 286/386, with some caveats. Not all the opcodes have been written in yet, and sound blaster support requires a little bit of finesse. But it’s under active development, which is exciting.

You load a game the same way you did back in the day… from the command line. Since the DS doesn’t have a keyboard, DSx86 includes one for you on the touch screen. It’s hilariously adorable.

Once the game is loaded you can either continue to use the “keyboard” or swap screens so that your game is shown in the touchscreen and you can use the stylus as a mouse. Holding down left/right on the d-pad to click took a bit of getting used to. There’s also a tap-to-click mode, but I found it difficult to use for gaming. It was a good illustration of how programs not designed for a touchscreen can be infuriating to use on one. Because most DOS games run at a slightly larger resolution than the DS, you have the option of either panning or resizing the screen. I found panning to be the most useful, and all it really cut off was the title/menu bar at the top.

Seeing the old Sierra logo along with the MIDI-tastic intro music on the DS was ridiculous and awesome. I’m just about finished my 20th or so lifetime play through of The Island of Dr. Brain. If you’re dying to take some of your old DOS games with you (you did save them all, right?) , check the compatibility list and give DSx86 a try.

Hacking

Numb3rs: "I Speak Leet"

Now I know how all my doctor friends feel watching medical dramas. I don’t know which is better, the completely incomprehensible analogy used for  IRC channels, or the notion that anyone over the age of 12 uses leetspeak. Either way, I can’t wait to get back to decoding backdoors. Like you do.

I had to double check to make sure it wasn’t Sandra Bullock.

Business

Coworking at Home

Earlier this month I found myself going stir-crazy being at home by myself all the time. Anyone who works in an office might thing I’m crazy – a space all to yourself away from your irritating coworker sounds amazing! But freelancers and other solo business owners know what I’m talking about.

I looked into the various coworking spaces in the area, and found them to all be a bit more than I was willing to spend or a bit farther than I was willing to travel. Instead, I reorganized my office out of the living room and into the spare bedroom. Now in order to work, I have to leave my toys, and when I’m downstairs relaxing I can’t be trying to sneak work in.

But it’s still a bit depressing to go sit in the spare bedroom by myself all day every day. So today a friend of mine who is a fellow freelancer came by for some home-based coworking. And it was all in all a success. There are a couple things that I think helped contribute to the usefulness, and some things we probably should have done:

Get off the couch

Being able to work from the couch, or bed, or hammock, is one of the perks of being self-employed. And while it’s great for a change of scenery, it’s not the most productive setting for most people. You probably already have a desk, but official canadian pharmacy make sure your guest coworker has a chair and a table on which to work.

Your coworker should not have to fight for space.

Clear a workspace for your friend

No one wants to work on the corner of your dining room table, sandwiched between your to-be-filed bills and that box of Christmas ornaments you keep forgetting to put away. Find a space you can clear off, where your friend can work comfortably without feeling cluttered. They should have enough room for their laptop and a mouse, and maybe even a real monitor if they so desire.

Have some snacks handy

Keeping some snacks and drinks on hand will reduce the temptation to go out for food, something companies like Google figured out long ago. Carrots, grapes, rice cakes, yogurt, and trail mix are all good to have around. Messy snacks like cheetos, oranges, and other things likely to get on your hands are less ideal. If you do decide to stock the fridge with snacks to share, let your friend know where they are, along with cups/plates, so they don’t have to bug you every time they want a glass of water.

Shut up

If you’re working with a good friend, it’s tempting to socialize instead of work. A few quick conversations is fine, but you really should let each other get things done. If the temptation to gossip is too strong, consider setting up your work stations so you don’t face each other.

Set a quitting time

Don’t let your friend be an enabler to bad work habits. And yes, working all night long is a bad habit. Your life needs some balance. Pick a time for your work day to end, at which point both of you should leave your office (or convert it back to the living room it was before). If you want to go out later for drinks or whatnot, letting your guest go home to have dinner, do a load of laundry, etc will keep their day from feeling super long.

Wedding

Reflections on the Whole Wedding Thing

First off, this post isn’t about LEGOs or code, it’s about my personal life, so if you’re just here for the bits and bytes you can skip it.

Folks may or may not know that at the end of April I became engaged to my wonderful boyfriend Chris aka RevolvingDork.

I used to ask my mom what her dream house would be like, and she’d reply “I don’t dream about houses.” I thought this was a weird response until I started looking at wedding stuff. And realized… I don’t dream about weddings. And at first, navigating the behemoth that is the wedding industry seemed very daunting and off-putting. I positioned myself squarely as the anti-bride, determined to have the smallest wedding possible with the least amount of drama.

When it turned out Chris wanted what I kept referring to as “a big stupid wedding,” well, it became clear I was going to need a bit of an attitude adjustment. What’s happened since then, in regard to the wedding and all that it encompasses, has been really interesting and not at all what I expected (in a good way!).

Continue reading “Reflections on the Whole Wedding Thing”

Crafting, lased, LEGO

Meta Lego Storage

In need of a way to organize and store my Lego obsession, I made a bunch of acrylic boxes which not only hold Legos, but also stack and interlock similarly:

Each brick box holds 64+ of the same-shape piece. So the 1×1 box will hold 64 1×1 bricks, and the 2×2 holds 64 2×2 bricks. The larger ones hold a few more due to how the sizing works out. The 1×1 box is 40mm per side (external dimensions).

I posted the patterns on Thingiverse should anyone wish to make their own. No,  I’m not going to make and sell them. They’re time consuming to make, and plus I’m pretty sure Lego would sue me. If you don’t have access to a laser cutter, I’d suggest using a service like Ponoko.

The patterns were generated in OpenSCAD using the following code. Change “rows” and “cols” to get the lego size you desire. By the way, I’m teaching a class on OpenSCAD in Brooklyn next weekend!

fundamental_unit = 0.8;
thickness =3;
h_pitch = 10;
v_pitch = 12;
tform = 5;
knob = fundamental_unit*h_pitch*tform;
module side(rows){
	lwidth = rows*fundamental_unit*h_pitch*tform;
	lheight = v_pitch*fundamental_unit*tform;
	difference() {

		square(size=[lwidth, lheight]);
		translate(v=[10,0,0]) square(size=[lwidth-20,thickness]);
		translate(v=[10,lheight-thickness,0]) square(size=[lwidth-20,thickness]);
		square(size=[thickness, 10]);
		translate(v=[0,lheight-10]) square(size=[thickness, 10]);
	translate(v=[lwidth-thickness,10]) square(size=[thickness, lheight-20]);
	}
}
module top(rows,cols,holes){
	lwidth = rows*fundamental_unit*h_pitch*tform;
	llength = cols*fundamental_unit*h_pitch*tform;
	difference(){
		square(size=[lwidth,llength]);
		square(size=[thickness,10]);
		square(size=[10,thickness]);
		translate(v=[lwidth,0,0]) square(size=[-thickness,10]);
		translate(v=[lwidth,0,0]) square(size=[-10,thickness]);
		translate(v=[lwidth,llength]) square(size=[-10,-thickness]);
		translate(v=[lwidth,llength]) square(size=[-thickness,-10]);
		translate(v=[0,llength]) square(size=[10,-thickness]);
		translate(v=[0,llength]) square(size=[thickness,-10]);
		if(holes==true){
			for (i = [1:cols]){
				for (j=[1:rows]){
				translate(v=[j*knob-knob/2,i*knob-(fundamental_unit*h_pitch*tform)/2,0]) circle(r=fundamental_unit*6*tform/2);
				}
			}
		}
	}
}

rows = 2;
cols = 4;

h_spacing =  rows*fundamental_unit*h_pitch*tform+10;
l_spacing =  cols*fundamental_unit*h_pitch*tform+10;
v_spacing = fundamental_unit*v_pitch*tform+10;

side(rows);
translate(v=[ rows*fundamental_unit*h_pitch*tform+10,0,0]) side(rows);
translate(v=[0,v_spacing]) side(cols);
translate(v=[ cols*fundamental_unit*h_pitch*tform+10,v_spacing]) side(cols);
translate(v=[0,2*v_spacing]) top(rows,cols,true);
translate(v=[ rows*fundamental_unit*h_pitch*tform+10,2*v_spacing]) top(rows,cols,false);

In the next batch I’m going to make the nubs a little smaller than the holes. They work now, but it’s a bit fiddly getting everything to line up just so. A little more forgiveness would be nice. Also, OpenSCAD does strange things with circles. Rather than simply write a circle in the DXF, it represents it as a bunch of line segments. I’m not sure if there’s a way around this, but it’s marginally irritating.

You can download a .dxf for a few different box sizes on Thingiverse.
I’ve also created a Flickr Collection for my various Lego stuff.

Meta Lego

Personal

I’m Sorry Nintendo, What?

This morning Nintendo had their keynote at E3, unveiling the new 3DS. As part of the event, they had an army of models bring 3DS units into the audience, to let people get up close with the hot new hardware.

Look carefully at the image. All the models are women. All of them. I looked through as much footage of the keynote as I could find, and I can’t find a single dude in that group.

I’m generally the last person to get up in arms about stuff like this. But really, what the fuck Nintendo. Wake up. Women play games. Women design games. Women produce games. Women write games. And while the audience at E3 undoubtedly skews male, is that really an excuse to use women exclusively as furniture at your press events? It says a lot to me that the only women on that stage are there as set dressing. Specifically, it tells me I don’t want to buy your products. It upsets me on  a deep level to see this sort of BS from a company I like and have spent thousands of dollars with over the years.

Look, I’m not trying to funnel all of feminism into this one photo, or say that it’s not OK to have hot women hawking your stuff. I’ve got no problem with hiring attractive people to show off your products. It’s marketing and it works. But the number of women interested in gaming has exploded lately. And I’ll let you in on a secret: you don’t have to paint everything pink and brand it with Lady Gaga to market to us. You just need to stop acting like we don’t exist.

Update: A few folks have asked, why get upset about just this. Why not booth babes (a staple of industry events for god knows how long) as well? After talking it out with my fiancee, who doesn’t quite get what I’m so up in arms about, he summed it up pretty well:

so the scale of the model force needed highlights the fact that it could not possibly have been an oversight to include men … [making it] worse than the average smaller scale promotion where the gender preference is merely implied.

Yeah, that’s about right. After all, I find it hard to believe that LA has a shortage of male and female models looking for work.

Wedding

Kellbot Plans a Wedding

Folks may or may not know that at the end of April I became engaged to my wonderful boyfriend Chris aka RevolvingDork.

I used to ask my mom what her dream house would be like, and she’d reply “I don’t dream about houses.” I thought this was a weird response until I started looking at wedding stuff. And realized… I don’t dream about weddings. And at first, navigating the behemoth that is the wedding industry seemed very daunting and off-putting. I positioned myself squarely as the anti-bride, determined to have the smallest wedding possible with the least amount of drama.

When it turned out Chris wanted what I kept referring to as “a big stupid wedding,” well, it became clear I was going to need a bit of an attitude adjustment. What’s happened since then, in regard to the wedding and all that it encompasses, has been really interesting and not at all what I expected (in a good way!).

Continue reading “Kellbot Plans a Wedding”

Programming, Software

Fixed: WordPress MU Uploaded Image Display Issues

Just a quick fix for something I couldn’t discount cialis without prescription find earlier:

If you’re on shared hosting which has PHP’s safe_mode enabled, you may run into problems with uploading images. Specifically, you can upload images just fine (assuming you’ve configured uploads correctly) but can’t see uploaded files. This is the case on NearlyFreeSpeech.Net (where my sites are hosted), and probably a few other hosts as well.

WordPress MU uses some .htaccess & PHP tomfoolery to obfuscate the real file path (among other things). Because safe_mode checks to see if the UID/GUIDs match on file_exists(), the script that fetches the images will fail and return a 404. Which is to say, the owner/group of the uploaded file is web/web (or whatever your server’s web user is), but since I manually uploaded the WPMU files originally, those are me/me. Since me != web, it failed. WordPress took this to mean the file was absent and returned 404.

On NearlyFreeSpeech, adding wp-content/blogs.php to the ‘web’ group was all it needed.

Software

Success!

Now that I have a few more runs worth of data, I was able to pick a little bit of information out of the miCoach binaries.

There are 40 EXRCS001.BIN files on the device (after the data has been unpacked), each one corresponding to an individual workout. This means you can store up to 40 workouts before you need to sync the device again. Knowing that, I had a bit of a better idea what I was looking at.

The miCoach pacer records various data points periodically – every few seconds as far as I can tell. The record length for these data points is 14 bytes. So far we have:
0x1E – row number, increments one each row
0x21 – distance
0x23 & 0x24 – Not sure exactly what the values are, but these dropped to 0 at a point where I paused the pacer and the miCoach graph shows a stride/pace of 0
0x25 – stride rate
0x26 – same situation as 0x23 and 0x24
0x27 – heart rate
0x28 – Not sure what this is, but it’s the same for each row
0x29 – time in. I think this is in seconds, but I’m not sure. It goes up by 5 each record.

At the start of the file, from 0x07 to 0x10, is a bunch of data that I suspect to be the date but haven’t figured out an obvious format. For my workout on 5/20/2010 9:58am, the hex values are 01 5A 4F B4 3C A7 53 B4 3C 24 8C

Yay progress!

Programming

Extracting + Graphing Wii Fit data

In preparation to tinker with the miCoach data, I started with some better-travelled exercise bits: WiiFit body test data. Starting with Jansen Price’s excellent blog post on the subject, I slowly worked through the data and wrote a python script to interpret the binaries and save them to a CSV. By using the excellent flot javascript library, I was able to generate the nice graph above. There was a lot of trial and error, but here’s an overview of the process:

  1. Copy Wii save game data to the SD card. This is done from Wii Options > Data Management > Save Data > Wii
  2. Find the save game data on the card. It’s in something like ‘private/wii/title/RFPE’, although different regions may have slightly different codes. RFPE is the code for WiiFit Plus. Copy the WiiFit data.bin file from the SD card to your local machine.
  3. Decrypt data.bin. This is explained pretty well here. To create the keys I ended up creating text files with the hex string for each and then using “xxd -r -p sd_iv_hex sd_iv” et al to save a binary version. If you’re getting “MD5 mismatch” errors, you probably saved the keys incorrectly. If you aren’t sure, check the file size. They should be 16 bytes each.
  4. Run the decrypted RPHealth.dat through a parser (I wrote one in Python for this)
  5. Run the CSV through your favorite graph generation library. I use flot because Google Charts don’t handle dates very well.

Thanks to Jansen’s handy chart of which bits are where, writing the parser was pretty easy. This isn’t the most elegant code I’ve ever written, but it gets the job done:

import struct
import string
import csv

mii = 0
#we know that each record is 0x9271 bytes long
record_length = 0x9281

record_start = 0

#path to WiiFit data file
infile = 'RPHealth.dat'

FH = open(infile, 'rb');

## It loops through 7 profiles, because I happen to know I have 7.
## A better approach would be to go to the end of the file, of course.
while (mii < 7):

    #go to the start of the current record
    FH.seek(record_start)

    #read the first 30 bytes (header + name)
    line = FH.read(30)

    #for some reason names are stored as N a m e instead of Name.
    #Throw away the header any extranous spaces
    data = struct.unpack("i",line)
        #bit shift to get the month, day, and year. Could also get time if you wanted.
        year = data[0] >> 20 & 0x7ff
        month = data[0] >> 16 & 0xf
        day = data[0] >> 11 & 0x1f

        #break the loop if the date comes back 0
        if(year == 0): break

        #format the date into something humans like to read
        date = str(int(year)) + '-' + str(int(month)+1) + '-' + str(int(day))

        #the next three sets of 2 byte data represent weight, BMI, and balance
        line = FH.read(17)
        data = struct.unpack(">3H",line[0:6])

        recordWriter.writerow([date] + [data[0]] + [data[1]] + [data[2]])

    #now that we're done with the record, advance to the start of the next one
    record_start = record_start + record_length

    mii = mii+1

You can download a copy of it here.