OCZ NIA hacking, now with Python!
Monday 25 May 2009 at 15:45.
Tags: code, eeg, emg, hacking, libraries, modules, ocz_nia, python, reverse_engineering, usb
Disclaimer the second: Where applicable, I've given credit for and linked to the work of others. I've independently discovered a few things that others have already figured out, so one or two things may not be attributed. In that case, please let me know and I'll put a reference where applicable.
Over the past few weeks I've been playing with my OCZ NIA on and off. My first attempt at getting anything out of it involved recompiling Windbringer's kernel with HID debugging and /dev/hidraw device support to maximize my chances of having a device node to play with. As far as I can tell these are probably unnecessary because when you plug in the NIA device nodes under /dev appear and some of them will emit binary when you read from them. While you can `cat` from the device node you won't get much from it. After running niasnoop (which defaults to maximum debugging output) it automatically found my NIA at device node /dev/bus/usb/005/002 and started pulling data from it, just as it's supposed to do.
Using niasnoop I captured a couple of megabytes of data in a text file and stared at it for a while in an attempt to gain more insight into the format of the data stream, only to no avail. I then got the bright idea to check out the OCZ forums again, and there discovered that someone called dr-mephisto had written a Python module that hooks into libusb and makes it possible to write apps in Python that read data from the NIA, thus beating me to the punch by a few weeks (realistically speaking, probably a few months). PyNIA has a few dependencies that have to be met before you can use it - the aforementioned libusb, Pyglet, pyusb, and numpy to provide the signal analysis algorithms. These dependencies are pretty easy to satisfy; you can probably pull what you need from your distribution's package repository (unless you're running Python on Windows or Mac OSX, in which case you're on your own). PyNIA seems pretty straightforward in how it works - it walks the USB buses and enumerates all connected devices to locate a NIA (which has to be plugged in before you try to do anything with it). The module implements an NIA_Interface() object which knows what it's looking for and can configure and calibrate itself. It also exposes the usual methods, like open(), close(), and read(), but these are actually for the benefit for the other half of the module. The class NIA_Data() is the one that you actually interact with when you write your own code. It takes the output from the NIA, runs a Fourier analysis against it to extract the six channels of signal data, and spawns threads which read one second of data each to make available for use while continuing to read in the background for near-realtime operation. PyNIA also generates waveform data suitable for use with OpenGL, incidentally.
The key to the object is the method NIA_Data.fingers(), which returns a list of six signed floating point values that represent the six channels of signal data picked up from the person wearing the headband. Everything can be done in the context of a simple loop:
my_nia.process()
array = my_nia.fingers()
for channel in range(len(array)):
my_process.do_stuff(my_nia.fingers()[channel])
(Note: The
HTML tag doesn't seem to display indentation the way it's supposed to. It's Python, so hit the space bar a few times and you should be okay.)If you poke around on the forums there is some proof of concept code written in Python floating around which implements a simple EEG/EMG using wxPython and a bunch of slider controls for visualization. With only a little work you can do pretty much whatever you want with the values returned from the NIA_Data.fingers() method.
To see if I could do it (and to have an excuse to play around with Python) I wrote a simple utility that prints the six channels of data to standard out as long as the NIA's plugged in and transmitting data. I've found that once in a while the utility will throw an exception and error out, and I think it's due to a synchronization glitch with the NIA: if PyNIA tries to read a packet of data from the USB subsystem but gets only a partial packet because it reads in the middle of a burst rather than at the beginning, it can't make sense of the data and falls over. Just try running the utility again and everything should be fine. I figured out how to do it by reading through dr-mephisto's hellonia.py application from the forums six or seven times; I've made it as simple as I possibly could and have it still have it do something useful. Between that and dr-mephisto's hellonia.py, you should be able to figure out how to write code for the NIA.
nia_number_dumper.zip - download it!
Fight Spam! Click Here!
nine comments.
Seems like a fair enough description to me. I hope you like my code :) I started learning python about half a year ago or maybe a bit more, and pynia is the first code I have released (as you could probably tell if you compare pynia-0.0.1 to pynia-0.0.2).
Dont get too caught up with brainfingers though; I am not convinced that looking at individual groups of frequencies is particularly useful. Now I run a PCA over all 40 fourier frequencies, and I’m getting much more interesting data that can be fed intos neural networks etc.
dr-mephesto () - 07-06-’09 10:54[kevin:1] I’ll take a look at that page and use it to rework my demo code a little bit.
Funny – the HTML entity showed up as expected when your comment was e-mailed to me (which is how I keep track of replies).
The Doctor () (URL) - 08-06-’09 21:04[dr-mephesto:3] I love it – you beat me to the punch by at least a couple of months because I was trying to teach myself device driver programming at the same time as Python, which really hamstrung me.
I’ll go over more of the threads on the forums.. I haven’t had much time lately to keep up with them due to work and other stuff going on.
Once again, PyNIA is awesome, and thank you for writing it.
The Doctor () (URL) - 08-06-’09 21:06[The Doctor:5]
BTW, the only dependency for pyNIA is pyusb and numpy. Pyglet is only used in the “name == main:” section for a demo on what the code can do. Also, a lot of the stuff in the process method can be dropped if speed is needed; the hanning window stuff is just for filtering out the 50/60 hz power hum and useless high frequency data so you can make the EEG graph look pretty, and a lot of code is just to transform the data into openGL data for display. Like I said, I wanted to learn python, so I was just trying out stuff for the sake of learning.
dr-mephesto () (URL) - 09-06-’09 17:53Raiijn: No, I haven’t. I got waylaid while teaching myself GUI programming by switching jobs and haven’t updated the code in a while. I also need to fix the download link, I see…
The Doctor (URL) - 12-03-’10 07:27
Try using http://docs.python.org/tutorial/errors.h.. to stop your program falling over. Also, is the html entity for a tab as far as I can tell.
Your code is better than my first foray into python. Really must come up with something to program in python, expand/regain some knowlege.
kevin (URL) - 26-05-’09 03:03