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.
As an extra, here’s the exported function list from Sensor.dll, there’s also a 64bit version by the way.