Tag: thinkpad sensor

(PB) Using the Thinkpad Accelerometer

Posted by on January 29, 2013

So I recently got a proper Thinkpad and I was wondering how to interface with the accelerometer to obtain data from it. First of all, I had a look around and it seems the ADXL320 is used in most models, it’s a Low Power, 3-Axis ±5 g MEMS Accelerometer manufactured by Analog Devices.

There are, at least on Windows, two possible interfaces. One is through a device manager, the other is directly through a DLL exposed by Lenovo.

I had yet another look around and found a few snippets in C# by Ben Suter. Decided to port the code and give it a go, instead of looking any further. Despite the fact that I had already exported the function names of the DLL (using my good ol’ dllspyr) I just couldn’t bother looking any further. I had to add the z value, since it was originally ignored. Perhaps because previously a mere 2 axis tilt sensor was used?

The other method involves getting a handle of “ShockMgr” with createFile(); setting up by DeviceIoControl(); and then reading through the data. This makes it easier to validate if the “service” is available, because the DLL could be exposed but non functional, for example.

Da codez:

Here’s the preliminary test code, implementing a crude alarm system:

Structure ACCDATA
  status.i
  x.w
  y.w
  z.w
EndStructure

Structure SHOCKSTATUS
  status.i
EndStructure

Enumeration 
  #SHOCKSTATUS_RUNNING
  #SHOCKSTATUS_STOPPED
  #SHOCKSTATUS_AUTOIGNORE
  #SHOCKSTATUS_UNDEFINED
EndEnumeration

Prototype.i pShockproofGetAccelerometerData( *AccData.ACCDATA )
Prototype.i pShockproofGetShockStatus( *ShockStatus.SHOCKSTATUS )


If OpenLibrary(0, "Sensor.dll")
  
  ShockproofGetAccelerometerData.pShockproofGetAccelerometerData = GetFunction(0, "ShockproofGetAccelerometerData")
  ShockproofGetShockStatus.pShockproofGetShockStatus = GetFunction(0, "ShockproofGetShockStatus")
  
  Define.ACCDATA old_data, new_data
  ShockproofGetAccelerometerData( old_data )
  
  Define.i triggered = #False
  Repeat
    
    Delay(200)
    
    ShockproofGetAccelerometerData( new_data )
    
    If Not CompareMemory( old_data, new_data, SizeOf(ACCDATA) ) Or triggered
      triggered = #True
      Beep_(1000, 1000)
    EndIf
    
  ForEver
  
  CloseLibrary(0)
EndIf

The status code is interpreted by another function, which I’m not using at the moment but the author had guessed the threshold values and addressed a name for each, from the known possible states exposed by Lenovo.

Procedure.i convertStatusCode( statusCode.i )
  
  If statusCode >= 0 And statusCode < = 4
    ProcedureReturn #SHOCKSTATUS_RUNNING
  ElseIf statusCode = 8 Or statusCode = 9
    ProcedureReturn #SHOCKSTATUS_STOPPED
  ElseIf statusCode = 13
    ProcedureReturn #SHOCKSTATUS_AUTOIGNORE
  Else
    ProcedureReturn #SHOCKSTATUS_UNDEFINED
  EndIf
  
EndProcedure

What now?

I'm going to clean up the code and start making use of this feature, I mean, why not?

As for a proper alarm, you'd have to manage the mute and volume settings plus instead of comparing against the baseline values you'd have to implement a threshold. I'm aware that they've issued an application that does exactly this, but I'm not a fan of big resident bloatware -- plus where's the fun in that?

Anyway, that's all for now!
Cheers.