Well, I see my last post attracted some interesting comments and I'd like to follow up with just another Python thought. While some still like to relegate Python, Perl, Ruby to the niche of 'scripting languages' we should be clear that there are some very complex applications out there written, and maintained, in these languages.
So, this week I received my nice new laptop, a ThinkPad T60p which I found out has a nice feature - the Active Protection System or a set of accelerometers that protect the hard drives from shock. So, being curious I found out that yes, you can access the data from the driver that manages the accelerometer programmatically... using IOCTLs.
Well, this doesn't sound like the usual realm for a scripting language, but I've seen others manage physical devices in both Perl and Python so why not. Some Google searches later gave me some .NET code that accessed the driver and away I went. Firstly I had to use the Python Win32 package to access the Windows API, but the rest was pretty simple and my first quick hack turned into a fairly usable module in quick time.
""" This module implements a (Windows only) interface to the IBM/Lenovo ThinkPad Active Protection System (APS). The APS uses an accelerometer to monitor the motion of the ThinkPad and to stop the hard drives when the motion indicates that possible sudden movement may damage them. The module provides a simple class that allows the user to read the status and X/Y positions indicated by the device driver.
Classes: ShockSensor """
__author__ = 'Simon Johnston (firstname.lastname@example.org)' __version__ = '1.0'
import win32file from win32con import * import struct
class ShockSensor: """ This is the only class provided by the module and acts as the programmer API to the ShockMgr device driver. """ STATUS_RUNNING = range(0, 4) STATUS_STOPPED = range(8, 9) STATUS_AUTO_IGNORE = range(13, 13) def __init__(self): """ Initialize an instance of ShockSensor. """ self.hDevice = None
def open(self): """ Open access to the device driver, this must be called before trying to read values from the driver. """ self.hDevice = win32file.CreateFile(r'//./ShockMgr', GENERIC_READ, FILE_SHARE_READ, None, OPEN_EXISTING, 0, 0)
def read(self): """ Read the current data from the driver, note that most users will want to use the status(), X() and Y() methods rather than accessing the raw buffer directly. """ state = None if self.hDevice: data = win32file.DeviceIoControl(self.hDevice, 0x733FC, '', 0x24, None) state = struct.unpack('i16h', data) return state
def status(self): """ Return the status of the hard drives, this status is set by ShockMgr based upon the accelerometer readings. """ if self.hDevice: return self.read()
def X(self): """ Return the value of the accelerometer in the X axis. """ if self.hDevice: return self.read()
def Y(self): """ Return the value of the accelerometer in the Y axis. """ if self.hDevice: return self.read() def close(self): """ Close the handle we use to read from the device driver. """ if self.hDevice: self.hDevice.Close() self.hDevice = None
So, how does this work? well the code below demonstrates it quite nicely and will loop reading the status of the accelerometers and showing their values (I put this in a loop so you can tilt your ThinkPad and watch the values change).
import time sensor = ShockSensor() sensor.open() for i in range(10): status = sensor.status() if status in ShockSensor.STATUS_RUNNING: status_str = 'Running' elif status in ShockSensor.STATUS_STOPPED: status_str = 'Stopped' elif status in ShockSensor.STATUS_AUTO_IGNORE: status_str = 'Running (Auto-Ignore)' else: status_str = str(status) print 'Status=%s; X=%d; Y=%d' % (status_str, sensor.X(), sensor.Y()) time.sleep(1) sensor.close()
So for all the Python programming ThinkPad users out there - enjoy.