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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
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.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
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.