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.
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
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!