using System; using System.Runtime.InteropServices; // A simple command-line application that demonstrates how // a C# .NET application can access basic sensor data from // the accelerometer present on many Thinkpad laptop computers. // The sensor.dll library is used by the // "Thinkvantage Active Protection System" task tray application // and provides a basic API. // // This sample application first attempts to print the current system // time, demonstrating access from C# to system functions in Kernel32.dll // via the DllImport annotation. // // Then we invoke a method on the sensor.dll API to read the current // accelerometer sensor data and print this data, which includes the // status of the protection mechanism and the x and y acceleration. // Another method is used to retrieve only the current status and we // provide a way to convert this status code to meaningful text. // Finally we initiate a loop that prints the sensor data once per second // (or as otherwise specified via a command-line argument), until the // application is terminated by the user. // // by Ben Suter (bsuter@stanfordalumni.org) March 2007 namespace ApsDemo { class Win32 { [DllImport("Kernel32.dll")] public static extern void GetSystemTime(ref SystemTime sysTime); [StructLayout(LayoutKind.Sequential)] public struct SystemTime { public ushort wYear; public ushort wMonth; public ushort wDayOfWeek; public ushort wDay; } } class APS { [DllImport("sensor.dll")] public static extern void ShockproofGetAccelerometerData(ref AccData accData); [DllImport("sensor.dll")] public static extern void ShockproofGetShockStatus(ref ShockStatus shockStatus); [StructLayout(LayoutKind.Sequential)] public struct AccData { internal int status; internal short x; internal short y; } [StructLayout(LayoutKind.Sequential)] public struct ShockStatus { internal int status; } // Note: I believe the status reported by the shock sensor can be interpreted as: // 0 - 4: running, 8 - 9: stopped, 13: auto-ignore // (see http://www-03.ibm.com/developerworks/blogs/page/johnston?entry=python_and_thinkpad) public static Status convertStatusCode(int statusCode) { if (statusCode >= 0 && statusCode <= 4) return Status.Running; else if (statusCode == 8 || statusCode == 9) return Status.Stopped; else if (statusCode == 13) return Status.AutoIgnore; else return Status.Undefined; } public enum Status { Running = 0, Stopped = 1, AutoIgnore = 2, Undefined = 3 } } class ApsDemo { static void Main(string[] args) { int millisToSleep = 1000; if (args.Length > 0) { String unparsed = args[0]; int parsed = Int32.Parse(unparsed); if (parsed > 100) millisToSleep = parsed; } report("Live Accelerometer Data"); report("A demonstration program by Ben Suter (bsuter@stanfordalumni.org) 2007"); report(""); report("Calling GetSystemTime in Kernel32.dll"); Win32.SystemTime sysTime = new Win32.SystemTime(); Win32.GetSystemTime(ref sysTime); report("System Time is: {0}-{1}-{2}", sysTime.wYear, sysTime.wMonth, sysTime.wDay); report(""); report("Calling method ShockproofGetAccelerometerData in sensor.dll"); APS.AccData accData = new APS.AccData(); APS.ShockproofGetAccelerometerData(ref accData); report(" accData.status: {0}", accData.status); report(" accData.x: {0}", accData.x); report(" accData.y: {0}", accData.y); report(""); report("Calling method ShockproofGetShockStatus in sensor.dll"); APS.ShockStatus shockStatus = new APS.ShockStatus(); APS.ShockproofGetShockStatus(ref shockStatus); report(" shockStatus.status: {0}", shockStatus.status); int s = shockStatus.status; APS.Status st = APS.convertStatusCode(s); report(" Status code converted to operational state: {0}", st.ToString()); report(""); report("The sensor data will now be printed every {0} milliseconds.", millisToSleep); report("The default period is 1000 milliseconds. To change this, "); report("you can pass in a command-line argument (in ms). You can use "); report("CTRL-C to exit the application, or press the Pause and Enter "); report("keys to pause and resume."); report(""); report("[X,Y,StatusCode,Status]"); report(""); APS.AccData data = new APS.AccData(); APS.Status status; while (true) { APS.ShockproofGetAccelerometerData(ref data); status = APS.convertStatusCode(data.status); report("[{0},{1},{2},{3}]", data.x, data.y, data.status, status.ToString()); System.Threading.Thread.Sleep(millisToSleep); } } static void report(String msg, params Object[] args) { System.Console.WriteLine(msg, args); //System.Diagnostics.Debug.WriteLine(msg, parameters); } static void report(String msg) { report(msg, new Object()); } } }